1. 整體
2. 重點
2.1 重要概念
- 切點
- 通知
- 代理
- 攔截
- 增強
2.2 動态代理原理
記住一點,AOP的核心技術就是動态代理
AOP用的是代理,管理代理。java有自帶的代理機制,還有Cglb代理機制。這兩種機制Aop都在應用,Java代理主要運用于接口,而Cglb主要是類。
很重要的一段話
了解一下ProxyCreatorSupport
AOP的具體實作就是在這個類中。
都是從DefaultAopProxyFactory中的createAopProxy()開始下面操作的。
- 生成代理對象
- 執行攔截器。
JdkDynamicAopProxy攔截器
從JdkDynamicAopProxy的invoke()方法,到ReflectiveMethodInvocation的process()
CglibAopProxy攔截器
intercept()方法,攔截器不是憑空來的,需要進行攔截器注冊才能儲存到攔截器鍊中,在攔截器注冊之間有一個:從攔截器注冊器中進行适配,确定哪些攔截器是該代理目标的攔截器的。
ReflectiveMethodInvocation反射
這裡通過反射調用目标方法。 process()方法中實作,這裡也是執行matches()的地方。
2.3 invoke()方法邏輯分析
代理中最主要的方法就是invoke()方法了,那就介紹一下該方法的邏輯。
- 擷取目标源TargetSource
- 指派代理目标對象Target
- 擷取代理對象類
- 擷取代理對象參數,用數組來存放
- 通過反射調用目标方法
- 擷取目标方法執行後傳回資訊
2.4 關于切點
知道切點都是到,就是增強的目标方法,一般是方法。但是Aop怎麼知道對那些方法進行操作,這就要在配置的時候告訴Aop需要操作哪些方法。
先看一下Pointcut的整體架構:
這裡每一個實作類都要實作一個方法matchs(),至于不同的切點比對規則不一樣。通常用到的
- 方法名
- 注解
- 正規表達式
2.4 Advisor通知器
将增強設計,也就是Advice和切點(Pointcut)結合起來。 也就是哪個切點上使用哪個通知。
2.4.1 DefaultPointcutAdvisor預設切點通知器
也就是當通知器為空的時候,就是用預設的。 預設就是對任何方法的比對都成功。
TrueMethodMatcher這個方法的比對對任何方法的比對都會成功
總結
-
關于Spring AOP的介紹
AOP是基于代理對象的,,通過ProxyCreateSuport來設定建立代理對象的通用操作,在這個類中主要就是擷取代理目标對象的SourceTarget,擷取代理對象的資訊。
-
再通過DefaultAopProxyFactory确定AopProxy代理對象的生成政策,生成政策的配置主要實在createAopProxy()方法中,其實也就是确定是有Java Proxy還是CGLIB第三來生成AopProxy代理對象。
在确定了生成政策之後,真正的Proxy實在ObjenesisCglibAopProxy和JdkDynamicAopProxy類中生成的。
- 代理對象生成之後,在ObjenesisCglibAopProxy-(intercept)和JdkDynamicAopProxy-(invoke)都有自己的回調函數,回調函數的作用就是對代理的方法進行各種增強操作。
- 回調函數的作用是,擷取目标對象(包括目标方法,方法參數),攔截器鍊,建立ReflectiveMethodInvocation的process()方法來完成Aop的各種增強處理。這裡的攔截器鍊其實就是通過周遊連接配接器鍊,用一個一個的攔截器來執行攔截增強。
-
這裡有一個問題,當攔截器為空的時候,直接使用反射來調用目标方法,不需要建立ReflectiveMethodInvocation。這也是我之前運用AOP的一個例子,沒有用到攔截器,擷取了代理的目标對象方法之後,通過目标對象方法調用invoke(target, args)來執行方法。
這裡記住一點這些操作是在ObjenesisCglibAopProxy-(intercept)和JdkDynamicAopProxy-(invoke)完成的,執行的方法是括号的方法。
- 攔截器分類兩種JdkDynamicAopProxy攔截器和CglibAopProxy攔截器,其實不難了解,既然是對AopProxy代理對象的攔截,針對AopProxy兩種生成政策,肯定也有兩種攔截器。上面已經講過了,當攔截器鍊不為空的時候,這兩種連接配接器都是通過ReflectiveMethodInvocation的process()方法進行代理目标函數的增強的。
- 是以接下來的重心就是ReflectiveMethodInvocation的process()方法,該方法中中實作了具體的增強邏輯。貼一個代碼吧。代碼的核心是從interceptorsAndDynamicMethodMatchers集合中擷取攔截器或者攔截通知,然後執行增強操作。這裡的interceptorsAndDynamicMethodMatchers連接配接器接口是從前面提到的方法中傳過來的,那就傳回擷取看看。
public Object proceed() throws Throwable {
// We start with an index of -1 and increment early.
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
// Evaluate dynamic method matcher here: static part will already have
// been evaluated and found to match.
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
}
else {
// Dynamic matching failed.
// Skip this interceptor and invoke the next in the chain.
return proceed();
}
}
else {
// It's an interceptor, so we just invoke it: The pointcut will have
// been evaluated statically before this object was constructed.
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
-
關于通知或者攔截器來源我們在JdkDynamicAopProxy的invoke方法中看到了下面這段代碼,跟進去發現是在AdvisedSupport擷取的。代碼如第二段代碼,該類中用了一個Map來緩存所有代理方法的攔截器,
Map定義:
從代碼中可以看到,真正擷取攔截器的方法是:private transient Map<MethodCacheKey, List<Object>> methodCache;
this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice( this, method, targetClass);
方法。跟進去看看。
這裡有一個問題,通過advisorChainFactory工程來擷取攔截器,advisorChainFactory是該類的一個屬性,看代碼發現,該屬性的具體執行個體被配置成DefaultAdvisorChainFactory類
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) {
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中。這裡算是找到了擷取攔截器鍊的源頭了。this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice( this, method, targetClass);
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
Advised config, Method method, @Nullable Class<?> targetClass) {
// This is somewhat tricky... We have to process introductions first,
// but we need to preserve order in the ultimate list.
AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
Advisor[] advisors = config.getAdvisors();
List<Object> interceptorList = new ArrayList<>(advisors.length);
Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
Boolean hasIntroductions = null;
for (Advisor advisor : advisors) {
if (advisor instanceof PointcutAdvisor) {
// Add it conditionally.
PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
boolean match;
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);
if (mm.isRuntime()) {
// Creating a new object instance in the getInterceptors() method
// isn't a problem as we normally cache created chains.
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 {
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}
return interceptorList;
}
- 接下來就來看看這個方法的邏輯,該方法就是用一個單例類來注冊通知-攔截器。首先通過擷取所有的advisors,然後周遊獲得所有advisiors,在比對代理目标方法切點是否有該攔截器,如果有,就将該攔截器注冊,儲存到一個List攔截器集合中。 這裡基本是了解了,但是有個問題,advisior是怎麼讀入系統的呢? 這将是整個Aop的最後一個環節了。
- advisior真正注冊的地方就是在ProxyFacrotyBean中的initializeAdvisorChain()。之前在代碼中有這一行代碼。
,那個時候我就在這裡的Advisor[] 從哪裡來的,經過一番檢視,就是從ProxyFacrotyBean中的initializeAdvisorChain()配置的。 這樣這個Aop的邏輯就很清晰了。Advisor[] advisors = config.getAdvisors();
AopProxy代理類的擷取,Advisior的注冊,執行增強操作。 這一套都能聯系起來。其實Aop的邏輯元件确實就這三個,了解深刻了就會化繁就簡。