Spring AOP
- It is implemented based on dynamic proxy. If an interface is used, use the JDK to provide the dynamic proxy implementation, if no interface, use CGLIB implementation.
- After Spring 3.2, Spring-core directly includes CGLIB and ASM source code.
- Spring AOP needs to rely on the IOC container for management.
- Spring provides AspectJ support, but only pointcut parsing and matching.
The source code
Turn on aop cutting
Spring through open @ EnableAspectJAutoProxy aop aspects, on the annotation class found @ Import (AspectJAutoProxyRegistrar. Class), AspectJAutoProxyRegistrar ImportBeanDefinitionRegistrar is achieved, so he’ll pass import beanDefinition registerBeanDefinitions method for our container.
Analytical section
The bean’s back processor is called the first time to go back and parse the slice. The parse class isAbstractAutoProxyCreator
And it didInstantiationAwareBeanPostProcessor
. Enter thepostProcessBeforeInstantiation
Methods.
Decide if you should skip it. The real analysis is inshouldSkip
In the.
Enter thefindCandidateAdvisors
Override method of.
callsuper.findCandidateAdvisors()
, to find the aspect class that implements the Advisor interface.
Public List<Advisor> findAdvisorBeans() {/** * cachedAdvisorBeanNames is used to hold our Advisor class name * in the probe field cache In the first single instance of the bean will go to the advisor name resolution out * / String [] advisorNames = this. CachedAdvisorBeanNames; If (advisorNames = = null) {/ * * * to our container gets to realize the Advisor interface implementation class annotation @ EnableTransactionManagement * and our affairs Import a call ProxyTransactionManagementConfiguration configuration class * and configured in the configuration class * @ Bean (name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME) @Role(BeanDefinition.ROLE_INFRASTRUCTURE) public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor(); Then put his name to get out to the class attribute variables cachedAdvisorBeanNames * / advisorNames = BeanFactoryUtils beanNamesForTypeIncludingAncestors ( this.beanFactory, Advisor.class, true, false); this.cachedAdvisorBeanNames = advisorNames; } // If (advisornames.length == 0) {return new ArrayList<>(); } List<Advisor> advisors = new ArrayList<>(); / / in the ioc container found we configure BeanFactoryTransactionAttributeSourceAdvisor for (String name: AdvisorNames) {// If (isEligibleBean(name)) { / / is BeanFactoryTransactionAttributeSourceAdvisor is creating bean if (this. The beanFactory. IsCurrentlyInCreation (name)) {if (logger.isDebugEnabled()) { logger.debug("Skipping currently created advisor '" + name + "'"); }} / / not else {try {/ / show the invocation of the method to create our BeanFactoryTransactionAttributeSourceAdvisor getBean method to return advisors.add(this.beanFactory.getBean(name, Advisor.class)); } catch (BeanCreationException ex) { Throwable rootCause = ex.getMostSpecificCause(); if (rootCause instanceof BeanCurrentlyInCreationException) { BeanCreationException bce = (BeanCreationException) rootCause; String bceBeanName = bce.getBeanName(); if (bceBeanName ! = null && this.beanFactory.isCurrentlyInCreation(bceBeanName)) { if (logger.isDebugEnabled()) { logger.debug("Skipping advisor '" + name + "' with dependency on currently created bean: " + ex.getMessage()); } // Ignore: indicates a reference back to the bean we're trying to advise. // We want to find advisors other than the currently created bean itself. continue; } } throw ex; } } } } return advisors; }Copy the code
callbuildAspectJAdvisors
Look for the annotation style aspect class.
/ * * * to the container to all aspects of information saved in the cache * @ return the list of {@ link org. Springframework. Aop) Advisor} beans * @ # see isEligibleBean * / Public List<Advisor> buildAspectJAdvisors() {/** * to save the name of the section, where aspectNames are our class-level cache, */ List<String> aspectNames = this.aspectBeannames; / / cache field aspectNames no value can be carried in the first singleton post processor (AnnotationAwareAspectJAutoProxyCreator after registration) could trigger the analytical aspects of operating the if (aspectNames = = null) AspectNames = this.aspectBeannames;} // Add a synchronized lock to prevent multithreading from loading Aspect synchronized (this) {aspectNames = this.aspectBeannames; If (aspectNames == null) {// Save the collection of all notifications List<Advisor> advisors = new ArrayList<>(); AspectNames = new ArrayList<>(); /** * Aop uses Object. Class to fetch the names of all the components in the container, and then go through them one by one. This process is very performance consuming, so spring will add a cache to store the aspect information. * But the transaction function is different, the function of the transaction module is to directly go to the container to obtain the Advisor type, the choice is small, and does not consume performance. So * spring didn't join in transaction module cache to preserve our affairs related advisor * / String [] beanNames = BeanFactoryUtils. BeanNamesForTypeIncludingAncestors ( this.beanFactory, Object.class, true, false); For (String beanName: beanNames) {if (! isEligibleBean(beanName)) { continue; } // Use beanName to get the corresponding class <? > beanType = this.beanFactory.getType(beanName); if (beanType == null) { continue; } // See if the class has an Aspect annotation on it and is not an AJC $file. If (this. AdvisorFactory. IsAspect (beanType)) {/ / was added to the cache section / / aspectNames. Add (beanName); AspectMetadata amd = new AspectMetadata(beanType, beanName); If (amd.getajType ().getperclause ().getkind () == perclausekind.singleton) {// Build an instance factory for section annotations MetadataAwareAspectInstanceFactory factory = new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName); / / true to get our notification object A detailed look at the following getAdvisors method List < Advisor > classAdvisors = this. AdvisorFactory. GetAdvisors (factory); / / added to the cache if (this. The beanFactory. IsSingleton (beanName)) {this. AdvisorsCache. Put (beanName classAdvisors); } else { this.aspectFactoryCache.put(beanName, factory); } advisors.addAll(classAdvisors); } else { // Per target or per this. if (this.beanFactory.isSingleton(beanName)) { throw new IllegalArgumentException("Bean with name '" + beanName + "' is a singleton, but aspect instantiation model is not singleton"); } MetadataAwareAspectInstanceFactory factory = new PrototypeAspectInstanceFactory(this.beanFactory, beanName); this.aspectFactoryCache.put(beanName, factory); advisors.addAll(this.advisorFactory.getAdvisors(factory)); } } } this.aspectBeanNames = aspectNames; return advisors; } } } if (aspectNames.isEmpty()) { return Collections.emptyList(); */ List<Advisor> advisors = new ArrayList<>(); / / 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
GetAdvisors method
@Override public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) { // Get our Class<? > aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass(); / / to get our plane class name String aspectName = aspectInstanceFactory. GetAspectMetadata () getAspectName (); // validate our section class validate(aspectClass); / / we use the packaging mode to wrap our MetadataAwareAspectInstanceFactory build MetadataAwareAspectInstanceFactory MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory = new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory); List<Advisor> advisors = new ArrayList<>(); // Get all the methods in the section class, but this Method will not parse the @pointcut annotated Method for (Method Method: Advisormethods (aspectClass) {advisorMethods (aspectClass) {advisorMethods (aspectClass) = advisorMethods (aspectClass); lazySingletonAspectInstanceFactory, advisors.size(), aspectName); if (advisor ! = null) { advisors.add(advisor); } } // If it's a per target aspect, emit the dummy instantiating aspect. if (! advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) { Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory); advisors.add(0, instantiationAdvisor); } // Find introduction fields. for (Field field : aspectClass.getDeclaredFields()) { Advisor advisor = getDeclareParentsAdvisor(field); if (advisor ! = null) { advisors.add(advisor); } } return advisors; }Copy the code
GetAdvisor method
public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrderInAspect, String aspectName) { validate(aspectInstanceFactory.getAspectMetadata().getAspectClass()); / / get the current inform the tangent point of expression detailed below getPointcut method AspectJExpressionPointcut expressionPointcut = getPointcut (candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass()); if (expressionPointcut == null) { return null; } / / the point of tangency expressions, and notify the packaging to InstantiationModelAwarePointcutAdvisorImpl objects look down InstantiationModelAwarePointcutAdvisorImpl detailed source code return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod, this, aspectInstanceFactory, declarationOrderInAspect, aspectName); }Copy the code
GetPointcut method
private AspectJExpressionPointcut getPointcut(Method candidateAdviceMethod, Class<? > candidateAspectClass) {// Find the annotation of aspectJ: // @Pointcut @Around @Before @After @AfterReturning @AfterThrowing AspectJAnnotation<? > aspectJAnnotation = AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod); // No annotation that must ignore if (aspectJAnnotation == null) {return null; } AspectJExpressionPointcut ajexp = new AspectJExpressionPointcut(candidateAspectClass, new String[0], new Class<? > [0]); ajexp.setExpression(aspectJAnnotation.getPointcutExpression()); if (this.beanFactory ! = null) { ajexp.setBeanFactory(this.beanFactory); } return ajexp; }Copy the code
InstantiationModelAwarePointcutAdvisorImpl function
public InstantiationModelAwarePointcutAdvisorImpl(AspectJExpressionPointcut declaredPointcut, Method aspectJAdviceMethod, AspectJAdvisorFactory aspectJAdvisorFactory, MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {this.declaredPointcut = declaredPointcut; / / cut class object enclosing declaringClass = aspectJAdviceMethod. The getDeclaringClass (); / / this. The name of the section method methodName = aspectJAdviceMethod. The getName (); / / section method of parameter type enclosing parameterTypes. = aspectJAdviceMethod getParameterTypes (); This.aspectjadvicemethod = aspectJAdviceMethod; / / aspectj to inform the factory this. AspectJAdvisorFactory = aspectJAdvisorFactory; / / the aspect the instance of the factory this. AspectInstanceFactory = aspectInstanceFactory; This. DeclarationOrder = declarationOrder; This.aspectname = aspectName; / * * * determine whether the current plane object need to delay loading * / if (aspectInstanceFactory. GetAspectMetadata () isLazilyInstantiated ()) {/ / Static parts 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; InstantiateAdvice = instantiateAdvice(this.declaredPointcut); }}Copy the code
InstantiateAdvice method
Private Advice instantiateAdvice (AspectJExpressionPointcut pointcut) {/ / detail see below getAdvice source Advice Advice = this.aspectJAdvisorFactory.getAdvice(this.aspectJAdviceMethod, pointcut, this.aspectInstanceFactory, this.declarationOrder, this.aspectName); return (advice ! = null ? advice : EMPTY_ADVICE); }Copy the code
GetAdvice source
public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut, MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {// Get the class object of our facet class class <? > candidateAspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass(); validate(candidateAspectClass); // Get the annotation on the section method AspectJAnnotation<? > aspectJAnnotation = AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod); If (aspectJAnnotation == null) {return null; } // Check whether the class object is a section information object if (! isAspect(candidateAspectClass)) { throw new AopConfigException("Advice must be declared inside an aspect type: " + "Offending method '" + candidateAdviceMethod + "' in class [" + candidateAspectClass.getName() + "]"); Logger.isdebugenabled ()) {logger.debug("Found AspectJ method: "+ candidateAdviceMethod); } AbstractAspectJAdvice springAdvice; / / judgment annotation on the method of annotation type switch (aspectJAnnotation. GetAnnotationType ()) {/ / is PointCut annotation Then throw an exception Because passed outside method has ruled out the case of pointcut method AtPointcut: if (logger.isDebugEnabled()) { logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'"); } return null; case AtAround: SpringAdvice = new AspectJAroundAdvice(candidateAdviceMethod, expressionPointcut, aspectInstanceFactory); break; case AtBefore: Prior notification / / build AspectJMethodBeforeAdvice springAdvice = new AspectJMethodBeforeAdvice (candidateAdviceMethod, expressionPointcut, aspectInstanceFactory); break; case AtAfter: AspectJAfterAdvice = new AspectJAfterAdvice(candidateAdviceMethod, expressionPointcut, aspectInstanceFactory); break; case AtAfterReturning: / / return notice AspectJAfterReturningAdvice springAdvice = new AspectJAfterReturningAdvice (candidateAdviceMethod, expressionPointcut, aspectInstanceFactory); AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation(); if (StringUtils.hasText(afterReturningAnnotation.returning())) { springAdvice.setReturningName(afterReturningAnnotation.returning()); } break; case AtAfterThrowing: / / exception notification AspectJAfterThrowingAdvice 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); } / / configure notification object springAdvice we constructed setAspectName (aspectName); springAdvice.setDeclarationOrder(declarationOrder); String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod); if (argNames ! = null) { springAdvice.setArgumentNamesFromStringArray(argNames); } springAdvice.calculateArgumentBindings(); return springAdvice; }Copy the code
ApplyBeanPostProcessorsBeforeInstantiation here after the first call to buy microprocessor finished the section analysis is called the next plane to create a dynamic proxy, to create a dynamic proxy is initialized beans before the call, Namely when doCreateBean back to initialize the Bean, initializeBean method to call applyBeanPostProcessorsAfterInitialization method to create a dynamic proxy.
ApplyBeanPostProcessorsAfterInitialization method
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName) throws BeansException { Object result = existingBean; // Get the backend processor for all the beans in our container. GetBeanPostProcessors ()) {/** * this is the post-processor's [9] call where aop and transactions will live proxy objects ** * we aop @enableAspectJAutoProxy imported for our container AnnotationAwareAspectJAutoProxyCreator * we transaction annotations @ EnableTransactionManagement container import for us InfrastructureAdvisorAutoProxyCreator * is implements the BeanPostProcessor interface InstantiationAwareBeanPostProcessor, * implemented here is postProcessAfterInitialization BeanPostProcessor interface to generate our proxy object * / / / Detailed look down AbstractAutoProxyCreator implementation method of postProcessAfterInitialization Object current = processor.postProcessAfterInitialization(result, beanName); If (current == null) {return result; } result = current; } return result; }Copy the code
PostProcessAfterInitialization method (AbstractAutoProxyCreator class implements)
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) throws BeansException {
if (bean != null) {
//获取缓存key
Object cacheKey = getCacheKey(bean.getClass(), beanName);
// 之前循环依赖创建的动态代理 如果是现在的bean 就不再创建,,并且移除
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
// 该方法将会返回动态代理实例
// 详细看wrapIfNecessary源码
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
Copy the code
WrapIfNecessary method
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {// Already handled (targetSourcedBeans appear when parsing the cut) is the implementation of creating the dynamic proxy logic if (stringutils.hasLength (beanName) && this.targetSourcedBeans.contains(beanName)) { return bean; } // Unenhanced if (boolea.false. Equals (this.advisedBeans.get(cacheKey))) {return bean; } // Whether the underlying bean needs to be skipped (since loop dependencies can change beans, If the bean is changed to advisor?) if (isInfrastructureClass (bean. GetClass () | | shouldSkip (bean. GetClass (), beanName)) { this.advisedBeans.put(cacheKey, Boolean.FALSE); return bean; } / / based on the current bean advisor to find matching Object [] specificInterceptors = getAdvicesAndAdvisorsForBean (bean. GetClass (), beanName, null); // The current bean matches advisor if (specificInterceptors! = DO_NOT_PROXY) {// Mark this.advisedBeans.put(cacheKey, boolea.true); CreateProxy Object Proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean)); // Add to cache this.proxytypes. put(cacheKey, proxy.getClass()); return proxy; } this.advisedBeans.put(cacheKey, Boolean.FALSE); return bean; }Copy the code
The createProxy method creates dynamic proxies
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); } // create a proxy object factory ProxyFactory ProxyFactory = new ProxyFactory(); proxyFactory.copyFrom(this); <aop:aspectj-autoproxy proxy-target-class="true"/> <aop:aspectj-autoproxy proxy-target-class="true"/> ProxyFactory. IsProxyTargetClass ()) {/ / set inside, Configuration class will set this property if (shouldProxyTargetClass (beanClass, beanName)) {proxyFactory. SetProxyTargetClass (true); EvaluateProxyInterfaces (beanClass, proxyFactory); }} // Convert the Advisor in our array of specificInterceptors to an array of Advisor[] advisors = buildAdvisors(beanName, specificInterceptors); // add the notifier to our proxyFactory, proxyfactory.addadvisors (advisors); / / set targetSource proxyFactory object. SetTargetSource (targetSource); customizeProxyFactory(proxyFactory); proxyFactory.setFrozen(this.freezeProxy); / / is for advise whether screening before. / / because inherited AbstractAdvisorAutoProxyCreator, filtered and call the findEligibleAdvisors before, So it is true the if (advisorsPreFiltered ()) {proxyFactory. SetPreFiltered (true); } return proxyFactory.getProxy(getProxyClassLoader()); }Copy the code
GetProxy method
Public Object getProxy(@nullable ClassLoader ClassLoader) {//createAopProxy() to get our proxy factory return createAopProxy().getProxy(classLoader); }Copy the code
CreateAopProxy method
/** ** @param config is used to specify our advisor information for us * this method is used to create our proxy object * our targetClass object implements the interface, ProxyTargetClass does not specify a mandatory cglib proxy. If the ProxyTargetClass is set to false and the proxy class is an interface, the JDK proxy will be used @Override public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException { / / whether we pre specified using additional agent ProxyTargetClass = true or if no interface (config. IsOptimize () | | config. IsProxyTargetClass () | | hasNoUserSuppliedProxyInterfaces(config)) { Class<? > targetClass = config.getTargetClass(); if (targetClass == null) { throw new AopConfigException("TargetSource cannot determine target class: " + "Either an interface or a target is required for proxy creation."); } / / targetClass is the interface using the JDK agent if (targetClass. IsInterface () | | Proxy. IsProxyClass (targetClass)) {return new JdkDynamicAopProxy(config); } //cglib proxy return new ObjenesisCglibAopProxy(config); } else {return new JdkDynamicAopProxy(config); }}Copy the code
The getProxy method has two implementations, CGLIB and JDK dynamic proxies.
At this point, you have created the AOP dynamic proxy, which, when invoked, will enterJdkDynamicAopProxy
theinvoke
Methods.
Invoke method
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object oldProxy = null; boolean setProxyContext = false; / / to get to our target TargetSource TargetSource = this. Advised. TargetSource; Object target = null; Try {// The equals method of the proxy object does not require the proxy if (! this.equalsDefined && AopUtils.isEqualsMethod(method)) { // The target does not implement the equals(Object) method itself. return equals(args[0]); } else if (! this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) { // The target does not implement the hashCode() method itself. return hashCode(); } // If the class object being executed is a DecoratingProxy, method enhancements are not applied to it. Else if (method.getdeclaringClass () == decoratingproxy.class) {// There is only getDecoratedClass() declared -> dispatch to proxy config. return AopProxyUtils.ultimateTargetClass(this.advised); } // If the target object implements the Advised interface, no method enhancements will be made to its application facets. Else if (! this.advised.opaque && method.getDeclaringClass().isInterface() && method.getDeclaringClass().isAssignableFrom(Advised.class)) { // Service invocations on ProxyConfig with the proxy config... return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args); } Object retVal; /** * This configuration is important and useful to use with @enableAspectJAutoProxy (exposeProxy = true) * Mode methods are all cut methods, but when another method is called by * this in the cut method, that method is not executed by the proxy. Public int mod(int numA,int numB){system.out.println (" execute target method :mod"); int retVal = ((Calculate) AopContext.currentProxy()).add(numA,numB); return retVal%numA; } if (this.advised. ExposeProxy) {// Expose our proxy object to thread variables oldProxy = AopContext.setCurrentProxy(proxy); setProxyContext = true; } // Get our target object target = targetsource.gettarget (); // Get the class <? > targetClass = (target ! = null ? target.getClass() : null); // Convert all of our AOP advisors to interceptors, Through the chain of responsibility pattern According to this call List < Object > chain = this. Advised. GetInterceptorsAndDynamicInterceptionAdvice (method, targetClass); / / to join our is empty if the interceptor chain (chain. IsEmpty ()) {/ / by reflection called directly execute the Object [] argsToUse = AopProxyUtils. AdaptArgumentsIfNecessary (method, args); retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse); } else {/ / create a method call object the MethodInvocation invocation = new ReflectiveMethodInvocation (proxy, target, method and the args, targetClass, chain); RetVal = invocation. Proceed (); } // Massage return value if necessary. Class<? > returnType = method.getReturnType(); if (retVal ! = null && retVal == target && returnType ! = Object.class && returnType.isInstance(proxy) && ! RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) { // Special case: it returned "this" and the return type of the method // is type-compatible. Note that we can't help if the target sets // a reference to itself in another returned object. 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()) { // Must have come from TargetSource. targetSource.releaseTarget(target); } if (setProxyContext) { // Restore old proxy. AopContext.setCurrentProxy(oldProxy); }}}Copy the code
Call through the chain of responsibility.
ReflectiveMethodInvocation
Proceed method
Public Object proceed() throws Throwable {// Starting with -1, the end conditional execution target method is subscript = interceptor length -1(when the last interceptor is executed) if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) { return invokeJoinpoint(); } / * * * to get the first method using interceptor is a former + + * / Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex); if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) { // Evaluate dynamic method matcher here: static part will already have // been evaluated and found to match. InterceptorAndDynamicMethodMatcher dm = (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice; if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) { return dm.interceptor.invoke(this); } else { // Dynamic matching failed. // Skip this interceptor and invoke the next in the chain. return proceed(); }} else {// Note here that the invoke method of the first interceptor, Incoming is the method of this current interceptor object return (MethodInterceptor interceptorOrInterceptionAdvice). Invoke (this); }}Copy the code