Just began to see the source code, a lot of places do not understand deep, this article is suitable as a beginner’s tutorial. Welcome your advice:)
Zero, terms and concepts
1.1 Advisor
-
==Advisor== a combination of ==PointCut==, ==Advice==, is the top-level abstraction of Spring Aop.
-
There are two main inheritance systems: PointCutAdvisor and cloud advisor
-
IntroductionAdvisor: Only applicable to class-level interceptions.
One, the introduction of AOP functionality – AnnotationAwareAspectJAutoProxyCreator
Aop functionality is introduced by @enableAspectJAutoProxy
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
boolean proxyTargetClass(a) default false;
boolean exposeProxy(a) default false;
}
Copy the code
class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
/ / register AnnotationAwareAspectJAutoProxyCreator, see the following code
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
AnnotationAttributes enableAspectJAutoProxy = AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
if(enableAspectJAutoProxy ! =null) {
if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}
if (enableAspectJAutoProxy.getBoolean("exposeProxy")) { AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry); }}}}@Nullable
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, @Nullable Object source) {
/ / register AnnotationAwareAspectJAutoProxyCreator
return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
}
Copy the code
The function of aop is mainly provided by the = = AnnotationAwareAspectJAutoProxyCreator = =, its inheritance diagram is as follows:
Can see AnnotationAwareAspectJAutoProxyCreator BeanPoseProcessor parent. Have postProcessorAfterInitialization BeanPostProcessor interface method, will be called after the bean is initialized.
public interface BeanPostProcessor {
default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
@Nullable
default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
returnbean; }}Copy the code
Second, build advisors that apply to beans
As a wholeThe flow chartAs follows:
Known by the first quarter, the entry for AnnotationAwareAspectJAutoProxyCreator# postProcessorAfterInitailization
AbstractAutoProxyCreator:
= = = postProcessAfterInitialization:public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if(bean ! =null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (this.earlyProxyReferences.remove(cacheKey) ! = bean) {// This method determines whether the bean needs to be proxied
returnwrapIfNecessary(bean, beanName, cacheKey); }}returnbean; } = = = wrapIfNecessary:protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
// Whether the current bean exists in the targetSourcedBeans cache (already processed) or returns if it does
/ / targetSourcedBeans. Add in beforePostProcessInitialization ()
if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
// Beans are aop base classes or should be skipped
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// Attention, see code1
// Action: Get the advisor or advice for the bean
/ / in AbstractAdvisorAutoProxyCreator specific logic
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
// The bean needs to be proxied
if(specificInterceptors ! = DO_NOT_PROXY) {this.advisedBeans.put(cacheKey, Boolean.TRUE);
Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
Copy the code
Code1 – Advisor to obtain the process – AbstractAdvisorAutoProxyCreator# getAdvicesAndAdvisorsForBean
// Find a valid Advisor on the bean
protected List<Advisor> findEligibleAdvisors(Class
beanClass, String beanName) {
/ / this method in AnnotationAwareAspectJAutoProxyCreator subclass implementation
List<Advisor> candidateAdvisors = findCandidateAdvisors();
// Find the advisor in the advisor that applies to the current bean
// See section code2
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
/ / in front of the interceptor chain add ExposeInvocationInterceptor DefaultPointcutAdvisor ADVISOR
extendAdvisors(eligibleAdvisors);
if(! eligibleAdvisors.isEmpty()) { eligibleAdvisors = sortAdvisors(eligibleAdvisors); }return eligibleAdvisors;
}
/ / AnnotationAwareAspectJAutoProxyCreator subclass implementation
protected List<Advisor> findCandidateAdvisors(a) {
// Get advisors' attention
List<Advisor> advisors = super.findCandidateAdvisors();
if (this.aspectJAdvisorsBuilder ! =null) {
advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
}
return advisors;
}
Copy the code
1. findCandidateAdvisors
Then see findCandidateAdvisors () = = the concrete implementation in BeanFactoryAdvisorRetrievalHelper# findAdvisorBeans = =
protected List<Advisor> findCandidateAdvisors(a) {
/ / for advisors
List<Advisor> advisors = super.findCandidateAdvisors();
// Build the advisor for the bean factory
if (this.aspectJAdvisorsBuilder ! =null) {
advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
}
return advisors;
}
Copy the code
2. buildAspectJAdvisors
BeanFactoryAspectJAdvisorsBuilder#buildAspectJAdvisors
:
public List<Advisor> buildAspectJAdvisors(a) {
List<String> aspectNames = this.aspectBeanNames;
/ * * this. AspectBeanNames cache is empty, that is not treated, to perform the following logic * in postProcessBeforeInstantiation into this method, Cache is null * after postProcessAfterInstantiation process, the cache is not null * /
if (aspectNames == null) {
synchronized (this) {
aspectNames = this.aspectBeanNames;
if (aspectNames == null) {
List<Advisor> advisors = new ArrayList<>();
aspectNames = new ArrayList<>();
/* * The object. class argument is used to fetch all beans. * This method is time-consuming, so Spring sets up a caching mechanism here * this.aspectBeannames */
String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.beanFactory, Object.class, true.false);
// Then iterate over the beanName
for (String beanName : beanNames) {
// Skip illegal beanName
if(! isEligibleBean(beanName)) {continue; }
// Get the class information from beanNameClass<? > beanType =this.beanFactory.getType(beanName);
if (beanType == null) { continue; }
// Process classes marked with AspectJ annotations
if (this.advisorFactory.isAspect(beanType)) {
// add cache
aspectNames.add(beanName);
AspectMetadata amd = new AspectMetadata(beanType, beanName);
if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
/ actual type is BeanFactoryAspectInstanceFactory * * * according to beanName beanName, find the corresponding class attribute * class encapsulated into AspectMetadata * /
MetadataAwareAspectInstanceFactory factory = new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
/** * parses the interceptor method to generate the enhancer ** using the beanName in factory, gets its class information, and then * 1. parsing@pointCutOn the expression of encapsulated into AspectJExpressionPointcut * 2. To obtain@Before,@AfterMethods, such as encapsulated into a Method * 3. The above parameters are encapsulated into InstantiationModelAwarePointcutAdvisorImpl, A subclass of the Advisor * * specific implementation in ReflectiveAspectJAdvisorFactory# getAdvisors * in order not to affect the analysis of the overall process, the concrete implementation of this method in the * / at the end of the article
List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
// The singleton directly puts the resolved enhancement method into the cache
if (this.beanFactory.isSingleton(beanName)) {
this.advisorsCache.put(beanName, classAdvisors);
}
// If not singleton, cache factory
else {
this.aspectFactoryCache.put(beanName, factory);
}
advisors.addAll(classAdvisors);
}
else {
if (this.beanFactory.isSingleton(beanName)) {
throw new IllegalArgumentException("");
}
MetadataAwareAspectInstanceFactory factory = new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
this.aspectFactoryCache.put(beanName, factory);
advisors.addAll(this.advisorFactory.getAdvisors(factory)); }}}this.aspectBeanNames = aspectNames;
returnadvisors; }}}if (aspectNames.isEmpty()) {
return Collections.emptyList();
}
List<Advisor> advisors = new ArrayList<>();
for (String aspectName : aspectNames) {
List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);
if(cachedAdvisors ! =null) {
advisors.addAll(cachedAdvisors);
}
else {
MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);
advisors.addAll(this.advisorFactory.getAdvisors(factory)); }}return advisors;
}
Copy the code
2. findAdvisorsThatCanApply
AopUtils# findAdvisorsThatCanApply:
/ * * *@paramCandidateAdvisors is returned in the previous step findCandidateAdvisor, that is, all advisors *@param clazz beanClass
*/
public static List<Advisor> findAdvisorsThatCanApply(List
candidateAdvisors, Class
clazz)
{
if (candidateAdvisors.isEmpty()) {
return candidateAdvisors;
}
List<Advisor> eligibleAdvisors = new ArrayList<>();
for (Advisor candidate : candidateAdvisors) {
// Introduction enhancement
if (candidate instanceofIntroductionAdvisor && canApply(candidate, clazz)) { eligibleAdvisors.add(candidate); }}booleanhasIntroductions = ! eligibleAdvisors.isEmpty();for (Advisor candidate : candidateAdvisors) {
if (candidate instanceof IntroductionAdvisor) {
// already processed
continue;
}
// Plain enhanced PointcutAdvisor
if(canApply(candidate, clazz, hasIntroductions)) { eligibleAdvisors.add(candidate); }}return eligibleAdvisors;
}
Copy the code
AopUtils#canApply
:
public static boolean canApply(Pointcut pc, Class<? > targetClass,boolean hasIntroductions) {
if(! pc.getClassFilter().matches(targetClass)) {return false;
}
MethodMatcher methodMatcher = pc.getMethodMatcher();
if (methodMatcher == MethodMatcher.TRUE) {
return true;
}
/ / AspectJExpressionPointcut, tangent point expression matcher
IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
if (methodMatcher instanceofIntroductionAwareMethodMatcher) { introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher; } Set<Class<? >> classes =new LinkedHashSet<>();
if(! Proxy.isProxyClass(targetClass)) { classes.add(ClassUtils.getUserClass(targetClass)); } classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass));for(Class<? > clazz : classes) { Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);for (Method method : methods) {
// If the pointcut expression matcher is not null, the pointcut expression match is used
if(introductionAwareMethodMatcher ! =null ? introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) : methodMatcher.matches(method, targetClass)) {
return true; }}}return false;
}
Copy the code
Generate proxy objects
Go back to ==AbstractAutoProxyCreator#wrapIfNecessary==. In this method, there are two important processes:
- Get the Advisor on the bean
- Generate a proxy object with the obtained Advisor as a parameter
AbstractAutoProxyCreator#wrapIfNecessary
:
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
// Whether the current bean exists in the targetSourcedBeans cache (already processed) or returns if it does
/ / targetSourcedBeans. Add in beforePostProcessInitialization ()
if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
// Beans are aop base classes or should be skipped
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if(specificInterceptors ! = DO_NOT_PROXY) {this.advisedBeans.put(cacheKey, Boolean.TRUE);
// Generate a proxy object
Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
Copy the code
This method creates a proxy for the bean, delegating the proxy creation to the proxyFactory, which initializes the proxyFactory. The main points are as follows:
- Copy attributes
- SetProxyTargetClass () to determine how the proxy works
- Adding a Proxy Interface
- Packaging advisor
- Execute the custom function customizeProxyFactory()
- To create the agent
protected Object createProxy(Class<? > beanClass,@Nullable String beanName, @Nullable Object[] specificInterceptors, TargetSource targetSource) {
if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
}
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this);
// proxyTargetClass defaults to false, true to use CGLib proxy, false to use JDK dynamic proxy
if(! proxyFactory.isProxyTargetClass()) {// Determine whether the CGLib proxy is based on the class proxy
if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
}else {
// For further evaluation of the proxy interface, see codeevaluateProxyInterfaces(beanClass, proxyFactory); }}// Wrap the interceptor as advisor, see code
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
proxyFactory.addAdvisors(advisors);
proxyFactory.setTargetSource(targetSource);
//
customizeProxyFactory(proxyFactory);
proxyFactory.setFrozen(this.freezeProxy);
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}
/ / call getProxy ()
return proxyFactory.getProxy(getProxyClassLoader());
}
Copy the code
Code2 — construct advisor abstractautoxyxy# buildAdvisors
In this approach, all interceptors are wrapped as advisors
protected Advisor[] buildAdvisors(@Nullable String beanName, @Nullable Object[] specificInterceptors) {
// Parse the public interceptor
Advisor[] commonInterceptors = resolveInterceptorNames();
List<Object> allInterceptors = new ArrayList<>();
if(specificInterceptors ! =null) {
allInterceptors.addAll(Arrays.asList(specificInterceptors));
// Determine the priority
if (commonInterceptors.length > 0) {
if (this.applyCommonInterceptorsFirst) {
allInterceptors.addAll(0, Arrays.asList(commonInterceptors));
}
else {
allInterceptors.addAll(Arrays.asList(commonInterceptors));
}
}
}
Advisor[] advisors = new Advisor[allInterceptors.size()];
for (int i = 0; i < allInterceptors.size(); i++) {
// Wrap the interceptor as an advisor
// DefaultAdvisorAdapterRegistry.wrap()
advisors[i] = this.advisorAdapterRegistry.wrap(allInterceptors.get(i));
}
return advisors;
}
Copy the code
Continue to look at the packaging process, enclosing advisorAdapterRegistry real object for = = DefaultAdvisorAdapterRegistry = =.
DefaultAdvisorAdapterRegistry#wrap
:
public Advisor wrap(Object adviceObject) throws UnknownAdviceTypeException {
if (adviceObject instanceof Advisor) {
return (Advisor) adviceObject;
}
if(! (adviceObjectinstanceof Advice)) {
throw new UnknownAdviceTypeException(adviceObject);
}
Advice advice = (Advice) adviceObject;
Rear / * * notice: AspectJAfterAdvice, pre inform: MethodBeforeAdviceInterceptor * is MethodInterceptor subclass * /
if (advice instanceof MethodInterceptor) {
return new DefaultPointcutAdvisor(advice);
}
for (AdvisorAdapter adapter : this.adapters) {
// Check that it is supported.
if (adapter.supportsAdvice(advice)) {
return newDefaultPointcutAdvisor(advice); }}throw new UnknownAdviceTypeException(advice);
}
Copy the code
Code3 — Create proxy — ProxyFactory
public Object getProxy(@Nullable ClassLoader classLoader) {
return createAopProxy().getProxy(classLoader);
}
Copy the code
DefaultAopProxyFactory#createAopProxy
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
/* * CGLib agent * optimize: Used to control whether agents created with CGLib use aggressive optimization strategies. Unless you fully understand how AOP handles proxy optimization, * isProxyTargetClass: defaults to false and can be configured manually. When true, force the CGLib proxy * config: ProxyFactory * hasNoUserSuppliedProxyInterfaces: determine whether realized interface * /
if(! IN_NATIVE_IMAGE && (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config))) { Class<? > targetClass = config.getTargetClass();if (targetClass == null) {
throw new AopConfigException("xxx");
}
/ * * to be agent of object is the interface | | targetClass is the Proxy class * to use the JDK dynamic Proxy * /
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
return new ObjenesisCglibAopProxy(config);
}
else {
return newJdkDynamicAopProxy(config); }}Copy the code
This method selects the proxy mode based on the situation:
- The JDK dynamic proxy is chosen by default if the bean implements the interface, but you can force the CGLib proxy by configuring proxyTargetClass=true
- Beans do not implement interfaces and can only use CGLib proxies
Four, invoke
1. JdkDynamicAopProxy
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
TargetSource targetSource = this.advised.targetSource;
Object target = null;
try {
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
return equals(args[0]);
}
else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
return hashCode();
}
else if (method.getDeclaringClass() == DecoratingProxy.class) {
return AopProxyUtils.ultimateTargetClass(this.advised);
}
else if (!this.advised.opaque && method.getDeclaringClass().isInterface() && method.getDeclaringClass().isAssignableFrom(Advised.class)) {
return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
}
Object retVal;
if (this.advised.exposeProxy) {
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true; } target = targetSource.getTarget(); Class<? > targetClass = (target ! =null ? target.getClass() : null);
// Get the interceptor chain, done by advisorChainFactory
/ / code
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
if (chain.isEmpty()) {
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
// Chain is wrapped in MethodInvocation
MethodInvocation invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// For detailed analysis, see coderetVal = invocation.proceed(); } Class<? > returnType = method.getReturnType();if(retVal ! =null&& retVal == target && returnType ! = Object.class && returnType.isInstance(proxy) && ! RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) { retVal = proxy; }else if (retVal == null&& returnType ! = Void.TYPE && returnType.isPrimitive()) {throw new AopInvocationException("Null return value from advice does not match primitive return type for: " + method);
}
return retVal;
} finally {
if(target ! =null && !targetSource.isStatic()) {
targetSource.releaseTarget(target);
}
if(setProxyContext) { AopContext.setCurrentProxy(oldProxy); }}}Copy the code
Code4 – ReflectiveMethodInvocation
public Object proceed(a) throws Throwable {
/ / this. CurrentInterceptorIndex initialized to 1
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
/ / in this interceptor in the chain, the index for ExposeInvocationInterceptor = 0
Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
if (interceptorOrInterceptionAdvice instanceofInterceptorAndDynamicMethodMatcher) { InterceptorAndDynamicMethodMatcher dm = (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice; Class<? > targetClass = (this.targetClass ! =null ? this.targetClass : this.method.getDeclaringClass());
if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
}else {
// Dynamic matching failed.
// Skip this interceptor and invoke the next in the chain.
returnproceed(); }}else {
/* * When the advisor is fetched, different implementation classes are returned according to the notification type, as shown in paragraph 5. * The invoke method of the corresponding implementation class is invoked * * before: MethodBeforeAdviceInterceptor * after: AspectJAfterAdvice @ * * param this above new ReflectiveMethodInvocation (). The proceed () * /
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this); }}Copy the code
2. CGLib
= = pre notice = = MethodBeforeAdviceInterceptor:
public Object invoke(MethodInvocation mi) throws Throwable {
this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
return mi.proceed();
}
Copy the code
== Afteradvice == AspectJAfterAdvice:
public Object invoke(MethodInvocation mi) throws Throwable {
try {
// Execute the method ontology first
return mi.proceed();
}finally {
invokeAdviceMethod(getJoinPointMatch(), null.null); }}Copy the code
Fifth, the specific process of Advisor acquisition
BeanFactoryAspectJAdvisorsBuilder#buildAspectJAdvisors
See 2 in Code1 for the main process:
- Get all beanName
- Walk through the beanName to find the beanName that has an @AspectJ annotation
- For beanName with @AspectJ annotations, parse the enhancements, such as @after, @before
- Add the results from step 3 to the cache
1. ReflectiveAspectJAdvisorFactory#getAdvisors
ReflectiveAspectJAdvisorFactory#getAdvisors
:
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
// Get the name and class of the aspectClass<? > aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass(); String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName(); validate(aspectClass);// Wrap this aspectInstanceFactory so that it is instantiated only once
MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory = new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);
List<Advisor> advisors = new ArrayList<>();
// getAdvisorMethods(), which reflects all advice methods in the cut that are not annotated by the @pointcut annotation
for (Method method : getAdvisorMethods(aspectClass)) {
// Generate the enhancer, as shown in the code below
Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, 0, aspectName);
if(advisor ! =null) { advisors.add(advisor); }}if(! advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) { Advisor instantiationAdvisor =new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
advisors.add(0, instantiationAdvisor);
}
for (Field field : aspectClass.getDeclaredFields()) {
Advisor advisor = getDeclareParentsAdvisor(field);
if(advisor ! =null) { advisors.add(advisor); }}return advisors;
}
Copy the code
ReflectiveAspectJAdvisorFactory#getAdvisor
:
public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrderInAspect, String aspectName) {
validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());
AspectJExpressionPointcut expressionPointcut = getPointcut(candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
if (expressionPointcut == null) { return null; }
/ / by InstantiationModelAwarePointcutAdvisorImpl unified encapsulation
return new InstantiationModelAwarePointcutAdvisorImpl(
expressionPointcut, candidateAdviceMethod, this,
aspectInstanceFactory, declarationOrderInAspect, aspectName
);
}
Copy the code
Continue to look at InstantiationModelAwarePointcutAdvisorImpl constructor:
public InstantiationModelAwarePointcutAdvisorImpl(AspectJExpressionPointcut declaredPointcut,
Method aspectJAdviceMethod, AspectJAdvisorFactory aspectJAdvisorFactory,
MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
this.declaredPointcut = declaredPointcut;
this.declaringClass = aspectJAdviceMethod.getDeclaringClass();
this.methodName = aspectJAdviceMethod.getName();
this.parameterTypes = aspectJAdviceMethod.getParameterTypes();
this.aspectJAdviceMethod = aspectJAdviceMethod;
this.aspectJAdvisorFactory = aspectJAdvisorFactory;
this.aspectInstanceFactory = aspectInstanceFactory;
this.declarationOrder = declarationOrder;
this.aspectName = aspectName;
if (aspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
// Static part of the pointcut is a lazy type.
Pointcut preInstantiationPointcut = Pointcuts.union(
aspectInstanceFactory.getAspectMetadata().getPerClausePointcut(), this.declaredPointcut);
// Make it dynamic: must mutate from pre-instantiation to post-instantiation state.
// If it's not a dynamic pointcut, it may be optimized out
// by the Spring AOP infrastructure after the first evaluation.
this.pointcut = new PerTargetInstantiationModelPointcut(
this.declaredPointcut, preInstantiationPointcut, aspectInstanceFactory);
this.lazy = true;
}
else {
// A singleton aspect.
this.pointcut = this.declaredPointcut;
this.lazy = false;
//
this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut); }}private Advice instantiateAdvice(AspectJExpressionPointcut pointcut) {
/ / here specific implementation in ReflectiveAspectJAdvisorFactory# getAdvice
Advice advice = this.aspectJAdvisorFactory.getAdvice(this.aspectJAdviceMethod, pointcut, this.aspectInstanceFactory, this.declarationOrder, this.aspectName);
return(advice ! =null ? advice : EMPTY_ADVICE);
}
/ * *Copy the code
Continue with the getAdvice method, where different implementation classes are returned depending on the type of the annotation
- AspectJMethodBeforeAdvice
- AspectJAroundAdvice
- AspectJAfterAdvice
- AspectJAfterReturningAdvice
ReflectiveAspectJAdvisorFactory#getAdvice
:
public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut, MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) { Class<? > candidateAspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass(); validate(candidateAspectClass); AspectJAnnotation<? > aspectJAnnotation = AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);if (aspectJAnnotation == null) {
return null;
}
// If we get here, we know we have an AspectJ method.
// Check that it's an AspectJ-annotated class
if(! isAspect(candidateAspectClass)) {throw new AopConfigException();
}
if (logger.isDebugEnabled()) {
logger.debug();
}
AbstractAspectJAdvice springAdvice;
switch (aspectJAnnotation.getAnnotationType()) {
case AtPointcut:
if (logger.isDebugEnabled()) {
logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");
}
return null;
case AtAround:
springAdvice = new AspectJAroundAdvice(candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtBefore:
springAdvice = new AspectJMethodBeforeAdvice(candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtAfter:
springAdvice = new AspectJAfterAdvice(candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtAfterReturning:
springAdvice = new AspectJAfterReturningAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();
if (StringUtils.hasText(afterReturningAnnotation.returning())) {
springAdvice.setReturningName(afterReturningAnnotation.returning());
}
break;
case AtAfterThrowing:
springAdvice = new AspectJAfterThrowingAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();
if (StringUtils.hasText(afterThrowingAnnotation.throwing())) {
springAdvice.setThrowingName(afterThrowingAnnotation.throwing());
}
break;
default:
throw new UnsupportedOperationException(
"Unsupported advice type on method: " + candidateAdviceMethod);
}
// Now to configure the advice...
springAdvice.setAspectName(aspectName);
springAdvice.setDeclarationOrder(declarationOrder);
String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod);
if(argNames ! =null) {
springAdvice.setArgumentNamesFromStringArray(argNames);
}
springAdvice.calculateArgumentBindings();
return springAdvice;
}
Copy the code