Categories
Uncategorized

spring5 source depth analysis of the AOP proxy generation —–

After obtaining all the corresponding bean enhancements, you can create a proxy. The back AbstractAutoProxyCreator wrapIfNecessary method, as follows:

 1 protected static final Object[] DO_NOT_PROXY = null;
 2 
 3 protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
 4     if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
 5         return bean;
 6     }
 7     if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
 8         return bean;
 9     }
10     if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
11         this.advisedBeans.put(cacheKey, Boolean.FALSE);
12         return bean;
13     }
14 
15     // Create proxy if we have advice.
16     Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
17     if (specificInterceptors != DO_NOT_PROXY) {
18         this.advisedBeans.put(cacheKey, Boolean.TRUE);
19         Object proxy = createProxy(
20                 bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
21         this.proxyTypes.put(cacheKey, proxy.getClass());
22         return proxy;
23     }
24 
25     this.advisedBeans.put(cacheKey, Boolean.FALSE);
26     return bean;
27 }

Our last article analyzes over line 16, to get all the corresponding booster bean and bean get to this goal all match Advisor, then we start the analysis from the line 17, specificInterceptors if not empty, will have to the current bean create a proxy class, then we create a proxy class method createProxy point of view is:

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();
    //

Gets the current class-related property

proxyFactory.copyFrom(this); if (!proxyFactory.isProxyTargetClass()) { // 决定对于给定的bean是否应该使用targetClass而不是他的接口代理, //

Check proxyTargetClass settings and properties preserveTargetClass

if (shouldProxyTargetClass(beanClass, beanName)) { proxyFactory.setProxyTargetClass(true); } else { evaluateProxyInterfaces(beanClass, proxyFactory); } } Advisor[] advisors = buildAdvisors(beanName, specificInterceptors); //

Join booster

proxyFactory.addAdvisors(advisors); //

To set the target class of agents

proxyFactory.setTargetSource(targetSource);
//

Custom agent

customizeProxyFactory(proxyFactory); // 用来控制代理工厂被配置之后,是否还允许修改通知。 //

The default is false (i.e., after the agent is configured, the proxy is not allowed to modify the configuration).

proxyFactory.setFrozen(this.freezeProxy); if (advisorsPreFiltered()) { proxyFactory.setPreFiltered(true); } //

True method of creating agents

return
proxyFactory.getProxy(getProxyClassLoader()); } @Override public void setTargetSource(@Nullable TargetSource targetSource) { this.targetSource = (targetSource != null ? targetSource : EMPTY_TARGET_SOURCE); } public void addAdvisors(Collection advisors) { if (isFrozen()) { throw new AopConfigException("Cannot add advisor: Configuration is frozen."); } if (!CollectionUtils.isEmpty(advisors)) { for (Advisor advisor : advisors) { if (advisor instanceof IntroductionAdvisor) { validateIntroductionAdvisor((IntroductionAdvisor) advisor); } Assert.notNull(advisor, "Advisor must not be null"); this.advisors.add(advisor); } updateAdvisorArray(); adviceChanged(); } }

We see from the above code to create a proxy class and handle spring is entrusted to the process of ProxyFactory

Creating an agent

public Object getProxy(@Nullable ClassLoader classLoader) {
    return createAopProxy().getProxy(classLoader);
}

In the above method createAopProxy getProxy method, which is implemented in DefaultAopProxyFactory, the main function of this method is to determine the dynamic proxy Jdk generate, or generate Cglib agent according to optimize, ProxyTargetClass parameters. We enter into the method:

protected final synchronized AopProxy createAopProxy() {
    if (!this.active) {
        activate();
    }
    //

Creating an agent

return getAopProxyFactory().createAopProxy(this); } public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException { if (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."); } //

After manually set the proxy class is created Cglib, if the target bean is an interface, but also to create a proxy class jdk

if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) { return new JdkDynamicAopProxy(config); } //

Create a proxy Cglib

return new ObjenesisCglibAopProxy(config); } else { //

Jdk agency created by default

return new JdkDynamicAopProxy(config); } }

We know that Spring’s proxy is achieved by JDKProxy implementation and CglibProxy. Spring is how to select it?

If the determination condition can be seen in these three aspects influence the judgment of Spring.

  • optimize: controls CGLIB created through a proxy whether or not aggressive optimization strategy, unless one fully understands how AOP proxy handles optimization, or do not recommend using this setting. This is currently only used for CGLIB agent, for JDK dynamic proxies (the default agent) is invalid.

  • proxyTargetClass: This attribute is true, the target class is to be proxied interfaces rather than the target class. If the value of this attribute is set to true, CGLIB proxy will be created, arrangement: .

  • hasNoUserSuppliedProxylnterfaces: whether there is a proxy interface

The following is a summary of the JDK and Cglib way.

  • If the target object implements the interface will use the JDK dynamic proxy AOP implementation by default.

  • If the target object implements the interface, you can force the use of CGLIB achieve AOP.

  • If the target object does not implement the interfaces must be used CGLIB library, Spring will automatically switch between JDK dynamic proxies and CGLIB.

How to force the use of CGLIB achieve AOP?

(1) add CGLIB library, Spring_HOME / cglib / *. Jar.

(2) added to the configuration file al Spring .

JDK dynamic proxy and bytecode generation CGLIB difference?

    JDK dynamic proxy class that implements the interface can only build agent, and not for the class.

    CGLIB is for the class to achieve agency, mainly to generate a subclass of the specified class, a method in which the cover, because it is inherited, so the class or method is best not to be declared as final.

Gets agent

This paper describes the realization of JDK dynamic proxy class before that, it is necessary to familiarize yourself with JDK agent to use examples, see my previous blog post, JDK dynamic proxy source code analysis article “java base (xviii) —– java dynamic Acting principle source analysis “

Spring AOP implementations actually use the Proxy and InvocationHandler two things.

Once again, we look back at the way agents use JDK, throughout the creation process for creating InvocationHandler is the most central, in a custom InvocationHandler the need to rewrite three functions.

    Constructor, the proxy object passed.

    invoke method, this method is implemented in all logical AOP enhanced.

    getProxy method that fits, but essential.

So, we take a look at JDK proxy realize Spring is not also do it? We take a look JdkDynamicAopProxy simplified.

  1 final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {
  2 
  3     private final AdvisedSupport advised;
  4 
  5     public JdkDynamicAopProxy(AdvisedSupport config) throws AopConfigException {
  6         Assert.notNull(config, "AdvisedSupport must not be null");
  7         if (config.getAdvisors().length == 0 && config.getTargetSource() == AdvisedSupport.EMPTY_TARGET_SOURCE) {
  8             throw new AopConfigException("No advisors and no TargetSource specified");
  9         }
 10         this.advised = config;
 11     }
 12 
 13 
 14     @Override
 15     public Object getProxy() {
 16         return getProxy(ClassUtils.getDefaultClassLoader());
 17     }
 18 
 19     @Override
 20     public Object getProxy(@Nullable ClassLoader classLoader) {
 21         if (logger.isTraceEnabled()) {
 22             logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
 23         }
 24         Class[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
 25         findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
 26         return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
 27     }
 28 
 29     @Override
 30     @Nullable
 31     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
 32         Object oldProxy = null;
 33         boolean setProxyContext = false;
 34 
 35         TargetSource targetSource = this.advised.targetSource;
 36         Object target = null;
 37 
 38         try {
 39             if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
 40                 // The target does not implement the equals(Object) method itself.
 41                 return equals(args[0]);
 42             }
 43             else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
 44                 // The target does not implement the hashCode() method itself.
 45                 return hashCode();
 46             }
 47             else if (method.getDeclaringClass() == DecoratingProxy.class) {
 48                 // There is only getDecoratedClass() declared -> dispatch to proxy config.
 49                 return AopProxyUtils.ultimateTargetClass(this.advised);
 50             }
 51             else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
 52                     method.getDeclaringClass().isAssignableFrom(Advised.class)) {
 53                 // Service invocations on ProxyConfig with the proxy config...
 54                 return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
 55             }
 56 
 57             Object retVal;
 58 
 59             if (this.advised.exposeProxy) {
 60                 // Make invocation available if necessary.
 61                 oldProxy = AopContext.setCurrentProxy(proxy);
 62                 setProxyContext = true;
 63             }
 64 
 65             // Get as late as possible to minimize the time we "own" the target,
 66             // in case it comes from a pool.
 67             target = targetSource.getTarget();
 68             Class targetClass = (target != null ? target.getClass() : null);
 69 
 70             // Get the interception chain for this method.
 71             List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
 72 
 73             // Check whether we have any advice. If we don't, we can fallback on direct
 74             // reflective invocation of the target, and avoid creating a MethodInvocation.
 75             if (chain.isEmpty()) {
 76                 // We can skip creating a MethodInvocation: just invoke the target directly
 77                 // Note that the final invoker must be an InvokerInterceptor so we know it does
 78                 // nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
 79                 Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
 80                 retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
 81             }
 82             else {
 83                 // We need to create a method invocation...
 84                 MethodInvocation invocation =
 85                         new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
 86                 // Proceed to the joinpoint through the interceptor chain.
 87                 retVal = invocation.proceed();
 88             }
 89 
 90             // Massage return value if necessary.
 91             Class returnType = method.getReturnType();
 92             if (retVal != null && retVal == target &&
 93                     returnType != Object.class && returnType.isInstance(proxy) &&
 94                     !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
 95                 // Special case: it returned "this" and the return type of the method
 96                 // is type-compatible. Note that we can't help if the target sets
 97                 // a reference to itself in another returned object.
 98                 retVal = proxy;
 99             }
100             else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
101                 throw new AopInvocationException(
102                         "Null return value from advice does not match primitive return type for: " + method);
103             }
104             return retVal;
105         }
106         finally {
107             if (target != null && !targetSource.isStatic()) {
108                 // Must have come from TargetSource.
109                 targetSource.releaseTarget(target);
110             }
111             if (setProxyContext) {
112                 // Restore old proxy.
113                 AopContext.setCurrentProxy(oldProxy);
114             }
115         }
116     }
117 
118 }

We also see JdkDynamicAopProxy and InvocationHandler our custom as to achieve the InvocationHandler interface, and provides a way to create a proxy class getProxy, rewrite invoke methods.

We look at the focus invoke the agent class. Learn Jdk dynamic proxies will know, in the realization of Jdk dynamic proxy function to achieve invoke method InvocationHandler interface (this method is a callback method). When the method of the proxy class is called, it is actually invoke the method call, we look at the implementation of this method.

 1 @Override
 2 @Nullable
 3 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
 4     MethodInvocation invocation;
 5     Object oldProxy = null;
 6     boolean setProxyContext = false;
 7 
 8     TargetSource targetSource = this.advised.targetSource;
 9     Object target = null;
10 
11     try {
12         if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
13             return equals(args[0]);
14         }
15         else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
16             return hashCode();
17         }
18         else if (method.getDeclaringClass() == DecoratingProxy.class) {
19             return AopProxyUtils.ultimateTargetClass(this.advised);
20         }
21         else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
22                 method.getDeclaringClass().isAssignableFrom(Advised.class)) {
23             return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
24         }
25 
26         Object retVal;
27         if (this.advised.exposeProxy) {
28             // Make invocation available if necessary.
29             oldProxy = AopContext.setCurrentProxy(proxy);
30             setProxyContext = true;
31         }
32 
33         target = targetSource.getTarget();
34         Class targetClass = (target != null ? target.getClass() : null);
35 
36         //

Gets the current method interceptor chain

37 List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); 38 39 if (chain.isEmpty()) { 40 //

If there are no interceptors so cut-point method calls directly

41 Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args); 42 retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse); 43 } 44 else { 45 // We need to create a method invocation... 46 // 将拦截器封装在ReflectiveMethodInvocation, 47 //

For a link table which proceed using interceptors

48 invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain); 49 // Proceed to the joinpoint through the interceptor chain. 50 //

Interceptor chain execution

51 retVal = invocation.proceed(); 52 } 53 54 Class returnType = method.getReturnType(); 55 //

Back to Results

56 if (retVal != null && retVal == target && 57 returnType != Object.class && returnType.isInstance(proxy) && 58 !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) { 59 retVal = proxy; 60 } 61 else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) { 62 throw new AopInvocationException( 63 "Null return value from advice does not match primitive return type for: " + method); 64 } 65 return retVal; 66 } 67 finally { 68 if (target != null && !targetSource.isStatic()) { 69 // Must have come from TargetSource. 70 targetSource.releaseTarget(target); 71 } 72 if (setProxyContext) { 73 // Restore old proxy. 74 AopContext.setCurrentProxy(oldProxy); 75 } 76 } 77 }

 

Let’s look at line 37, the target acquisition method of the target bean intensifier, and the booster package to intercept chain

 1 @Override
 2 public List getInterceptorsAndDynamicInterceptionAdvice(
 3         Advised config, Method method, @Nullable Class targetClass) {
 4 
 5     // This is somewhat tricky... We have to process introductions first,
 6     // but we need to preserve order in the ultimate list.
 7     AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
 8     Advisor[] advisors = config.getAdvisors();
 9     List interceptorList = new ArrayList<>(advisors.length);
10     Class actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
11     Boolean hasIntroductions = null;
12 
13     //

Get all of booster bean

14 for (Advisor advisor : advisors) { 15 if (advisor instanceof PointcutAdvisor) { 16 // Add it conditionally. 17 PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor; 18 if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) { 19 MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher(); 20 boolean match; 21 if (mm instanceof IntroductionAwareMethodMatcher) { 22 if (hasIntroductions == null) { 23 hasIntroductions = hasMatchingIntroductions(advisors, actualClass); 24 } 25 match = ((IntroductionAwareMethodMatcher) mm).matches(method, actualClass, hasIntroductions); 26 } 27 else { 28 //根据增强器中的Pointcut判断增强器是否能匹配当前类中的method 29 //

We want to know that not all of the target Bean method requires enhanced, there are some common methods

30 match = mm.matches(method, actualClass);
31 } 32 if (match) { 33 //

If matching advisor will be encapsulated into the MethodInterceptor added to interceptorList

34 MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
35 if (mm.isRuntime()) { 36 // Creating a new object instance in the getInterceptors() method 37 // isn't a problem as we normally cache created chains. 38 for (MethodInterceptor interceptor : interceptors) { 39 interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm)); 40 } 41 } 42 else { 43 interceptorList.addAll(Arrays.asList(interceptors)); 44 } 45 } 46 } 47 } 48 else if (advisor instanceof IntroductionAdvisor) { 49 IntroductionAdvisor ia = (IntroductionAdvisor) advisor; 50 if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) { 51 Interceptor[] interceptors = registry.getInterceptors(advisor); 52 interceptorList.addAll(Arrays.asList(interceptors)); 53 } 54 } 55 else { 56 Interceptor[] interceptors = registry.getInterceptors(advisor); 57 interceptorList.addAll(Arrays.asList(interceptors)); 58 } 59 } 60 61 return interceptorList; 62 }

 

We know that the target Bean not all methods require reinforcement, so we have to traverse all Advisor, according Pointcut determines whether the booster can match the current class Method, taken to match the booster, MethodInterceptor encapsulated, is added to the block in the chain, we take a look at line 34

@Override
public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
    List interceptors = new ArrayList<>(3);
    Advice advice = advisor.getAdvice();
    if (advice instanceof MethodInterceptor) {
        interceptors.add((MethodInterceptor) advice);
    }
    //这里遍历三个适配器,将对应的advisor转化成Interceptor
    //

The three adapters are MethodBeforeAdviceAdapter, AfterReturningAdviceAdapter, ThrowsAdviceAdapter

for (AdvisorAdapter adapter : this.adapters) { if (adapter.supportsAdvice(advice)) { interceptors.add(adapter.getInterceptor(advisor)); } } if (interceptors.isEmpty()) { throw new UnknownAdviceTypeException(advisor.getAdvice()); } return interceptors.toArray(new MethodInterceptor[0]); } private final List adapters = new ArrayList<>(3); /** * Create a new DefaultAdvisorAdapterRegistry, registering well-known adapters. */ public DefaultAdvisorAdapterRegistry() { registerAdvisorAdapter(new MethodBeforeAdviceAdapter()); registerAdvisorAdapter(new AfterReturningAdviceAdapter()); registerAdvisorAdapter(new ThrowsAdviceAdapter()); } @Override public void registerAdvisorAdapter(AdvisorAdapter adapter) { this.adapters.add(adapter); }

As Spring involved in too many interceptors, enhancer, enhancement and other ways to enhance logical, in the last article we know to create several booster, AspectJAroundAdvice, AspectJAfterAdvice, AspectJAfterThrowingAdvice implement these booster MethodInterceptor the interfaces, and AspectJAfterReturningAdvice AspectJMethodBeforeAdvice MethodInterceptor does not implement the interface, and therefore can not meet AspectJAfterReturningAdvice AspectJMethodBeforeAdvice and invoke methods MethodInterceptor interface, the adapter mode AspectJMethodBeforeAdvice used herein and AspectJAfterReturningAdvice MethodInterceptor converted to meet the needs of the implementation class.

Traversing adapters, to find the corresponding adapter advice by adapter.supportsAdvice (advice), adapter.getInterceptor (advisor) into the corresponding advisor the interceptor

Let’s look at these booster

AspectJAroundAdvice

public class AspectJAroundAdvice extends AbstractAspectJAdvice implements MethodInterceptor, Serializable {

    public AspectJAroundAdvice(
            Method aspectJAroundAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aif) {

        super(aspectJAroundAdviceMethod, pointcut, aif);
    }

    @Override
    public boolean isBeforeAdvice() {
        return false;
    }

    @Override
    public boolean isAfterAdvice() {
        return false;
    }

    @Override
    public Object invoke(MethodInvocation mi) throws Throwable {
        if (!(mi instanceof ProxyMethodInvocation)) {
            throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi);
        }
        ProxyMethodInvocation pmi = (ProxyMethodInvocation) mi;
        ProceedingJoinPoint pjp = lazyGetProceedingJoinPoint(pmi);
        JoinPointMatch jpm = getJoinPointMatch(pmi);
        return invokeAdviceMethod(pjp, jpm, null, null);
    }

}

View Code

AspectJMethodBeforeAdvice

public class AspectJMethodBeforeAdvice extends AbstractAspectJAdvice implements MethodBeforeAdvice, Serializable {

    public AspectJMethodBeforeAdvice(
            Method aspectJBeforeAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aif) {

        super(aspectJBeforeAdviceMethod, pointcut, aif);
    }

    @Override
    public void before(Method method, Object[] args, @Nullable Object target) throws Throwable {
        invokeAdviceMethod(getJoinPointMatch(), null, null);
    }

    @Override
    public boolean isBeforeAdvice() {
        return true;
    }

    @Override
    public boolean isAfterAdvice() {
        return false;
    }

}

View Code

AspectJAfterAdvice

public class AspectJAfterAdvice extends AbstractAspectJAdvice
        implements MethodInterceptor, AfterAdvice, Serializable {

    public AspectJAfterAdvice(
            Method aspectJBeforeAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aif) {

        super(aspectJBeforeAdviceMethod, pointcut, aif);
    }


    @Override
    public Object invoke(MethodInvocation mi) throws Throwable {
        try {
            return mi.proceed();
        }
        finally {
            invokeAdviceMethod(getJoinPointMatch(), null, null);
        }
    }

    @Override
    public boolean isBeforeAdvice() {
        return false;
    }

    @Override
    public boolean isAfterAdvice() {
        return true;
    }

}

View Code

AspectJAfterReturningAdvice

public class AspectJAfterReturningAdvice extends AbstractAspectJAdvice
        implements AfterReturningAdvice, AfterAdvice, Serializable {

    public AspectJAfterReturningAdvice(
            Method aspectJBeforeAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aif) {

        super(aspectJBeforeAdviceMethod, pointcut, aif);
    }


    @Override
    public boolean isBeforeAdvice() {
        return false;
    }

    @Override
    public boolean isAfterAdvice() {
        return true;
    }

    @Override
    public void afterReturning(@Nullable Object returnValue, Method method, Object[] args, @Nullable Object target) throws Throwable {
        if (shouldInvokeOnReturnValueOf(method, returnValue)) {
            invokeAdviceMethod(getJoinPointMatch(), returnValue, null);
        }
    }
}

View Code

AspectJAfterThrowingAdvice

public class AspectJAfterThrowingAdvice extends AbstractAspectJAdvice
        implements MethodInterceptor, AfterAdvice, Serializable {

    public AspectJAfterThrowingAdvice(
            Method aspectJBeforeAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aif) {

        super(aspectJBeforeAdviceMethod, pointcut, aif);
    }


    @Override
    public boolean isBeforeAdvice() {
        return false;
    }

    @Override
    public boolean isAfterAdvice() {
        return true;
    }

    @Override
    public Object invoke(MethodInvocation mi) throws Throwable {
        try {
            return mi.proceed();
        }
        catch (Throwable ex) {
            if (shouldInvokeOnThrowing(ex)) {
                invokeAdviceMethod(getJoinPointMatch(), null, ex);
            }
            throw ex;
        }
    }

}

View Code

Next we look at MethodBeforeAdviceAdapter and AfterReturningAdviceAdapter two adapters, two adapters is MethodBeforeAdvice and AfterReturningAdvice adapted to the corresponding Interceptor

MethodBeforeAdviceAdapter

class MethodBeforeAdviceAdapter implements AdvisorAdapter, Serializable {
    @Override
    public boolean supportsAdvice(Advice advice) {
        //

Determining whether the type of advice MethodBeforeAdvice

return (advice instanceof MethodBeforeAdvice); } @Override public MethodInterceptor getInterceptor(Advisor advisor) { MethodBeforeAdvice advice = (MethodBeforeAdvice) advisor.getAdvice(); //

The advice packaged into MethodBeforeAdviceInterceptor

return new MethodBeforeAdviceInterceptor(advice); } } //

MethodBeforeAdviceInterceptor MethodInterceptor implements the interface, implements the invoke method, and properties as advice

public class MethodBeforeAdviceInterceptor implements MethodInterceptor, BeforeAdvice, Serializable { private final MethodBeforeAdvice advice; public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) { Assert.notNull(advice, "Advice must not be null"); this.advice = advice; } @Override public Object invoke(MethodInvocation mi) throws Throwable { this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis()); return mi.proceed(); } }

AfterReturningAdviceAdapter

class AfterReturningAdviceAdapter implements AdvisorAdapter, Serializable {
    @Override
    public boolean supportsAdvice(Advice advice) {
        return (advice instanceof AfterReturningAdvice);
    }

    @Override
    public MethodInterceptor getInterceptor(Advisor advisor) {
        AfterReturningAdvice advice = (AfterReturningAdvice) advisor.getAdvice();
        return new AfterReturningAdviceInterceptor(advice);
    }
}

public class AfterReturningAdviceInterceptor implements MethodInterceptor, AfterAdvice, Serializable {

    private final AfterReturningAdvice advice;

    public AfterReturningAdviceInterceptor(AfterReturningAdvice advice) {
        Assert.notNull(advice, "Advice must not be null");
        this.advice = advice;
    }

    @Override
    public Object invoke(MethodInvocation mi) throws Throwable {
        Object retVal = mi.proceed();
        this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
        return retVal;
    }

}

At this point we get into an interceptor chain, the chain includes AspectJAroundAdvice, AspectJAfterAdvice, AspectJAfterThrowingAdvice, MethodBeforeAdviceInterceptor, AfterReturningAdviceInterceptor

Next ReflectiveMethodInvocation class is encapsulated chain, and achieve proceed method ReflectiveMethodInvocation class one by one call interceptor, then we continue to explore, in the process is how to proceed to achieve enhanced pre-post enhancement before calling the target method after the target logical method call it?

Let’s take a look at ReflectiveMethodInvocation constructor, just a simple attribute assignment, but we have to pay attention to a particular variable currentInterceptorIndex, this variable is the representative of the Executive index Interceptor, starting at -1, Interceptor execute a first ++ this .currentInterceptorIndex

protected ReflectiveMethodInvocation(
        Object proxy, @Nullable Object target, Method method, @Nullable Object[] arguments,
        @Nullable Class targetClass, List interceptorsAndDynamicMethodMatchers) {

    this.proxy = proxy;
    this.target = target;
    this.targetClass = targetClass;
    this.method = BridgeMethodResolver.findBridgedMethod(method);
    this.arguments = AopProxyUtils.adaptArgumentsIfNecessary(method, arguments);
    this.interceptorsAndDynamicMethodMatchers = interceptorsAndDynamicMethodMatchers;
}

private int currentInterceptorIndex = -1;

The following are categories Proceed ReflectiveMethodInvocation Method:

public Object proceed() throws Throwable {
    // 首先,判断是不是所有的interceptor(也可以想像成advisor)都被执行完了。
    // 判断的方法是看currentInterceptorIndex这个变量的值,增加到Interceptor总个数这个数值没有,
    //

If it arrives, it executes the proxy method (invokeJoinpoint ()); if not to, continuing with the Interceptor.

if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) { return invokeJoinpoint(); } // 如果Interceptor没有被全部执行完,就取出要执行的Interceptor,并执行。 //

currentInterceptorIndex first increment

Object interceptorOrInterceptionAdvice =this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex); //

If Interceptor is PointCut type

if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) { InterceptorAndDynamicMethodMatcher dm = (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice; //

If the current method PointCut restrictions in line with the Interceptor, Interceptor implementation

if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {    //

When this variable here will pass into it, this is a very important point

return dm.interceptor.invoke(this
); } //

If not, then skip the current Interceptor, Interceptor to the next

else { return proceed(); } } //

If not PointCut type Interceptor, Interceptor executed directly inside enhancements.

else { return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this); } }

Because of how the length of the process, methods and target enhancement is executed, we will re-write an article to explain

 

Leave a Reply