Spring AOP之基于AbstractAutoProxyCreator的自动代理

本文介绍了在Spring AOP中,当系统需要大量使用AOP织入时,使用AbstractAutoProxyCreator作为自动代理的优势。详细阐述了其工作流程,包括在bean创建前的代理判断、接口过滤、代理需求判断及代理对象的创建。并讨论了两类自动代理的差异。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

当系统比较复杂,或者中需要进行aop进行织入的bean较多时,简单采用ProxyFacotryBean无疑会增加很多工作量,同时由于要从ProxyFactoryBean获得代理对象,也会使应用和Spring之间的耦合度增加,并且很多时候可维护性不强,譬如,我们需要给bean名字满足“*service”的bean每个方法增加事务功能,如果采用ProxyFacotryBean必须为每个以service结尾的bean增加一个配置。当然,如果愿意当然可以重复copy-past可以满足,若以后又有人增加了一个bean:Abcservice,这时若他忘记增加对应的ProxyFacotyBean配置,可能导致灾难性的后果。这样的情况下,自动代理的方式就能发挥它巨大的优势了。

1. 使用举例

<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
  <property name="beanNames"><value>*service</value></property>
  <property name="interceptorNames">
    <list>
      <value>myInterceptor</value>
    </list>
  </property>
</bean>
通过配置beanNames属性,beanName是以service结尾时将会织入myInterceptor中指定的横切逻辑。

2. 类结构图


2.1 调用时机
从类结构图中可以看出,AbstractAutoProxyCreator实现了SmartInstantiantionAwareBeanPostProcessor接口,作为一个BeanPostProcessor,它与ProxyFactoryBean的处理时机不同,通过前面的 Spring Bean实例化过程(2),可以知道,InstantiantionAwareBeanPostProcessor这个后置处理器是在bean对象被创建的之前回调用InstantiantionAwareBeanPostProcessor.postProcessBeforeInstantiation()方法,若此方法返回的结果不为null,则会中断后面bean对象的创建过程。InstantiantionAwareBeanPostProcessor.postProcessAfterInstantiation()是在对象被创建之后,属性注入之前,若该方法返回false,会中断属性的注入,并且也会中断InstantiantionAwareBeanPostProcessor链在当前bean上的调用。这里AbstractAutoProxyCreator默认返回true。

由于AbstractAutoProxyCreator实现了BeanPostProcessor接口,因此它的调用时机也可以是在属性注入之后,初始化方法调用前后。AbstractAutoProxyCreator给出初始化方法调用之后创建代理对象的实现。
2.2 共同的代理创建逻辑
默认情况下,代理是通过AbstractAutoProxyCreator中的postProcessAfterInitialization()创建的。
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        Object cacheKey = getCacheKey(bean.getClass(), beanName);
        if (!this.earlyProxyReferences.contains(cacheKey)) {
            return wrapIfNecessary(bean, beanName, cacheKey);
        }
        return bean;
    }
上述方法的执行逻辑为:
a.获取缓存的bean名字,getCacheKey()方法实际上是便于子类扩展。默认返回className_beanName
b.若earlyProxyReferences缓存中不包含当前cacheKey,则调用wrapIfNecessary()创建代理对象。
earlyProxyReferences这个缓存是干嘛的呢?
从上下文中可以找到getEarlyBeanReference()方法中会将相应的cacheKey保存到earlyProxyReferences中,同时也会调用wrapIfNecessary()方法,因此可以看出该缓存用于保存已经创建过代理对象的cachekey,避免重复创建。代码如下:
public Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
        Object cacheKey = getCacheKey(bean.getClass(), beanName);
        this.earlyProxyReferences.add(cacheKey);
        return wrapIfNecessary(bean, beanName, cacheKey);
}
那么getEarlyBeanReference()方法又是何时被调用的呢?
通过分析可以看到,getEarlyBeanReference()方法在SmartInstantiantionAwareBeanPostProcessor中声明,通过前面 Spring Bean实例化过程(2)可以知道,它是为了解决单例bean之间的循环依赖问题,提前将代理对象暴露出去。
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
        if (this.targetSourcedBeans.contains(beanName)) {
            return bean;
        }
        if (this.nonAdvisedBeans.contains(cacheKey)) {
            return bean;
        }
        if (isInfrastructureClass(bean.getClass(), beanName) || shouldSkip(bean.getClass(), beanName)) {
            this.nonAdvisedBeans.add(cacheKey);
            return bean;
        }
 
        // Create proxy if we have advice.
        Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
        if (specificInterceptors != DO_NOT_PROXY) {
            this.advisedBeans.add(cacheKey);
            Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
            this.proxyTypes.put(cacheKey, proxy.getClass());
            return proxy;
        }
 
        this.nonAdvisedBeans.add(cacheKey);
        return bean;
}

