基于Spring源码分析AOP的实现机制

Spring一个重要的特性就是提供了AOP,使得我们可以在原有的基础上增加我们自己的系统业务逻辑。使得我们系统业务逻辑与应用业务逻辑相分离,耦合性降低,并且大大的提高了开发的效率。Spring的AOP利用的就是动态代理方式,在Spring的AOP中,有两种实现方式。第一种,就是利用JDK的Proxy,另外一种就是采用CGLIB来实现的。 

基本概念:

Advice:

   通知,制定在连接点做什么,在Sping 中,他主要描述Spring 围绕方法调用注入的额外的行为,具有增强的功能 ,只能应用于所有方法,主要是由aopalliance.jar中包含aop定义中的接口,按这个接口实现aop标准。

PointCut

   切点,其决定一个 advice 应该应用于哪个连接点,也就是需要插入额外处理的地方的集合,例如,被某个advice 作为目标的一组方法。Spring pointcut 通常意味着标示方法,可以选择一组方法调用作为pointcut。

Advisor:

   通知器,把Advice封闭起来,加入Pointcut(切入点),Spring就可以知道在什么方法上拦截,以及拦截后所要做的具体行为了。Advisor有两种实现NameMatchMethodPointcutAdvisor按方法名字匹配。RegexpMethodPointcutAdvisor,按正则匹配。

AOP创建:

   AOP的创建主要分为两种一种是JDK的Proxy还有一种是CGLIB的,整个创建AOP的时序图一样,只不过差异在于最终AOPProxy产生AOP的过程。

   首先AOP的具体创建的时序图如下:

   以该时序图来分析我们AOP的创建过程。当我们使用AOP需要对某一个对象进行切面系统业务的时候,Spring会为该对象生成一个代理。具体是使用ProxyFactoryBean来配置我们的代理对象和方面行为。而具体的代理实现是通过JDK的Proxy或者CGLIB来完成的。ProxyFactoryBean是FactoryBean,调用该getObject方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
public  Object getObject()  throws  BeansException {
                 //初始化通知器链,实际上就是注册拦截器
     initializeAdvisorChain();
                 if  (isSingleton()) {
                     //返回生成的一个单件Proxy
       return  getSingletonInstance();
     }
     else  {
                     ....
                   //返回生成的Prototype的Proxy
     return  newPrototypeInstance();
     }
}

   整个方法包含了拦截器的初始化,以及获取代理对象的代理的过程。

   第一行主要就是初始化通知器链,注册被代理对象上的拦截器。

   当判断是一个单例对象的时候,就会通过getSingletonInstance()来获取单件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
private  synchronized  Object getSingletonInstance()
{
       if  ( this .singletonInstance ==  null )
{
      this .targetSource = freshTargetSource();
       if  ( this .autodetectInterfaces && getProxiedInterfaces().length ==  0  && !isProxyTargetClass())
           {
              //获取要代理的类
             Class targetClass = getTargetClass();
             ...设置该类的接口类型
              setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass, this .proxyClassLoader));
            }
           super .setFrozen( this .freezeProxy);
             //这里才是真正的获取Proxy,
              this .singletonInstance = getProxy(createAopProxy());
              }
     return  this .singletonInstance;
}

   在获取单件的时候,首先要做的就是要获取目标对象的接口,然后再次创建一个AopProxy来用于创建我们的AOP对象,这里createAopProxy的调用就是调用具体父类ProxyCreatorSupport来完成创建一个DefaultAopProxyFactory。当我们new一个ProxyFactoryBean的时候,它会调用父类的无参构造器,这里面就会默认的创建一个DefaultAopProxyFactory。这个就是我们默认的AOP代理工厂,最终是由它来决定我们到底使用JDK的Proxy还是CGLIB来创建代理的过程。在该类的成员属性中cglibAvailable初始化的时候会监测

