spring注解-AOP動態代理-@EnableAspectJAutoProxy注解如何工作


一.概述

        AOP面向切面編程,生成目標方法所屬類的代理類。代理類和目標類的關系:代理類繼承目標類,並重載了目標類的方法。

   代理類重載方法體里加入了切面業務邏輯和目標類方法的調用。

          用戶如何使用:從容器中獲取目標類,實際上是獲取代理類的實例, 代理類實例調用重載了父類的方法,就實現了AOP。

二.步驟

    1.在配置類上添加@EnableAspectJAutoProxy注解,開啟注解版的AOP功能

     2.聲明切面類:@Aspect表明這是一個切面類,注:@Aspect是spring-annotation2/libs/com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar的注解,

        在其org.aspectj.lang.annotation包下包含了切面相關的的注解。aop包下載地址:https://www.eclipse.orgaspectj

     3.聲明切面方法:

             1.切點:在哪些目標方法上添加該切面方法 。切點表達式:execution(* com.dr.service.*.buy*(..)):方法訪問權限  包路徑.類名.方法名(參數類型,參數類型...)

                參數類型可以用“..”代替。

              2.重用切點:在切面中聲明切點方法:添加@Pointcut注解, @Pointcut(value="execution(*******)")  切點方法返回值 void,方法體為空。

                                  在切面方法上引用切點:在通知類型注解里指定 pointcut="切面類.切點方法()"

              3.幾種通知類型:

                  1.@Before

 

    到此,AOP功能就實現了。。。

三、運行流程源碼解析

     1.spring容器用DefaultListableBeanFactory保存 beanNames集合 ,beanName和BeanDefinition映射的集合

          

       默認加載這6個bean定義:

    

       這6個bean定義信息加載時機:

1.開始: ApplicationContext ctx=new AnnotationConfigApplicationContext(MainConfig.class); 2.進入構造方法: public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) { this(); register(annotatedClasses); refresh(); } 3.進入this() public AnnotationConfigApplicationContext() { this.reader = new AnnotatedBeanDefinitionReader(this); this.scanner = new ClassPathBeanDefinitionScanner(this); } 4.進入this.reader = new AnnotatedBeanDefinitionReader(this); public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry) { this(registry, getOrCreateEnvironment(registry)); } 5.再進入 public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) { Assert.notNull(registry, "BeanDefinitionRegistry must not be null"); Assert.notNull(environment, "Environment must not be null"); this.registry = registry; this.conditionEvaluator = new ConditionEvaluator(registry, environment, null); AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry); } 6.AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry); 最終調用AnnotationConfigUtils的方法: public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors( BeanDefinitionRegistry registry, @Nullable Object source) 完成注冊

 

AnnotationConfigApplicationContext調用自己的屬性AnnotatedBeanDefinitionReader完成注冊,AnnotatedBeanDefinitionReader又調

用AnnotationConfigUtils完成注冊,而AnnotationConfigUtils定義了這6個beanName常量。

 這6個bean如何注冊:

if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
            RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
            def.setSource(source);
            beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
        }

這6個beanName,spring內部有對應的類: RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);

 

開始分析AOP原理:

一、@EnableAspectJAutoProxy如何開啟aop動態代理功能

    它的注解源碼如下:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {

    boolean proxyTargetClass() default false;

    boolean exposeProxy() default false;

}
@Import(AspectJAutoProxyRegistrar.class)的功能是注冊一個bean:AspectJAutoProxyRegistrar.class是AspectJ自動代理注冊器

那么spring什么時候解析配置類上面的注解:(也是解析配置類上的注解,加載bean的流程)

1.
進入AnnotationConfigApplicationContext構造器,運行到refresh()
 
        
public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
        this();
        register(annotatedClasses);
        refresh();
    }
