【spring原始碼】六、@EnableAspectJAutoProxy

hancoder發表於2020-12-20

invokeBeanFactoryPostProcessors()

先說明:invokeBeanFactoryPostProcessors()是在refresh()方法中的第⑤步,他的作用是註冊bean的定義資訊,但還沒進行建立例項。我們下面介紹了註解@EnableAspectJAutoProxy就是在這個階段註冊一個bean定義,但例項化要推遲到第⑥步registerBeanPostProcessor()完成

@EnableAspectJAutoProxy

@EnableAspectJAutoProxy的作用是給spring容器中註冊一個bean:這個bean名為internalAutoProxyCreator,型別為AnnotationAwareAspectJAutoProxyCreator.class “註冊裝配模式的切面自動代理建立器”

另外可以注意,是在invokeBeanFactoryPostProcessors()階段進來呼叫註冊的

@EnableAspectJAutoProxy標準在配置類上,在EnableAspectJAutoProxy介面類上有@Import(AspectJAutoProxyRegistrar.class),該@Import給容器中匯入了AspectJAutoProxyRegistrar這個bean,而這個bean作用是手動註冊bean定義到ac容器中。

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({AspectJAutoProxyRegistrar.class})
public @interface EnableAspectJAutoProxy {
    // 用於強制使用cglib動態代理,即使實現了介面。
    // 如果希望強制使用CGLIB代理(例如希望代理目標物件的所有方法,而不只是實現自介面的方法)// 但需要保證有CGLIB包
    boolean proxyTargetClass() default false;

    // 事務中會用到 // 是否暴露代理物件,暴露出來的代理物件和執行緒繫結,用的是threadLocal // 設定為true之後還得用(AopContext.currentProxy()).被調方法() 替換原來的 被調方法()
    // 比如切入點表示式是save方法,saveAll方法沒在切入點表示式裡,saveAll呼叫了save方法,此時呼叫saveAll方法並不執行save的AOP方法//走save的時候該輪到增強的事情已經過去了//AopContext.currentProxy()獲取代理物件
    boolean exposeProxy() default false;
}

exposeProxy解釋:

public interface UserService{
	public void a();
	public void a();
}

public class UserServiceImpl implements UserService{
	@Transactional(propagation = Propagation.REQUIRED)
	public void a(){
		this.b();
	}
	@Transactional(propagation = Propagation.REQUIRED_NEW)
	public void b(){
		System.out.println("b has been called");
	}
}
程式碼參照《Spring原始碼解析》p173頁。
Q1:b中的事務會不會生效?
A1:不會,a的事務會生效,b中不會有事務,因為a中呼叫b屬於內部呼叫,沒有通過代理,所以不會有事務產生。
Q2:如果想要b中有事務存在,要如何做?
A2:<aop:aspectj-autoproxy expose-proxy=true> ,設定expose-proxy屬性為true,將代理暴露出來,使用AopContext.currentProxy()獲取當前代理,將this.b()改為((UserService)AopContext.currentProxy()).b()

Import(AspectJAutoProxyRegistrar)

而註解驅動裡的知識告訴我們@Import與實現ImportBeanDefinitionRegistrar介面的類註冊bean的用法,這時@Import就會呼叫這個類的registerBeanDefinitions()方法,(可以在這個方法上打斷點)

class AspectJAutoProxyRegistrar 
    implements ImportBeanDefinitionRegistrar {	// 實現該介面的話會自動呼叫registerBeanDefinitions()方法

    @Override
    public void registerBeanDefinitions(//註冊bean定義,而不是註冊bean例項
        AnnotationMetadata importingClassMetadata, 
        BeanDefinitionRegistry registry) {//bean定義註冊器
        
        // 去註冊bean // 如有必要就註冊AspectJ註解自動代理建立器
        AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);

        // 拿到註解@EnableAspectJAutoProxy註解的屬性資訊,proxyTargetClass、exposeProxy
        AnnotationAttributes enableAspectJAutoProxy =
            AnnotationConfigUtils.attributesFor(importingClassMetadata, //當前類的後設資料
                                                EnableAspectJAutoProxy.class);// 哪個註解
        // 如果拿到了註解資訊
        if (enableAspectJAutoProxy != null) {
            if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
                AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
            }
            if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
                AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
            }
        }
    }

    ...;
}
//==========多次過載跳到===============================
public abstract class AopConfigUtils {
    // 註冊類
    private static BeanDefinition registerOrEscalateApcAsRequired(
        Class<?> cls, //AnnotationAwareAspectJAutoProxyCreator.class
        BeanDefinitionRegistry registry, //註冊器
        @Nullable Object source) {

        Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
        // 如果bean定義存在了
        if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
            BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
            if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
                int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
                int requiredPriority = findPriorityForClass(cls);
                if (currentPriority < requiredPriority) {
                    apcDefinition.setBeanClassName(cls.getName());
                }
            }
            return null;
        }
        // else 如果該bean定義不存在
        RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);//AnnotationAwareAspectJAutoProxyCreator.class
        beanDefinition.setSource(source);
        beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
        beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
        // 註冊bean定義
        registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
        return beanDefinition;
    }

