Spring AOP源码分析(四)Spring AOP的JDK动态代理

本篇文章将会介绍上一个例子中的源码执行情况,从中熟悉整个SpringAOP的一些概念和接口设计。 

首先整个SpringAOP的分两大过程。 
第一个过程:根据xml文件或者注解中配置的拦截信息,生成相应的代理对象,这个代理对象包含了对应的拦截器。 
第二个过程:执行所拦截的方法时,就是调用代理对象的执行逻辑,完成各种拦截。 

本文章先对第二个过程进行源码解析。 
对第一个过程先做简单概述,如果拦截的类的对应方法是接口方法,则使用JDK的Proxy进行代理对象的创建否则使用CGLIB进行代理对象的创建。 

本工程采用的之前文章所给出案例链接:http://www.iteye.com/topic/336873 

简单概述如下: 
拦截类:TestAspect 

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

public void doAfter(JoinPoint jp) { 

        System.out.println("log Ending method: " 

                + jp.getTarget().getClass().getName() + "." 

                + jp.getSignature().getName()); 

    

   

    public Object doAround(ProceedingJoinPoint pjp) throws Throwable { 

        long time = System.currentTimeMillis(); 

        Object retVal = pjp.proceed(); 

        time = System.currentTimeMillis() - time; 

        System.out.println("process time: " + time + " ms"); 

        return retVal; 

    

   

    public void doBefore(JoinPoint jp) { 

        System.out.println("log Begining method: " 

                + jp.getTarget().getClass().getName() + "." 

                + jp.getSignature().getName()); 

    

   

    public void doThrowing(JoinPoint jp, Throwable ex) { 

        System.out.println("method " + jp.getTarget().getClass().getName() 

                + "." + jp.getSignature().getName() + " throw exception"); 

        System.out.println(ex.getMessage()); 

    }

xml的配置: 

?


1

2

3

4

5

6

7

8

9

10

11

12

<aop:config> 

        <aop:aspect id="TestAspect" ref="aspectBean"

             

            <!-- 配置com.spring.service包下所有类或接口的所有方法   -->

            <aop:pointcut id="businessService" 

                expression="execution(* com.lg.aop.service.*.*(..))" /> 

            <aop:before pointcut-ref="businessService" method="doBefore"/> 

            <aop:after pointcut-ref="businessService" method="doAfter"/> 

            <aop:around pointcut-ref="businessService" method="doAround"/>

            <aop:after-throwing pointcut-ref="businessService" method="doThrowing" throwing="ex"/> 

        </aop:aspect> 

    </aop:config>

建立单元测试类: 

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

@RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration(locations = "file:src/main/webapp/WEB-INF/mvc-servlet.xml")

public class AOPTest {

 

    @Autowired

    private AService aService;

    @Autowired

    private BServiceImpl bServiceImpl;

     

    @Test

    public void testAOP(){

        aService.barA();

        bServiceImpl.fooB();

    }

     

}

运行,效果如下: 

?


1

2

3

4

5

6

7

8

log Begining method: com.lg.aop.service.impl.AServiceImpl.barA

AServiceImpl.barA()

process time: 0 ms

log Ending method: com.lg.aop.service.impl.AServiceImpl.barA

log Begining method: com.lg.aop.service.BServiceImpl.fooB

BServiceImpl.fooB()

process time: 12 ms

log Ending method: com.lg.aop.service.BServiceImpl.fooB

接下来就是分析这一过程。 
首先我们会看到:此时的AService不再是它的实现者AServiceImpl,而是一个代理对象。 
由于barA()是接口方法,所以会选择使用JDK的Proxy进行代理对象的创建。如下在JdkDynamicAopProxy中: 

?


1

2

3

4

5

6

7

8

9

@Override

    public Object getProxy(ClassLoader classLoader) {

        if (logger.isDebugEnabled()) {

            logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());

        }

        Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised);

        findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);

        return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);

    }