2.refresh()方法里運行到invokeBeanFactoryPostProcessors(beanFactory),該方法的作用是:調用beanFactory(這里的beanFactory實例是:DefaultListableBeanFactory)的后置處理器
public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            ......

                // Invoke factory processors registered as beans in the context.
 invokeBeanFactoryPostProcessors(beanFactory);

                
            ......
        }
    }

    3.進入invokeBeanFactoryPostProcessors(beanFactory),

protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
        PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors()); // Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
        // (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
        if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
            beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
            beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
        }
    }

 

4.PostProcessorRegistrationDelegate類invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors()),調用beanFactory的后置處理器
invokeBeanFactoryPostProcessors執行流程:

1.判斷beanFactory是否 BeanDefinitionRegistry類型
如果是:
1.遍歷ApplicationContext中的beanFactory后置處理器:
如果beanFactory是BeanDefinitionRegistryPostProcessor類型:
調用BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry(registry)

postProcessBeanDefinitionRegistry(registry)作用是:Derive further bean definitions from the configuration classes in the registry
從beanFactory中解析出所有要加載的bean
              否則就先加到集合中保存。

2.從DefaultListableFactory之前默認加載6個BeanDefinition中找到BeanDefinitionRegistryPostProcessor類型並且實現了PriorityOrdered接口的bean定義。
把它實例化:
beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class))保存到集合中

// First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
      if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
           currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
           processedBeans.add(ppName);
      }
}

                          3.invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);遍歷第2步得到的BeanDefinitionRegistryPostProcessor集合,調用它的

                             postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) 從所有配置類中解析出要加載的bean。

 
        
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
        int registryId = System.identityHashCode(registry);
        if (this.registriesPostProcessed.contains(registryId)) {
            throw new IllegalStateException(
                    "postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);
        }
        if (this.factoriesPostProcessed.contains(registryId)) {
            throw new IllegalStateException(
                    "postProcessBeanFactory already called on this post-processor against " + registry);
        }
        this.registriesPostProcessed.add(registryId);

        processConfigBeanDefinitions(registry);
    }

第4步解析到這里,停止,因為現在要了解 EnableAspectJAutoProxy注解什么時候加載AspectJAutoProxyRegistrar

5.進入processConfigBeanDefinitions(registry)方法。這里提醒一下:ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor
以下操作是在ConfigurationClassPostProcessor類中運行。
1.從DefaultListableBeanFactory的bean定義集合中找出標了@Configuration的bean定義,加到集合中
2.解析所有的配置類:使用ConfigurationClassParser類解析所有配置類--->parse(配置類集合)

6.進入ConfigurationClassParser.parse(配置類集合)
遍歷配置類,對每個配置類的每個注解遞歸解析找到 @Import注解,再加加載該注解指定要加載的類
於是,這時加載了AspectJAutoProxyRegistrar.class,這個類的作用是加載AnnotationAwareAspectJAutoProxyCreator.class
 
        
---------------------現在分析AspectJAutoProxyRegistrar如何注冊AnnotationAwareAspectJAutoProxyCreator-------------------------

 1.ConfigurationClassParser解析完配置類后(上個解析第5步),ConfigurationClassPostProcessor類中的ConfigurationClassBeanDefinitionReader調用loadBeanDefinitions(ConfigurationClass configClasses集合)

   ConfigurationClass包含了對應配置類解析出的所有bean定義

 2.ConfigurationClassParser中的方法loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());這時就加載了AnnotationAwareAspectJAutoProxyCreator

 3. AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar  ,這時 AspectJAutoProxyRegistrar調用registerBeanDefinitions(metadata, this.registry)

private void loadBeanDefinitionsFromRegistrars(Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> registrars) {
        registrars.forEach((registrar, metadata) ->
                registrar.registerBeanDefinitions(metadata, this.registry));
    }

 

 4.

@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")) {
                AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
            }
            if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
                AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
            }
        }
    }
@Nullable
    public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) {
        return registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry, null);
    }
