`
huibin
  • 浏览: 756949 次
  • 性别: 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源代码解析(五):Spring AOP获取Proxy Spring源代码解析(六):Spring声明式事务处理 Spring源代码解析(七):Spring AOP中对拦截器调用的实现 Spring源代码解析(八):Spring驱动Hibernate的实现 Spring源...

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

    本文将深入解析Spring AOP如何获取代理对象,即Proxy。 首先,我们需要理解AOP的核心概念: 1. **Advice**:通知,是切面实际执行的操作。在Spring中,Advice可以是Before、AfterReturning、AfterThrowing以及...

    springyuanmaaping.zip

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

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

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

    spring源代码解析

    "spring源代码解析(五):spring AOP获得proxy.doc"和"spring源代码解析(七):spring AOP中对拦截器调用的实现.doc"详细解释了AOP代理的生成过程,以及Aspect的实现和通知的执行流程。 5. **事务管理**:"spring...

    Spring源代码解析(七):Spring_AOP中对拦截器调用的实现.doc

    本文将详细解析Spring AOP如何利用这两个组件来实现拦截器链的调用。 首先,Spring在生成代理对象时,会使用`Proxy.newProxyInstance()`方法,这个方法需要三个参数:类加载器、被代理对象实现的接口列表以及一个...

    spring源代码分析:aop的实现

    《Spring源代码分析:AOP的实现》 在软件开发领域,Spring框架因其强大的功能和易用性,已经成为Java企业级应用的事实标准。其中,面向切面编程(Aspect Oriented Programming,简称AOP)是Spring的重要特性之一,...

    spring4 AOP 源代码

    接下来,我们将深入探讨Spring 4中的AOP概念、实现机制以及源代码解析。 **AOP概念** 1. **切面(Aspect)**:切面是关注点的模块化,它将一组相关或相互关联的功能封装在一起,可以看作是跨越多个对象的行为或责任...

    springIOC核心组件分析.vsdx

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

    spring aop jar 包

    Spring AOP(Aspect Oriented Programming,面向切面编程)是Spring框架的重要组成部分,它提供了一种在不修改源代码的情况下,对程序进行功能增强的技术。这个"spring aop jar 包"包含了实现这一功能所需的类和接口,...

    spring-aop AND proxy

    标题中的“spring-aop”指的是Spring框架中的面向切面编程(Aspect-Oriented Programming, AOP)模块,它提供了一种在不修改源代码的情况下,对程序进行功能增强的技术。AOP的核心概念包括切面(Aspect)、通知...

    Spring3.0源代码

    `org.springframework.aop`包包含了AOP的实现,如`Advisor`、`Pointcut`和`Proxy`等概念。 3. **IoC容器**:Spring的IoC容器负责管理应用的对象及其依赖。在`src`中,`BeanFactory`是IoC容器的基础,而`...

    SPRING_AOP_概念解析以及例子示范.docx

    5. **引入(Introduction)**:引入允许我们在现有类中添加新的方法和属性,无需修改源代码。 6. **目标(Target)**:目标对象是指被通知的对象,即切面关注的业务逻辑对象。 7. **代理(Proxy)**:代理是AOP的实现...

    spring源代码包

    源代码是理解任何软件系统内部运作的关键,对于Spring框架而言,通过阅读源码,我们可以深入理解其设计理念和实现机制。 在Spring框架的源代码中,有几个关键部分值得我们关注: 1. **IoC容器**:这是Spring的核心...

    Spring源代码(spring.zip)

    在Spring源代码中,我们可以看到以下几个关键组件: 1. **IoC容器**:IoC(Inversion of Control,控制反转)是Spring的核心,它负责管理对象的生命周期和对象间的依赖关系。在源代码中,`org.springframework....

    SpringIOC,DI+dynamic proxy 实现盗版AOP

    本文将深入探讨如何使用Spring的IOC和DI特性,结合动态代理(Dynamic Proxy)来实现一种类似AOP(面向切面编程)的功能,以达到在不修改原有代码的情况下增强或拦截方法调用的目的。 **一、Spring IOC(控制反转)*...

    springAop与spring定时器

    Spring AOP(面向切面编程)是Spring框架中的一个重要组件,它允许我们在不修改源代码的情况下,通过在程序运行时动态地将代码插入到方法调用中,来实现跨切面的关注点,如日志记录、性能监控、事务管理等。而Spring...

Global site tag (gtag.js) - Google Analytics