深入理解Spring AOP之二代理对象生成

深入理解Spring AOP之二代理对象生成

spring代理对象

上一篇博客中讲到了Spring的一些基本概念和初步讲了实现方法,当中提到了动态代理技术,包含JDK动态代理技术和Cglib动态代理

动态代理这部分我有过一篇博客介绍:动态代理,想深入了解的朋友能够看一看,再回想一下,Spring中怎样区分採用JDK动态代理和CGlib动态代理:

  1. 假设目标对象的实现类实现了接口。Spring AOP 将会採用 JDK 动态代理来生成 AOP 代理类;
  2. 假设目标对象的实现类没有实现接口,Spring AOP 将会採用 CGLIB 来生成 AOP 代理类

将下载编译好的Spring-aop包中的源代码打开,例如以下图所看到的

对应的源代码能够在Github上面。然后用工具编译成project文件。再导入eclipse里面来阅读,网上有对应的方法

Spring AOP 使用类 org.springframework.aop.framework.ProxyFactory进行织入。找到ProxyFactory相应的相关内容,然后整理例如以下类图

Spring代理类怎样生成

调用方法步骤能够例如以下所看到的:

  • 新建一个target,target使我们须要操作的目标
  • 定义一个代理工厂,能够是ProxyFactory或者ProxyFactorybean两种方法,Bean顾名思义,採用的Spring中的IOC机制,而ProxyFactory方法则能够直接得到
  • 增加通知
  • 得到代理实例,通过getproxy()方法

    先看ProxyFactory是怎样得到代理类的

  • 找到proxyFactory中的getProxy()方法;
    
    public Object getProxy() {
            return createAopProxy().getProxy();
        }
    
    protected final synchronized AopProxy createAopProxy() {
            if (!this.active) {
                activate();
            }
            return getAopProxyFactory().createAopProxy(this);
        }
    
    

    实现它获得一个用来产生代理的实例, createAopProxy() 方法返回 AopProxy, 然后再调用 getProxy() 方法产生详细的代理对象,这里以下再细讲。由于在ProxyFactoryBean中也用到了一样的父类。

  • 得到了一个AopProxy之后,再利用AopProxy的方法,依据条件获得一个用来产生代理的实例。要么是JDK动态代理生成,要么是Cglib代理生成。

    ProxyFactoryBean是怎样获得代理类的

    找到ProxyFactoryBean方法,ProxyFactoryBean是在Spring IoC环境中,创建AOP应用的最底层方法,从中。能够看到一条实现AOP的基本线索。借助如上类图,看看AOP代理类是怎样产生的(回想下动态代理中的代理类生成方法)

  • 先看看ProxyFactoryBean中的getObject方法

    为什么要先看getObject方法呢:假设容器中的某个对象持有某个FactoryBean的引用,它取得的不是FactoryBean本身,而是FactoryBean的getObject()方法所返回的对象。

    所以。假设容器中某个对象依赖于ProxyFactoryBean,那么它将会使用到ProxyFactoryBean的getObject()方法所返回的代理对象

        @Override
        public Object getObject() throws BeansException {
            initializeAdvisorChain(); //初始化通知器
            if (isSingleton()) {
                return getSingletonInstance();//依据定义生成单例的Proxy
            }
            else {
                if (this.targetName == null) {
                    logger.warn("Using non-singleton proxies with singleton targets is often undesirable. " +
                            "Enable prototype proxies by setting the ‘targetName‘ property.");
                }
                return newPrototypeInstance(); //这里依据定义生成prototype的Proxy
            }
        }
    
    
  • 继续跟踪getSingletonInstance()方法。这个地方能够看出点东西
    
    private synchronized Object getSingletonInstance() {
            if (this.singletonInstance == null) {
                this.targetSource = freshTargetSource();//返回被 代 理的 目标对象
                if (this.autodetectInterfaces && getProxiedInterfaces().length == 0 && !isProxyTargetClass()) {
                    //从targetSource中获取目标对象的Class
    
                    Class<?> targetClass = getTargetClass();
                    if (targetClass == null) {
                        throw new FactoryBeanNotInitializedException("Cannot determine target class for proxy");
                    }
        //这里设置代理对象的接口         setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass, this.proxyClassLoader));
                }
                // 初始化共享的单例
                super.setFrozen(this.freezeProxy);
            //这里会使用ProxyFactory来生成须要的Proxy
                this.singletonInstance = getProxy(createAopProxy());
            }
            return this.singletonInstance;
        }
    
    

    这里看看setFrozen()和createAopProxy()方法,调用的是proxyFactoryBean上一层接口ProxyCreatorSupport中的方法(看类图),

    
    protected final synchronized AopProxy createAopProxy() {
            if (!this.active) {
                activate();
            }
            return getAopProxyFactory().createAopProxy(this); //这里借助了AopProxyFactory
        }
    

    以下这非常重要。getAopProxyFactory()方法,

    public AopProxyFactory getAopProxyFactory() {
            return this.aopProxyFactory;
        }
    
    

    尽管返回的是aopProxyFactory可是我们假设追踪到构造函数中,我们发现其有用的是new DefaultAopProxyFactory();

    
    private AopProxyFactory aopProxyFactory;
        public ProxyCreatorSupport() {
            this.aopProxyFactory = new DefaultAopProxyFactory();
        }
    
    

    继续追踪到DefaultAopProxyFactory中,找到createAopProxy()方法,最终真相大白,例如以下

    
    @Override
        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.");
                }
                if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
                    return new JdkDynamicAopProxy(config);
                }
                return new ObjenesisCglibAopProxy(config);
            }
            else {
                return new JdkDynamicAopProxy(config);
            }
        }
    

    能够看到当中的代理对象能够由JDK或者Cglib来生成的,JdkDynamicAopProxy类和Cglib2AopProxy都实现的是AopProxy的接口。上面的这些逻辑就是要推断採用两种动态代理中的那一种。详细的规则能够參考最上面的介绍。到了这里。可能对JDK动态代理有点心动,毕竟动态代理中接触过了,例如以下是JdkDynamicAopProxy中实现代理的方法-getproxy()方法

    
    @Override
        public Object getProxy(ClassLoader classLoader) {
            if (logger.isDebugEnabled()) {
                logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());
            }
            //依据advised 中 的 配 置信息,将proxy须要代 理的接口放入proxiedInterfaces 中
            Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised);
            findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
            //以下这种方法眼熟吧,哈哈 没错就是JDK中的动态代理经典方法
            return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
        }
    
    

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

    总结

    上面讲了怎么多,简单回想下代理对象是怎样生成的

    1、上面讲到了两种生成代理对象的方法,一种是通过ProxyFactory,一种是通过ProxyFactoryBean。

    第一种获取比較简单。可是须要手工的进行写代码,而另外一种是通过Spring的IOC机制来控制Bean的生成。

    2、不管是ProxyFactory或者ProxyFactoryBean都是要通过createAopProxy().getProxy()来获取对应的代理对象,而通过Proxyfactory比較直接,上面重点介绍的是通过ProxyFactoryBean获得proxy。

    3、首先,找到ProxyFactoryBean的getObject方法。为什么?(主要是跟Bean容器中getObject能返回代理对象)

    4、其次调用getSingletonInstance()。在getSingletonInstance方法中引入了super中的方法,super是指ProxyCreatorSupport。这里ProxyCreatorSupport是ProxyFactoryBean和ProxyFactory的父类,已经做了非常多工作,仅仅需在ProxyFactoryBean的getObject()方法中通过父类的createAopProxy()取得对应的AopProxy。

    5、跟踪createAopProxy方法。追踪到了ProxyCreatorSupport中,然后,借助了AopProxyFactory,此时得到的aopProxyFactory,在构造函数中已经定义为new DefaultAopProxyFactory()

    6、进入DefaultAopProxyFactory中。找到createAopProxy方法。在这里推断是调用JDK动态或者CGlib动态中的一种。

  • 时间: 2024-10-21 10:55:26

    深入理解Spring AOP之二代理对象生成的相关文章

    深入理解Spring AOP之基本概念

    深入理解Spring AOP之基本概念 AOP到底是什么 Spring AOP和IOC是听到的关于Spring最频繁的两个词了.现在来重点关注AOP这个词,IOC先放一边,下面这段话摘自Spring优势中关于面向切面的介绍: 面向切面--Spring提供了面向切面编程的丰富支持,允许通过分离应用的业务逻辑与系统级服务(例如审计(auditing)和事务(transaction)管理)进行内聚性的开发.应用对象只实现它们应该做的--完成业务逻辑--仅此而已.它们并不负责(甚至是意识)其它的系统级关

    AOP代理对象生成

    AOP(Aspect-OrientedProgramming,面向方面编程)是OOP(Object-Oriented Programing,面向对象编程)的良好补充与完善,后者侧重于解决 从上到下的存在明显层次逻辑关系的问题,而前者则侧重于由左至右的水平散布的无明显逻辑关系但具备相同行为的问题.AOP抽象的是相同的行为而非 关联的行为,用于提供通用服务支持,而非业务逻辑处理,其核心思想是"将应用程序中的商业逻辑同对其提供支持的通用服务进行分离. AOP植入有多种不同方式,主要分为以下三种方式:

    用spring aop实现动态代理的例子

    下面由我来给大家展示用spring aop实现动态代理的例子(电脑打印) 下面就看一下具体的代码: 先定义一个打印机的接口 1 package aop007_ComPrint; 2 3 public interface Print { 4 5 public void ColorPrint(); //彩色打印 6 public void WhitePrint(); //黑白打印 7 } 然后定义两个实现类,分别实现彩色打印和黑白打印 1 package aop007_ComPrint; 2 3 p

    Spring AOP --JDK动态代理方式

    我们知道Spring是通过JDK或者CGLib实现动态代理的,今天我们讨论一下JDK实现动态代理的原理. 一.简述 Spring在解析Bean的定义之后会将Bean的定义生成一个BeanDefinition对象并且由BeanDefinitionHolder对象持有.在这个过程中,如果Bean需要被通知切入,BeanDefinition会被重新转换成一个proxyDefinition(其实也是一个BeanDefinition对象,只不过描述的是一个ProxyFactoryBean).ProxyFa

    Spring AOP不拦截从对象内部调用的方法

    拦截器的实现原理很简单,就是动态代理,实现AOP机制.当外部调用被拦截bean的拦截方法时,可以选择在拦截之前或者之后等条件执行拦截方法之外的逻辑,比如特殊权限验证,参数修正等操作. 但是最近在项目中要在一个事务中跨数据源进行操作.数据库跨源就不在这里说了,可以自行百度. 这里出现的问题就是,如果我们要拦截某个类的多个方法,且在该类的方法中使用this调用要拦截的方法时会导致拦截失败. 这样说有点抽象,看一个代码: package com.intsmaze.before; public clas

    Spring AOP不拦截从对象内部调用的方法原因

    拦截器的实现原理很简单,就是动态代理,实现AOP机制.当外部调用被拦截bean的拦截方法时,可以选择在拦截之前或者之后等条件执行拦截方法之外的逻辑,比如特殊权限验证,参数修正等操作. 但是最近在项目中要在一个事务中跨数据源进行操作.数据库跨源就不在这里说了,可以自行百度. 这里出现的问题就是,如果我们要拦截某个类的多个方法,且在该类的方法中使用this调用要拦截的方法时会导致拦截失败. 这样说有点抽象,看一个代码: package com.intsmaze.before; public clas

    Spring——AOP(动态代理)

    以例子说明: 一.创建两个接口,并创建各自的实现类,实现类在XML文件中进行配置,并在测试类中取得各实现类的实例 二.创建代理类,实现InvocationHandler接口 (1)声明实际代理的对象 1 private Object obj;  (2)创建绑定的方法,通过传入的实际代理对象创建对应的代理对象 1 /** 2 * @param obj 3 * @return 代理对象 4 */ 5 public Object bind(Object obj) 6 { 7 this.obj = ob

    如何简单理解spring aop和事务

    用比喻的方法理解吧: 初学者的理解,仅仅为了个人好记 aop:由三部分组成:工具箱,工人,为工人分配工具 tx事务:由四部分组成:管理者,制度,工人,向工人通知管理制度  为什么这样理解呢?个人觉得好记: 在aop 中有切面:切面内的东西用来公共使用,类似于工具箱: ref就是这个工具箱的具体bean.. <aop:aspect id="***" ref="*****"> 切点:切点是许多符合切点表达式的东西,只要符合就可以使用公共的东西.根据表达式,挑

    正确理解Spring AOP中的Around advice

    Spring AOP中,有Before advice和After advice,这两个advice从字面上就可以很容易理解,但是Around advice就有点麻烦了. 乍一看好像是Before advice和After advice的组合,也就是说pointcut会在joinpoint执行前后各执行一次.但是这种理解是不正确的,如果这样理解的话,就会产生这样的疑问:spring aop Around类型为什么只执行一次 ,这个帖子是我碰巧看到. 那么怎么样理解才是正确的呢?我们来看一下Spri