spring-AOP(一) 手動(dòng)代理
spring的設(shè)計(jì)原理是構(gòu)造一個(gè)個(gè)原子功能,然后不斷的通過設(shè)計(jì)模式在外圍進(jìn)行包裝、組合調(diào)用,最后實(shí)現(xiàn)復(fù)雜的邏輯功能。
知識(shí)導(dǎo)讀
- 了解Aop聯(lián)盟定義的幾個(gè)概念,連接點(diǎn)、通知、攔截、切點(diǎn)、增強(qiáng)
- ProxyFactory 定義了創(chuàng)建代理對(duì)象的工廠方法,不過該類主要用于提供代理配置
- AopProxy 定義創(chuàng)建代理對(duì)象的接口,實(shí)現(xiàn)類有 jdk代理 和 cglib代理
- 代理的本質(zhì)就是對(duì)目標(biāo)方法執(zhí)行的攔截增強(qiáng)
- 創(chuàng)建代理最主要是提供 被代理對(duì)象 和 增強(qiáng)列表 AdvisorList
- Advisor封裝了通知和切點(diǎn),實(shí)質(zhì)就是封裝了一個(gè)可以決定在什么類的什么方法上進(jìn)行增強(qiáng)的通知
- 代理的最終目的就是在方法的執(zhí)行前后添加邏輯,最終構(gòu)建 ReflectiveMethodInvocation,創(chuàng)建代理類的目的就是為了實(shí)現(xiàn)選擇性的對(duì)目標(biāo)對(duì)象方法的攔截,然后將方法調(diào)用封裝為ReflectiveMethodInvocation
- Pointcut提供了怎么篩選攔截哪些對(duì)象的哪些方法
- 切面是通知的載體,通知是個(gè)方法,切面就是定義這些方法的對(duì)象。攔截器將這些通知按照順序串成一個(gè)鏈
AOP聯(lián)盟和Spring擴(kuò)展
AOP的實(shí)質(zhì)對(duì)連接點(diǎn)的增強(qiáng),一般通俗點(diǎn)講是對(duì)對(duì)方法執(zhí)行的攔截增強(qiáng)
AOP聯(lián)盟定義了AOP的規(guī)范接口,聲明了兩個(gè)最基礎(chǔ)的接口,連接點(diǎn) 和 增強(qiáng) 。
連接點(diǎn) Joinpoint
public interface Joinpoint {
//連接點(diǎn)的執(zhí)行
Object proceed() throws Throwable;
//一般用于返回被代理對(duì)象
Object getThis();
//一般用于返回目標(biāo)方法的Method對(duì)象
AccessibleObject getStaticPart();
}

Joinpoint(連接點(diǎn)) 代表一個(gè)對(duì)象可以切入的地方,一般來說就是一個(gè)方法的執(zhí)行,MehtodInvocation將方法的調(diào)用過程進(jìn)行了封裝。spring實(shí)現(xiàn)擴(kuò)展了MethodInvocation,在ReflectiveMethodInvocation中既實(shí)現(xiàn)了方法調(diào)用的封裝,又定義了攔截器鏈,用于在方法執(zhí)行過程中進(jìn)行攔截增強(qiáng)。
通知 Advice
public interface Advice {
}
AOP聯(lián)盟聲明了通知的接口,用于標(biāo)記通知類型,最主要的接口實(shí)現(xiàn)是攔截器Interceptor
public interface Interceptor extends Advice {
}
@FunctionalInterface
public interface MethodInterceptor extends Interceptor {
//定義了對(duì) 方法調(diào)用 進(jìn)行攔截的接口
Object invoke(MethodInvocation invocation) throws Throwable;
}
在MethodInterceptor接口中聲明了invoke方法,需要一個(gè)MethodInvocation對(duì)象參數(shù)。用于對(duì)方法調(diào)用進(jìn)行攔截,然后執(zhí)行增強(qiáng)邏輯,在合適的時(shí)機(jī)回調(diào)MethodInvocation,實(shí)現(xiàn)增強(qiáng)的功能
spring對(duì)MethodInterceptor接口進(jìn)行了具體實(shí)現(xiàn),例如提供了前置通知、后置通知、最終通知、異常通知、環(huán)繞通知的實(shí)現(xiàn)類。


切點(diǎn) Pointcut
Pointcut是spring定義的一個(gè)接口,用于過濾目標(biāo)類和匹配目標(biāo)方法(連接點(diǎn))
public interface Pointcut {
//用于過濾目標(biāo)類
ClassFilter getClassFilter();
//用于匹配目標(biāo)方法
MethodMatcher getMethodMatcher();
Pointcut TRUE = TruePointcut.INSTANCE;
}
Pointcut 的具體實(shí)現(xiàn),spring中Pointcut是很重的一塊邏輯,可以單獨(dú)出一篇文檔

