Spring aop解析(2)2018-08-13

接著上一節(jié):Spring aop(1)開篇的測試類分析:

public class TestAop {
    public static void main(String[] args) {
        //手工創(chuàng)建一個實例(Target)
        ProxyService aspectJService = new ProxyServiceImpl();
        //使用AspectJ語法 自動創(chuàng)建代理對象
        AspectJProxyFactory aspectJProxyFactory = new AspectJProxyFactory(aspectJService);
        //添加切面和通知類
        aspectJProxyFactory.addAspect(AopAdviceConfig.class);
        //創(chuàng)建代理對象
        ProxyService proxyService = aspectJProxyFactory.getProxy();
        //進行方法調(diào)用
        proxyService.testProxy();
    }
}

從測試的代碼可以看出,這段代碼的重點是AspectJProxyFactory,首先我們來看下AspectJProxyFactory的UML類圖:


AspectJProxyFactory繼承關(guān)系.png

我們來看看繼承體系中涉及到類的作用:
a、Advisor:組合了Advice。
b、Advised:組合了Advisor和TargetSource即目標對象
c、AdvisedSupport:Advised的一個實現(xiàn)類。繼承了ProxyConfig實現(xiàn)了Advised。
d、ProxyConfig:在Advised中定義了一系列的配置接口,像:是否暴露對象、是否強制使用CGlib等。ProxyConfig是對這些接口的實現(xiàn),但是ProxyConfig卻不是Advised的實現(xiàn)類
e、ProxyCreatorSupport:AdvisedSupport的子類。引用了AopProxyFactory用來創(chuàng)建代理對象。
f、AspectJProxyFactory:ProxyCreatorSupport的子類。用來創(chuàng)建代理對象。使用AspectJ語法。(ProxyFactory、ProxyFactoryBean、AspectJProxyFactory這三個類功能都是一樣的,但是使用場景各不相同。)

測試類解析:

1、我們先來看看new AspectJProxyFactory(aspectJService)構(gòu)造方法代碼如下:

public AspectJProxyFactory(Object target) {
        //檢測目標對象不能為null
        Assert.notNull(target, "Target object must not be null");
        //設(shè)置目標對象的所有的接口 
        this.setInterfaces(ClassUtils.getAllInterfaces(target));
        //設(shè)置目標對象
        this.setTarget(target);
    }

2、接著我們來看看aspectJProxyFactory.addAspect(AopAdviceConfig.class):

 public void addAspect(Class<?> aspectClass) {
        //全限定類名
        String aspectName = aspectClass.getName();
        //根據(jù)切面對象創(chuàng)建切面元數(shù)據(jù)類
        AspectMetadata am = this.createAspectMetadata(aspectClass, aspectName);
        //根據(jù)傳入的切面類創(chuàng)建元數(shù)據(jù) 切面class實例 將切面實例封裝為切面實例工廠
        MetadataAwareAspectInstanceFactory instanceFactory = this.createAspectInstanceFactory(am, aspectClass, aspectName);
        //從切面實例工廠中獲取Advisor。
        this.addAdvisorsFromAspectInstanceFactory(instanceFactory);
    }

上面的代碼分別執(zhí)行了:this.createAspectMetadata、this.createAspectInstanceFactory、this.addAdvisorsFromAspectInstanceFactory這三個方法,我們分別來看下:

2.1: this.createAspectMetadata

a、我們來先看看那元數(shù)據(jù)的存儲基本信息:

/**
  * AspectMetadata 切面元數(shù)據(jù)類
  */
public class AspectMetadata implements Serializable {

    /**
    * 切面的名字 可能是類的全限定類名 也可能是Spring容器中bean的名字
    */
    private final String aspectName;

    /**
    * 切面類 指帶有切面注解的類
    */
    private final Class<?> aspectClass;
    /**
    * 類的類型 這個是AspectJ中定義的類  存儲了aspectClass類的類相關(guān)信息
    * 實現(xiàn)類為 AjTypeImpl
    */
    private transient AjType<?> ajType;

    /**
    * Spring AOP 中的切點表達式
    */
    private final Pointcut perClausePointcut;
}

AspectMetadata這個類中主要存儲了切面類的名字、切面類對象和AspectJ中定義的存儲切面類Class對象的類以及SpringAOP中的切點表達式。

