成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專欄INFORMATION COLUMN

Spring AOP從零單排-織入時(shí)期源碼分析

honmaple / 1072人閱讀

摘要:何為簡(jiǎn)單點(diǎn)來定義就是切面,是一種編程范式。定義一個(gè)切面的載體定義一個(gè)切點(diǎn)定義一個(gè)為,并指定對(duì)應(yīng)的切點(diǎn)一個(gè)注冊(cè)配置類,啟動(dòng)容器,初始化時(shí)期獲取對(duì)象,獲取對(duì)象時(shí)期,并進(jìn)行打印好了,這樣我們整體的代理就已經(jīng)完成。

問題:Spring AOP代理中的運(yùn)行時(shí)期,是在初始化時(shí)期織入還是獲取對(duì)象時(shí)期織入?

織入就是代理的過程,指目標(biāo)對(duì)象進(jìn)行封裝轉(zhuǎn)換成代理,實(shí)現(xiàn)了代理,就可以運(yùn)用各種代理的場(chǎng)景模式。
何為AOP

簡(jiǎn)單點(diǎn)來定義就是切面,是一種編程范式。與OOP對(duì)比,它是面向切面,為何需要切面,在開發(fā)中,我們的系統(tǒng)從上到下定義的模塊中的過程中會(huì)產(chǎn)生一些橫切性的問題,這些橫切性的問題和我們的主業(yè)務(wù)邏輯關(guān)系不大,假如不進(jìn)行AOP,會(huì)散落在代碼的各個(gè)地方,造成難以維護(hù)。AOP的編程思想就是把業(yè)務(wù)邏輯和橫切的問題進(jìn)行分離,從而達(dá)到解耦的目的,使代碼的重用性、侵入性低、開發(fā)效率高。

AOP使用場(chǎng)景

日志記錄;記錄調(diào)用方法的入?yún)⒑徒Y(jié)果返參。

用戶的權(quán)限驗(yàn)證;驗(yàn)證用戶的權(quán)限放到AOP中,與主業(yè)務(wù)進(jìn)行解耦。

性能監(jiān)控;監(jiān)控程序運(yùn)行方法的耗時(shí),找出項(xiàng)目的瓶頸。

事務(wù)管理;控制Spring事務(wù),Mysql事務(wù)等。

AOP概念點(diǎn) AOP和Spring AOP的關(guān)系

在這里問題中,也有一個(gè)類似的一對(duì)IOC和DI(dependency injection)的關(guān)系,AOP可以理解是一種編程目標(biāo),Spring AOP就是這個(gè)實(shí)現(xiàn)這個(gè)目標(biāo)的一種手段。同理IOC也是一種編程目標(biāo),DI就是它的一個(gè)手段。

SpringAOP和AspectJ是什么關(guān)系

在Spring官網(wǎng)可以看到,AOP的實(shí)現(xiàn)提供了兩種支持分別為@AspectJ、Schema-based AOP。其實(shí)在Spring2.5版本時(shí),Spring自己實(shí)現(xiàn)了一套AOP開發(fā)的規(guī)范和語言,但是這一套規(guī)范比較復(fù)雜,可讀性差。之后,Spring借用了AspectJ編程風(fēng)格,才有了@AspectJ的方式支持,那么何為編程風(fēng)格。

Annotation注解方式;對(duì)應(yīng)@AspectJ

JavaConfig;對(duì)應(yīng)Schema-based AOP

SpringAOP和AspectJ的詳細(xì)對(duì)比,在之后的章節(jié)會(huì)在進(jìn)行更加詳細(xì)的說明,將會(huì)在他們的背景、織入方法、性能做介紹。

Spring AOP的應(yīng)用

閱讀官網(wǎng),是我們學(xué)習(xí)一個(gè)新知識(shí)的最好途徑,這個(gè)就是Spring AOP的核心概念點(diǎn),跟進(jìn)它們的重要性,我做了重新的排序,以便好理解,這些會(huì)為我們后續(xù)的源碼分析起到作用。