增強(qiáng) Advisor
spring中定義的增強(qiáng)類,用于封裝一個(gè)Pointcut和一個(gè)Advice,實(shí)質(zhì)就是封裝了一個(gè)可以決定在什么類的什么方法上應(yīng)用的通知
public interface Advisor {
Advice EMPTY_ADVICE = new Advice() {};
//封裝的通知
Advice getAdvice();
boolean isPerInstance();
}
public interface PointcutAdvisor extends Advisor {
//切點(diǎn),用于匹配連接點(diǎn),是否應(yīng)用Advice通知
Pointcut getPointcut();
}

工廠方式創(chuàng)建代理對(duì)象
ProxyFactory
通過ProxyFactory創(chuàng)建代理對(duì)象,需要配置以下信息
- 被代理對(duì)象
- 增強(qiáng)Advisor列表
- 被代理接口(非必須)
- 其他一些非必須配置(非必須)
下圖是ProxyFactory的繼承關(guān)系圖,通過看各個(gè)層級(jí)的字段,可以看出ProxyFactory主要定義的是一些創(chuàng)建代理的配置信息。

AopProxy
已知的可以創(chuàng)建代理對(duì)象的方式
- 使用jdk Proxy,需要?jiǎng)?chuàng)建一個(gè)InvocationHandler的實(shí)現(xiàn)類,調(diào)用代理對(duì)象的方法都會(huì)去調(diào)用InvocationHandler的實(shí)現(xiàn)類的invoke方法,所有的攔截和增強(qiáng)在invoke方法中做
- 使用cglib的Enhancer,需要?jiǎng)?chuàng)建一批MethodInterceptor的實(shí)現(xiàn)類,調(diào)用代理對(duì)象所有方法都會(huì)去調(diào)用MethodInterceptor實(shí)現(xiàn)類的intercept方法,所有的攔截和增強(qiáng)都在intercept方法中做
spring中定義了一個(gè)AopProxy接口,用于獲取代理類,實(shí)現(xiàn)類是JdkProxy和cglibProxy,ProxyFactory提供了創(chuàng)建AopProxy的配置信息,創(chuàng)建代理類對(duì)象的工作交由AopProxy的實(shí)現(xiàn)類實(shí)現(xiàn)。

