深入理解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动态中的一种。
  • 深入理解Spring AOP之二代理对象生成的更多相关文章

    1. 死磕Spring之AOP篇 - Spring AOP两种代理对象的拦截处理

      该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读. Spring 版本:5.1 ...

    2. Spring Aop(十四)——Aop自动创建代理对象的原理

      转发地址:https://www.iteye.com/blog/elim-2398725 Aop自动创建代理对象的原理 我们在使用Spring Aop时,通常Spring会自动为我们创建目标bean的 ...

    3. Spring AOP 和 动态代理技术

      AOP 是什么东西 首先来说 AOP 并不是 Spring 框架的核心技术之一,AOP 全称 Aspect Orient Programming,即面向切面的编程.其要解决的问题就是在不改变源代码的情 ...

    4. AOP代理对象生成

      AOP(Aspect-OrientedProgramming,面向方面编程)是OOP(Object-Oriented Programing,面向对象编程)的良好补充与完善,后者侧重于解决 从上到下的存 ...

    5. spring AOP 之二:@AspectJ注解的3种配置

      @AspectJ相关文章 <spring AOP 之二:@AspectJ注解的3种配置> <spring AOP 之三:使用@AspectJ定义切入点> <spring ...

    6. Spring AOP之动态代理

      软件151 李飞瑶 一.Spring 动态代理中的基本概念  1.关注点(concern)    一个关注点可以是一个特定的问题,概念.或者应用程序的兴趣点.总而言之,应用程序必须达到一个目标    ...

    7. spring 理解Spring AOP 一个简单的约定游戏

      应该说AOP原理是Spring技术中最难理解的一个部分,而这个约定游戏也许会给你很多的帮助,通过这个约定游戏,就可以理解Spring AOP的含义和实现方法,也能帮助读者更好地运用Spring AOP ...

    8. 深入理解Spring AOP 1.0

      本文相关代码(来自官方源码spring-test模块)请参见spring-demysify org.springframework.mylearntest包下. 统称能够实现AOP的语言为AOL,即( ...

    9. 深入理解Spring AOP思想

      什么是AOP?AOP解决了什么问题? 在传统的开发模式中,以下层次的是非常常见的一种,业务层每一个方法都要有重复的事务代码 如何改善这个问题? AOP希望将A.B 这些分散在各个业务逻辑中的相同代码, ...

    随机推荐

    1. 使用Markdown写作

      简介 Markdown是一种轻量级标记语言,创始人为约翰·格鲁伯(John Gruber).它允许人们"使用易读易写的纯文本格式编写文档,然后转换成有效的XHTML(或者HTML)文档&qu ...

    2. windows nginx配置https访问

      本文主要记录在windows下安装nginx 环境:win10-64位. 1.  到nginx官网上下载相应的安装包,http://nginx.org/en/download.html: 下载进行解压 ...

    3. iOS 开发网络篇—监测网络状态

      iOS开发网络篇—监测网络状态 一.说明 在网络应用中,需要对用户设备的网络状态进行实时监控,有两个目的: (1)让用户了解自己的网络状态,防止一些误会(比如怪应用无能) (2)根据用户的网络状态进行 ...

    4. ICE简单介绍及使用示例

      转自:http://blog.csdn.net/zhu2695/article/details/51494664 1.ICE是什么? ICE是ZEROC的开源通信协议产品,它的全称是:The Inte ...

    5. 1.介绍(introduction)

      这里主要记录一本书的学习过程: 条件独立: 意思是X和Y在given Z的情况下是独立的. 满足P(X,Y|Z) = P(X|Z)*P(Y|Z)以及P(X|Y,Z) = P(X|Z) 条件独立的一些性 ...

    6. JavaScript之JS的数据类型

      前言 JavaScript一共有6中数据类型: 基本数据类型(5):字符串(String).数字(Number).布尔(Boolean).数组(Array).空(Null).未定义(Undefined ...

    7. babel配置项目目录支持转换es6语法,引入非项目目录js后,引入Js转换无效

      我遇到了一个问题,我在已经配置babel的项目中通过require引入了一个项目目录外层的另一个js文件,前期是可以成功转换并打包的,但是到了后期就不行了,报错: 这个报错的意思是,引入的js文件中有 ...

    8. Kindeditor视频上传问题处理

      初始的时候,video这个标签kindeditor是不识别的,只要html处理或者全屏的时候,都会被排除掉.如果想要video存在,则需要设置属性filterMode :false 如果只是想要某个标 ...

    9. Sublime Text 插件之HTML-CSS-JS Prettify—格式化HTML CSS JS与显示函数列表

      插件名称:HTML-CSS-JS Prettify 安装步骤: 1.ctrl + shift + p 打开控制台2.输入install package,选择install package(如果已经安装 ...

    10. 关于linux - Centos 7 下DHCP服务的安装与配置

      DHCP(Dynamic Host Configuration Protocol,动态主机配置协议)是一个局域网的网络协议,使用UDP协议工作, 主要有两个用途:给内部网络或网络服务供应商自动分配IP ...