b、createAspectMetadata方法:

 private AspectMetadata createAspectMetadata(Class<?> aspectClass, String aspectName) {
        //直接調(diào)用 AspectMetadata的構(gòu)造函數(shù) 
        AspectMetadata am = new AspectMetadata(aspectClass, aspectName);
        //這里判斷我們傳入的切面類是不是切面很簡單,即判斷切面類上是否存在@Aspect注解。
        if (!am.getAjType().isAspect()) {
            throw new IllegalArgumentException("Class [" + aspectClass.getName() + "] is not a valid aspect type");
        }
        return am;
    }

c、接著看看AspectMetadata的構(gòu)造方法:

public AspectMetadata(Class<?> aspectClass, String aspectName) {
        //傳入的切面類名直接賦值
        this.aspectName = aspectName;
        Class<?> currClass = aspectClass;

        AjType ajType;
        //這里循環(huán)查找 帶有Aspect的類,一直找到父類為Object
        for(ajType = null; currClass != Object.class; currClass = currClass.getSuperclass()) {
            AjType<?> ajTypeToCheck = AjTypeSystem.getAjType(currClass);
            if (ajTypeToCheck.isAspect()) {
                //這里的AjType所持有的aspectClass為帶有@Aspect注解的類。
                ajType = ajTypeToCheck;
                break;
            }
        }

        if (ajType == null) {
            throw new IllegalArgumentException("Class '" + aspectClass.getName() + "' is not an @AspectJ aspect");
        } else if (ajType.getDeclarePrecedence().length > 0) {
            throw new IllegalArgumentException("DeclarePrecendence not presently supported in Spring AOP");
        } else {
            this.aspectClass = ajType.getJavaClass();
            this.ajType = ajType;
            switch(this.ajType.getPerClause().getKind()) {
            //perClausePointcut切點表達式初始化
            //正常我們的Aspect類 都是SINGLETON  其他類型還不知道是什么
            case SINGLETON:
                this.perClausePointcut = Pointcut.TRUE;
                return;
            case PERTARGET:
            case PERTHIS:
                AspectJExpressionPointcut ajexp = new AspectJExpressionPointcut();
                ajexp.setLocation(aspectClass.getName());
                ajexp.setExpression(this.findPerClause(aspectClass));
                ajexp.setPointcutDeclarationScope(aspectClass);
                this.perClausePointcut = ajexp;
                return;
            case PERTYPEWITHIN:
                this.perClausePointcut = new ComposablePointcut(new TypePatternClassFilter(this.findPerClause(aspectClass)));
                return;
            default:
                throw new AopConfigException("PerClause " + ajType.getPerClause().getKind() + " not supported by Spring AOP for " + aspectClass);
            }
        }
    }

2.2: this.createAspectInstanceFactory

a、我們在看createAspectInstanceFactory這個方法的代碼:

 private MetadataAwareAspectInstanceFactory createAspectInstanceFactory(AspectMetadata am, Class<?> aspectClass, String aspectName) {
        Object instanceFactory;
        //我們在使用 @Aspect注解的時候都是直接在類上添加@Aspect注解所以以下條件會成立
        if (am.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
             //根據(jù)傳入的切面類創(chuàng)建 切面對象 是一個單例 要求有無參構(gòu)造函數(shù)
            Object instance = this.getSingletonAspectInstance(aspectClass);
            instanceFactory = new SingletonMetadataAwareAspectInstanceFactory(instance, aspectName);
        } else {
            //創(chuàng)建一個 SimpleMetadataAwareAspectInstanceFactory
            instanceFactory = new SimpleMetadataAwareAspectInstanceFactory(aspectClass, aspectName);
        }

        return (MetadataAwareAspectInstanceFactory)instanceFactory;
    }

今天先到這里。。。。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 從三月份找實習到現(xiàn)在,面了一些公司,掛了不少,但最終還是拿到小米、百度、阿里、京東、新浪、CVTE、樂視家的研發(fā)崗...
    時芥藍閱讀 42,757評論 11 349
  • 以前寫的文章直接上源碼分析,這會讓不了解的人看著很累,得不到想要的效果。本篇文章則從背景-原理-使用-源碼的順序為...
    oneWeekOneTopic閱讀 15,407評論 2 25
  • 本章內(nèi)容: 面向切面編程的基本原理 通過POJO創(chuàng)建切面 使用@AspectJ注解 為AspectJ切面注入依賴 ...
    謝隨安閱讀 3,390評論 0 9
  • 辛辛苦苦寫了一篇博客,發(fā)現(xiàn)簡書markdown插入代碼居然沒有行序,我都懵逼了。看來這個編輯器對程序猿不太友好啊,...
    司徒文德閱讀 435評論 0 1
  • 雨,我在哪兒?
    寫小書閱讀 98評論 0 0

友情鏈接更多精彩內(nèi)容