比如現在我們有個邏輯(有紅藍色顏料就能造出彩虹),該方法可以通過registry.containsBeanDefinition("com.atguigu.bean.MyRed");判斷容器中是否有了對應的紅bean(的定義資訊),同理還判斷有沒有藍bean定義,如紅藍bean定義資訊都有,就建立一個彩虹BeanDefinition定義資訊,:new RootBeanDefinition(RainBow.class);,然後註冊bean定義資訊到容器中:registry.registerBeanDefinition("rainBow", beanDefinition);從而建立bean的時候工廠容器就知道要建立哪些bean了。

也就是說:@Import(AspectJAutoProxyRegistrar)的作用的註冊一個bean定義資訊:這個bean名為internalAutoProxyCreator,型別為AnnotationAwareAspectJAutoProxyCreator.class

AnnotationAwareAspectJAutoProxyCreator

“org.springframework.aop.config.internalAutoProxyCreator”

上面說了:AspectJAutoProxyRegistrar的作用的註冊一個bean:internalAutoProxyCreator。而internalAutoProxyCreator是bean name,對應的值是類AnnotationAwareAspectJAutoProxyCreator(註解裝配方式的切面自動代理建立器)。他是一個後置處理器。AnnotationAwareAspectJAutoProxyCreator的繼承關係如下:

類繼承關係
public class AnnotationAwareAspectJAutoProxyCreator extends AspectJAwareAdvisorAutoProxyCreator {}
public class AspectJAwareAdvisorAutoProxyCreator extends AbstractAdvisorAutoProxyCreator {}
public abstract class AbstractAdvisorAutoProxyCreator extends AbstractAutoProxyCreator {}
public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {}
總結關係如下:
---AnnotationAwareAspectJAutoProxyCreator
------AnnotationAwareAspectJAutoProxyCreator
--------->AspectJAwareAdvisorAutoProxyCreator
------------>AbstractAdvisorAutoProxyCreator
--------------->AbstractAutoProxyCreator 
------------------>BeanFactoryAware  //(這個介面可以把bean工廠拿到)
------------------>SmartInstantiationAwareBeanPostProcessor //(注意這個)
---------------------->InstantiationAwareBeanPostProcessor
-------------------------->BeanPostProcessor

img

每個類的作用:
==父類-->子類
=====AbstractAutoProxyCreator======
public void setBeanFactory(BeanFactory beanFactory) {}
public boolean postProcessBeforeInstantiation();
public boolean postProcessAfterInstantiation(Object bean, String beanName) {}

=====AbstractAdvisorAutoProxyCreator========;
public void setBeanFactory(BeanFactory beanFactory);{initBeanFactory((ConfigurableListableBeanFactory)beanFactory);}//子類重寫了setBeanFactory方法//refresh(){registerBeanPostProcessor(){這裡呼叫了set方法}}

========AspectJAwareAdvisorAutoProxyCreator===========;
========AnnotationAwareAspectJAutoProxyCreator====protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {}//前面的setBeanFactory呼叫了該方法,這裡重寫了

如果想了解xml方式的AspectJAwareAdvisorAutoProxyCreator是如何注入到容器的,可以參考https://blog.csdn.net/qq_26323323/article/details/81012855

第⑤部分更多的內容我們放後面點擴充部分再講

AnnotationAwareAspectJAutoProxyCreator註冊時機

這裡說下流程,具體步驟可以看後文的附錄的⑤

main方法
invokeBeanFactoryPostPostProcessors() 註冊bean工廠的後置處理器
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
遍歷所有所有bean工廠後置處理器,依次例項化工廠後置處理器,然後依次呼叫他們裡面重寫了的registerBeanDefinitions方法
refresh();

invokeBeanFactoryPostProcessors(beanFactory);

PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());

invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);

postProcessor.postProcessBeanDefinitionRegistry(registry);//

processConfigBeanDefinitions(registry);

this.reader.loadBeanDefinitions(configClasses);//ConfigurationClassPostProcessor.java

loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);//此處的變數內容如下圖 //並不是每個configModel都會走這個方法
loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
registrars.forEach((registrar, metadata) ->
                   registrar.registerBeanDefinitions(metadata, this.registry, this.importBeanNameGenerator));


class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {

    @Override
    public void registerBeanDefinitions(
        AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        // 這個方法就是我們之前看過的
        AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
        AnnotationAttributes enableAspectJAutoProxy =
            AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
        if (enableAspectJAutoProxy != null) {
            if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {//jdk動態代理還是CGLIB動態代理
                AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
            }
            if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {//暴露代理物件
                AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);//就是給bean定義中新增一個屬性是exposeProxy
            }
        }
    }

相關文章