通過ProxyFactory配置創(chuàng)建AopProxy實(shí)現(xiàn)
spring中定義了ProxyFactory用于創(chuàng)建代理對(duì)象,下面是創(chuàng)建代理對(duì)象的一個(gè)demo。
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTargetSource(targetSource);//設(shè)置被代理對(duì)象
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è)置目標(biāo)類的增強(qiáng) Advisor列表
return proxyFactory.getProxy(getProxyClassLoader());//創(chuàng)建代理類對(duì)象
調(diào)用ProxyFactory的getProxy創(chuàng)建代理類對(duì)象,首先會(huì)創(chuàng)建一個(gè)AopProxy對(duì)象,然后調(diào)用AopProxy的getProxy方法獲取代理類對(duì)象,在整個(gè)創(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的具體實(shí)現(xiàn),會(huì)通過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)建代理類對(duì)象
創(chuàng)建完AopProxy之后,調(diào)用AopProxy實(shí)現(xiàn)類的getProxy就可以創(chuàng)建代理類,和代理類對(duì)象。
jdk代理
首先來分析spring是如何實(shí)現(xiàn)jdk代理的,在JdkDynamicAopProxy中g(shù)etProxy中通過調(diào)用Proxy的api創(chuàng)建代理類對(duì)象
@Override
public Object getProxy(@Nullable ClassLoader classLoader) {
//獲取ProxyFactory提供的配置,接口
Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
//調(diào)用Proxy的api創(chuàng)建代理類對(duì)象。
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
由于JdkDynamicAopProxy自己本身實(shí)現(xiàn)了InvocationHandler接口,所以在創(chuàng)建代理對(duì)象的時(shí)候傳遞的是this
cglib代理
jdk代理比較簡單,接下來看下CglibAopProxy是如何通過cglib來創(chuàng)建代理類對(duì)象的
@Override
public Object getProxy(@Nullable ClassLoader classLoader) {
try {
//獲取ProxyFactory配置的目標(biāo)類型
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需要的攔截器實(shí)現(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)建,接下來對(duì)代理類的方法調(diào)用都會(huì)去調(diào)用InvocationHandler的invoke方法或者Callback的intercept方法。
代理類的方法調(diào)用
jdk代理的方法調(diào)用

JdkDynamicAopProxy實(shí)現(xiàn)了InvocationHandler的invoke方法,代理類對(duì)象所有方法的執(zhí)行都會(huì)通過invoke方法來調(diào)用
根據(jù)Pointcut篩選應(yīng)用目標(biāo)方法的Advisor,將Advisor中的Advice封裝為增強(qiáng)目標(biāo)方法的攔截器鏈
基于攔截器鏈封裝MethodInvocation實(shí)現(xiàn)類對(duì)象,方法的調(diào)用和攔截增強(qiáng)全由MethodInvocation實(shí)現(xiàn),
注意每次目標(biāo)方法執(zhí)行都會(huì)新建一個(gè)MethodInvocation對(duì)象
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//用于記錄ThreadLocal中之前的代理類對(duì)象
Object oldProxy = null;
boolean setProxyContext = false;
//被代理對(duì)象
TargetSource targetSource = this.advised.targetSource;
Object target = null;
try {
//此處省略代碼....
Object retVal;
//判斷如果要暴露代理類對(duì)象,如果是將代理對(duì)象放入ThreadLocal,通過AopContext.currentProxy獲取
//同時(shí)要記錄下 ThreadLocal中之前存儲(chǔ)的代理類對(duì)象,方法執(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)用被代理對(duì)象的方法
if (chain.isEmpty()) {
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}else {
//如果存在攔截器鏈,構(gòu)造方法調(diào)用的封裝對(duì)象MethodInvocation,被代理對(duì)象方法的調(diào)用以及攔截器的增強(qiáng)封裝都通過該類實(shí)現(xiàn),每次都新建ReflectiveMethodInvocation對(duì)象,這個(gè)對(duì)象中有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中的代理類對(duì)象
AopContext.setCurrentProxy(oldProxy);
}
}
}
來看下spring中是如何篩選目標(biāo)方法的攔截器鏈的,在getInterceptorsAndDynamicInterceptionAdvice會(huì)首先去獲取緩存中的攔截器鏈,如果沒有,再進(jìn)行篩選解析,感覺這里還是直接new一個(gè)list,然后將cached放進(jìn)去,避免后續(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來篩選能夠增強(qiáng)目標(biāo)方法的Advisor,然后封裝為攔截器MethodInterceptor對(duì)象,組裝成攔截器鏈返回
@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,篩選能夠增強(qiáng)目標(biāo)方法的Advisor,并封裝為攔截器鏈返回
for (Advisor advisor : advisors) {
//如果是PointcutAdvisor,判斷Advisor的Pointcut是否攔截本方法
if (advisor instanceof PointcutAdvisor) {
PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
//先通過ClassFilter判斷是否攔截目標(biāo)類
if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
boolean match;
//再通過MethodMatcher判斷是否攔截目標(biāo)方法
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ù)運(yùn)行時(shí)參數(shù)進(jìn)行方法校驗(yàn),需要封裝攔截器,將methodMatcher傳下去,用于執(zhí)行時(shí)判斷參數(shù)
if (mm.isRuntime()) {
for (MethodInterceptor interceptor : interceptors) {
interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
}
}else {
interceptorList.addAll(Arrays.asList(interceptors));
}
}
}
}//引介增強(qiáng),作用范圍是類,只需判斷是否攔截目標(biāo)類就行
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,不需要過濾,默認(rèn)攔截所有方法
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}
return interceptorList;
}
獲取到目標(biāo)方法的攔截器鏈之后,接下來構(gòu)建MethodInvocation對(duì)象,調(diào)用MethodInvocation的proceed方法。在MethodInvocation中會(huì)在目標(biāo)方法執(zhí)行前后執(zhí)行攔截器鏈中的增強(qiáng)方法,然后在合適的時(shí)機(jī)再回調(diào)目標(biāo)方法,實(shí)現(xiàn)代理的邏輯。
通過ReflectiveMethodInvocation的構(gòu)造器可以看出,該對(duì)象就是對(duì)目標(biāo)方法調(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;//代理類對(duì)象
this.target = target;//被代理對(duì)象
this.targetClass = targetClass;//被代理對(duì)象類型
this.method = BridgeMethodResolver.findBridgedMethod(method);//目標(biāo)方法
this.arguments = AopProxyUtils.adaptArgumentsIfNecessary(method, arguments);//方法參數(shù)
this.interceptorsAndDynamicMethodMatchers = interceptorsAndDynamicMethodMatchers;//攔截器鏈
}
再來看如何在proceed方法完成對(duì)方法的增強(qiáng),在該方法中會(huì)遍歷執(zhí)行攔截器鏈中的攔截方法,所有攔截器都執(zhí)行完畢后再調(diào)用被代理類的目標(biāo)方法。攔截器鏈?zhǔn)窃诖眍惖姆椒ㄖ袀魅氲模沂蔷彺孢^的共享對(duì)象,這里避免修改該鏈,使用currentInterceptorIndex來記錄鏈的執(zhí)行位置。其實(shí)這塊是可以進(jìn)行優(yōu)化的
private int currentInterceptorIndex = -1;//記錄攔截器鏈執(zhí)行第幾個(gè)攔截器
public Object proceed() throws Throwable {
// 攔截器鏈遍歷完畢后,調(diào)用目標(biāo)方法
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
//遍歷獲取下一個(gè)攔截器
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
//如果是動(dòng)態(tài)執(zhí)行過程中攔截,需要根據(jù)參數(shù)來判斷是否需要對(duì)目標(biāo)方法進(jìn)行攔截增強(qiáng)
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
//通過參數(shù)判斷是否需要增強(qiáng),如果需要直接調(diào)用攔截器的invoke方法,并把當(dāng)前MethodInvocation傳遞過來,以便方法攔截邏輯執(zhí)行后再次調(diào)回來
if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
} else {
//如果不進(jìn)行攔截,遞歸,重新執(zhí)行下一個(gè)攔截器.
return proceed();
}
} else {
//靜態(tài)攔截器,直接調(diào)用攔截器對(duì)方法進(jìn)行增強(qiáng)
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
ReflectiveMethodInvocation中,在執(zhí)行完攔截器鏈中所有的攔截器邏輯之后,會(huì)調(diào)用被代理對(duì)象的目標(biāo)方法,默認(rèn)是通過反射調(diào)用
@Nullable
protected Object invokeJoinpoint() throws Throwable {
return AopUtils.invokeJoinpointUsingReflection(this.target, this.method, this.arguments);
}
CglibMethodInvocation中覆寫了ReflectiveMethodInvocation的invokeJoinpoint方法,會(huì)通過cglib的MethodProxy進(jìn)行調(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中定義的幾種通知類型是如何在攔截器中進(jìn)行調(diào)用的。
攔截器中通知方法的執(zhí)行
spring中對(duì)通知advice和攔截器MethodInterceptor的繼承實(shí)現(xiàn)由點(diǎn)亂,不太明白為什么要這樣做,不如分開
在攔截器中可以方便的在目標(biāo)方法執(zhí)行前后添加邏輯,很簡單。在使用@Aspect的切面的時(shí)候,會(huì)調(diào)用@Aspect注冊(cè)的bean中的方法通知。這里重點(diǎn)看下@Aspect是如何實(shí)現(xiàn)的
前置通知
首先來看下前置通知攔截器中如何調(diào)用前置通知。在invoke方法中先調(diào)用通知,然后再回調(diào)MethodInvocation目標(biāo)方法
public class MethodBeforeAdviceInterceptor implements MethodInterceptor, BeforeAdvice, Serializable {
//包裝了一個(gè)前置通知
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) 連接點(diǎn)的方法執(zhí)行
return mi.proceed();
}
}
AspectJMethodBeforeAdvice實(shí)現(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)用,對(duì)象是@aspect注冊(cè)的bean
return this.aspectJAdviceMethod.invoke(this.aspectInstanceFactory.getAspectInstance(), actualArgs);
}
catch (IllegalArgumentException ex) {
//...
}
}
環(huán)繞通知
看完了前置通知,后置通知、異常通知基本都一樣,這里看下環(huán)繞通知,環(huán)繞通知實(shí)現(xiàn)比較復(fù)雜
環(huán)繞通知直接調(diào)用了通知方法,在這里沒有再回調(diào)目標(biāo)方法的執(zhí)行,因?yàn)榄h(huán)繞通知對(duì)目標(biāo)方法的執(zhí)行寫在通知方法內(nèi)部,接下來看環(huán)繞通知是如何完成既完成對(duì)目標(biāo)方法的調(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返回了一個(gè)ProceedingJoinPoint,封裝了原始的MethodInvocation對(duì)象
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 會(huì)將原始的 MethodInvocation克隆一份,會(huì)將剩余攔截器鏈和下標(biāo)復(fù)制下來,然后重新調(diào)用 proceed方法
@Override
public Object proceed() throws Throwable {
return this.methodInvocation.invocableClone().proceed();
}
ReflectiveMethodInvocation進(jìn)行深克隆
@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;
}