执行逻辑解析:


a. 判断bean是否在postProcessBeforeInstantiation()中,即在bean对象创建之前已经被创建代理,在postProcessBeforeInstantiation()中成功创建的代理对象都会将beanName加入到targetSourceBeans中。

b.对于实现了Advice,Advisor,AopInfrastructureBean接口的bean,都认为是spring aop的基础框架类,不能对他们创建代理对象,同时子类也可以覆盖shouldSkip方法来指定不对哪些bean进行代理。

c.调用getAdvicesAndAdvisorsForBean()方法判断当前bean是否需要进行代理,若需要则返回满足条件的Advice或者Advisor集合。根据getAdvicesAndAdvisorsForBean()方法的具体实现的不同,AbstractAutoProxyCreator又分成了两类自动代理机制。

d.若需要代理,则调用createProxy方法创建代理对象,并将创建的代理的key缓存起来,避免重复创建

protected Object createProxy(
            Class beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {
 
        ProxyFactory proxyFactory = new ProxyFactory();
        // Copy our properties (proxyTargetClass etc) inherited from ProxyConfig.
        proxyFactory.copyFrom(this);
 
        if (!shouldProxyTargetClass(beanClass, beanName)) {
            // Must allow for introductions; can't just set interfaces to
            // the target's interfaces only.
            Class[] targetInterfaces = ClassUtils.getAllInterfacesForClass(beanClass, this.proxyClassLoader);
            for (int i = 0; i < targetInterfaces.length; i++) {
                proxyFactory.addInterface(targetInterfaces[i]);
            }
        }
 
        Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
        for (int i = 0; i < advisors.length; i++) {
            proxyFactory.addAdvisor(advisors[i]);
        }
 
        proxyFactory.setTargetSource(targetSource);
        customizeProxyFactory(proxyFactory);
 
        proxyFactory.setFrozen(this.freezeProxy);
        if (advisorsPreFiltered()) {
            proxyFactory.setPreFiltered(true);
        }
 
        return proxyFactory.getProxy(this.proxyClassLoader);
    }
从createProxy的代码中可以看到,这里是采用ProxyFactory来进行代理创建,ProxyFacotry的类结构图在Spring AOP之基于ProxyFactoryBean的代理中已经介绍过,这个方法的主要逻辑是

a.创建ProxyFactory实例,并复制当前类的相关配置,

b.然后检查当前类是否有实现基于类的代理,还是基于接口,以此来决定是否采用cglib来创建代理对象。

c.整理合并Advisor,这里AbstractAutoProxyCreator定义了属性interceptorNames用于设置拦截器,同时子类通过getAdvicesAndAdvisorsForBean()方法也可以返回一组Advisor,buildAdvisors()方法就是整理合并这些切面。至于调用的先后顺序,通过applyCommonInterceptorsFirst参数可以进行设置,若applyCommonInterceptorsFirst为true,interceptorNames属性指定的Advisor优先调用。默认为true;

d通过customizeProxyFactory()方法,子类可以对proxyFactory进行设置更改。

e.最后调用proxyFactory.getProxy()方法返回代理对象。

2.3 两类自动代理

AbstractAutoProxyCreator有两个子类,

一个是BeanNameAutoProxyCreator,它是基于bean名字的自动代理类。

它会给spring容器中bean名字与指定名字匹配的bean自动创建代理。其中匹配的规则定义在PatternMatchUtils.simpleMatch()方法中。注意:若需要给某个FactoryBean创建代理,可以在bean名字前面加上&.

第二类是AbstractAdvisorAutoProxyCreator,相对BeanNameAutoProxyCreator而言,它更为强大,它会自动获取spring容器中注册的所有的Advisor类(除了子类中isEligibleAdvisorBean()方法指定的不满足条件的Advisor除外。),然后自动给spring容器中满足Advisor中pointCut创建代理。

DefaultAdvisorAutoProxyCreator是默认实现,默认会自动代理所有的Advisor,当然也可以通过设置usePrefix和advisorBeanNamePrefix来过滤部分advisor

AspectJAwareAdvisorAutoProxyCreator用于支持AspectJ方式的自动代理。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值