Spring源码分析-SpringAop什么时候调用jdk动态代理?什么时候调用cglib

摘要:
proxyFactory.isProxyTargetClass()){如果{proxyFactory.setProxyTargetClass;}否则{evaluateProxyInterface;}}Advisor[]advisors=buildAdvisors;代理工厂。addAdvisors;代理工厂。setTargetSource;定制代理工厂;代理工厂。setFrozen;如果{proxyFactory.setPreFiltered;}//核心代码returnproxyFactory getProxy;}然后在ProxyFactory{//createAopProxy方法中输入getProxy方法publicObjectgetProxy,以确定是选择jdk动态代理还是cglib代理returncreateAopProxy().getProxy;}然后输入createAopProxy方法protectedfinalsynchronizedOpProxycreateAopProxy(){if(!

1.导入log4j.jar,开启log4j DEBUG模式

2.查看打印日志,可以发现一个重要信息:

2020-03-03 15:13:31,870 DEBUG [org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator] - Creating implicit proxy for bean 'userService' with 0 common interceptors and 4 specific interceptors

spring再执行aop时,执行了 AnnotationAwareAspectJAutoProxyCreator 类中的某个方法。

备注:有时候通过打印日志,可以快速了解代码执行了哪些过程。

 
3.通过打印日志提示的类 AnnotationAwareAspectJAutoProxyCreator 及“Creating implicit proxy”找到最终执行的是其父类 AbstractAutoProxyCreator 中的 protected Advisor[] buildAdvisors(String beanName, Object[] specificInterceptors) 方法

4. 重新在 buildAdvisors 这个方法打断点进行调试

Spring源码分析-SpringAop什么时候调用jdk动态代理?什么时候调用cglib第1张

5.AbstractAutoProxyCreator 类中发现有一个重要的方法createProxy 如下:

protected Object createProxy(
    Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {

    if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
        AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
    }

    ProxyFactory proxyFactory = new ProxyFactory();
    proxyFactory.copyFrom(this);

    if (!proxyFactory.isProxyTargetClass()) {
        if (shouldProxyTargetClass(beanClass, beanName)) {
            proxyFactory.setProxyTargetClass(true);
        }
        else {
            evaluateProxyInterfaces(beanClass, proxyFactory);
        }
    }

    Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
    proxyFactory.addAdvisors(advisors);
    proxyFactory.setTargetSource(targetSource);
    customizeProxyFactory(proxyFactory);

    proxyFactory.setFrozen(this.freezeProxy);
    if (advisorsPreFiltered()) {
        proxyFactory.setPreFiltered(true);
    }
    // 核心代码
    return proxyFactory.getProxy(getProxyClassLoader());
}

接着进入 ProxyFactory 中的 getProxy 方法

public Object getProxy(ClassLoader classLoader) {
    // createAopProxy 方法中判断是选择jdk动态代理还是cglib方式代理
    return createAopProxy().getProxy(classLoader);
}

再进入到 ProxyCreatorSupport 中的 createAopProxy 方法

protected final synchronized AopProxy createAopProxy() {
    if (!this.active) {
        activate();
    }
    // getAopProxyFactory() 返回的是 DefaultAopProxyFactory对象,所以重点还是在 createAopProxy 方法上
    return getAopProxyFactory().createAopProxy(this);
}

6.进入到 DefaultAopProxyFactory 类中的 createAopProxy 方法,这个方法就是如何选择JDK动态代理还是Cglib代理

@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
    // 1.config.isProxyTargetClass() 代表 配置中的proxy-target-class属性true/false,默认false
    // 
    if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
        // 目标代理类,如 com.service.impl.UserServiceImpl
        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.");
        }
        // 目标类如果是一个接口 或者 (Proxy是JDK动态代理用到的一个类)也就是说这里表示目标类是否为这个Proxy 类型
        if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
            return new JdkDynamicAopProxy(config);
        }
        return new ObjenesisCglibAopProxy(config);
    }
    else {
        return new JdkDynamicAopProxy(config);
    }
}

 这段代码是确定Spring选择JDK动态代理还理CGLIB代理的核心,

  • config.isOptimize:表示是否使用了优化策略,配置的属性optimize值决定;
  • config.isProxyTargetClass:表示是否是代理目标类,配置的属性proxy-target-class值决定;
  • hasNoUserSuppliedProxyInterfaces:就是在判断代理的对象是否有实现接口