ClassUtils.isPresent("net.sf.cglib.proxy.Enhancer", DefaultAopProxyFactory.class.getClassLoader());是否当前路径有cglib2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public  AopProxy createAopProxy(AdvisedSupport config)  throws  AopConfigException
{
if  (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
     Class targetClass = config.getTargetClass();
                 //代理类为空的时候
     if  (targetClass ==  null ) {
                 ....
     }
                // 代理对象为接口的时候
     if  (targetClass.isInterface()) {
          return  new  JdkDynamicAopProxy(config);
     }
     if  (!cglibAvailable) {
                                                                                                                                                                                                                                   
     }
     eturn CglibProxyFactory.createCglibProxy(config);
     }
          else  {
     return  new  JdkDynamicAopProxy(config);
  }

   当我们的AopProxy产生后,接着就可以调用getProxy来返回产生的代理对象,这里以JdkDynamicAopProxy为例来分析其创建的过程。

1
2
3
4
5
6
7
public  Object getProxy(ClassLoader classLoader) {
     if  (logger.isDebugEnabled()) {
             ....}
     Class[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces( this .advised);
     findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
         return  Proxy.newProxyInstance(classLoader, proxiedInterfaces,  this );
}

   当我们的Spring创建了代理对象后,当调用目标对象上的方法时,将都会被代理到InvocationHandler类的invoke方法中执行。在这里JdkDynamicAopProxy类实现了InvocationHandler接 口。

AOP拦截器

当使用JDK和CGLIB会生成不同的AopProxy代理对象,从而构造了不同的回调方法来启动对拦截器链的调用,比如在JdkDynamicAopProxy中的invoke方法,以及Cglib2AopProxy中使用DynamicAdvisedInterceptor的intercept方法。它们都使用了不同的AopProxy代理对象,但最终对AOP拦截的处理都是基本一样:它们对拦截器链的调用都是在ReflectiveMethodInvocation中通过proceed方法实现的。在这个proceed方法里,会逐个运行拦截器的拦截方法。在运行拦截器的拦截方法之前,需要对代理方法完成一个匹配判断,通过这个匹配判断来决定拦截器是否满足切面增强的要求。

   AOP拦截器的实现的时序图如下:  

   对目标的对象都会首先被代理至代理对象的invoke来调用,不管使用哪种创建代理对象的过程

下面是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
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)) {
         return  equals(args[ 0 ]);
     }
     if  (! this .hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
        return  hashCode();
     }
     if  (! this .advised.opaque && method.getDeclaringClass().isInterface() &&
     method.getDeclaringClass().isAssignableFrom(Advised. class )) {
     // 利用Proxy配置来调用服务,直接调用目标方法
     return  AopUtils.invokeJoinpointUsingReflection( this .advised, method, args);
     }
              Object retVal;
              if  ( this .advised.exposeProxy) {
              oldProxy = AopContext.setCurrentProxy(proxy);
              setProxyContext =  true ;
     }
                  //获取所要代理的对象
     target = targetSource.getTarget();
     if  (target !=  null ) {
            targetClass = target.getClass();
     }
     // 获得该方法上的拦截器链
     List<Object> chain =  this .advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
      //是否定义拦截器,否则直接调用目标对象的方法
     if  (chain.isEmpty()) {
                  //直接调用目标对象的方法
                     retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args);
     }
     else  {
           //如果不为空,则就创建一个ReflectiveMethodInvocation对象来先调用拦截器后调用目标方法
               invocation =  new  ReflectiveMethodInvocation
             (proxy, target, method, args, targetClass, chain);
     // 处理切入点上的拦截器的方法
     retVal = invocation.proceed();
     }
     if  (retVal !=  null  && retVal == target && method.getReturnType().isInstance(proxy) &&
     !RawTargetAccess. class .isAssignableFrom(method.getDeclaringClass())) {
         retVal = proxy;
     }
            return  retVal;
     }
     finally  {
     if  (target !=  null  && !targetSource.isStatic()) {           
         targetSource.releaseTarget(target);
     }
     if  (setProxyContext) {   
         AopContext.setCurrentProxy(oldProxy);
         }
     }


   对目标对象的方法直接调用是利用AopUtils.invokeJoinpointUsingReflection,该方法内部直接调用method.invoke(target, args),利用jdk自身的反射机制实现的;对拦截器链的调用时由ReflectiveMethodInvocation的proceed方法来实现的。

   在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
public  Object proceed()  throws  Throwable {
//直接调用目标方法,可能是拦截器调用结束或者无拦截器
//interceptorsAndDynamicMethodMatchers这个其实就是目标方法上的拦截器链的大小
if  ( this .currentInterceptorIndex ==  this .interceptorsAndDynamicMethodMatchers.size() -  1 ) {
             return  invokeJoinpoint();
}
//调用拦截器链上的对象,依次
Object interceptorOrInterceptionAdvice = this .interceptorsAndDynamicMethodMatchers.get(++ this .currentInterceptorIndex);
if  (interceptorOrInterceptionAdvice  instanceof  InterceptorAndDynamicMethodMatcher)
{
     // 这里获得相应的拦截器,如果拦截器可以匹配的上的话,那就调用拦截器的invoke 方法    
     InterceptorAndDynamicMethodMatcher dm = (InterceptorAndDynamicMethodMatcher)     interceptorOrInterceptionAdvice;
      if  (dm.methodMatcher.matches( this .method,  this .targetClass,  this .arguments)) {
         return  dm.interceptor.invoke( this );
       } else  {
            //调用拦截器链中的下一个拦截器
     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 );
       }
}


本文出自 “在云端的追梦” 博客,请务必保留此出处http://computerdragon.blog.51cto.com/6235984/1251718

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值