spring代理和切面
今天在deepseek上偶然問了這個問題,給出的描述很清楚,抄下來。
攔截器鏈執(zhí)行核心
public class ReflectiveMethodInvocation implements MethodInvocation { private final Object target; private final Method method; private final Object[] args; private final List<MethodInterceptor> interceptors; // 關(guān)鍵:當(dāng)前攔截器索引,記錄執(zhí)行位置 private int currentInterceptorIndex = -1; public ReflectiveMethodInvocation(Object target, Method method, Object[] args, List<MethodInterceptor> interceptors) { this.target = target; this.method = method; this.args = args; this.interceptors = interceptors; } @Override public Object proceed() throws Throwable { // 所有攔截器都執(zhí)行完畢,執(zhí)行原始目標(biāo)方法 if (currentInterceptorIndex == interceptors.size() - 1) { return method.invoke(target, args); } // 獲取下一個攔截器并執(zhí)行 MethodInterceptor interceptor = interceptors.get(++currentInterceptorIndex); return interceptor.invoke(this); // 關(guān)鍵:遞歸調(diào)用鏈 } }
里面的invoke代碼不難,類似這樣:
@Override public Object invoke(MethodInvocation invocation) throws Throwable { // 先執(zhí)行前置邏輯 beforeAdvice.run(); // 繼續(xù)執(zhí)行鏈 return invocation.proceed(); }
所以proceed差不多可以簡化成這樣:
@Override public Object proceed() throws Throwable { // 所有攔截器都執(zhí)行完畢,執(zhí)行原始目標(biāo)方法 if (currentInterceptorIndex == interceptors.size() - 1) { return method.invoke(target, args); } // 獲取下一個攔截器并執(zhí)行 MethodInterceptor interceptor = interceptors.get(++currentInterceptorIndex); return proceed(); }
spring把controller里我們實現(xiàn)的method用一個結(jié)構(gòu)體(class)描述出來,調(diào)用的method名字,參數(shù),包括外面用aspect做的切面都塞到結(jié)構(gòu)體里。叫做ReflectiveMethodInvocation。按我的習(xí)慣就叫execution。proceed()是一個遞歸函數(shù),它總是執(zhí)行下一個切面,除非沒有切面了,再執(zhí)行真正的用戶方法。
注意method本體的調(diào)用是在else里的,一個切面如果進(jìn)入另一個切面,它就不執(zhí)行method了。所以只有咀內(nèi)層(最末序)的切面有調(diào)用method的機會,它不是直接調(diào)用,它也是調(diào)用proceed,如果它不調(diào)用,那這個controller的方法就被繞過了。
沒接觸spring的時候,猜測切面應(yīng)該就是鉤子吧,其實是比鉤子高級的鉤子,重要的是它把方法調(diào)用描述成數(shù)據(jù)結(jié)構(gòu),然后再“手動”調(diào)用,這樣對方法所處的執(zhí)行點位的執(zhí)行流和執(zhí)行內(nèi)容能全權(quán)控制。

浙公網(wǎng)安備 33010602011771號