手寫Spring AOP,快來瞧一瞧看一看撒!
點(diǎn)擊上方藍(lán)色字體,選擇“標(biāo)星公眾號”
優(yōu)質(zhì)文章,第一時間送達(dá)
作者 | 狐言不胡言
來源 | urlify.cn/zyUNfi
76套java從入門到精通實(shí)戰(zhàn)課程分享

AOP分析
AOP是什么
Aspect Oriented Programming 面向切面編程,在不改變類的代碼的情況下,對類的方法進(jìn)行功能增強(qiáng)
那么如果要實(shí)現(xiàn)一個AOP,需要做的事情就是要向使用的用戶提供AOP功能,能夠通過AOP技術(shù)實(shí)現(xiàn)對類的方法進(jìn)行功能增強(qiáng)
AOP中的元素
Advice 通知,即增強(qiáng)的功能
Join points 連接點(diǎn),可以選擇的方法點(diǎn),即有哪些可以增強(qiáng)的方法供選擇
Pointcut 切入點(diǎn),選擇切入的方法點(diǎn),即對哪些方法進(jìn)行增強(qiáng)
Aspact 切面,選擇的多個方法點(diǎn) + 增強(qiáng)的功能,即Advice和Pointcut的組合
Introduction 引入,添加新的方法、屬性到已經(jīng)存在的類中,叫做引入
Weaving 織入,即不改變原來的代碼,加入增強(qiáng)的功能
手寫AOP的話,上面幾個元素有的是需要用戶提供的:Advice、Pointcut、Aspact,用戶需要提供增強(qiáng)的功能和切入點(diǎn)、切面信息;AOP框架需要提供Join points、Weaving
AOP提供的功能
需要功能的增強(qiáng),即Advice通知
對類的方法進(jìn)行增強(qiáng),那需要可以選擇的要增強(qiáng)的方法點(diǎn),即Pointcut切入點(diǎn)
需要在不改變原類代碼的情況下,進(jìn)行功能的增強(qiáng),即Weaving織入
圖解AOP
假設(shè)我們現(xiàn)在玩一局王者榮耀,選擇了一個英雄魯班,這個魯班需要參與整個游戲直到結(jié)束,不管是否掛機(jī);剛剛開始的時候,沒有任何裝備,假設(shè)魯班身上的各個部位是Join points,即這些部位需要裝備去增強(qiáng)它,那每一個裝備就是Advice增強(qiáng)的功能,比如增加攻速、生命等,現(xiàn)在買了一個鞋子,那么就是選擇在速度上進(jìn)行增強(qiáng),即穿在腳上,那么就是Pointcut,那么這個鞋子加上腳就是Aspact切面,上面說的例子可能不夠好,見諒?。?/span>
特點(diǎn)分析
Advice
實(shí)現(xiàn)一個Advice,就需要知道Advice有哪些特點(diǎn),從上面可以知道Advice是用戶來提供的,所以有很多不可控的因素
用戶性:由用戶來提供增強(qiáng)的功能,即增強(qiáng)功能的代碼是用戶來進(jìn)行編寫的
多變性:既然用戶來提供,那么對于不同的需求,增強(qiáng)的邏輯都是不一樣的
可選時機(jī):用戶可以選擇在方法的前面、后面、異常時進(jìn)行功能增強(qiáng)
多重性:同一個切入點(diǎn),即同一個方法,可以有多重的增強(qiáng),不止增強(qiáng)一次
Pointcut
切入點(diǎn),通過上面知道它也是用戶提供的,所以它的特點(diǎn)和Advice基本上差不多
用戶性:由用戶來指定,對哪些方法進(jìn)行功能增強(qiáng)
多變性:用戶可以靈活的來指定
多點(diǎn)性:用戶可以選擇在多個方法點(diǎn)上進(jìn)行功能增強(qiáng)
Weaving
織入,這部分代碼,是需要框架提供的,即是需要我們自己去實(shí)現(xiàn)的邏輯,通過這個可以把增強(qiáng)的功能加入到用戶指定的方法上面
無侵入性:不改變原來類的代碼,去實(shí)現(xiàn)功能的增強(qiáng)
需要我們在AOP框架中自己實(shí)現(xiàn)邏輯
通過上面的內(nèi)容,可以知道,需要做的事情就是Advice、Pointcut、Weaving三個部分,Join points為什么不需要去實(shí)現(xiàn)呢,這部分內(nèi)容在編寫代碼的過程中就可以知道了
Advice實(shí)現(xiàn)
Advice是由用戶來實(shí)現(xiàn)的,這部分邏輯需要用戶寫好然后我們實(shí)現(xiàn)AOP的時候來進(jìn)行使用;我們需要認(rèn)識用戶的東西,用戶需要使用我們寫的框架,而且還需要隔絕用戶的多變性
那么需要做的事情是啥呢,可以定義一個標(biāo)準(zhǔn)的接口,用戶通過實(shí)現(xiàn)接口來提供不同的增強(qiáng)邏輯,這就是應(yīng)對變化的方式,面向接口編程
定義Advice接口
定義的Advice是一個頂級接口,不需要寫任何的方法,然后根據(jù)前置、后置、環(huán)繞、異常增強(qiáng),來去實(shí)現(xiàn)Advice接口,那么這些增強(qiáng)需要的參數(shù)是一樣的嗎,請往下看
Advice接口:
/**
* @className: Advice
* @description: 通知的標(biāo)準(zhǔn)接口
* @author TR
*/
public interface Advice {
}
首先,我們知道,增強(qiáng)是對方法進(jìn)行增強(qiáng),那么使用Advice的時候,需要給的就是方法的一些信息
前置增強(qiáng)
在方法執(zhí)行前進(jìn)行增強(qiáng),那么可以知道前置增強(qiáng)是不需要返回值的,需要的參數(shù)如下:
方法自身 Method
方法的參數(shù) Object[]
方法所在的類(對象) Object
后置增強(qiáng)
在方法執(zhí)行后進(jìn)行增強(qiáng),那需要的參數(shù)是不是需要增加一個啊,即需要方法的返回值,因?yàn)槲胰绻枰獙Ψ祷刂底鲆幌绿幚?,就需要用到它,而且后置增?qiáng)也是不需要返回值的,需要的參數(shù)如下:
方法自身 Method
方法的參數(shù) Object[]
方法所在的類(對象) Object
方法的返回值 Object
環(huán)繞增強(qiáng)
包裹方法進(jìn)行增強(qiáng),它是需要包裹整個方法,即方法由它來執(zhí)行,那么環(huán)繞增強(qiáng)是需要返回值的,這個返回值是需要增強(qiáng)方法的返回值,需要的參數(shù)如下:
方法自身 Method
方法的參數(shù) Object[]
方法所在的類(對象) Object
異常增強(qiáng)
捕獲方法執(zhí)行時的異常信息,然后進(jìn)行增強(qiáng),而且它也是需要包裹方法進(jìn)行增強(qiáng)的,即它可以在環(huán)繞增強(qiáng)中來實(shí)現(xiàn)
通過上面知道,需要定義三個方法:前置增強(qiáng)的方法、后置增強(qiáng)的方法、環(huán)繞和異常增強(qiáng)的方法,那這三個方法是定義在一個接口里面,還是分三個接口呢,根據(jù)單一職責(zé)原則,還是分三個接口來實(shí)現(xiàn)比較好,而且還可以根據(jù)不同的接口類型來區(qū)分是哪個Advice
定義前置、后置、環(huán)繞和異常增強(qiáng)接口
定義前置增強(qiáng)接口MethodBeforeAdvice:
/**
* @className: MethodBeforeAdvice
* @description: 前置增強(qiáng)接口
* @author TR
*/
public interface MethodBeforeAdvice extends Advice {
/**
* 前置增強(qiáng)方法
* @param method: 將要被執(zhí)行的方法
* @param target: 執(zhí)行方法的目標(biāo)對象
* @param args: 執(zhí)行方法的參數(shù)
* @return: void
**/
void before(Method method, Object target, Object[] args);
}
定義后置增強(qiáng)接口AfterReturningAdvice:
/**
* @className: AfterReturningAdvice
* @description: 后置增強(qiáng)接口
* @author TR
*/
public interface AfterReturningAdvice extends Advice {
/**
* 后置增強(qiáng)方法
* @param method: 將要被執(zhí)行的方法
* @param target: 執(zhí)行方法的目標(biāo)對象
* @param args: 執(zhí)行方法的參數(shù)
* @param returnValue: 執(zhí)行方法的返回值
* @return: void
**/
void after(Method method, Object target, Object[] args, Object returnValue);
}
定義環(huán)繞、異常增強(qiáng)接口MethodInterceptor:
/**
* @className: MethodInterceptor
* @description: 環(huán)繞、異常增強(qiáng)接口
* @author TR
*/
public interface MethodInterceptor extends Advice {
/**
* 環(huán)繞、異常增強(qiáng)方法,在方法實(shí)現(xiàn)中需要調(diào)用目標(biāo)方法
* @param method: 將要被執(zhí)行的方法
* @param target: 執(zhí)行方法的目標(biāo)對象
* @param args: 執(zhí)行方法的參數(shù)
* @return: java.lang.Object 執(zhí)行方法的返回值
* @throws Throwable
**/
Object invoke(Method method, Object target, Object[] args) throws Throwable;
}
類圖如下:
Pointcut實(shí)現(xiàn)
Pointcut的特點(diǎn):
用戶性:由用戶來指定,對哪些方法進(jìn)行功能增強(qiáng)
多變性:用戶可以靈活的來指定
多點(diǎn)性:用戶可以選擇在多個方法點(diǎn)上進(jìn)行功能增強(qiáng)
我們需要給用戶提供一個東西,讓用戶可以靈活的來指定方法點(diǎn),而且我們獲取到的時候又能夠知道,用戶對哪些方法點(diǎn)進(jìn)行了指定
指定對哪些方法進(jìn)行增強(qiáng),指定的信息是什么,其實(shí)就是一個或者多個方法,而且如果有重載存在呢,所以這個指定的東西,就是一個完整的方法簽名
那該怎么做到靈活性、多點(diǎn)性呢,這個指定的信息是可以描述一類方法的,比如:
某個包下某個類的某個方法
某個包下某個類的所有方法
某個包下所有類中以get開頭的方法
某個包下所有類中以get開頭以sevice結(jié)尾的方法
某個包下及其子包下所有類中以get開頭以sevice結(jié)尾的方法
那么可以定義一個表達(dá)式,來去描述上面的信息,這個描述的信息是包名.類名.方法名(參數(shù)類型)
每一部分是如何要求的呢?
包名:需要有父子特點(diǎn),可以模糊匹配
類名:可以模糊匹配
方法名:可以模糊匹配
參數(shù)類型:可以有多個
定義的表達(dá)式是需要來判斷:是否需要對某個類的某個方法進(jìn)行增強(qiáng),那么需要去匹配類和匹配方法
匹配的表達(dá)式:
正則表達(dá)式
AspactJ表達(dá)式
AspactJ表達(dá)式學(xué)習(xí)
/**
* @className: AspectJTest
* @description: AspectJ測試類
*/
public class AspectJTest {
public static void main(String[] args) throws NoSuchMethodException {
//獲得切點(diǎn)解析器
PointcutParser pp = PointcutParser
.getPointcutParserSupportingAllPrimitivesAndUsingContextClassloaderForResolution();
//切點(diǎn)解析器根據(jù)規(guī)則,解析出一個類型匹配器
TypePatternMatcher tp = pp.parseTypePattern("di.*");
//根據(jù)表達(dá)式生成一個切點(diǎn)表達(dá)式
PointcutExpression pe = pp.parsePointcutExpression("execution(* demo.beans.BeanFactory.get*(..))");
//匹配MagicGril的getName方法
Class<?> cl = MagicGril.class;
Method method = cl.getMethod("getName", null);
//匹配方法執(zhí)行
ShadowMatch sm = pe.matchesMethodExecution(method);
System.out.println("是否匹配到方法:" + sm.alwaysMatches());
System.out.println(cl.getName() + ",是否匹配表達(dá)式:" + pe.couldMatchJoinPointsInType(cl));
System.out.println(DefaultBeanFactory.class + ",是否匹配表達(dá)式:" + pe.couldMatchJoinPointsInType(DefaultBeanFactory.class));
System.out.println(cl.getName() +"類下的所有方法:");
for (Method method1 : cl.getMethods()) {
System.out.println(method1.getName());
}
}
}
輸出結(jié)果:
通過上面的描述,可以知道,切點(diǎn)該怎么去設(shè)計了
切點(diǎn)需要有的屬性就是切點(diǎn)表達(dá)式,需要提供的功能就是匹配類和匹配方法
而且這里也可以像Advice一樣定義一個頂級接口,因?yàn)槿绻院笥衅渌谋磉_(dá)式更加好用的話,需要擴(kuò)展,那么只需要繼承定義的這個頂級接口就行了,不管它內(nèi)部如何實(shí)現(xiàn),都要去實(shí)現(xiàn)我們定義的匹配類和匹配方法的行為
定義PointCut接口
/**
* @className: PointCut
* @description: 切點(diǎn)匹配接口
* @author: TR
*/
public interface PointCut {
/**
* 匹配類
* @author: jinpeng.sun
* @date: 2021/4/19 13:46
* @param targetClass: 匹配的目標(biāo)類
* @return: boolean
**/
boolean matchClass(Class<?> targetClass);
/**
* 匹配方法
* @author: jinpeng.sun
* @date: 2021/4/19 13:46
* @param method: 匹配的目標(biāo)方法
* @param targetClass: 匹配的目標(biāo)類
* @return: boolean
**/
boolean matchMethod(Method method, Class<?> targetClass);
}
定義正則表達(dá)式的實(shí)現(xiàn)類:RegExpressionPointcut
此處不實(shí)現(xiàn),主要使用AspactJ的方式
/**
* @className: RegExpressionPointcut
* @description: 正則表達(dá)式實(shí)現(xiàn)類
* @author: TR
*/
public class RegExpressionPointcut implements PointCut {
@Override
public boolean matchClass(Class<?> targetClass) {
return false;
}
@Override
public boolean matchMethod(Method method, Class<?> targetClass) {
return false;
}
}
定義AspectJ切點(diǎn)表達(dá)式的實(shí)現(xiàn)類:AspectJExpressionPointcut
/**
* @className: AspectJExpressionPointcut
* @description: AspectJ切點(diǎn)表達(dá)式實(shí)現(xiàn)類
* @author: TR
*/
public class AspectJExpressionPointcut implements PointCut {
/** 獲得切點(diǎn)解析器 */
PointcutParser pp = PointcutParser
.getPointcutParserSupportingAllPrimitivesAndUsingContextClassloaderForResolution();
/** 切點(diǎn)表達(dá)式的字符串形式 */
private String expression;
/** AspectJ中的切點(diǎn)表達(dá)式 */
private PointcutExpression pe;
public AspectJExpressionPointcut(String expression) {
super();
this.expression = expression;
pe = pp.parsePointcutExpression(expression);
}
@Override
public boolean matchClass(Class<?> targetClass) {
return pe.couldMatchJoinPointsInType(targetClass);
}
@Override
public boolean matchMethod(Method method, Class<?> targetClass) {
ShadowMatch sm = pe.matchesMethodExecution(method);
return sm.alwaysMatches();
}
public String getExpression() {
return expression;
}
}
實(shí)現(xiàn)步驟:
maven引入Aspectj的jar
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.6</version>
</dependency>
獲得切點(diǎn)解析器
PointcutParser pp = PointcutParser
.getPointcutParserSupportingAllPrimitivesAndUsingContextClassloaderForResolution();
解析切點(diǎn)表達(dá)式,獲得PointcutExpression
PointcutExpression pe = pp.parsePointcutExpression(
"execution(* edu.dongnao.courseware.beans.BeanFactory.get*(..))");
使用PointcutExpression匹配類,不可靠
pe.couldMatchJoinPointsInType(targetClass)
使用PointcutExpression匹配方法,可靠
ShadowMatch sm = pe.matchesMethodExecution(method);
return sm.alwaysMatches();
類圖如下:
Aspact實(shí)現(xiàn)
上面實(shí)現(xiàn)了Advice和Pointcut,那么用戶該如何使用呢?
Advice是用戶提供的功能增強(qiáng)實(shí)現(xiàn),是需要繼承接口的,那么可以把Advice配置成一個bean,Pointcut是切點(diǎn)表達(dá)式,是用來匹配類和方法的,是不需要配置成bean的,只需要提供一個字符串形式的表達(dá)式就行了,那么adviceBeanName+expression就組成了切面
下面通過外觀模式來實(shí)現(xiàn)切面,把Advice和Pointcut組合起來
定義Advisor接口
/**
* @className: Advisor
* @description: 構(gòu)建切面的接口,組合advice和pointcut
* @author: TR
*/
public interface Advisor {
/**
* 獲取通知bean的名稱
* @return: java.lang.String
**/
String getAdviceBeanName();
/**
* 獲取切點(diǎn)表達(dá)式
* @return: java.lang.String
**/
String getExpression();
}
定義PointcutAdvisor接口
/**
* @className: PointcutAdvisor
* @description: 切點(diǎn)通知者,繼承自Advisor,擴(kuò)展了pointcut
* @author: TR
*/
public interface PointcutAdvisor extends Advisor {
/**
* 獲取切點(diǎn)
* @return: PointCut
**/
PointCut getPointCut();
}
定義AspectJPointcutAdvisor實(shí)現(xiàn)類
/**
* @className: AspectJPointcutAdvisor
* @description: AspectJ切點(diǎn)表達(dá)式的通知者實(shí)現(xiàn)類
* @author: TR
*/
public class AspectJPointcutAdvisor implements PointcutAdvisor {
/** 通知bean的名稱 */
private String adviceBeanName;
/** 表達(dá)式 */
private String expression;
/** 切點(diǎn) */
private PointCut pointCut;
public AspectJPointcutAdvisor(String adviceBeanName, String expression) {
this.adviceBeanName = adviceBeanName;
this.expression = expression;
this.pointCut = new AspectJExpressionPointcut(expression);
}
@Override
public PointCut getPointCut() {
return pointCut;
}
@Override
public String getAdviceBeanName() {
return adviceBeanName;
}
@Override
public String getExpression() {
return expression;
}
}
下面的類不予實(shí)現(xiàn),主要使用AspactJ的形式
/**
* @className: RegPointcutAdvisor
* @description: 正則切點(diǎn)表達(dá)式的通知者實(shí)現(xiàn)類
* @author: TR
*/
public class RegPointcutAdvisor implements PointcutAdvisor {
/** 通知bean的名稱 */
private String adviceBeanName;
/** 表達(dá)式 */
private String expression;
/** 切點(diǎn) */
private PointCut pointCut;
public RegPointcutAdvisor(String adviceBeanName, String expression) {
this.adviceBeanName = adviceBeanName;
this.expression = expression;
this.pointCut = new RegExpressionPointcut();
}
@Override
public PointCut getPointCut() {
return null;
}
@Override
public String getAdviceBeanName() {
return null;
}
@Override
public String getExpression() {
return null;
}
}
類圖如下:
從上面的圖中看到了,如果再擴(kuò)展其他的切點(diǎn)表達(dá)式,那么在實(shí)現(xiàn)類中,可以看到,有很多的重復(fù)代碼,那么是不是還可以優(yōu)化一下呢,可以在實(shí)現(xiàn)類的上層再加一個抽象類,來繼承PointcutAdvisor,然后主要的切點(diǎn)實(shí)現(xiàn)繼承這個抽象類就行了
Weaving實(shí)現(xiàn)
要完成的事情
將用戶提供的增強(qiáng)功能加入到指定的方法上,需要我們來實(shí)現(xiàn)
什么時候做織入
在創(chuàng)建Bean實(shí)例的時候,在Bean初始化完成后,再進(jìn)行織入
怎么知道Bean要進(jìn)行增強(qiáng)
需要遍歷Bean類及其所有的方法,然后依次的去匹配用戶指定的切面,如果存在匹配的切面,就是需要增強(qiáng)了
怎么織入呢,就是需要用到代理了!
用戶需要去注冊切面,我們還需要實(shí)現(xiàn)判斷匹配、織入的的邏輯,這部分代碼改如何寫,需要寫到哪里呢
現(xiàn)在要做的事情,就是在Bean創(chuàng)建的過程中加一項(xiàng)處理,后面可能會在Bean的創(chuàng)建過程中加入更多的處理,如果這部分代碼都寫在BeanFactory中,那么這個類是不是就會有特別多的代碼,而且后面不方便擴(kuò)展
看下Bean的創(chuàng)建過程:
上面圖中,每個箭頭都是加的擴(kuò)展點(diǎn),后面可能存在的是,需要在這些點(diǎn)上加入更多的處理邏輯,那么就需要設(shè)計一種方式,在不改變BeanFactory的情況下,能靈活的擴(kuò)展,那么可以使用觀察者模式,有幾個擴(kuò)展點(diǎn),就是有幾個主題,六個觀察者
定義觀察者接口BeanPostProcessor
/**
* @className: BeanPostProcessor
* @description: 后置處理器,Bean實(shí)例化完成后及依賴注入完成后觸發(fā)
* @author: TR
*/
public interface BeanPostProcessor {
/**
* bean初始化前的處理
* @author: TR
* @param bean: bean實(shí)例
* @param beanName: bean名稱
* @return: java.lang.Object
**/
default Object postProcessBeforeInitialization(Object bean, String beanName) throws Exception {
return bean;
}
/**
* bean初始化后的處理
* @author: TR
* @param bean: bean實(shí)例
* @param beanName: bean名稱
* @return: java.lang.Object
**/
default Object postProcessAfterInitialization(Object bean, String beanName) throws Exception {
return bean;
}
}
定義通知接口Aware
**
* @className: Aware
* @description: 構(gòu)建通知接口
* @date: 2021/4/19 16:38
* @author: jinpeng.sun
*/
public interface Aware {
}
/**
* @className: BeanFactoryAware
* @description: bean工廠構(gòu)建通知接口
* @author: TR
*/
public interface BeanFactoryAware extends Aware {
/**
* 接口實(shí)現(xiàn)者獲得bean工廠方法
* @author: TR
* @param bf:
* @return: void
**/
void setBeanFactory(BeanFactory bf);
}
上面的接口主要用來獲得Bean工廠信息
定義通知者注冊接口AdvisorRegistry
這個接口主要用來把Advisor注冊到增強(qiáng)功能的實(shí)現(xiàn)類里面
/**
* @className: AdvisorRegistry
* @description: 通知者注冊接口
* @author: TR
*/
public interface AdvisorRegistry {
/**
* 注冊通知者
* @author: TR
* @param advisor:
* @return: void
**/
public void registerAdvisor(Advisor advisor);
/**
* 獲得通知者列表
* @author: TR
* @date: 2021/4/19 16:45
*
* @return: java.util.List<demo.aop.advisor.Advisor>
**/
public List<Advisor> getAdvisors();
}
定義增強(qiáng)處理的觀察者實(shí)現(xiàn)類AdvisorAutoProxyCreator
/**
* @className: AdvisorAutoProxyCreator
* @description: 功能增強(qiáng)的實(shí)現(xiàn)類,用戶和框架交互的核心類
* 用戶通過Advisor提供切面,向DefaultBeanFactory注入該實(shí)現(xiàn)
* 框架內(nèi)部:DefaultBeanFactory注入ioc容器
* DefaultBeanFactory調(diào)用BeanPostProcessor接口相關(guān)方法,進(jìn)行功能增強(qiáng)
* @author: TR
*/
public class AdvisorAutoProxyCreator implements BeanPostProcessor, BeanFactoryAware, AdvisorRegistry {
/** 通知者列表 */
private List<Advisor> advisors;
/** 當(dāng)前的bean */
private BeanFactory beanFactory;
public AdvisorAutoProxyCreator() {
this.advisors = new ArrayList<>();
}
@Override
public void registerAdvisor(Advisor advisor) {
this.advisors.add(advisor);
}
@Override
public List<Advisor> getAdvisors() {
return this.advisors;
}
@Override
public void setBeanFactory(BeanFactory bf) {
this.beanFactory = bf;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws Exception {
return null;
}
注冊BeanPostProcessor
BeanFactory接口中增加注冊BeanPostProcessor的方法
/** 注冊BeanPostProcessor */
void registerBeanPostProcessor(BeanPostProcessor beanPostProcessor);
DefaultBeanFactory實(shí)現(xiàn)類中增加如下方法:
private List<BeanPostProcessor> postProcessors = Collections.synchronizedList(new ArrayList<>());
@Override
public void registerBeanPostProcessor(BeanPostProcessor beanPostProcessor) {
postProcessors.add(beanPostProcessor);
if (beanPostProcessor instanceof BeanFactoryAware) {
((BeanFactoryAware) beanPostProcessor).setBeanFactory(this);
}
}
getBean方法中增加bean初始化前后的處理:
@Override
public Object getBean(String beanName) throws Exception {
//獲取bean定義
BeanDefinition bd = beanDefinitionMap.get(beanName);
Object bean = doGetBean(beanName);
//屬性注入
setPropertyDIValues(bd, bean);
//bean初始化前的處理
bean = this.applyPostProcessBeforeInitialization(bean, beanName);
//bean的生命周期
if (StringUtils.isNotBlank(bd.getInitMethodName())) {
doInitMethod(bean,bd);
}
//bean初始化后的處理
bean = this.applyPostProcessAfterInitialization(bean, beanName);
return bean;
}
/**
* bean初始化后的處理
* @author: TR
* @param bean:
* @param beanName:
* @return: java.lang.Object
**/
private Object applyPostProcessAfterInitialization(Object bean, String beanName) throws Exception {
for (BeanPostProcessor bp : this.postProcessors) {
bean = bp.postProcessBeforeInitialization(bean, beanName);
}
return bean;
}
/**
* bean初始化前的處理
* @author: TR
* @param bean:
* @param beanName:
* @return: java.lang.Object
**/
private Object applyPostProcessBeforeInitialization(Object bean, String beanName) throws Exception {
for (BeanPostProcessor bp : this.postProcessors) {
bean = bp.postProcessAfterInitialization(bean, beanName);
}
return bean;
}
下面需要實(shí)現(xiàn)的就是判斷bean是否需要增強(qiáng)了,那么需要獲取到bean的所有方法,然后根據(jù)注冊進(jìn)來的advisors去遍歷它,然后得到切點(diǎn)去匹配類和方法
修改AdvisorAutoProxyCreator類中的postProcessAfterInitialization方法:
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws Exception {
//判斷是否需要進(jìn)行切面增強(qiáng),及獲得增強(qiáng)的通知實(shí)現(xiàn)
List<Advisor> advisors = getMatchedAdvisors(bean, beanName);
//如果需要增強(qiáng),返回增強(qiáng)后的對象
if (CollectionUtils.isNotEmpty(advisors)) {
//使用代理模式進(jìn)行功能增強(qiáng)
}
return bean;
}
下面是獲取匹配的方法代碼:
/**
* 獲取匹配的方法
* @author: TR
* @param bean: bean實(shí)例
* @param beanName: bean名稱
* @return: void
**/
private List<Advisor> getMatchedAdvisors(Object bean, String beanName) {
if (CollectionUtils.isEmpty(advisors)) {
return null;
}
//得到類
Class<?> beanClass = bean.getClass();
//得到所有的方法
List<Method> allMethods = getAllMethodForClass(beanClass);
//存放匹配的Advisor
List<Advisor> advisors = new ArrayList<>();
for (Advisor ad : this.advisors) {
if (ad instanceof PointcutAdvisor) {
//判斷是否匹配
if (isPointcutMatchBean((PointcutAdvisor) ad, beanClass, allMethods)) {
advisors.add(ad);
}
}
}
return advisors;
}
獲取所有的方法,使用的是Spring framework提供的工具類,來找到類下面所有的方法:
/**
* 獲取所有的方法
* @author: TR
* @param beanClass:
* @return: void
**/
private List<Method> getAllMethodForClass(Class<?> beanClass) {
List<Method> allMethods = new LinkedList<>();
Set<Class<?>> classes = new LinkedHashSet<>(ClassUtils.getAllInterfacesForClassAsSet(beanClass));
classes.add(beanClass);
for (Class<?> cc : classes) {
//根據(jù)工具類獲取所有的方法
Method[] methods = ReflectionUtils.getAllDeclaredMethods(cc);
for (Method m : methods) {
allMethods.add(m);
}
}
return allMethods;
}
下面是判斷是否有匹配切點(diǎn)規(guī)則的方法,使用PointCut中定義的方法來實(shí)現(xiàn):
/**
* 判斷是否有匹配切點(diǎn)規(guī)則的方法
* @author: TR
* @param ad: 切面
* @param beanClass: 指定的類
* @param allMethods: 指定的類下面所有的方法
* @return: void
**/
private boolean isPointcutMatchBean(PointcutAdvisor ad, Class<?> beanClass, List<Method> allMethods) {
PointCut p = ad.getPointCut();
//匹配類
if (!p.matchClass(beanClass)) {
return false;
}
for (Method m : allMethods) {
//匹配方法
if (p.matchMethod(m, beanClass)) {
return true;
}
}
return false;
}
判斷是否增強(qiáng)之后,就是需要進(jìn)行代理增強(qiáng)了,那么這里的實(shí)現(xiàn)邏輯又是啥樣的呢
通過上圖可以看到,需要判斷代理的方式,即使用JDK動態(tài)代理還是CGLIB動態(tài)代碼,那么這里也可以抽象出一個接口。然后不同的代理方式分別去實(shí)現(xiàn)
定義AopProxy代理接口
/**
* @className: AopProxy
* @description: AOP代理接口,用來創(chuàng)建和獲取代理對象
* @author: TR
*/
public interface AopProxy {
Object getProxy();
Object getProxy(ClassLoader classLoader);
}
JDK動態(tài)代理實(shí)現(xiàn)
我們知道JDK動態(tài)代理是對接口進(jìn)行的,那么在實(shí)現(xiàn)中需要哪些數(shù)據(jù)呢?
要實(shí)現(xiàn)的接口
目標(biāo)對象
匹配的Advisors
BeanFactory
需要的參數(shù):
需要實(shí)現(xiàn)的接口
InvocationHandler
/**
* @className: JdkDynamicAopProxy
* @description: JDK動態(tài)代理實(shí)現(xiàn)
* @author: TR
*/
public class JdkDynamicAopProxy implements AopProxy, InvocationHandler {
private static final Logger logger = LoggerFactory.getLogger(JdkDynamicAopProxy.class);
//bean名稱
private String beanName;
//bean對象,需要被代理的對象
private Object target;
//通知列表,需要被增強(qiáng)的功能
private List<Advisor> advisors;
//當(dāng)前的bean
private BeanFactory beanFactory;
public JdkDynamicAopProxy(String beanName, Object target, List<Advisor> advisors, BeanFactory beanFactory) {
this.beanName = beanName;
this.target = target;
this.advisors = advisors;
this.beanFactory = beanFactory;
}
@Override
public Object getProxy() {
return this.getProxy(target.getClass().getClassLoader());
}
@Override
public Object getProxy(ClassLoader classLoader) {
if (logger.isDebugEnabled()) {
logger.debug("為" + target + "創(chuàng)建JDK代理。");
}
return Proxy.newProxyInstance(classLoader, target.getClass().getInterfaces(), this);
}
/**
* InvocationHandler接口的實(shí)現(xiàn)
* 用來進(jìn)行代理增強(qiáng)后返回實(shí)際的結(jié)果
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return AopProxyUtils.applyAdvices(target, method, args, advisors, proxy, beanFactory);
}
}
CGLIB動態(tài)代理實(shí)現(xiàn)
CGLIB動態(tài)代理可以對接口和類進(jìn)行,那么它需要下面的數(shù)據(jù):
要繼承的類
要實(shí)現(xiàn)的接口
目標(biāo)對象
匹配的Advisors
BeanFactory
構(gòu)造參數(shù)類
構(gòu)造參數(shù)
需要的參數(shù):
繼承的類
需要實(shí)現(xiàn)的接口
Callback
構(gòu)造參數(shù)類型
構(gòu)造參數(shù)
構(gòu)造參數(shù)類型和構(gòu)造參數(shù)在創(chuàng)建實(shí)例的時候會有的
/**
* @className: CglibDynamicAopProxy
* @description: Cglib動態(tài)代理
* @author: TR
*/
public class CglibDynamicAopProxy implements AopProxy, MethodInterceptor {
private static final Logger logger = LoggerFactory.getLogger(CglibDynamicAopProxy.class);
private static Enhancer enhancer = new Enhancer();
//bean名稱
private String beanName;
//bean對象,需要被代理的對象
private Object target;
//通知列表,需要被增強(qiáng)的功能
private List<Advisor> advisors;
//當(dāng)前的bean
private BeanFactory beanFactory;
public CglibDynamicAopProxy(String beanName, Object target, List<Advisor> advisors, BeanFactory beanFactory) {
this.beanName = beanName;
this.target = target;
this.advisors = advisors;
this.beanFactory = beanFactory;
}
@Override
public Object getProxy() {
return this.getProxy(target.getClass().getClassLoader());
}
@Override
public Object getProxy(ClassLoader classLoader) {
if (logger.isDebugEnabled()) {
logger.debug("為" + target + "創(chuàng)建cglib代理。");
}
Class<?> superClass = this.target.getClass();
enhancer.setSuperclass(superClass);
enhancer.setInterfaces(this.getClass().getInterfaces());
enhancer.setCallback(this);
Constructor<?> constructor = null;
try {
constructor = superClass.getConstructor(new Class<?>[] {});
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
if (constructor != null) {
return enhancer.create();
} else {
BeanDefinition bd = ((DefaultBeanFactory)beanFactory).getBeanDefinition(beanName);
return enhancer.create(bd.getConstructor().getParameterTypes(), bd.getConstructorArgumentRealValues());
}
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
return AopProxyUtils.applyAdvices(target, method, objects, advisors, o, beanFactory);
}
}
AopProxyUtils它是用來干什么的呢,從上面可以看到,這部分的處理,主要是用來實(shí)現(xiàn)增強(qiáng)的,都是使用Advice來增強(qiáng)的,所以增強(qiáng)的邏輯是一樣的
/**
* @className: AopProxyUtils
* @description: aop代理工具類
* @author: TR
*/
public class AopProxyUtils {
/**
* 對方法應(yīng)用advice增強(qiáng),獲得最終返回結(jié)果
* @author: TR
* @param target: 需要被增強(qiáng)的對象
* @param method: 需要被增強(qiáng)的方法
* @param args: 增強(qiáng)方法的參數(shù)
* @param advisors: 匹配到的切面
* @param proxy: bean對象功能增強(qiáng)后的代理對象
* @param beanFactory: bean工廠
* @return: java.lang.Object
**/
public static Object applyAdvices(Object target, Method method, Object[] args, List<Advisor> advisors,
Object proxy, BeanFactory beanFactory) throws Throwable {
//獲取對當(dāng)前方法進(jìn)行增強(qiáng)的advices
List<Object> advices = AopProxyUtils.getShouldApplyAdvices(target.getClass(), method, advisors, beanFactory);
if (CollectionUtils.isEmpty(advices)) {
return method.invoke(target, args);
} else {
//使用責(zé)任鏈進(jìn)行增強(qiáng)
AopAdviceChainInvocation ac = new AopAdviceChainInvocation(proxy, target, method, args, advices);
return ac.invoke();
}
}
/**
* 獲得與方法匹配的Advice切面列表
* @author: TR
* @param aClass:
* @param method:
* @param advisors:
* @param beanFactory:
* @return: java.util.List<demo.aop.advice.Advice>
**/
private static List<Object> getShouldApplyAdvices(Class<?> aClass, Method method,
List<Advisor> advisors, BeanFactory beanFactory) throws Exception {
if (CollectionUtils.isEmpty(advisors)) {
return null;
}
List<Object> advices = new ArrayList<>();
for (Advisor advisor : advisors) {
if (advisor instanceof PointcutAdvisor) {
if (((PointcutAdvisor)advisor).getPointCut().matchMethod(method, aClass)) {
advices.add(beanFactory.getBean(advisor.getAdviceBeanName()));
}
}
}
return advices;
}
}
如何來傳遞創(chuàng)建bean實(shí)例時獲得的數(shù)據(jù)到初始化后的Aop中,就是要在BeanDefinition中使用ThreadLocal持有參數(shù)值
BeanDefinition增加如下方法:
/** 獲取構(gòu)造參數(shù)值 */
public Object[] getConstructorArgumentRealValues();
/** 設(shè)置構(gòu)造參數(shù)值 */
public void setConstructorArgumentRealValues(Object[] values);
GeneralBeanDefinition類中相應(yīng)的實(shí)現(xiàn):
private ThreadLocal<Object[]> realConstructorArgumentValues = new ThreadLocal<>();
@Override
public Object[] getConstructorArgumentRealValues() {
return realConstructorArgumentValues.get();
}
@Override
public void setConstructorArgumentRealValues(Object[] values) {
this.realConstructorArgumentValues.set(values);
}
責(zé)任鏈AopAdviceChainInvocation類
/**
* @className: AopAdviceChainInvocation
* @description: AOP責(zé)任鏈調(diào)用類
* @author: TR
*/
public class AopAdviceChainInvocation {
/** AOP責(zé)任鏈執(zhí)行的方法 */
private static Method invokeMethod;
static {
try {
invokeMethod = AopAdviceChainInvocation.class.getMethod("invoke", null);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
//代理類對象
private Object proxy;
//目標(biāo)類對象
private Object target;
//調(diào)用執(zhí)行的對象方法
private Method method;
//執(zhí)行方法的參數(shù)
private Object[] args;
//方法被增強(qiáng)的功能:通知列表
private List<Object> advices;
public AopAdviceChainInvocation(Object proxy, Object target, Method method, Object[] args, List<Object> advices) {
this.proxy = proxy;
this.target = target;
this.method = method;
this.args = args;
this.advices = advices;
}
//責(zé)任鏈執(zhí)行記錄的索引號
private int i = 0;
public Object invoke() throws Throwable {
if (i < this.advices.size()) {
Object advice = this.advices.get(i++);
if (advice instanceof MethodBeforeAdvice) {
//執(zhí)行前增強(qiáng)
((MethodBeforeAdvice)advice).before(method, target, args);
} else if (advice instanceof MethodInterceptor) {
//執(zhí)行環(huán)繞增強(qiáng)和異常增強(qiáng),這里給的method和對象是invoke方法和鏈對象
((MethodInterceptor)advice).invoke(invokeMethod,this, null);
} else if (advice instanceof AfterReturningAdvice) {
//后置增強(qiáng),先獲得結(jié)果,在增強(qiáng)
Object returnValue = this.invoke();
((AfterReturningAdvice)advice).after(method, target, args, returnValue);
return returnValue;
}
//回調(diào)
return this.invoke();
} else {
return method.invoke(target, args);
}
}
}
定義AopProxyFactory接口
代理的方式實(shí)現(xiàn)完了之后,就需要使用它了,這里使用工廠模式實(shí)現(xiàn):
/**
* @className: AopProxyFactory
* @description: AOP代理的工廠接口
* @author: TR
*/
public interface AopProxyFactory {
/**
* 根據(jù)參數(shù)獲取AOP代理接口的實(shí)現(xiàn)
* @param bean: 實(shí)例
* @param beanName: bean名稱
* @param advisors: advisors列表
* @param beanFactory: bean工廠
* @return: AopProxyFactory
**/
AopProxy createAopProxy(Object bean, String beanName, List<Advisor> advisors, BeanFactory beanFactory);
/**
* 獲取默認(rèn)的AopProxyFactory
* @return: AopProxyFactory
**/
static AopProxyFactory getDefaultAopProxyFactory() {
return new DefaultAopProxyFactory();
}
}
實(shí)現(xiàn)類:
/**
* @className: DefaultAopProxyFactory
* @description: 代理工廠實(shí)現(xiàn)類
* @author: TR
*/
public class DefaultAopProxyFactory implements AopProxyFactory {
@Override
public AopProxy createAopProxy(Object bean, String beanName, List<Advisor> advisors, BeanFactory beanFactory) {
//是用JDK動態(tài)代理還是CGLIB動態(tài)代理
if (shouldUseJDKDynamicProxy(bean, beanName)) {
return new JdkDynamicAopProxy(beanName, bean, advisors, beanFactory);
} else {
return new CglibDynamicAopProxy(beanName, bean, advisors, beanFactory);
}
}
private boolean shouldUseJDKDynamicProxy(Object bean, String beanName) {
return false;
}
}
下面需要修改下AdvisorAutoProxyCreator類中的postProcessAfterInitialization方法:
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws Exception {
//判斷是否需要進(jìn)行切面增強(qiáng),及獲得增強(qiáng)的通知實(shí)現(xiàn)
List<Advisor> advisors = getMatchedAdvisors(bean, beanName);
//如果需要增強(qiáng),返回增強(qiáng)后的對象
if (CollectionUtils.isNotEmpty(advisors)) {
//使用代理模式進(jìn)行功能增強(qiáng)
bean = this.createProxy(bean, beanName, advisors);
}
return bean;
}
private Object createProxy(Object bean, String beanName, List<Advisor> advisors) {
return AopProxyFactory.getDefaultAopProxyFactory()
.createAopProxy(bean, beanName, advisors, beanFactory)
.getProxy();
}
DefaultBeanFactory類中緩存構(gòu)造函數(shù)的方式需要改變一下
determineConstructor方法中緩存的代碼注釋掉:
if (ct != null) {
// //對于原型bean,緩存起來
// if (bd.isProtoType()) {
// bd.setConstructor(ct);
// }
return ct;
} else {
throw new Exception("找不到對應(yīng)的構(gòu)造方法:" + bd);
}
在createBeanByConstructor中增加代碼
/** 通過構(gòu)造函數(shù)構(gòu)建bean */
private Object createBeanByConstructor(BeanDefinition bd) throws Exception {
Object object = null;
if (CollectionUtils.isEmpty(bd.getConstructorArgumentValues())) {
//獲得的構(gòu)造參數(shù)值是空的,就不傳參
object = bd.getBeanClass().newInstance();
} else {
//獲得的參數(shù)值是空的,就不傳參
Object[] args = getConstructorArgumentValues(bd);
if (args == null) {
object = bd.getBeanClass().newInstance();
} else {
// 根據(jù)參數(shù)匹配決定構(gòu)造方法,然后進(jìn)行實(shí)例化調(diào)用
bd.setConstructorArgumentRealValues(args);
Constructor<?> ct = this.determineConstructor(bd, args);
// 緩存構(gòu)造函數(shù)由determineConstructor 中移到了這里,無論原型否都緩存,因?yàn)楹竺鍭OP需要用
bd.setConstructor(ct);
return ct.newInstance(args);
}
}
return object;
}
測試一下
前置增強(qiáng)實(shí)現(xiàn):
public class MyBeforeAdvice implements MethodBeforeAdvice {
@Override
public void before(Method method, Object target, Object[] args) {
System.out.println(this + " 對 " + target + " 進(jìn)行了前置增強(qiáng)!");
}
}
后置增強(qiáng)實(shí)現(xiàn):
public class MyAfterReturningAdvice implements AfterReturningAdvice {
@Override
public void after(Method method, Object target, Object[] args, Object returnValue) {
System.out.println(this + " 對 " + target + " 做了后置增強(qiáng),得到的返回值=" + returnValue);
}
}
環(huán)繞增強(qiáng)實(shí)現(xiàn):
public class MyMethodInterceptor implements MethodInterceptor {
@Override
public Object invoke(Method method, Object target, Object[] args) throws Throwable {
System.out.println(this + "對 " + target + "進(jìn)行了環(huán)繞--前增強(qiáng)");
Object ret = method.invoke(target, args);
System.out.println(this + "對 " + target + "進(jìn)行了環(huán)繞 --后增強(qiáng)。方法的返回值為:" + ret);
return ret;
}
}
測試類:
public class AopTest {
static PreBuildBeanFactory bf = new PreBuildBeanFactory();
@Test
public void testCirculationDI() throws Throwable {
GeneralBeanDefinition bd = new GeneralBeanDefinition();
bd.setBeanClass(Lad.class);
List<Object> args = new ArrayList<>();
args.add("孫悟空");
args.add(new BeanReference("baigujing"));
bd.setConstructorArgumentValues(args);
bf.registerBeanDefinition("swk", bd);
bd = new GeneralBeanDefinition();
bd.setBeanClass(MagicGirl.class);
args = new ArrayList<>();
args.add("白骨精");
bd.setConstructorArgumentValues(args);
bf.registerBeanDefinition("baigujing", bd);
bd = new GeneralBeanDefinition();
bd.setBeanClass(Renminbi.class);
bf.registerBeanDefinition("renminbi", bd);
// 前置增強(qiáng)advice bean注冊
bd = new GeneralBeanDefinition();
bd.setBeanClass(MyBeforeAdvice.class);
bf.registerBeanDefinition("myBeforeAdvice", bd);
// 環(huán)繞增強(qiáng)advice bean注冊
bd = new GeneralBeanDefinition();
bd.setBeanClass(MyMethodInterceptor.class);
bf.registerBeanDefinition("myMethodInterceptor", bd);
// 后置增強(qiáng)advice bean注冊
bd = new GeneralBeanDefinition();
bd.setBeanClass(MyAfterReturningAdvice.class);
bf.registerBeanDefinition("myAfterReturningAdvice", bd);
// 往BeanFactory中注冊AOP的BeanPostProcessor
AdvisorAutoProxyCreator aapc = new AdvisorAutoProxyCreator();
bf.registerBeanPostProcessor(aapc);
// 向AdvisorAutoProxyCreator注冊Advisor
aapc.registerAdvisor(
new AspectJPointcutAdvisor("myBeforeAdvice", "execution(* demo.di.MagicGirl.*(..))"));
// 向AdvisorAutoProxyCreator注冊Advisor
aapc.registerAdvisor(
new AspectJPointcutAdvisor("myMethodInterceptor", "execution(* demo.di.Lad.say*(..))"));
// 向AdvisorAutoProxyCreator注冊Advisor
aapc.registerAdvisor(new AspectJPointcutAdvisor("myAfterReturningAdvice",
"execution(* demo.di.Renminbi.*(..))"));
bf.preInstantiateSingletons();
System.out.println("-----------------myBeforeAdvice---------------");
MagicGirl gril = (MagicGirl) bf.getBean("baigujing");
gril.getFriend();
gril.getName();
System.out.println("----------------myMethodInterceptor----------------");
Boy boy = (Boy) bf.getBean("swk");
boy.sayLove();
System.out.println("-----------------myAfterReturningAdvice---------------");
Renminbi rmb = (Renminbi) bf.getBean("renminbi");
rmb.pay();
}
}
運(yùn)行結(jié)果:


鋒哥最新SpringCloud分布式電商秒殺課程發(fā)布
??????
??長按上方微信二維碼 2 秒
感謝點(diǎn)贊支持下哈 
