`
huibin
  • 浏览: 740509 次
  • 性别: Icon_minigender_1
  • 来自: 郑州
社区版块
存档分类
最新评论

Spring源代码解析(五):Spring AOP获取Proxy

阅读更多

下面我们来看看Spring的AOP的一些相关代码是怎么得到Proxy的,让我们我们先看看AOP和Spring AOP的一些基本概念:
Advice:
    通知,制定在连接点做什么,在Sping中,他主要描述Spring围绕方法调用注入的额外的行为,Spring提供的通知类型有:
    before advice,AfterReturningAdvice,ThrowAdvice,MethodBeforeAdvice,这些都是Spring AOP定义的接口类,具体的动作实现需要用户程序来完成。
Pointcut:
    切点,其决定一个advice应该应用于哪个连接点,也就是需要插入额外处理的地方的集合,例如,被某个advice作为目标的一组方法。Spring pointcut通常意味着标示方法,可以选择一组方法调用作为pointcut,Spring提供了具体的切点来给用户使用,比如正则表达式切点 JdkRegexpMethodPointcut通过正则表达式对方法名进行匹配,其通过使用 AbstractJdkRegexpMethodPointcut中的对MethodMatcher接口的实现来完成pointcut功能:

Java代码 复制代码
  1. public   final   boolean  matches(Method method, Class targetClass) {   
  2.      //这里通过放射得到方法的全名   
  3.     String patt = method.getDeclaringClass().getName() +  "."  + method.getName();   
  4.      for  ( int  i =  0 ; i <  this .patterns.length; i++) {   
  5.          // 这里是判断是否和方法名是否匹配的代码   
  6.          boolean  matched = matches(patt, i);   
  7.          if  (matched) {   
  8.              for  ( int  j =  0 ; j <  this .excludedPatterns.length; j++) {   
  9.                  boolean  excluded = matchesExclusion(patt, j);   
  10.                  if (excluded) {   
  11.                      return   false ;   
  12.                 }   
  13.             }   
  14.              return   true ;   
  15.         }   
  16.     }   
  17.      return   false ;   
  18. }  
    public final boolean matches(Method method, Class targetClass) {
        //这里通过放射得到方法的全名
        String patt = method.getDeclaringClass().getName() + "." + method.getName();
        for (int i = 0; i < this.patterns.length; i++) {
            // 这里是判断是否和方法名是否匹配的代码
            boolean matched = matches(patt, i);
            if (matched) {
                for (int j = 0; j < this.excludedPatterns.length; j++) {
                    boolean excluded = matchesExclusion(patt, j);
                    if(excluded) {
                        return false;
                    }
                }
                return true;
            }
        }
        return false;
    }


在JDKRegexpMethodPointcut中通过JDK中的正则表达式匹配来完成pointcut的最终确定:

Java代码 复制代码
  1. protected   boolean  matches(String pattern,  int  patternIndex) {   
  2.     Matcher matcher =  this .compiledPatterns[patternIndex].matcher(pattern);   
  3.      return  matcher.matches();   
  4. }  
    protected boolean matches(String pattern, int patternIndex) {
        Matcher matcher = this.compiledPatterns[patternIndex].matcher(pattern);
        return matcher.matches();
    }


Advisor:
当我们完成额外的动作设计(advice)和额外动作插入点的设计(pointcut)以后,我们需要一个对象把他们 结合起来,这就是通知器 - advisor,定义应该在哪里应用哪个通知。Advisor的实现有:DefaultPointcutAdvisor他有两个属性advice和 pointcut来让我们配置advice和pointcut。
接着我们就可以通过ProxyFactoryBean来配置我们的代理对象和方 面行为,在ProxyFactoryBean中有interceptorNames来配置已经定义好的通知器-advisor,虽然这里的名字叫做 interceptNames,但实际上是供我们配置advisor的地方,具体的代理实现通过JDK 的Proxy或者CGLIB来完成。因为ProxyFactoryBean是一个FactoryBean,在ProxyFactoryBean中我们通过 getObject()可以直接得到代理对象:

Java代码 复制代码
  1. public  Object getObject()  throws  BeansException {   
  2.      //这里初始化通知器链   
  3.     initializeAdvisorChain();   
  4.      if  (isSingleton()) {   
  5.      //根据定义需要生成单件的Proxy   
  6.          return  getSingletonInstance();   
  7.     }   
  8.      else  {   
  9.     .......   
  10.          //这里根据定义需要生成Prototype类型的 Proxy   
  11.          return  newPrototypeInstance();   
  12.     }   
  13. }  
    public Object getObject() throws BeansException {
        //这里初始化通知器链
        initializeAdvisorChain();
        if (isSingleton()) {
        //根据定义需要生成单件的Proxy
            return getSingletonInstance();
        }
        else {
        .......
            //这里根据定义需要生成Prototype类型的Proxy
            return newPrototypeInstance();
        }
    }


我们看看怎样生成单件的代理对象:

Java代码 复制代码
  1. private   synchronized  Object getSingletonInstance() {   
  2.      if  ( this .singletonInstance ==  null ) {   
  3.          this .targetSource = freshTargetSource();   
  4.          if  ( this .autodetectInterfaces && getProxiedInterfaces().length ==  0  && !isProxyTargetClass()) {   
  5.              // 这里设置代理对象的接口   
  6.             setInterfaces(ClassUtils.getAllInterfacesForClass( this .targetSource.getTargetClass()));   
  7.         }   
  8.          // Eagerly initialize the shared singleton instance.   
  9.          super .setFrozen( this .freezeProxy);   
  10.          // 注意这里的方法会使用ProxyFactory 来生成我们需要的Proxy   
  11.          this .singletonInstance = getProxy(createAopProxy());   
  12.          // We must listen to superclass advice change events to recache the singleton   
  13.          // instance if necessary.   
  14.         addListener( this );   
  15.     }   
  16.      return   this .singletonInstance;   
  17. }   
  18.   
  19. //使用createAopProxy放回的AopProxy来得到代理对象。   
  20. protected  Object getProxy(AopProxy aopProxy) {   
  21.      return  aopProxy.getProxy( this .beanClassLoader);   
  22. }  
    private synchronized Object getSingletonInstance() {
        if (this.singletonInstance == null) {
            this.targetSource = freshTargetSource();
            if (this.autodetectInterfaces && getProxiedInterfaces().length == 0 && !isProxyTargetClass()) {
                // 这里设置代理对象的接口
                setInterfaces(ClassUtils.getAllInterfacesForClass(this.targetSource.getTargetClass()));
            }
            // Eagerly initialize the shared singleton instance.
            super.setFrozen(this.freezeProxy);
            // 注意这里的方法会使用ProxyFactory来生成我们需要的Proxy
            this.singletonInstance = getProxy(createAopProxy());
            // We must listen to superclass advice change events to recache the singleton
            // instance if necessary.
            addListener(this);
        }
        return this.singletonInstance;
    }

    //使用createAopProxy放回的AopProxy来得到代理对象。
    protected Object getProxy(AopProxy aopProxy) {
        return aopProxy.getProxy(this.beanClassLoader);
    }


ProxyFactoryBean的父类是AdvisedSupport,Spring使用AopProxy接口把AOP代理的实现与框架的其他 部分分离开来;在AdvisedSupport中通过这样的方式来得到AopProxy,当然这里需要得到AopProxyFactory的帮助 - 下面我们看到Spring为我们提供的实现,来帮助我们方便的从JDK或者cglib中得到我们想要的代理对象:

Java代码 复制代码
  1. protected   synchronized  AopProxy createAopProxy() {   
  2.      if  (! this .isActive) {   
  3.         activate();   
  4.     }   
  5.      return  getAopProxyFactory().createAopProxy( this );   
  6. }  
    protected synchronized AopProxy createAopProxy() {
        if (!this.isActive) {
            activate();
        }
        return getAopProxyFactory().createAopProxy(this);
    }


而在ProxyConfig中对使用的AopProxyFactory做了定义:

Java代码 复制代码
  1. //这个DefaultAopProxyFactory是Spring用来生成 AopProxy的地方,   
  2. //当然了它包含JDK和Cglib两种实现方式。   
  3. private   transient  AopProxyFactory aopProxyFactory =  new  DefaultAopProxyFactory();  
    //这个DefaultAopProxyFactory是Spring用来生成AopProxy的地方,
    //当然了它包含JDK和Cglib两种实现方式。
    private transient AopProxyFactory aopProxyFactory = new DefaultAopProxyFactory();


其中在DefaultAopProxyFactory中是这样生成AopProxy的:

Java代码 复制代码
  1. public  AopProxy createAopProxy(AdvisedSupport advisedSupport)  throws  AopConfigException {   
  2.      //首先考虑使用cglib来实现代理对象,当然如果同时目标 对象不是接口的实现类的话   
  3.      if  (advisedSupport.isOptimize() || advisedSupport.isProxyTargetClass() ||   
  4.         advisedSupport.getProxiedInterfaces().length ==  0 ) {   
  5.          //这里判断如果不存在cglib库,直接抛出异常。   
  6.          if  (!cglibAvailable) {   
  7.              throw   new  AopConfigException(   
  8.                      "Cannot proxy target class because CGLIB2 is not available. "  +   
  9.                      "Add CGLIB to the class path or specify proxy interfaces." );   
  10.         }   
  11.          // 这里使用Cglib来生成Proxy,如果 target不是接口的实现的话,返回cglib类型的AopProxy   
  12.          return  CglibProxyFactory.createCglibProxy(advisedSupport);   
  13.     }   
  14.      else  {   
  15.          // 这里使用JDK来生成Proxy,返回JDK类 型的AopProxy   
  16.          return   new  JdkDynamicAopProxy(advisedSupport);   
  17.     }   
  18. }  
    public AopProxy createAopProxy(AdvisedSupport advisedSupport) throws AopConfigException {
        //首先考虑使用cglib来实现代理对象,当然如果同时目标对象不是接口的实现类的话
        if (advisedSupport.isOptimize() || advisedSupport.isProxyTargetClass() ||
            advisedSupport.getProxiedInterfaces().length == 0) {
            //这里判断如果不存在cglib库,直接抛出异常。
            if (!cglibAvailable) {
                throw new AopConfigException(
                        "Cannot proxy target class because CGLIB2 is not available. " +
                        "Add CGLIB to the class path or specify proxy interfaces.");
            }
            // 这里使用Cglib来生成Proxy,如果target不是接口的实现的话,返回cglib类型的AopProxy
            return CglibProxyFactory.createCglibProxy(advisedSupport);
        }
        else {
            // 这里使用JDK来生成Proxy,返回JDK类型的AopProxy
            return new JdkDynamicAopProxy(advisedSupport);
        }
    }


于是我们就可以看到其中的代理对象可以由JDK或者Cglib来生成,我们看到JdkDynamicAopProxy类和 Cglib2AopProxy都实现的是AopProxy的接口,在JdkDynamicAopProxy实现中我们可以看到Proxy是怎样生成的:

Java代码 复制代码
  1. public  Object getProxy(ClassLoader classLoader) {   
  2.      if  (logger.isDebugEnabled()) {   
  3.         Class targetClass =  this .advised.getTargetSource().getTargetClass();   
  4.         logger.debug( "Creating JDK dynamic proxy"  +   
  5.                 (targetClass !=  null  ?  " for ["  + targetClass.getName() +  "]"  :  "" ));   
  6.     }   
  7.     Class[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces( this .advised);   
  8.     findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);   
  9.      //这里我们调用JDK Proxy来生成需要的Proxy实 例   
  10.      return  Proxy.newProxyInstance(classLoader, proxiedInterfaces,  this );   
  11. }  
    public Object getProxy(ClassLoader classLoader) {
        if (logger.isDebugEnabled()) {
            Class targetClass = this.advised.getTargetSource().getTargetClass();
            logger.debug("Creating JDK dynamic proxy" +
                    (targetClass != null ? " for [" + targetClass.getName() + "]" : ""));
        }
        Class[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised);
        findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
        //这里我们调用JDK Proxy来生成需要的Proxy实例
        return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
    }


这样用Proxy包装target之后,通过ProxyFactoryBean得到对其方法的调用就被Proxy拦截了, ProxyFactoryBean的getObject()方法得到的实际上是一个Proxy了,我们的target对象已经被封装了。对 ProxyFactoryBean这个工厂bean而言,其生产出来的对象是封装了目标对象的代理对象。

分享到:
评论

相关推荐

    Spring源代码解析.rar

    Spring源代码解析5:Spring AOP获取Proxy .doc Spring源代码解析6:Spring声明式事务处理 .doc Spring源代码解析7:Spring AOP中对拦截器调用的实现 .doc Spring源代码解析8:Spring驱动Hibernate的实现.doc Spring...

    Spring 源代码解析

    Spring源代码解析5:Spring AOP获取Proxy;Spring源代码解析6:Spring声明式事务处理 ; Spring源代码解析7:Spring AOP中对拦截器调用的实现 Spring源代码解析8:Spring驱动Hibernate的实现;Spring源代码解析9:...

    Spring源代码解析(五):Spring_AOP获取Proxy.doc

    Spring源代码解析(五):Spring_AOP获取Proxy.doc

    Spring源代码解析

    Spring源代码解析(五):Spring AOP获取Proxy Spring源代码解析(六):Spring声明式事务处理 Spring源代码解析(七):Spring AOP中对拦截器调用的实现 Spring源代码解析(八):Spring驱动Hibernate的实现 Spring源...

    springyuanmaaping.zip

    Spring源代码解析5:Spring AOP获取Proxy;Spring源代码解析6:Spring声明式事务处理 ; Spring源代码解析7:Spring AOP中对拦截器调用的实现 Spring源代码解析8:Spring驱动Hibernate的实现;Spring源代

    spring源码分析(1-10)

    Spring源代码解析(五):Spring AOP获取Proxy Spring源代码解析(六):Spring声明式事务处理 Spring源代码解析(七):Spring AOP中对拦截器调用的实现 Spring源代码解析(八):Spring驱动Hibernate的实现 Spring源...

    spring源码分析

    5.Spring源代码解析(五):Spring AOP获取Proxy 6. Spring源代码解析(六):Spring声明式事务处理 7. Spring源代码解析(七):Spring AOP中对拦截器调用的实现 8. Spring源代码解析(八):Spring驱动Hibernate...

    Spring源码学习文档,绝对值得好好研究~~

    Spring源代码解析(五):Spring AOP获取Proxy.doc Spring源代码解析(六):Spring声明式事务处理.doc Spring源代码解析(七):Spring AOP中对拦截器调用的实现.doc Spring源代码解析(八):Spring驱动Hibernate的...

    springIOC核心组件分析.vsdx

    pring源代码各个模块作用 核心模块: 1 spring-core:核心模块 依赖注入IOC和DI的最基本实现 spring-beans:Bean工厂与装配 spring-context:上下文,即IOC容器 spring-context-support:对IOC的扩展,以及IOC子容器 ...

    SpringIOC,DI+dynamic proxy 实现盗版AOP

    SpringIOC,DI+dynamic proxy 实现盗版AOP的源代码

    Spring.net框架

    ConfigHandler类将根据该结点下的内容处理并创建一ConfigInfo对象(关于ConfigInfo、 ObjectInfo以及PropertyInfo的代码可自行查看源代码,这里就不再赘述)。ConfigHandler类的代码实现如下: using System; using ...

    spring_batch.zip

    spring boot整合mybatis plus 集成 starter多数据源 数据源加载在基于DataProperteis的基础上配置了 master slave, 将它们配置成map,map中是多个数据源的主键和数据源属性的映射; 因此, 再通过线程隔离 ...

    《MyEclipse 6 Java 开发中文教程》前10章

    3.2.23 CVS团队源代码管理(在线阅读) 66 3.2.24 修改文件的字符编码 66 3.3小结 66 第四章 用MyEclipse Database Explorer管理数据库 67 4.1功能一览 67 4.2使用MyEclipse Database Explorer透视图 69 4.2.1介绍 ...

    asp.net知识库

    ASP.NET 2.0 中的数据源控件 使用 ASP.NET 2.0 ObjectDataSource 控件 ASP.NET 2.0 的内部变化 使用SQL Cache Dependency 代替 Ibatisnet 提供的CacheModel ASP.NET 2.0中小心Profile命名冲突 使用ASP.NET 2.0 ...

Global site tag (gtag.js) - Google Analytics