@Nullable
    public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(
            BeanDefinitionRegistry registry, @Nullable Object source) {

        return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
    }

 

 最后是調用DefaultListableBeanFactory 注冊registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition), beanDefinition就是AnnotationAwareAspectJAutoProxyCreator

的bean定義信息。

 

------------------------------------------------------------------------------------到此,如何注冊AnnotationAwareAspectJAutoProxyCreator就分析完了。

 

 

 現在開始分析,如何spring AOP如何創建切面目標類的代理類:

1.refresh()方法中:finishBeanFactoryInitialization(beanFactory);的作用是:實例化所有已解析加載的bean定義信息,bean就在這個方法中初始化

2.beanFactory.preInstantiateSingletons();這個方法遍歷DefaultListableBeanFactory中所有的bean定義信息(BeanDefinition)如果容器中沒有,就初始化

3.以下也是bean的初始化步驟:

   getBean(beanName) ——>  doGetBean(beanName,...)  ——>getSingleton(beanName,()->{... return CreateBean(beanName,RootBeanDefinition,args)})——>doCreateBean(...)

4.要知道AOP如何創建代理,分析doCreateBean(...)方法

    doCreateBean(...)方法:{

           populateBean(beanName, mbd, instanceWrapper);  beanName,BeanDefinition,包含new 出來的目標對象的包裝類

           exposedObject = initializeBean(beanName, exposedObject, mbd);

  }

5. exposedObject = initializeBean(beanName, exposedObject, mbd);解析:

          1. invokeAwareMethods(beanName, bean);如果屬於BeanFactoryAware,setBeanFactory(DefaultListableBeanFactory )

          2. applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);

          3. invokeInitMethods(beanName, wrappedBean, mbd);

          4. applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);這個方法遍歷DefaultListableBeanFactory里面beanPostProcessors的集合

                  依次執行processor.postProcessAfterInitialization(result, beanName),如果返回null,技術遍歷,

                  當遍歷到AnnotationAwareAspectJAutoProxyCreator時,創建bean的代理對象:

                         它繼承自 AbstractAutoProxyCreator extends ProxyProcessorSupport implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware

                         創建代理:1.Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);獲得通知信息,如切點                             

        // Create proxy if we have advice.
        Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
        if (specificInterceptors != DO_NOT_PROXY) {
            this.advisedBeans.put(cacheKey, Boolean.TRUE);
            Object proxy = createProxy(
                    bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
            this.proxyTypes.put(cacheKey, proxy.getClass());
            return poxy

      到此代理類創建完畢,代理類包含了目標類和目標類實現的接口,和切面類的切點信息。

 

現在分析動態代理 -方法調用- 插入切面邏輯的實現:

 1.

public static void main(String[] args) {
        // TODO Auto-generated method stub
        ApplicationContext ctx=new AnnotationConfigApplicationContext(MainConfig.class);
        Calculator cl=(Calculator) ctx.getBean("calculator");
        cl.add(5, 5);
    }

 

 

2.這里Calculator實際上是對應的代理類   cl.add(5,5)也是調用代理類的方法

  CglibAopProxy內部類DynamicAdvisedInterceptor ,調用inteceptor(...)方法 運行摘要如下:

           new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();責任鏈模式實現鏈式執行切面邏輯:

 

 

         ReflectiveMethodInvocation是責任鏈執行器,所有切面通知(before,after, ...)對應的類都實現了MethodInterceptor接口,這個接口有invoke()方法

         執行流程:

                ReflectiveMethodInvocation的proceed()方法遍歷通知類,依次調用invoke( 傳入ReflectiveMethodInvocation的this )  方法

                invoke(...)方法里面做兩件事:1.調用切面通知(before,after,...)對應的類對象,執行對應的切面方法     2.傳入的this.proceed()又回到proceed()方法中繼續遍歷

                這是遞歸調用,1 和 2的順序根據通知類型順序不一樣

到此,分析結束。

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM