spring-AOP(一) 手動代理
spring的設(shè)計原理是構(gòu)造一個個原子功能,然后不斷的通過設(shè)計模式在外圍進行包裝躺涝、組合調(diào)用厨钻,最后實現(xiàn)復(fù)雜的邏輯功能。
知識導(dǎo)讀
- 了解Aop聯(lián)盟定義的幾個概念坚嗜,連接點夯膀、通知、攔截苍蔬、切點诱建、增強
- ProxyFactory 定義了創(chuàng)建代理對象的工廠方法,不過該類主要用于提供代理配置
- AopProxy 定義創(chuàng)建代理對象的接口碟绑,實現(xiàn)類有 jdk代理 和 cglib代理
- 代理的本質(zhì)就是對目標方法執(zhí)行的攔截增強
- 創(chuàng)建代理最主要是提供 被代理對象 和 增強列表 AdvisorList
- Advisor封裝了通知和切點俺猿,實質(zhì)就是封裝了一個可以決定在什么類的什么方法上進行增強的通知
- 代理的最終目的就是在方法的執(zhí)行前后添加邏輯,最終構(gòu)建 ReflectiveMethodInvocation格仲,創(chuàng)建代理類的目的就是為了實現(xiàn)選擇性的對目標對象方法的攔截押袍,然后將方法調(diào)用封裝為ReflectiveMethodInvocation
- Pointcut提供了怎么篩選攔截哪些對象的哪些方法
- 切面是通知的載體,通知是個方法抓狭,切面就是定義這些方法的對象伯病。攔截器將這些通知按照順序串成一個鏈
AOP聯(lián)盟和Spring擴展
AOP的實質(zhì)對連接點的增強造烁,一般通俗點講是對對方法執(zhí)行的攔截增強
AOP聯(lián)盟定義了AOP的規(guī)范接口否过,聲明了兩個最基礎(chǔ)的接口,連接點 和 增強 惭蟋。
連接點 Joinpoint
public interface Joinpoint {
//連接點的執(zhí)行
Object proceed() throws Throwable;
//一般用于返回被代理對象
Object getThis();
//一般用于返回目標方法的Method對象
AccessibleObject getStaticPart();
}
Joinpoint(連接點) 代表一個對象可以切入的地方苗桂,一般來說就是一個方法的執(zhí)行,MehtodInvocation將方法的調(diào)用過程進行了封裝告组。spring實現(xiàn)擴展了MethodInvocation煤伟,在ReflectiveMethodInvocation中既實現(xiàn)了方法調(diào)用的封裝,又定義了攔截器鏈,用于在方法執(zhí)行過程中進行攔截增強便锨。
通知 Advice
public interface Advice {
}
AOP聯(lián)盟聲明了通知的接口围辙,用于標記通知類型,最主要的接口實現(xiàn)是攔截器Interceptor
public interface Interceptor extends Advice {
}
@FunctionalInterface
public interface MethodInterceptor extends Interceptor {
//定義了對 方法調(diào)用 進行攔截的接口
Object invoke(MethodInvocation invocation) throws Throwable;
}
在MethodInterceptor接口中聲明了invoke方法放案,需要一個MethodInvocation對象參數(shù)姚建。用于對方法調(diào)用進行攔截,然后執(zhí)行增強邏輯吱殉,在合適的時機回調(diào)MethodInvocation掸冤,實現(xiàn)增強的功能
spring對MethodInterceptor接口進行了具體實現(xiàn),例如提供了前置通知友雳、后置通知稿湿、最終通知、異常通知押赊、環(huán)繞通知的實現(xiàn)類饺藤。
切點 Pointcut
Pointcut是spring定義的一個接口,用于過濾目標類和匹配目標方法(連接點)
public interface Pointcut {
//用于過濾目標類
ClassFilter getClassFilter();
//用于匹配目標方法
MethodMatcher getMethodMatcher();
Pointcut TRUE = TruePointcut.INSTANCE;
}
Pointcut 的具體實現(xiàn)考杉,spring中Pointcut是很重的一塊邏輯策精,可以單獨出一篇文檔
增強 Advisor
spring中定義的增強類,用于封裝一個Pointcut和一個Advice崇棠,實質(zhì)就是封裝了一個可以決定在什么類的什么方法上應(yīng)用的通知
public interface Advisor {
Advice EMPTY_ADVICE = new Advice() {};
//封裝的通知
Advice getAdvice();
boolean isPerInstance();
}
public interface PointcutAdvisor extends Advisor {
//切點咽袜,用于匹配連接點,是否應(yīng)用Advice通知
Pointcut getPointcut();
}
工廠方式創(chuàng)建代理對象
ProxyFactory
通過ProxyFactory創(chuàng)建代理對象枕稀,需要配置以下信息
- 被代理對象
- 增強Advisor列表
- 被代理接口(非必須)
- 其他一些非必須配置(非必須)
下圖是ProxyFactory的繼承關(guān)系圖询刹,通過看各個層級的字段,可以看出ProxyFactory主要定義的是一些創(chuàng)建代理的配置信息萎坷。
AopProxy
已知的可以創(chuàng)建代理對象的方式
- 使用jdk Proxy凹联,需要創(chuàng)建一個InvocationHandler的實現(xiàn)類,調(diào)用代理對象的方法都會去調(diào)用InvocationHandler的實現(xiàn)類的invoke方法哆档,所有的攔截和增強在invoke方法中做
- 使用cglib的Enhancer蔽挠,需要創(chuàng)建一批MethodInterceptor的實現(xiàn)類,調(diào)用代理對象所有方法都會去調(diào)用MethodInterceptor實現(xiàn)類的intercept方法瓜浸,所有的攔截和增強都在intercept方法中做
spring中定義了一個AopProxy接口澳淑,用于獲取代理類,實現(xiàn)類是JdkProxy和cglibProxy插佛,ProxyFactory提供了創(chuàng)建AopProxy的配置信息杠巡,創(chuàng)建代理類對象的工作交由AopProxy的實現(xiàn)類實現(xiàn)。
通過ProxyFactory配置創(chuàng)建AopProxy實現(xiàn)
spring中定義了ProxyFactory用于創(chuàng)建代理對象雇寇,下面是創(chuàng)建代理對象的一個demo氢拥。
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTargetSource(targetSource);//設(shè)置被代理對象
factory.setInterfaces(IUserService.class);//設(shè)置要代理的接口
proxyFactory.setProxyTargetClass(true);//設(shè)置使用cglib創(chuàng)建代理
proxyFactory.setExposeProxy(true);//設(shè)置是否暴露代理類
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
proxyFactory.addAdvisors(advisors);//設(shè)置目標類的增強 Advisor列表
return proxyFactory.getProxy(getProxyClassLoader());//創(chuàng)建代理類對象
調(diào)用ProxyFactory的getProxy創(chuàng)建代理類對象蚌铜,首先會創(chuàng)建一個AopProxy對象,然后調(diào)用AopProxy的getProxy方法獲取代理類對象嫩海,在整個創(chuàng)建代理類過程中冬殃,ProxyFactory用于提供配置
public Object getProxy(@Nullable ClassLoader classLoader) {
return createAopProxy().getProxy(classLoader);
}
調(diào)用父類ProxyCreatorSupport中的createAopProxy創(chuàng)建AopProxy。
protected final synchronized AopProxy createAopProxy() {
if (!this.active) {
activate();
}
return getAopProxyFactory().createAopProxy(this);
}
在AopProxyFactory的createAopProxy創(chuàng)建了AopProxy的具體實現(xiàn)叁怪,會通過ProxyFactory中提供的配置來選擇使用jdk代理還是cglib代理
注意造壮,cglib也可以創(chuàng)建基于接口的代理
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
Class<?> targetClass = config.getTargetClass();
if (targetClass == null) {
throw new AopConfigException("TargetSource cannot determine target class: " +
"Either an interface or a target is required for proxy creation.");
}
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
return new ObjenesisCglibAopProxy(config);
}
else {
return new JdkDynamicAopProxy(config);
}
}
通過AopProxy創(chuàng)建代理類對象
創(chuàng)建完AopProxy之后,調(diào)用AopProxy實現(xiàn)類的getProxy就可以創(chuàng)建代理類骂束,和代理類對象耳璧。
jdk代理
首先來分析spring是如何實現(xiàn)jdk代理的,在JdkDynamicAopProxy中g(shù)etProxy中通過調(diào)用Proxy的api創(chuàng)建代理類對象
@Override
public Object getProxy(@Nullable ClassLoader classLoader) {
//獲取ProxyFactory提供的配置展箱,接口
Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
//調(diào)用Proxy的api創(chuàng)建代理類對象旨枯。
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
由于JdkDynamicAopProxy自己本身實現(xiàn)了InvocationHandler接口,所以在創(chuàng)建代理對象的時候傳遞的是this
cglib代理
jdk代理比較簡單混驰,接下來看下CglibAopProxy是如何通過cglib來創(chuàng)建代理類對象的
@Override
public Object getProxy(@Nullable ClassLoader classLoader) {
try {
//獲取ProxyFactory配置的目標類型
Class<?> rootClass = this.advised.getTargetClass();
Class<?> proxySuperClass = rootClass;
//如果當(dāng)前的類型已經(jīng)是cglib創(chuàng)建的代理類攀隔,使用代理類的父類
if (ClassUtils.isCglibProxyClass(rootClass)) {
proxySuperClass = rootClass.getSuperclass();
Class<?>[] additionalInterfaces = rootClass.getInterfaces();
for (Class<?> additionalInterface : additionalInterfaces) {
this.advised.addInterface(additionalInterface);
}
}
//檢查下方法是否是final修飾和 private
validateClassIfNecessary(proxySuperClass, classLoader);
//使用cglib的Enhancer創(chuàng)建代理
Enhancer enhancer = createEnhancer();
if (classLoader != null) {
enhancer.setClassLoader(classLoader);
if (classLoader instanceof SmartClassLoader &&
((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
enhancer.setUseCache(false);
}
}
enhancer.setSuperclass(proxySuperClass);//設(shè)置父類
enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
enhancer.setStrategy(new ClassLoaderAwareUndeclaredThrowableStrategy(classLoader));
//最重要的一步,組裝cglib需要的攔截器實現(xiàn)
Callback[] callbacks = getCallbacks(rootClass);
Class<?>[] types = new Class<?>[callbacks.length];
for (int x = 0; x < types.length; x++) {
types[x] = callbacks[x].getClass();
}
//設(shè)置攔截器過濾器栖榨,用于指定什么方法應(yīng)用什么攔截器
enhancer.setCallbackFilter(new ProxyCallbackFilter(
this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
enhancer.setCallbackTypes(types);
// enhancer創(chuàng)建代理
return createProxyClassAndInstance(enhancer, callbacks);
}
catch (CodeGenerationException | IllegalArgumentException ex) {
//此處省略代碼....
}
catch (Throwable ex) {
//此處省略代碼....
}
}
通過以上邏輯昆汹,spring就完成了代理類的創(chuàng)建,接下來對代理類的方法調(diào)用都會去調(diào)用InvocationHandler的invoke方法或者Callback的intercept方法婴栽。
代理類的方法調(diào)用
jdk代理的方法調(diào)用
JdkDynamicAopProxy實現(xiàn)了InvocationHandler的invoke方法满粗,代理類對象所有方法的執(zhí)行都會通過invoke方法來調(diào)用
根據(jù)Pointcut篩選應(yīng)用目標方法的Advisor,將Advisor中的Advice封裝為增強目標方法的攔截器鏈
基于攔截器鏈封裝MethodInvocation實現(xiàn)類對象愚争,方法的調(diào)用和攔截增強全由MethodInvocation實現(xiàn)映皆,
注意每次目標方法執(zhí)行都會新建一個MethodInvocation對象
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//用于記錄ThreadLocal中之前的代理類對象
Object oldProxy = null;
boolean setProxyContext = false;
//被代理對象
TargetSource targetSource = this.advised.targetSource;
Object target = null;
try {
//此處省略代碼....
Object retVal;
//判斷如果要暴露代理類對象,如果是將代理對象放入ThreadLocal轰枝,通過AopContext.currentProxy獲取
//同時要記錄下 ThreadLocal中之前存儲的代理類對象捅彻,方法執(zhí)行完畢后要重置回去
if (this.advised.exposeProxy) {
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
target = targetSource.getTarget();
Class<?> targetClass = (target != null ? target.getClass() : null);
//最重要的一步 封裝獲取攔截器鏈
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
//如果攔截器鏈為空,直接反射調(diào)用被代理對象的方法
if (chain.isEmpty()) {
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}else {
//如果存在攔截器鏈鞍陨,構(gòu)造方法調(diào)用的封裝對象MethodInvocation步淹,被代理對象方法的調(diào)用以及攔截器的增強封裝都通過該類實現(xiàn),每次都新建ReflectiveMethodInvocation對象诚撵,這個對象中有currentInterceptorIndex缭裆,避免污染
MethodInvocation invocation =
new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
retVal = invocation.proceed();
}
//此處省略代碼....
return retVal;
}
finally {
if (target != null && !targetSource.isStatic()) {
// Must have come from TargetSource.
targetSource.releaseTarget(target);
}
if (setProxyContext) {
// 方法執(zhí)行完畢后重置ThreadLocal中的代理類對象
AopContext.setCurrentProxy(oldProxy);
}
}
}
來看下spring中是如何篩選目標方法的攔截器鏈的,在getInterceptorsAndDynamicInterceptionAdvice會首先去獲取緩存中的攔截器鏈砾脑,如果沒有幼驶,再進行篩選解析艾杏,感覺這里還是直接new一個list韧衣,然后將cached放進去,避免后續(xù)流程修改列表
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) {
//使用方法名作為緩存key,將攔截器鏈緩存起來畅铭,避免重復(fù)解析
MethodCacheKey cacheKey = new MethodCacheKey(method);
List<Object> cached = this.methodCache.get(cacheKey);
if (cached == null) {
cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
this, method, targetClass);
this.methodCache.put(cacheKey, cached);
}
return cached;
}
通過DefaultAdvisorChainFactory構(gòu)建攔截器鏈氏淑,主要就是通過Advisor中的Pointcut的ClassFilter和MethodMatcher來篩選能夠增強目標方法的Advisor,然后封裝為攔截器MethodInterceptor對象硕噩,組裝成攔截器鏈返回
@Override
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
Advised config, Method method, @Nullable Class<?> targetClass) {
AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
Advisor[] advisors = config.getAdvisors();//獲取配置中的Advisor列表
List<Object> interceptorList = new ArrayList<>(advisors.length);
Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
Boolean hasIntroductions = null;
//遍歷Advisor假残,篩選能夠增強目標方法的Advisor,并封裝為攔截器鏈返回
for (Advisor advisor : advisors) {
//如果是PointcutAdvisor炉擅,判斷Advisor的Pointcut是否攔截本方法
if (advisor instanceof PointcutAdvisor) {
PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
//先通過ClassFilter判斷是否攔截目標類
if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
boolean match;
//再通過MethodMatcher判斷是否攔截目標方法
if (mm instanceof IntroductionAwareMethodMatcher) {
if (hasIntroductions == null) {
hasIntroductions = hasMatchingIntroductions(advisors, actualClass);
}
match = ((IntroductionAwareMethodMatcher) mm).matches(method, actualClass, hasIntroductions);
}
else {
match = mm.matches(method, actualClass);
}
if (match) {
MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
//如果是要根據(jù)運行時參數(shù)進行方法校驗辉懒,需要封裝攔截器,將methodMatcher傳下去谍失,用于執(zhí)行時判斷參數(shù)
if (mm.isRuntime()) {
for (MethodInterceptor interceptor : interceptors) {
interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
}
}else {
interceptorList.addAll(Arrays.asList(interceptors));
}
}
}
}//引介增強眶俩,作用范圍是類,只需判斷是否攔截目標類就行
else if (advisor instanceof IntroductionAdvisor) {
IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}else {//其他類型Advisor快鱼,不需要過濾颠印,默認攔截所有方法
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}
return interceptorList;
}
獲取到目標方法的攔截器鏈之后,接下來構(gòu)建MethodInvocation對象抹竹,調(diào)用MethodInvocation的proceed方法线罕。在MethodInvocation中會在目標方法執(zhí)行前后執(zhí)行攔截器鏈中的增強方法,然后在合適的時機再回調(diào)目標方法窃判,實現(xiàn)代理的邏輯钞楼。
通過ReflectiveMethodInvocation的構(gòu)造器可以看出,該對象就是對目標方法調(diào)用和攔截器鏈的封裝
//構(gòu)造器
protected ReflectiveMethodInvocation(
Object proxy, @Nullable Object target, Method method, @Nullable Object[] arguments,
@Nullable Class<?> targetClass, List<Object> interceptorsAndDynamicMethodMatchers) {
this.proxy = proxy;//代理類對象
this.target = target;//被代理對象
this.targetClass = targetClass;//被代理對象類型
this.method = BridgeMethodResolver.findBridgedMethod(method);//目標方法
this.arguments = AopProxyUtils.adaptArgumentsIfNecessary(method, arguments);//方法參數(shù)
this.interceptorsAndDynamicMethodMatchers = interceptorsAndDynamicMethodMatchers;//攔截器鏈
}
再來看如何在proceed方法完成對方法的增強袄琳,在該方法中會遍歷執(zhí)行攔截器鏈中的攔截方法窿凤,所有攔截器都執(zhí)行完畢后再調(diào)用被代理類的目標方法。攔截器鏈是在代理類的方法中傳入的跨蟹,而且是緩存過的共享對象雳殊,這里避免修改該鏈,使用currentInterceptorIndex來記錄鏈的執(zhí)行位置窗轩。其實這塊是可以進行優(yōu)化的
private int currentInterceptorIndex = -1;//記錄攔截器鏈執(zhí)行第幾個攔截器
public Object proceed() throws Throwable {
// 攔截器鏈遍歷完畢后夯秃,調(diào)用目標方法
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
//遍歷獲取下一個攔截器
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
//如果是動態(tài)執(zhí)行過程中攔截,需要根據(jù)參數(shù)來判斷是否需要對目標方法進行攔截增強
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
//通過參數(shù)判斷是否需要增強痢艺,如果需要直接調(diào)用攔截器的invoke方法仓洼,并把當(dāng)前MethodInvocation傳遞過來,以便方法攔截邏輯執(zhí)行后再次調(diào)回來
if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
} else {
//如果不進行攔截堤舒,遞歸色建,重新執(zhí)行下一個攔截器.
return proceed();
}
} else {
//靜態(tài)攔截器,直接調(diào)用攔截器對方法進行增強
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
ReflectiveMethodInvocation中舌缤,在執(zhí)行完攔截器鏈中所有的攔截器邏輯之后箕戳,會調(diào)用被代理對象的目標方法某残,默認是通過反射調(diào)用
@Nullable
protected Object invokeJoinpoint() throws Throwable {
return AopUtils.invokeJoinpointUsingReflection(this.target, this.method, this.arguments);
}
CglibMethodInvocation中覆寫了ReflectiveMethodInvocation的invokeJoinpoint方法,會通過cglib的MethodProxy進行調(diào)用,避免反射
@Override
protected Object invokeJoinpoint() throws Throwable {
if (this.methodProxy != null) {
return this.methodProxy.invoke(this.target, this.arguments);
} else {
return super.invokeJoinpoint();
}
}
分析到現(xiàn)在陵吸,AOP剩下的功能就是要看Spring中定義的幾種通知類型是如何在攔截器中進行調(diào)用的玻墅。
攔截器中通知方法的執(zhí)行
spring中對通知advice和攔截器MethodInterceptor的繼承實現(xiàn)由點亂,不太明白為什么要這樣做壮虫,不如分開
在攔截器中可以方便的在目標方法執(zhí)行前后添加邏輯澳厢,很簡單。在使用@Aspect的切面的時候囚似,會調(diào)用@Aspect注冊的bean中的方法通知剩拢。這里重點看下@Aspect是如何實現(xiàn)的
前置通知
首先來看下前置通知攔截器中如何調(diào)用前置通知。在invoke方法中先調(diào)用通知饶唤,然后再回調(diào)MethodInvocation目標方法
public class MethodBeforeAdviceInterceptor implements MethodInterceptor, BeforeAdvice, Serializable {
//包裝了一個前置通知
private final MethodBeforeAdvice advice;
public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) {
this.advice = advice;
}
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
//調(diào)用前置通知方法
this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());裸扶、
//通知方法調(diào)用完畢之后,回調(diào) 連接點的方法執(zhí)行
return mi.proceed();
}
}
AspectJMethodBeforeAdvice實現(xiàn)了MethodBeforeAdvice
public class AspectJMethodBeforeAdvice extends AbstractAspectJAdvice implements MethodBeforeAdvice, Serializable {
public AspectJMethodBeforeAdvice(
Method aspectJBeforeAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aif) {
super(aspectJBeforeAdviceMethod, pointcut, aif);
}
@Override
public void before(Method method, Object[] args, @Nullable Object target) throws Throwable {
//調(diào)用 @aspect 切面中聲明的方法
invokeAdviceMethod(getJoinPointMatch(), null, null);
}
}
在AbstractAspectJAdvice定義了切面方法調(diào)用過程
protected Object invokeAdviceMethod(JoinPoint jp, @Nullable JoinPointMatch jpMatch,
@Nullable Object returnValue, @Nullable Throwable t) throws Throwable {
//獲取方法參數(shù)搬素,反射調(diào)用通知方法
return invokeAdviceMethodWithGivenArgs(argBinding(jp, jpMatch, returnValue, t));
}
通知方法反射調(diào)用呵晨,完成前置通知的調(diào)用
protected Object invokeAdviceMethodWithGivenArgs(Object[] args) throws Throwable {
Object[] actualArgs = args;
if (this.aspectJAdviceMethod.getParameterCount() == 0) {
actualArgs = null;
}
try {
ReflectionUtils.makeAccessible(this.aspectJAdviceMethod);
//通知方法反射調(diào)用,對象是@aspect注冊的bean
return this.aspectJAdviceMethod.invoke(this.aspectInstanceFactory.getAspectInstance(), actualArgs);
}
catch (IllegalArgumentException ex) {
//...
}
}
環(huán)繞通知
看完了前置通知熬尺,后置通知摸屠、異常通知基本都一樣,這里看下環(huán)繞通知粱哼,環(huán)繞通知實現(xiàn)比較復(fù)雜
環(huán)繞通知直接調(diào)用了通知方法季二,在這里沒有再回調(diào)目標方法的執(zhí)行,因為環(huán)繞通知對目標方法的執(zhí)行寫在通知方法內(nèi)部揭措,接下來看環(huán)繞通知是如何完成既完成對目標方法的調(diào)用又完成剩余通知的執(zhí)行
public class AspectJAroundAdvice extends AbstractAspectJAdvice implements MethodInterceptor{
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
if (!(mi instanceof ProxyMethodInvocation)) {
//...
}
ProxyMethodInvocation pmi = (ProxyMethodInvocation) mi;
ProceedingJoinPoint pjp = lazyGetProceedingJoinPoint(pmi);
JoinPointMatch jpm = getJoinPointMatch(pmi);
//調(diào)用通知方法
return invokeAdviceMethod(pjp, jpm, null, null);
}
}
lazyGetProceedingJoinPoint返回了一個ProceedingJoinPoint胯舷,封裝了原始的MethodInvocation對象
protected ProceedingJoinPoint lazyGetProceedingJoinPoint(ProxyMethodInvocation rmi) {
return new MethodInvocationProceedingJoinPoint(rmi);
}
接下來通知方法的調(diào)用跟前置通知一樣,只不過是將ProceedingJoinPoint作為參數(shù)傳遞給了通知方法
@Around("test()")
public Object aroundTest(ProceedingJoinPoint p) {
System.out.println("around before");
Object result = null;
try {
//調(diào)用原始方法
result = p.proceed();
} catch (Throwable e) {
}
System.out.println("around after");
return result;
}
調(diào)用p.proceed() 绊含,在 MethodInvocationProceedingJoinPoint 會將原始的 MethodInvocation克隆一份桑嘶,會將剩余攔截器鏈和下標復(fù)制下來,然后重新調(diào)用 proceed方法
@Override
public Object proceed() throws Throwable {
return this.methodInvocation.invocableClone().proceed();
}
ReflectiveMethodInvocation進行深克隆
@Override
public MethodInvocation invocableClone() {
Object[] cloneArguments = this.arguments;
if (this.arguments.length > 0) {
// Build an independent copy of the arguments array.
cloneArguments = new Object[this.arguments.length];
System.arraycopy(this.arguments, 0, cloneArguments, 0, this.arguments.length);
}
return invocableClone(cloneArguments);
}
@Override
public MethodInvocation invocableClone(Object... arguments) {
ReflectiveMethodInvocation clone = (ReflectiveMethodInvocation) clone();
clone.arguments = arguments;
return clone;
}