总结: 

1、如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP
2、如果目标对象实现了接口,可以强制使用CGLIB实现AOP
3、如果目标对象没有实现了接口,必须采用CGLIB库,spring会自动在JDK动态代理和CGLIB之间转换

从这个逻辑也可以间接看出spring推荐使用JDK动态代理,因为高版本的JDK中,至少JDK1.6以上JDK动态代理的效率远高于CGLIB(无论是单例模式还是多例模式)。但是如果代理的类没有相应的接口,此时只能使用CGLIB代理了,例如代理模式应用在POJO实体类上,或者是说你的JDK版本较低,这时你可以手动设置CGLIB代理。

 方法中参数config 是一个 AdvisedSupport类型, AdvisedSupport 继承了 ProxyConfig 类,

public class ProxyConfig implements Serializable {
    // 代表 配置中的proxy-target-class,如果设置true,则使用Cglib方式代理
    private boolean proxyTargetClass = false;
   // 是否优化
    private boolean optimize = false;

    boolean opaque = false;

    boolean exposeProxy = false;

    private boolean frozen = false;

    // 省略部分代码
    
}

免责声明:文章转载自《Spring源码分析-SpringAop什么时候调用jdk动态代理?什么时候调用cglib》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇Django框架第一篇发现一个不错的十六进制编辑器-HxD下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

shiro源码解析

一、web.xml 文件中配置的 DelegatingFilterProxy 的 <filter-name>为啥与Spring文件中配置的ShiroFilterFactoryBean的Bean id 保持一致? <filter> <filter-name>shiroFilter</filter-n...

Windows下 VS2015编译RocksDB

VS2015编译RocksDB RocksDB 是一个来自 facebook 的可嵌入式的支持持久化的 key-value 存储系统,也可作为 C/S 模式下的存储数据库,但主要目的还是嵌入式。RocksDB 基于 LevelDB 构建。 1、下载rocksdb源码 git clone https://github.com/facebook/rocksdb...

TFS(Team Foundation Server)简介和新手入门

在两部分的文章。我会介绍Team Foundation Server一些核心功能,着重于产品的日常应用是如何将这些功能结合使用。 作为一个软件开发。在我的职业生涯,。我常常用于支持软件开发过程中大量的开发工具,版本控制工具如、包、生成脚本语言、单元測试框架和需求分析工具等等。在.NET平台上,大量的支持工具可以非常好地独立工作,可是。为了使得各种工具之间...

织网的日子里——第一章:TCP时间获取之客户端和服务器端程序

环境: Ubuntu10.04 g++ / gcc 4.4.3 特别标注: 有些网站转载我的文章不标明出处,并且转载不到位,没有把相应的链接一块转过去,比如说下载链接或相关文献的链接等,导致一些网友阅读和使用出现障碍和知识的不连续,所以在此特别标注:我的这篇文章发表在CSDN—— jasonque的博客上,可以到CSDN博客来阅读。 正文: 开始啃《UN...

Java探针技术-动态agent机制:在main函数启动之后运行agent

premain是Java SE5开始就提供的代理方式,由于其必须在命令行指定代理jar,并且代理类必须在main方法前启动。因此,要求开发者在应用前就必须确认代理的处理逻辑和参数内容等等。在有些场合下,premain代理方式不能满足需求。为解决运行时启动代理类的问题,Java SE6开始提供了在应用程序的VM启动后在动态添加代理的方式,即agentmain...

NDK+MSYS2+Android sdk编译opencv源码

由于今天太晚了,详细笔记有空再记。     要添加的有ANDROID_ABI,这个根据需求添加自己需要的ABI          然后是ANDROID_STL,因为gunstl已经不被支持,这里使用c++_shared或c++_static都可以。    然后是ANDROID_STL,因为gunstl已经不被支持,这里使用c++_shared或c++_st...