learn and grow up

解析springBean类的注解引发的一系列如AOP|cglib代理等问题二

字数统计: 1.4k阅读时长: 6 min
2020/05/25 Share

写在前面

接上一篇,这篇主要是梳理一下自己在查找问题中遇到的疑惑点和解决过程

疑惑&解答

  1. Springboot动态代理全是cglib吗?还是根据是否接口来判断是使用jdk代理还是cglib呢?

    跟踪代码和查阅资料发现,springboot默认全部是cglib代理,我们可以从生成代理类的BeanPostProcessor看到,具体如下

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    //org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator
    //继承自org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator
    public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) throws BeansException {
    if (bean != null) {
    //生成canchekey
    Object cacheKey = this.getCacheKey(bean.getClass(), beanName);
    //如果一级缓存不存在该key,则说明没有生成过,进行生成
    if (!this.earlyProxyReferences.contains(cacheKey)) {
    return this.wrapIfNecessary(bean, beanName, cacheKey);
    }
    }

    return bean;
    }
    //org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#wrapIfNecessary
    //生成动态代理bean
    protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
    //最终缓存已经存在,则直接返回
    if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
    return bean;
    }
    //不需要动态代理,返回
    if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
    return bean;
    }
    //是特殊接口实现类或者需要跳过的,放入缓存并跳过
    if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
    this.advisedBeans.put(cacheKey, Boolean.FALSE);
    return bean;
    }

    // Create proxy if we have advice.
    //需要添加的aop拦截类
    Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
    if (specificInterceptors != DO_NOT_PROXY) {
    //判断缓存放置为true
    this.advisedBeans.put(cacheKey, Boolean.TRUE);
    //创建代理类,重点
    Object proxy = createProxy(
    bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
    //放入缓存
    this.proxyTypes.put(cacheKey, proxy.getClass());
    return proxy;
    }
    //否则不需要代理
    this.advisedBeans.put(cacheKey, Boolean.FALSE);
    return bean;
    }

    //org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#createProxy
    protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
    @Nullable Object[] specificInterceptors, TargetSource targetSource) {
    //如果需要,暴露特殊的bean
    if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
    AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
    }
    //构建代理类创建工厂
    ProxyFactory proxyFactory = new ProxyFactory();
    //copy 原有属性,我们这里注意这个属性,this.proxyTargetClass,这个属性是是否使用jdk代理还是cglib代理的关键,跟踪代码可以发现这个属性是配置来的

    proxyFactory.copyFrom(this);

    //根据proxyTargetClass判断
    if (!proxyFactory.isProxyTargetClass()) {
    if (shouldProxyTargetClass(beanClass, beanName)) {
    //再次确认proxyTargetClass
    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());
    }

    //org.springframework.aop.framework.ProxyFactory#getProxy(java.lang.ClassLoader)
    public Object getProxy(@Nullable ClassLoader classLoader) {
    //1、重点:创建代理类生成工具类 2、创建代理类
    return createAopProxy().getProxy(classLoader);
    }

    //org.springframework.aop.framework.ProxyCreatorSupport#createAopProxy
    protected final synchronized AopProxy createAopProxy() {
    //添加监听
    if (!this.active) {
    activate();
    }
    //创建代理实现工厂和实现类
    return getAopProxyFactory().createAopProxy(this);
    }

    //重点,
    //org.springframework.aop.framework.DefaultAopProxyFactory#createAopProxy
    @Override
    public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
    //这里首先判断Optimize是否主动优化,默认false;ProxyTargetClass就是前面讲的,这里是true,因为AnnotationAwareAspectJAutoProxyCreator配置为true。见下图
    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.");
    }
    //是否是接口或者实现了jdk的proxy的接口亦或者proxy的chahe有该对象的代理类,才使用jdk代理
    if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
    return new JdkDynamicAopProxy(config);
    }
    return new ObjenesisCglibAopProxy(config);
    }
    else {
    return new JdkDynamicAopProxy(config);
    }
    }

    AOP

    ​ 根据上面代码分析,我们可以看到在springboot中,代理的方式是由bean:AnnotationAwareAspectJAutoProxyCreator.proxyTargetClass来做基础判断,具体判断总结如下

    proxyTargetClass的值 代理对象 代理方式
    true 实现接口 cglib
    true 没有实现接口 cglib
    true 实现接口 Jdk
    False 没有实现接口 cglib

    ​ 总结来说AnnotationAwareAspectJAutoProxyCreator后置处理器主要作用:

    ​ 主要就是用于在bean实例化之前调用的是postProcessBeforeInstantiation方法,主要进行了一些必要判断,以及如果通知方法list集合为空,进行遍历所有@Aspect等先关声明切面注解的类,并解析该类中的各个切面和切面类型为一个个的通知方法保存到list中(这个list位于这个后置处理器的aspectJAdvisorsBuilder属性下的advisorsCache属性中),在bean实例化后调用后置处理器的postProcessAfterInitialization用于将对象生成动态代理对象返回放入容器中(跟该类被切方法相关的通知方法的集合会参与代理类的生成)。这里需要额外一提的是如果涉及到了循环引用,对象需要进行早期暴露,那么必须暴露出去的是代理对象,而不能是未代理的原始bean实例,所以如果对象参与进了循环引用那么他的代理对象的生成是在对外暴露早期引用时的方法getEarlyBeanReference中进行wrapIfNecessary的,提前暴露代理对象

  2. AnnotationAwareAspectJAutoProxyCreator.proxyTargetClass默认配置在哪呢?

    AnnotationAwareAspectJAutoProxyCreator这个bean的默认配置是在org.springframework.boot.autoconfigure.aop.AopAutoConfiguration内配置的

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    @Configuration
    @ConditionalOnClass({ EnableAspectJAutoProxy.class, Aspect.class, Advice.class,
    AnnotatedElement.class })
    //spring.aop.auto=ture时生效,也就是启用aop。默认也启动
    @ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true)
    public class AopAutoConfiguration {

    //spring.aop.proxy-target-class=false生效,默认不生效:配置proxyTargetClass=false
    @Configuration
    @EnableAspectJAutoProxy(proxyTargetClass = false)
    @ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false", matchIfMissing = false)
    public static class JdkDynamicAutoProxyConfiguration {

    }
    //spring.aop.proxy-target-class=true生效,默认生效,配置:配置proxyTargetClass=true
    @Configuration
    @EnableAspectJAutoProxy(proxyTargetClass = true)
    @ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true", matchIfMissing = true)
    public static class CglibAutoProxyConfiguration {

    }

    }

    上面代码表面Springboot默认就会启动aop,也就是@EnableAspectJAutoProxy(proxyTargetClass = true),所以proxy-target-class默认也为true,有兴趣的不妨可以试试。

CATALOG
  1. 1. 写在前面
  2. 2. 疑惑&解答