Aspect:切面;使用@Aspect注解的Java類來實(shí)現(xiàn),集合了所有的切點(diǎn),做為切點(diǎn)的一個(gè)載體,做一個(gè)比喻就像是我們的一個(gè)數(shù)據(jù)庫(kù)。
Tips:這個(gè)要實(shí)現(xiàn)的話,一定要交給Spirng IOC去管理,也就是需要加入@Component。

Pointcut:切點(diǎn);表示為所有Join point的集合,就像是數(shù)據(jù)庫(kù)中一個(gè)表。

Join point:連接點(diǎn);俗稱為目標(biāo)對(duì)象,具體來說就是servlet中的method,就像是數(shù)據(jù)庫(kù)表中的記錄。

Advice:通知;這個(gè)就是before、after、After throwing、After (finally)。

Weaving:把代理邏輯加入到目標(biāo)對(duì)象上的過程叫做織入。

target:目標(biāo)對(duì)象、原始對(duì)象。

aop Proxy:代理對(duì)象 包含了原始對(duì)象的代碼和增加后的代碼的那個(gè)對(duì)象。

Tips
這個(gè)應(yīng)用點(diǎn),有很多的知識(shí)點(diǎn)可以讓我們?nèi)ネ诰颍热鏟ointcut中execution、within的區(qū)別,我相信你去針對(duì)性搜索或者官網(wǎng)都未必能有好的解釋,稍后會(huì)再專門挑一個(gè)文章做重點(diǎn)的使用介紹;
SpringAOP源碼分析

為了回答我們的一開始的問題,前面的幾個(gè)章節(jié)我們做了一些簡(jiǎn)單的概念介紹做為鋪墊,那么接下來我們回歸正題,正面去切入問題。以碼說話,我們以最簡(jiǎn)潔的思路把AOP實(shí)現(xiàn),我們先上代碼。

項(xiàng)目結(jié)構(gòu)介紹

項(xiàng)目目錄結(jié)構(gòu),比較簡(jiǎn)單,5個(gè)主要的文件;

pom.xml核心代碼;spring-content是核心jar,已經(jīng)包含了spring所有的基礎(chǔ)jar,aspectjweaver是為了實(shí)現(xiàn)AOP。

AppConfig.java;定義一個(gè)Annotation,做為我們Spirng IOC容器的啟動(dòng)類。

package com.will.config;
?
@Configuration
@ComponentScan("com.will")
@EnableAspectJAutoProxy(proxyTargetClass = false)
public class AppConfig {
    
}

WilAspect.java ;按照官網(wǎng)首推的方式(@AspectJ support),實(shí)現(xiàn)AOP代理。

package com.will.config;
?
/**
 * 定義一個(gè)切面的載體
 */
@Aspect
@Component
public class WilAspect {
    /**
     * 定義一個(gè)切點(diǎn)
     */
    @Pointcut("execution(* com.will.dao.*.*(..))")
    public void pointCutExecution(){
    }
?
    /**
     * 定義一個(gè)Advice為Before,并指定對(duì)應(yīng)的切點(diǎn)
     * @param joinPoint
     */
    @Before("pointCutExecution()")
    public  void before(JoinPoint joinPoint){
        System.out.println("proxy-before");
    }
}

Dao.java

package com.will.dao;
public interface Dao {
    public void query();
}

UserDao.java

package com.will.dao;
import org.springframework.stereotype.Component;
@Component
public class UserDao implements Dao {
    public void query() {
        System.out.println("query user");
    }
}

Test.java

package com.will.test;
import com.will.config.AppConfig;
import com.will.dao.Dao;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Test {
    public static void main(String[] args) {
        /**
         * new一個(gè)注冊(cè)配置類,啟動(dòng)IOC容器,初始化時(shí)期;
         */
        AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
?
        /**
         * 獲取Dao對(duì)象,獲取對(duì)象時(shí)期,并進(jìn)行query打印
         */
        Dao dao = annotationConfigApplicationContext.getBean(Dao.class);
        dao.query();
        annotationConfigApplicationContext.start();
    }
}

好了,這樣我們整體的AOP代理就已經(jīng)完成。

問題分析測(cè)試

究竟是哪個(gè)時(shí)期進(jìn)行對(duì)象織入的,比如Test類中,究竟是第一行還是第二行進(jìn)行織入的,我們只能通過源碼進(jìn)行分析,假如是你,你會(huì)進(jìn)行如何的分析源碼解讀。

Spring的代碼非常優(yōu)秀,同時(shí)也非常復(fù)雜,那是一個(gè)大項(xiàng)目,里面進(jìn)行了很多的代碼封裝,那么的代碼你三天三夜也讀不完,甚至于你都不清楚哪一行的該留意的,哪一行是起到關(guān)鍵性作用的,這里教幾個(gè)小技巧。

看方法返回類型;假如是void返回類型的,看都不看跳過。返回結(jié)果是對(duì)象,比如T果斷進(jìn)行去進(jìn)行跟蹤。

假設(shè)法;就當(dāng)前場(chǎng)景,我們大膽假設(shè)是第二行進(jìn)行的織入。

借助好的IDE;IDEA可以幫我們做很多的事情,它的debug模式中的條件斷點(diǎn)、調(diào)用鏈(堆棧)會(huì)幫助到我們。

假設(shè)法源碼分析

debug模式StepInfo(F5)后,進(jìn)入 AbstractApplicationContext.getBean方法,這個(gè)是Spring應(yīng)用上下文中最重要的一個(gè)類,這個(gè)抽象類中提供了幾乎ApplicationContext的所有操作。這里第一個(gè)語句返回void,我們可以直接忽略,看下面的關(guān)鍵性代碼。

繼續(xù)debug后,會(huì)進(jìn)入到 DefaultListableBeanFactory 類中,看如下代碼

return new NamedBeanHolder<>(beanName, getBean
(beanName, requiredType, args));

在該語句中,這個(gè)可以理解為 DefaultListableBeanFactory 容器,幫我們獲取相應(yīng)的Bean。

進(jìn)入到AbstractBeanFactory類的doGetBean方法之后,我們運(yùn)行完。

Object sharedInstance = getSingleton(beanName);

語句之后,看到 sharedInstance 對(duì)象打印出&Proxyxxx ,說明在getSingleton 方法的時(shí)候就已經(jīng)獲取到了對(duì)象,所以需要跟蹤進(jìn)入到 getSingleton 方法中,繼續(xù)探究。

不方便不方便我們進(jìn)行問題追蹤到這個(gè)步驟之后,我需要引入IDEA的條件斷點(diǎn),不方便我們進(jìn)行問題追蹤因?yàn)镾pring會(huì)初始化很多的Bean,我們?cè)?b>ObjectsharedInstance=getSingleton(beanName);加入條件斷點(diǎn)語句。

繼續(xù)debug進(jìn)入到DefaultSingletonBeanRegistrygetSingleton方法。
我們觀察下執(zhí)行完ObjectsingletonObject=this.singletonObjects.get(beanName); 之后的singletonObject已經(jīng)變成為&ProxyUserDao,這個(gè)時(shí)候Spring最關(guān)鍵的一行代碼出現(xiàn)了,請(qǐng)注意這個(gè)this.singletonObjects

this.singletonObjects就是相當(dāng)IOC容器,反之IOC容器就是一個(gè)線程安全的線程安全的HashMap,里面存放著我們需要Bean。


我們來看下singletonObjects存放著的數(shù)據(jù),里面就有我們的UserDao類。

這就說明,我們的初始化的時(shí)期進(jìn)行織入的,上圖也有整個(gè)Debug模式的調(diào)用鏈。

源碼深層次探索

通過上一個(gè)環(huán)節(jié)已經(jīng)得知是在第一行進(jìn)行初始化的,但是它在初始化的時(shí)候是什么時(shí)候完成織入的,抱著求知的心態(tài)我們繼續(xù)求證。

還是那個(gè)問題,那么多的代碼,我的切入點(diǎn)在哪里?

既然singletonObjects是容器,存放我們的Bean,那么找到關(guān)鍵性代碼在哪里進(jìn)行存放(put方法)就可以了。于是我們通過搜索定位到了。


我們通過debug模式的條件斷點(diǎn)和debug調(diào)用鏈模式,就可以進(jìn)行探索。

這個(gè)時(shí)候借助上圖中的調(diào)用鏈,我們把思路放到放到IDEA幫我定位到的兩個(gè)方法代碼上。

DefaultSingletonBeanRegistry.getSingleton

我們一步步斷點(diǎn),得知,當(dāng)運(yùn)行完singletonObject=singletonFactory.getObject();之后,singletonObject已經(jīng)獲得了代理。

至此我們知道,代理對(duì)象的獲取關(guān)鍵在于singletonFactory對(duì)象,于是又定位到了AbstractBeanFactorydoGetBean方法,發(fā)現(xiàn)singletonFactory參數(shù)是由createBean方法創(chuàng)造的。這個(gè)就是Spring中IOC容器最核心的地方了,這個(gè)代碼的模式也值得我們?nèi)W(xué)習(xí)。

sharedInstance = getSingleton(beanName, () -> {
                        try {
                            return createBean(beanName, mbd, args);
                        }
                        catch (BeansException ex) {
                            // Explicitly remove instance from singleton cache: It might have been put there
                            // eagerly by the creation process, to allow for circular reference resolution.
                            // Also remove any beans that received a temporary reference to the bean.
                            destroySingleton(beanName);
                            throw ex;
                        }
                    });

這個(gè)第二個(gè)參數(shù)是用到了jdk8中的lambda,這一段的含義是就是為了傳參,重點(diǎn)看下 createBean(beanName,mbd,args);代碼。隨著斷點(diǎn),我們進(jìn)入到這個(gè)類方法里面。

AbstractAutowireCapableBeanFactory.createBean中的;

ObjectbeanInstance=doCreateBean(beanName,mbdToUse,args)方法;

doCreateBean方法中,做了簡(jiǎn)化。

Initialize the bean instance.
        Object exposedObject = bean;
        try {
            populateBean(beanName, mbd, instanceWrapper);
            exposedObject = initializeBean(beanName, exposedObject, mbd);
        }
        ...
?
        return exposedObject;

當(dāng)運(yùn)行完 exposedObject=initializeBean(beanName,exposedObject,mbd);之后,我們看到exposedObject已經(jīng)是一個(gè)代理對(duì)象,并執(zhí)行返回。這一行代碼就是取判斷對(duì)象要不要執(zhí)行代理,要的話就去初始化代理對(duì)象,不需要直接返回。后面的initializeBean方法是涉及代理對(duì)象生成的邏輯(JDK、Cglib),后續(xù)會(huì)有一個(gè)專門的章節(jié)進(jìn)行詳細(xì)介紹。

總結(jié)

通過源碼分析,我們得知,Spring AOP的代理對(duì)象的織入時(shí)期是在運(yùn)行Spring初始化的時(shí)候就已經(jīng)完成的織入,并且也分析了Spring是如何完成的織入。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/73659.html