来看下Proxy.newProxyInstance(classLoader, proxiedInterfaces, this)(详情见上一篇文章http://lgbolgger.iteye.com/blog/2117215)这个代码就是创建代理对象,第一个参数指定classLoader,第二个参数指定代理对象要实现的接口,第三个对象那个是InvocationHandler类型。来看下InvocationHandler: 

?


1

2

public Object invoke(Object proxy, Method method, Object[] args)

        throws Throwable;

一个代理对象和一个InvocationHandler绑定,当执行代理对象的方法时,就会去执行InvocationHandler的invoke(Object proxy, Method method, Object[] args)方法,在该方法中你可以选择相应的处理或者不执行代理对象的method方法。 
JdkDynamicAopProxy继承了InvocationHandler,所以上文中在创建代理对象时传的参数是this,即这个代理对象的方法的执行拦截情况全部在JdkDynamicAopProxy的invoke(Object proxy, Method method, Object[] args)方法中。 
我们先来了解下JdkDynamicAopProxy的一些属性: 

?


1

2

3

4

5

6

7

8

final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {

    /** Config used to configure this proxy */

    private final AdvisedSupport advised;

 

    private boolean equalsDefined;

    private boolean hashCodeDefined;

        //略

}

最关键的就是这个AdvisedSupport advised属性,它包含了我们在xml中配置的拦截信息,同时还包含了这个JdkDynamicAopProxy要代理的接口及其实现类,对于本文来说就是AService和AServiceImpl。JdkDynamicAopProxy可以根据这些配置信息来创建一个代理对象实现拦截,同时又可以执行AServiceImpl本身的业务方法。 

AdvisedSupport有两个重要的内容:TargetSource和List<Advisor> advisors和List<Class<?>> interfaces。 
TargetSource是目标类型和目标对象的包裹,在这里是AServiceImpl类和AServiceImpl对象。 
List<Class<?>> interfaces:包含了目标类型实现的接口,在这里就是AService 
List<Advisor> advisors:这里包含了我们在xml文件中配置的所有信息。这一部分是每个AdvisedSupport所共享的信息,而前面两个是每个AdvisedSupport所独有的信息。 

在详细看下AdvisedSupport: 

?


1

public class AdvisedSupport extends ProxyConfig implements Advised

接口Advised:主要包含TargetSource和List<Advisor> advisors和List<Class<?>> interface 
ProxyConfig:则是对要产生的代理对象的一些配置,如下: 

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

public class ProxyConfig implements Serializable {

 

    /** use serialVersionUID from Spring 1.2 for interoperability */

    private static final long serialVersionUID = -8409359707199703185L;

 

 

    private boolean proxyTargetClass = false;

 

    private boolean optimize = false;

 

    boolean opaque = false;

 

    boolean exposeProxy = false;

 

    private boolean frozen = false;

}

其中proxyTargetClass:表示是否强制使用CGLIB进行代理对象的创建 
exposeProxy :表示是否暴漏代理对象,实现线程内共享,这里又是使用ThreadLocal模式。 
他们分别对应xml配置中的 

?


1

2

<aop:config expose-proxy="false" proxy-target-class="false">

</aop:config>

继续回到AdvisedSupport ,对于它的List<Advisor> advisors则分别对应xml中的配置: 

?


1

2

3

4

<aop:before pointcut-ref="businessService1" method="doBefore" /> 

<aop:after pointcut-ref="businessService2" method="doAfter"/> 

<aop:around pointcut-ref="businessService2" method="doAround"/>

<aop:after-throwing pointcut-ref="businessService1" method="doThrowing" throwing="ex"/>

则产生的Advisor如下:每一个都是AspectJPointcutAdvisor对象,该对象所包含的内容如下: 

?


1

2

3

private final AbstractAspectJAdvice advice;

private final Pointcut pointcut;

private Integer order;

分别和xml配置中的内容相对应,在xml中你还可以指定order值,用来排序,这个顺序关系到这些拦截方法的执行顺序,之后我们会详细分析这个拦截器链的执行情况。 
如aop:before产生的AspectJPointcutAdvisor的AbstractAspectJAdvice 为AspectJMethodBeforeAdvice,Pointcut 为ComposablePointcut。具体的内容已在上文中接口说明中给出了说明。 

至此xml中的配置对应到AdvisedSupport基本上简单的了解了,这些内容的创建都是为下文方法的拦截做准备。 
下面继续回到JdkDynamicAopProxy,来看看拦截过程,即调用代理对象的方法,然后被拦截到代理对象的InvocationHandler的invoke方法,JdkDynamicAopProxy的invoke方法如下: 

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        MethodInvocation invocation;

        Object oldProxy = null;

        boolean setProxyContext = false;

 

        TargetSource targetSource = this.advised.targetSource;

        Class<?> targetClass = null;

        Object target = null;

 

        try {

            if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {

                // The target does not implement the equals(Object) method itself.

                return equals(args[0]);

            }

            if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {

                // The target does not implement the hashCode() method itself.

                return hashCode();

            }

            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;

 

//我们关注的重点1

            if (this.advised.exposeProxy) {

                // Make invocation available if necessary.

                oldProxy = AopContext.setCurrentProxy(proxy);

                setProxyContext = true;

            }

 

            // May be null. Get as late as possible to minimize the time we "own" the target,

            // in case it comes from a pool.

            target = targetSource.getTarget();

            if (target != null) {

                targetClass = target.getClass();

            }

//关注的重点2

            // Get the interception chain for this method.

            List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

 

            // Check whether we have any advice. If we don't, we can fallback on direct

            // reflective invocation of the target, and avoid creating a MethodInvocation.

            if (chain.isEmpty()) {

                // We can skip creating a MethodInvocation: just invoke the target directly

                // Note that the final invoker must be an InvokerInterceptor so we know it does

                // nothing but a reflective operation on the target, and no hot swapping or fancy proxying.

//关注的重点3

                retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args);

            }

            else {

//关注的重点4

                // We need to create a method invocation...

                invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);

                // Proceed to the joinpoint through the interceptor chain.

                retVal = invocation.proceed();

            }

 

            // Massage return value if necessary.

            Class<?> returnType = method.getReturnType();

            if (retVal != null && retVal == target && 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);

            }

        }

    }

关注的重点1:this.advised.exposeProxy即我们在xml文件中所配置的<aop:config expose-proxy="false">。如果配置为true,默认false,则意味着在该线程内将会暴露proxy代理对象,实现共享,即在该线程中的任何地方都可以都可以取到proxy代理对象。具体是由ThreadLocal设计模式来实现的,可以见我的另一篇博客对ThreadLocal设计模式的分析(http://lgbolgger.iteye.com/blog/2117216),来看下AopContext: 

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

private static final ThreadLocal<Object> currentProxy = new NamedThreadLocal<Object>("Current AOP proxy");

 

public static Object currentProxy() throws IllegalStateException {

        Object proxy = currentProxy.get();

        if (proxy == null) {

            throw new IllegalStateException(

                    "Cannot find current proxy: Set 'exposeProxy' property on Advised to 'true' to make it available.");

        }

        return proxy;

    }

 

static Object setCurrentProxy(Object proxy) {

        Object old = currentProxy.get();

        if (proxy != null) {

            currentProxy.set(proxy);

        }

        else {

            currentProxy.remove();

        }

        return old;

    }

AopContext内部使用了一个ThreadLocal<Object> currentProxy,它的两个方法都是静态方法,任何线程都可以调用这两个方法,当线程一调用setCurrentProxy方法时,AopContext的currentProxy就会去操作线程一内部的数据,当线程二调用setCurrentProxy方法时,AopContext的currentProxy就会去操作线程二内部的数据,互不干扰。这种情况不会引起多线程争抢资源数据的情况,同时实现了在某个线程中实现的数据的共享,而不用在某个线程中来回的传递参数。这就是ThreadLocal的设计模式,对于ThreadLocal<Object> currentProxy这样的类型属性,它仅仅是操作调用currentProxy的方法的当前线程的工具类,仅此而已。 

继续,这样的话就可以实现了在本线程中共享proxy代理对象,这就意味着我们在我们自定义的advice上通过AopContext可以获取到当前的代理对象。 
关注的重点2:根据我们的目标类和方法找到对应的拦截器链 
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); 
它内部是通过advised的一个this.advisorChainFactory来实现这一过程,advisorChainFactory默认为DefaultAdvisorChainFactory,实现过程如下: 

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

