1. 程式人生 > >spring——AOP原理及原始碼(一)

spring——AOP原理及原始碼(一)

教程共分為五篇,從AOP例項的構建及其重要元件、基本執行流程、容器建立流程、關鍵方法呼叫、原理總結歸納等幾個方面一步步走進AOP的世界。

本篇主要為讀者演示構建AOP例項及AOP核心元件分析。

 

一、專案構建

讀者可直接下載示例工程,或複製以下的程式碼到本地工程開啟教程。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.tlj</groupId>
    <artifactId>spring-test</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>4.3.13.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>4.3.13.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13</version>
            <scope>test</scope>
        </dependency>
        <!-- https://mvnrepository.com/artifact/javax.inject/javax.inject -->
        <dependency>
            <groupId>javax.inject</groupId>
            <artifactId>javax.inject</artifactId>
            <version>1</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/com.mchange/c3p0 -->
        <dependency>
            <groupId>com.mchange</groupId>
            <artifactId>c3p0</artifactId>
            <version>0.9.5.2</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.44</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>4.3.12.RELEASE</version>
        </dependency>
    </dependencies>


</project>
pom.xml
package config;

import aop.LogAspects;
import aop.MathCalculator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@EnableAspectJAutoProxy
@Configuration
public class ConfigOfAOP {

    @Bean
    public MathCalculator calculator(){
        return new MathCalculator();
    }

    @Bean
    public LogAspects logAspects(){
        return new LogAspects();
    }
}
ConfigOfAOP
package aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;

import java.util.Arrays;

/**
 * 切面類
 */
@Aspect
public class LogAspects {

    @Pointcut("execution(public int aop.MathCalculator.*(..))")
    public void poinCut(){}

    @Before("poinCut()")
    public void logStart(JoinPoint joinPoint){
        Object[] args = joinPoint.getArgs();
        System.out.println(joinPoint.getSignature().getName()+" 執行。。。@Before "+ Arrays.asList(args));
    }

    @After("poinCut()")
    public void  logEnd(){
        System.out.println("除法結束..@After");
    }

    @AfterReturning(value = "poinCut()",returning = "result")//獲取方法返回值
    public void logReturning(Object result){
        System.out.println("除法正常返回..@AfterReturning "+result);
    }

    @AfterThrowing(value = "poinCut()",throwing = "e")
    public void logException(Exception e){
        System.out.println("除法異常..@AfterThrowing "+e);
    }
}
LogAspects
package aop;

public class MathCalculator {

    public int div(int i,int j){
        System.out.println("MathCalculator");
        return i/j;
    }
}
MathCalculator

專案目錄結構如下:

到這裡,我們的專案是構建完了。

 

 

二、日誌切面方法測試

開啟測試類,執行測試方法

 我們可以看到,總共列印了四行,除了第二行列印是業務方法的呼叫,其他都是呼叫日誌切面類中的方法打印出來的。

這就是AOP的使用效果,除了用在日誌,還有其他很多用法,這裡就不贅述了。

 

 

三、關鍵元件探究

為什麼AOP能在業務方法呼叫的前後和發生異常時呼叫切面方法呢,首先我們需要了解它引入了什麼元件。

為了讓AOP起作用,我們需要在配置類上新增@EnableAspectJAutoProxy註解,從字面上看,翻譯為啟動切面自動代理,那它是怎麼啟動的呢

ctrl+滑鼠左鍵進入這個註解,我們可以看到EnableAspectJAutoProxy介面使用@Import註解匯入了AspectJAutoProxyRegistrar這個類

再次ctrl+滑鼠左鍵進入AspectJAutoProxyRegistrar,可以看到,它實現了ImportBeanDefinitionRegistrar介面。

此介面中的registerBeanDefinitions方法,正是用來像容器中註冊元件的。

看來想要知道@EnableAspectJAutoProxy註解到底給容器中添加了什麼元件,我們需要進行除錯,找到ImportBeanDefinitionRegistrar方法給容器中新增的元件。這個元件一定就是AOP實現的關鍵。

 

 

 四、除錯尋找元件

如下圖,我們在ImportBeanDefinitionRegistrar介面的註冊方法中打上斷點。

 

點選debug開始除錯,程式來到了AspectJAutoProxyRegistrar的registerBeanDefinitions方法

正在執行的是AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry),方法的字面意思:註冊切面自動代理創造元件如果需要的話

 

接著進入這個方法直到以下這個方法,可以看到返回的是BeanDefinition型別,說明在方法裡面有元件定義或註冊相關的動作。

 110行進行判斷,如果容器中存在AUTO_PROXY_CREATOR_BEAN_NAME這個定義資訊,進行以下判斷,巴拉巴拉,最後return null,退出這個方法。

如果不存在,可以看到在125行已經有註冊名為AUTO_PROXY_CREATOR_BEAN_NAME的元件的動作。

把滑鼠放在AUTO_PROXY_CREATOR_BEAN_NAME上,可以看到它實際是叫internalAutoProxyCreator

接著我們進行下一步,到110行時,顯然第一次它是不存在這個類的,所以跳過if{}中的內容,到121行時,我們可以看看cls的資訊,發現這個類叫AnnotationAwareAspectJAutoProxyCreator

 

 到125行時,已經設定好AnnotationAwareAspectJAutoProxyCreator的各種屬性,將其命名為internalAutoProxyCreator註冊進容器,在126行進行返回。

在上面過程中,我們可以得到的結論是,@EnableAspectJAutoProxy註解實際上就是給容器中添加了名為internalAutoProxyCreator的元件,實際就是AnnotationAwareAspectJAutoProxyCreator這個類。

我們可以得出AnnotationAwareAspectJAutoProxyCreator就是實現AOP的核心元件。

接下來我們來探究一下AnnotationAwareAspectJAutoProxyCreator的繼承關係,以及它是什麼。

 

 

五、AnnotationAwareAspectJAutoProxyCreator元件是什麼

進入這個類,發現它繼承了AspectJAwareAdvisorAutoProxyCreator

 

那麼AspectJAwareAdvisorAutoProxyCreator又是什麼呢,接著進入AspectJAwareAdvisorAutoProxyCreator

發現AspectJAwareAdvisorAutoProxyCreator又繼承了AbstractAdvisorAutoProxyCreator

我們接著進入AbstractAdvisorAutoProxyCreator中檢視

可以看到AbstractAdvisorAutoProxyCreator繼承了AbstractAutoProxyCreator

再進入AbstractAutoProxyCreator

可以看到AbstractAutoProxyCreator繼承了ProxyProcessorSupport

並實現了SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware兩個介面

 

 接下來我們主要看這兩個介面

SmartInstantiationAwareBeanPostProcessor明顯是一個後置處理器介面,BeanFactoryAware是一個底層元件介面,實現BeanFactoryAware就可以注入並呼叫BeanFactory。

經過層層的進入,可以得到如下的關係

這樣看來,我們可以得出結論——AnnotationAwareAspectJAutoProxyCreator是一個後置處理器(後置處理器原理)

 

 

總結

  經過以上五個步驟,我們看到AOP的使用效果,發現了AOP的核心元件AnnotationAwareAspectJAutoProxyCreator是一個後置處理器,理清了AnnotationAwareAspectJAutoProxyCreator的繼承實現關係。

總得來說,就是明白了核心元件是什麼。

 

在接下來的篇章我們將從核心元件在哪發揮作用,何時發揮,以及做了什麼,一步步深入原