相關(guān)文章

  • Spring AOP 源碼分析系列文章導(dǎo)讀

    摘要:在寫完容器源碼分析系列文章中的最后一篇后,沒敢懈怠,趁熱打鐵,花了天時(shí)間閱讀了方面的源碼。從今天開始,我將對(duì)部分的源碼分析系列文章進(jìn)行更新。全稱是,即面向切面的編程,是一種開發(fā)理念。在中,切面只是一個(gè)概念,并沒有一個(gè)具體的接口或類與此對(duì)應(yīng)。 1. 簡(jiǎn)介 前一段時(shí)間,我學(xué)習(xí)了 Spring IOC 容器方面的源碼,并寫了數(shù)篇文章對(duì)此進(jìn)行講解。在寫完 Spring IOC 容器源碼分析系列...

    張春雷 評(píng)論0 收藏0
  • Spring AOP 入門

    摘要:一以及術(shù)語是的簡(jiǎn)稱,被譯為面向切面編程。切面由切點(diǎn)和增強(qiáng)組成,他包括了連接點(diǎn)定義和橫切邏輯代碼的定義,就是負(fù)責(zé)實(shí)施切面的框架。五使用來定義純粹的切面使用方法也非常簡(jiǎn)單,使用的標(biāo)簽。采用動(dòng)態(tài)代理和動(dòng)態(tài)代理技術(shù)在運(yùn)行期間織入。 引言 AOP是軟件開發(fā)思想發(fā)展到一定階段的產(chǎn)物,AOP的出現(xiàn)并不是為了代替OOP,僅作為OOP的有益補(bǔ)充,在下面的例子中這個(gè)概念將會(huì)得到印證。AOP的應(yīng)用場(chǎng)合是受限...

    CodeSheep 評(píng)論0 收藏0
  • 看起來很長(zhǎng)但還是有用的Spring學(xué)習(xí)筆記

    摘要:關(guān)于依賴注入注入的注解提供的注解不僅僅是對(duì)象,還有在構(gòu)造器上,還能用在屬性的方法上。與之相反,的限定符能夠在所有可選的上進(jìn)行縮小范圍的操作,最終能夠達(dá)到只有一個(gè)滿足所規(guī)定的限制條件。注解是使用限定符的主要方式。 本文首發(fā)于泊浮目的專欄:https://segmentfault.com/blog... Spring致力于提供一種方法管理你的業(yè)務(wù)對(duì)象。在大量Java EE的應(yīng)用中,隨處可...

    DTeam 評(píng)論0 收藏0
  • Spring bean的生命流程

    摘要:如果依賴靠構(gòu)造器方式注入,則無法處理,直接會(huì)報(bào)循環(huán)依賴異常。光繼承這個(gè)接口還不夠,繼承這個(gè)接口只能獲取,要想讓生效,還需要拿到切面對(duì)象包含和才行。有了目標(biāo)對(duì)象,所有的切面類,此時(shí)就可以為生成代理對(duì)象了。 Spring 是一個(gè)輕量級(jí)的 J2EE 開源框架,其目標(biāo)是降低企業(yè)級(jí)應(yīng)用開發(fā)難度,提高企業(yè)級(jí)應(yīng)用開發(fā)效率。在日程開發(fā)中,我們會(huì)經(jīng)常使用 Spring 框架去構(gòu)建應(yīng)用。所以作為一個(gè)經(jīng)常使...

    趙連江 評(píng)論0 收藏0
  • 吃透動(dòng)態(tài)代理,解密spring AOP源碼(四)

    摘要:值得一提的是由于采用動(dòng)態(tài)創(chuàng)建子類的方式生成代理對(duì)象,所以不能對(duì)目標(biāo)類中的方法進(jìn)行代理。動(dòng)態(tài)代理中生成的代理類是子類,調(diào)試的時(shí)候可以看到,打開源碼可看到實(shí)現(xiàn)了和也就實(shí)現(xiàn)方法。 前面講到了動(dòng)態(tài)代理的底層原理,接下來我們來看一下aop的動(dòng)態(tài)代理.Spring AOP使用了兩種代理機(jī)制:一種是基于JDK的動(dòng)態(tài)代理,一種是基于CGLib的動(dòng)態(tài)代理. ①JDK動(dòng)態(tài)代理:使用JDK創(chuàng)建代理有一個(gè)限制...

    Codeing_ls 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<