public List<Object> getInterceptorsAndDynamicInterceptionAdvice(

            Advised config, Method method, Class<?> targetClass) {

 

        // This is somewhat tricky... we have to process introductions first,

        // but we need to preserve order in the ultimate list.

        List<Object> interceptorList = new ArrayList<Object>(config.getAdvisors().length);

        boolean hasIntroductions = hasMatchingIntroductions(config, targetClass);

        AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();

        for (Advisor advisor : config.getAdvisors()) {

            if (advisor instanceof PointcutAdvisor) {

                // Add it conditionally.

                PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;

                if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(targetClass)) {

                    MethodInterceptor[] interceptors = registry.getInterceptors(advisor);

                    MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();

                    if (MethodMatchers.matches(mm, method, targetClass, hasIntroductions)) {

                        if (mm.isRuntime()) {

                            // Creating a new object instance in the getInterceptors() method

                            // isn't a problem as we normally cache created chains.

                            for (MethodInterceptor interceptor : interceptors) {

                                interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));

                            }

                        }

                        else {

                            interceptorList.addAll(Arrays.asList(interceptors));

                        }

                    }

                }

            }

            else if (advisor instanceof IntroductionAdvisor) {

                IntroductionAdvisor ia = (IntroductionAdvisor) advisor;

                if (config.isPreFiltered() || ia.getClassFilter().matches(targetClass)) {

                    Interceptor[] interceptors = registry.getInterceptors(advisor);

                    interceptorList.addAll(Arrays.asList(interceptors));

                }

            }

            else {

                Interceptor[] interceptors = registry.getInterceptors(advisor);

                interceptorList.addAll(Arrays.asList(interceptors));

            }

        }

        return interceptorList;

    }

上述过程分了三种情况来获取对应的Interceptor拦截器,config.getAdvisors()是我们在xml文件中所配置的所有的拦截情况,对于这些所有的拦截情况: 

当Advisor为PointcutAdvisor类型的时: 
这是我们本工程的配置的拦截,每个拦截都有pointcut,针对这种情况,首先判断该PointcutAdvisor的ClassFilter是否拦截了targetClass,若拦截则需继续判断PointcutAdvisor的MethodMatcher是否拦截targetClass的method方法。如果也拦截了,就需要将PointcutAdvisor的adice添加进去,则继续判断这个PointcutAdvisor的MethodMatcher是否是动态变化的,若是则需要将interceptor进一步包装成InterceptorAndDynamicMethodMatcher然后添加进去。 

当Advisor为IntroductionAdvisor类型的时候: 
IntroductionAdvisor应用在类上,不需要判断是否拦截了相应的方法。IntroductionAdvisor只有一个ClassFilter。此时仅仅去判断下是否拦截相应的类即可。 

其他情况: 
直接获取相应的interceptor。 

我们来看下根据Advisor来获取对应的MethodInterceptor方法: 

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {

        List<MethodInterceptor> interceptors = new ArrayList<MethodInterceptor>(3);

        Advice advice = advisor.getAdvice();

        if (advice instanceof MethodInterceptor) {

            interceptors.add((MethodInterceptor) advice);

        }

        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[interceptors.size()]);

    }

首先是判断advisor.getAdvice()是否已实现了MethodInterceptor,如AspectJAfterAdvice、AspectJAfterThrowingAdvice等。 
然后又是利用适配器模式,将不用的advice封装成对应的MethodInterceptor。如MethodBeforeAdviceAdapter,默认硬编码注册了三个 

?


1

2

3

4

5

public DefaultAdvisorAdapterRegistry() {

        registerAdvisorAdapter(new MethodBeforeAdviceAdapter());

        registerAdvisorAdapter(new AfterReturningAdviceAdapter());

        registerAdvisorAdapter(new ThrowsAdviceAdapter());

    }

看下MethodBeforeAdviceAdapter: 

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

class MethodBeforeAdviceAdapter implements AdvisorAdapter, Serializable {

 

    @Override

    public boolean supportsAdvice(Advice advice) {

        return (advice instanceof MethodBeforeAdvice);

    }

 

    @Override

    public MethodInterceptor getInterceptor(Advisor advisor) {

        MethodBeforeAdvice advice = (MethodBeforeAdvice) advisor.getAdvice();

        return new MethodBeforeAdviceInterceptor(advice);

    }

 

}

这就是典型的适配器模式,当Advice为MethodBeforeAdvice时,就会封装成MethodBeforeAdviceInterceptor。 

至此获取MethodInterceptor链的过程就完成了,回到List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);即List<Object>是一系列的MethodInterceptor构成的。 

继续看JdkDynamicAopProxy的invoke拦截方法: 

关注重点3:在获取MethodInterceptor链后,如果为空,则没有拦截器直接执行目标对象的方法。retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args);中的target对于本工程来说就是AServiceImpl,所以此方法的本质就是利用反射执行AServiceImpl的method方法。如下: 

?


1

2

3

4

5

6

7

8

9

10

11

public static Object invokeJoinpointUsingReflection(Object target, Method method, Object[] args)

            throws Throwable {

 

        // Use reflection to invoke the method.

        try {

            ReflectionUtils.makeAccessible(method);

            return method.invoke(target, args);

        }

           //略

     

    }

关注的重点4: 有了拦截器链后,就构造一个ReflectiveMethodInvocation来完成这一个调用过程。 
首先说下接口情况:ReflectiveMethodInvocation实现了ProxyMethodInvocation,ProxyMethodInvocation继承了MethodInvocation, 
MethodInvocation继承了Invocation, 
Invocation继承了Joinpoint,此时的Joinpoint是AOP联盟定义的接口。 
aspectj也有一个类似的JoinPoint,这两个是不一样的。 
Joinpoint:能够得到目标对象,同时指定了对目标对象的处理方法 

?


1

2

3

4

//定义了一个proceed()方法,来处理这些拦截器链的调用过程

 Object proceed() throws Throwable;

//返回目标对象,针对本工程就是AServiceImpl

   Object getThis();

Invocation:能够获取方法参数,此时方法可以是构造方法也可以是一般方法 

?


1

Object[] getArguments();

MethodInvocation:能够获取方法而不是构造方法,ConstructorInvocation才是获取构造方法,所以有了MethodInvocation就可以执行目标对象的方法了。 

?


1

Method getMethod();

ProxyMethodInvocation:能够获取代理代理对象,这个在Around通知时发挥作用,稍后会看到。 

?


1

Object getProxy();

此时ReflectiveMethodInvocation就拥有以下数据: 

?


1

2

3

4

5

6

protected final Object proxy;

    protected final Object target;

    protected final Method method;

    protected Object[] arguments;

    private final Class<?> targetClass;

        protected final List<?> interceptorsAndDynamicMethodMatchers;

interceptorsAndDynamicMethodMatchers则是由重点2中得出的拦截器链传给ReflectiveMethodInvocation的。然后看下ReflectiveMethodInvocation作为一个Joinpoint的proceed方法的执行过程: 

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

public Object proceed() throws Throwable {

        //  We start with an index of -1 and increment early.

        if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {

            return invokeJoinpoint();

        }

 

        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 {

            // It's an interceptor, so we just invoke it: The pointcut will have

            // been evaluated statically before this object was constructed.

            return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);

        }

    }

首先就是this.currentInterceptorIndex,它是ReflectiveMethodInvocation的一个属性,从-1开始: 

?


1

private int currentInterceptorIndex = -1;

当currentInterceptorIndex达到this.interceptorsAndDynamicMethodMatchers.size() - 1时,拦截器链执行完毕了,就去执行目标对象的方法。invokeJoinpoint()方法就是上文我们所说的通过反射进行目标方法的调用。 

继续看,拿出一个interceptorOrInterceptionAdvice,判断它是不是InterceptorAndDynamicMethodMatcher类型,这个类型在获取拦截器链的时候遇见了,我们再次回顾下: 

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

for (Advisor advisor : config.getAdvisors()) {

            if (advisor instanceof PointcutAdvisor) {

                // Add it conditionally.

                PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;

                if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(targetClass)) {

                    MethodInterceptor[] interceptors = registry.getInterceptors(advisor);

                    MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();

//重点在这里重点在这里重点在这里重点在这里重点在这里

                    if (MethodMatchers.matches(mm, method, targetClass, hasIntroductions)) {

                        if (mm.isRuntime()) {

                            // Creating a new object instance in the getInterceptors() method

                            // isn't a problem as we normally cache created chains.

                            for (MethodInterceptor interceptor : interceptors) {

                                interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));

                            }

                        }

                        else {

                            interceptorList.addAll(Arrays.asList(interceptors));

                        }

                    }

                }

            }

//略

因为InterceptorAndDynamicMethodMatcher的MethodMatcher是可变的,所以在执行前仍要进行判断一次,符合的话就执行InterceptorAndDynamicMethodMatcher中所包含的MethodInterceptor。不符合的话跳过本次拦截器,继续执行下一个拦截器。 

当拦截器是MethodInterceptor,则是执行这个拦截器。 
然后我们来看下具体有哪些拦截器链,以及具体是怎样的执行过程: 

我们会看到会有如下5个拦截器,依次是: 
ExposeInvocationInterceptor、MethodBeforeAdviceInterceptor、AspectJAfterAdvice、AspectJAroundAdvice、AspectJAfterThrowingAdvice。 

首先看第一个ExposeInvocationInterceptor: 
它是Spring自动帮我们添加的,它不属于InterceptorAndDynamicMethodMatcher类型,即不再进行判断是否符合当前函数。 
看下它的invoke方法的内容: 

?


1

2

3

4

5

6

7

8

9

10

public Object invoke(MethodInvocation mi) throws Throwable {

        MethodInvocation oldInvocation = invocation.get();

        invocation.set(mi);

        try {

            return mi.proceed();

        }

        finally {

            invocation.set(oldInvocation);

        }

    }

其中MethodInvocation mi始终是刚创建的ReflectiveMethodInvocation对象,它包含了一切要执行的信息。invocation则是一个ThreadLocal类型,如下: 

?


1

2

private static final ThreadLocal<MethodInvocation> invocation =

            new NamedThreadLocal<MethodInvocation>("Current AOP method invocation");

这里使用了ThreadLocal模式,将ReflectiveMethodInvocation对象这一重要对象存进当前线程的map集合中(ThreadLocal模式参见http://lgbolgger.iteye.com/blog/2117216),实现线程内ReflectiveMethodInvocation对象这一重要数据的共享,这就意味着我们在自定义的advice中可以通过invocation来获取ReflectiveMethodInvocation对象这一重要数据。 
同时ExposeInvocationInterceptor的currentInvocation方法用于获取当前线程的ReflectiveMethodInvocation对象 

?


1

2

3

4

5

6

7

8

9

public static MethodInvocation currentInvocation() throws IllegalStateException {

        MethodInvocation mi = invocation.get();

        if (mi == null)

            throw new IllegalStateException(

                    "No MethodInvocation found: Check that an AOP invocation is in progress, and that the " +

                    "ExposeInvocationInterceptor is upfront in the interceptor chain. Specifically, note that " +

                    "advices with order HIGHEST_PRECEDENCE will execute before ExposeInvocationInterceptor!");

        return mi;

    }

ExposeInvocationInterceptor即分析完了,此时ExposeInvocationInterceptor的invoke函数还没有执行完毕,然后就嵌套执行ReflectiveMethodInvocation对象的proceed方法, 
获取下一个拦截器MethodBeforeAdviceInterceptor,并且判断类型也属于InterceptorAndDynamicMethodMatcher类型的(我们自定义的几个都不属于), 
和ExposeInvocationInterceptor一样,直接执行,看下MethodBeforeAdviceInterceptor的invoke函数: 

?


1

2

3

4

public Object invoke(MethodInvocation mi) throws Throwable {

        this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() );

        return mi.proceed();

    }

先会执行我们在xml文件中配置好的advice,即我们自定义的doBefore方法,这就是前置通知。然后继续嵌套执行ReflectiveMethodInvocation对象的proceed方法,轮到了AspectJAfterAdvice的invoke方法: 

?


1

2

3

4

5

6

7

8

9

@Override

    public Object invoke(MethodInvocation mi) throws Throwable {

        try {

            return mi.proceed();

        }

        finally {

            invokeAdviceMethod(getJoinPointMatch(), null, null);

        }

    }

它的执行顺序则是先去执行后面的内容,当都执行完毕了才返回来执行这个advice。这就是后置通知。继续嵌套执行ReflectiveMethodInvocation对象的proceed方法,来到了AspectJAroundAdvice的invoke方法: 

?


1

2

3

4

5

6

7

8

9

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

    }

?


1

2

3

protected ProceedingJoinPoint lazyGetProceedingJoinPoint(ProxyMethodInvocation rmi) {

        return new MethodInvocationProceedingJoinPoint(rmi);

    }

lazyGetProceedingJoinPoint(pmi)就是将ReflectiveMethodInvocation对象作为一个ProxyMethodInvocation封装成一个MethodInvocationProceedingJoinPoint,如下: 

?


1

2

3

4

public MethodInvocationProceedingJoinPoint(ProxyMethodInvocation methodInvocation) {

        Assert.notNull(methodInvocation, "MethodInvocation must not be null");

        this.methodInvocation = methodInvocation;

    }

这个就是环绕通知,我们看下这通知我们所写的具体内容: 

?


1

2

3

4

5

6

7

public Object doAround(ProceedingJoinPoint pjp) throws Throwable { 

        long time = System.currentTimeMillis(); 

        Object retVal = pjp.proceed(); 

        time = System.currentTimeMillis() - time; 

        System.out.println("process time: " + time + " ms"); 

        return retVal; 

    }

这里面有一个很重要的信息ProceedingJoinPoint pjp,它决定了ReflectiveMethodInvocation的执行链是否继续执行下去,所以pjp.proceed()的本质仍然是调用ReflectiveMethodInvocation的proceed()方法,来继续下面拦截器的执行,也可以选择不执行,则拦截器链的执行就会终止了,会从不断嵌套的proceed函数中不断返回。 
这里将会执行到我们自定义的上面的doAround方法,当执行到pjp.proceed()时,又会返还到 
ReflectiveMethodInvocation的proceed()执行下一个拦截器,来到AspectJAfterThrowingAdvice,它的invoke方法为: 

?


1

2

3

4

5

6

7

8

9

10

11

public Object invoke(MethodInvocation mi) throws Throwable {

        try {

            return mi.proceed();

        }

        catch (Throwable t) {

            if (shouldInvokeOnThrowing(t)) {

                invokeAdviceMethod(getJoinPointMatch(), null, t);

            }

            throw t;

        }

    }

即先执行后面的拦截器,但后面的拦截器执行过程中出现异常时才会发挥该拦截器的作用。继续执行后面的拦截器,发现已经没了,则终于轮到目标对象的方法了,目标方法执行完毕后,返回上一个proceed的嵌套即AspectJAfterThrowingAdvice的invoke方法,发现没有抛出异常,则继续返回到上一个proceed嵌套,即AspectJAroundAdvice,即我们自定义的doAround中这一行代码Object retVal = pjp.proceed()返回了,继续完成我们自定义的doAround函数,完成后再返回上一个proceed嵌套,来到AspectJAfterAdvice,则开始执行这个advice的处理工作,即我们自定义的doAfter方法。再返回上一个proceed嵌套,来到MethodBeforeAdviceInterceptor,发现已经执行完毕继续返回上一个嵌套来到ExposeInvocationInterceptor,继续完成余下的工作,至此整个拦截过程就分析完毕了。在此过程中一个重要的参数就是我们配置的拦截器的顺序,顺序不同时执行过程就不一样,我们可以通过在xml配置中指定,下面附上我画的拦截器链的执行流程图。 

 

时间: 2025-01-21 01:45:18

Spring AOP源码分析(四)Spring AOP的JDK动态代理的相关文章

spring源码学习之【准备】jdk动态代理例子

一:被代理的对象所要实现的接口 1 package com.yeepay.testpoxy; 2 3 import java.util.Map; 4 5 /** 6 * 被动态代理的接口 7 * @author shangxiaofei 8 * 9 */ 10 public interface MyCheckPay { 11 /** 12 * 付钱的接口 13 * @param name 14 * @param money 15 * @return 16 */ 17 public Map<Str

Spring源码分析:实现AOP(转载)

这两天一直在读spring1.2的AOP实现源码,AOP实现原理说起来很简单,对于实现业务接口的对象使用java代理机制实现,而对于一般的类使用cglib库实现,但spring的实现还是比较复杂的,不过抓住了本质去看代码就容易多了.发现一篇04年写的<spring源码分析:实现AOP>,倒是不用自己再写了,04年的时候已经有很多人研读过spring的源码,而那时的我还在学校,对java半懂不懂的状态,就算到现在也不敢说真的懂了,继续学习.努力.文章如下:     我的问题        为了完

Spring AOP源码分析(八)SpringAOP要注意的地方

SpringAOP要注意的地方有很多,下面就举一个,之后想到了再列出来:  (1)SpringAOP对于最外层的函数只拦截public方法,不拦截protected和private方法,另外不会对最外层的public方法内部调用的其他方法也进行拦截,即只停留于代理对象所调用的方法.如下案例:  B类有两个public方法,foo1()和foo2(),foo1内部调用了foo2,简单如下:  ? 1 2 3 4 5 6 7 8 public void foo2() {          Syste

Spring AOP源码分析(七)ProxyFactoryBean介绍

这篇文章里面就要说说Spring自己的AOP,搞清楚哪种方式是Spring自己实现的AOP,哪种方式是Spring引入aspectj的AOP.  Spring自己的AOP实现在于ProxyFactoryBean.先看下使用案例(仍和之前的案例是一样的):接口AService.实现类AServiceImpl.通知MyBeforeAdvice  ? 1 2 3 4 5 6 public interface AService {       public void fooA(String _msg);

Spring AOP源码分析(五)Spring AOP的Cglib代理

上一篇文章介绍了Spring AOP的JDK动态代理的过程,这一篇文章就要介绍下Spring AOP的Cglib代理过程,仍然是使用上一篇文章的工程案例.  JDK动态代理是由JdkDynamicAopProxy来生成代理对象的,Cglib则是由CglibAopProxy来生成代理对象的.JdkDynamicAopProxy.CglibAopProxy实现了AopProxy接口,如下:  ? 1 2 3 4 5 6 7 public interface AopProxy {       Obje

Spring AOP源码分析(二)JDK动态代理和CGLIB介绍

本篇是介绍java实现代理对象的两种方法,JDK动态代理和CGLIB.  JDK动态代理:针对你所调用的方法是接口所定义的方法.动态的创建一个类,通过实现目标类的接口来实现代理.  CGLIB:没有限制.通过继承目标类来创建代理类,实现代理.  下面看案例:  案例一,JDK动态代理:  Person和Animals都实现了Say接口sayHello方法.现在就需要对他们的sayHello方法进行拦截.  Say接口如下:  ? 1 2 3 4 public interface Say {  

Spring事务源码分析(一)Spring事务入门

有时为了保证一些操作要么都成功,要么都失败,这就需要事务来保证.  传统的jdbc事务如下:  ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 @Test     public void testAdd(){         Connection con=null;         try {             con=DriverManager.getConnection(url , username

JUnit源码分析(四)——从Decorator模式说起

其实我这系列小文,名为源码分析,其实是自己读<设计模式>的读书笔记.Decorator模式在java的IO库中得到应用,java的IO库看起来复杂,其实理解了Decorator模式再回头看可以很好理解并使用.     Decorator模式,也就是装饰器模式,是对象结构型模式之一. 1.意图:动态地给一个对象添加一些额外的职责.给对象添加功能,我们首先想到的是继承,但是如果每增一个功能都需要继承,类的继承体系将无可避免地变的庞大和难以理解.面向对象设计的原则:优先使用组合,而非继承,继承的层次

spring cloud源码分析-zuul路由的部分源码解析

版本:spring-boot:1.5.3.RELEASE:spring cloud:Dalston.RELEASE(1.3.0.RELEASE) 路由定位器 配置所在jar包:spring-cloud-netflix-core-1.3.0.RELEASE.jar 顶层接口:RouteLocator 可刷新的路由:RefreshableRouteLocator extends RouteLocator 路由处理器:CompositeRouteLocator implements Refreshab