Spring原始碼分析(十)AOP原始碼分析
AOP中的幾個概念
Advisor 和 Advice
Advice
我們通常都會把他翻譯為通知,其實很不好理解,其實他還有另外一個意思,就是“建議”,我覺得把Advice理解為“建議”會更好。就是代理的邏輯。
比如,我們已經完成了一個功能,這時客戶跟我們說,我建議在這個功能之前可以再增加一些邏輯,再之後再增加一些邏輯。
在Spring中,Advice分為:
- 前置Advice:MethodBeforeAdvice
- 後置Advice:AfterReturningAdvice
- 環繞Advice:MethodInterceptor
- 異常Advice:ThrowsAdvice
在利用Spring AOP去生成一個代理物件時,我們可以設定這個代理物件的Advice。
而對於Advice來說,它只表示了“建議”,它沒有表示這個“建議”可以用在哪些方面。
就好比,我們已經完成了一個功能,客戶給這個功能提了一個建議,但是這個建議也許也能用到其他功能上。
這時,就出現了Advisor,表示一個Advice可以應用在哪些地方,而“哪些地方”就是Pointcut(切點)。
Pointcut
切點,表示我想讓哪些地方加上我的代理邏輯。
比如某個方法,
比如某些方法,
比如某些方法名字首為“find”的方法,
比如某個類下的所有方法,等等。
在Pointcut中,有一個MethodMatcher,表示方法匹配器。
Advisor
就等於Pointcut+Advice.
Spring中的AOP代理類是通過一個ProxyFactory類來實現的。
先簡單介紹下這個類的簡單用法:
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
UserInterface userService = (UserInterface) applicationContext.getBean("userService");
userService.test();
// testAop();
}
public static void testAop(){
ProxyFactory proxyFactory = new ProxyFactory();
// 設定目標物件
proxyFactory.setTarget(new UserService());
// proxyFactory.setTargetClass(UserService.class);
proxyFactory.addInterface(UserInterface.class); // 表示想使用jdk動態代理
proxyFactory.getTargetSource();
// 生成代理邏輯 ,注意這裡新增的只是一個Advice,底層是要封裝成一個Advisor來交給代理工廠管理的。
// 這裡添加了Advice,底層使用 DefaultPointcutAdvisor 封裝,它的PointCut是Pointcut.TRUE 表示匹配所有類的切點的都使用
proxyFactory.addAdvice(new MethodBeforeAdvice() {
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println(method.getName()+"方法呼叫之前執行的代理邏輯");
}
});
// UserService 實現了 UserInterface 介面
// 生成代理物件 UserService 是個實現類,如果是cglib動態代理,代理類是可以強轉成它的,但是如果是jdk動態代理,它就不能強轉成UserService類
// 因為cglib是基於子類來實現的,jdk動態代理是基於介面實現類來的
// UserService proxy = (UserService) proxyFactory.getProxy();
// jdk動態代理 {代理類 extends Proxy implement 目標介面}
UserInterface proxy = (UserInterface) proxyFactory.getProxy();
proxy.test();
}
1:上面ProxyFactory的構造方法,會把傳進去的目標物件封裝成一個TargetSource
public void setTarget(Object target) { setTargetSource(new SingletonTargetSource(target)); }
2: 還有一種設定目標物件的方式,就是:proxyFactory.setTargetClass(UserService.class);
public void setTargetClass(@Nullable Class<?> targetClass) { this.targetSource = EmptyTargetSource.forClass(targetClass); }
兩種設定方式得到的this.targetSource 這個屬性是不一樣的,
一個是:EmptyTargetSource ,一個是SingletonTargetSource,他們都繼承了TargetSource,但是對於SingletonTargetSource來說,它的target屬性,和getTargetClass都是可以得到值的。
但是對於EmptyTargetSource 來說,它只有getTargetClass能得到值,因為是直接賦值的,它的getTarget是直接返回null的。
上面代理工廠ProxyFactory#getProxy得到一個代理類中,會先得到一個具體的代理工廠,有兩種jdk的代理工廠和cglib的代理工廠。
public Object getProxy() { return createAopProxy().getProxy(); }
protected final synchronized AopProxy createAopProxy() { if (!this.active) { activate(); } // 預設用的就是DefaultAopProxyFactory return getAopProxyFactory().createAopProxy(this); }
DefaultAopProxyFactory#createAopProxy 中:
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException { // Spring到底何時使用cglib,何時使用jdk動態代理 // 如果設定的targetClass是一個介面,會使用jdk動態代理 // 預設情況下(optimize為false, isProxyTargetClass為false), ProxyFactory添加了介面時,也會使用jdk動態代理 // 這個config 就是外面的按個ProxyFactory 它的父類 extends ProxyConfig implements Advised // config.isOptimize() 跟CGlib優化 可以在外面設定 ,預設為false // config.isProxyTargetClass() 預設為false ,是否使用cglib, 這個屬性也可以通過 @EnableAspectJAutoProxy 註解設定,註解屬性裡面也有這個屬性 // hasNoUserSuppliedProxyInterfaces 是不是沒有使用者提供的代理介面 :這個指的是 可以通過proxyFactory.addInterface() 新增介面 // 新增之後 hasNoUserSuppliedProxyInterfaces(config)會判斷 是否進入下面的邏輯 if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) { // 這個 getTargetClass() 就是外面setTarget或者 setTargetClass 之後可以得到的值 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."); } // 如果 targetClass 是介面就使用jdk的動態代理 ,如果外面是通過setTarget賦值的,那麼targetClass肯定不是介面,因為引數是個物件 // setTargetClass 設定的可以是個介面 if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) { // 返回jdk的代理工廠 return new JdkDynamicAopProxy(config); } // 返回cglib的代理工廠 return new ObjenesisCglibAopProxy(config); } else { return new JdkDynamicAopProxy(config); } }
而一般在我們使用過程中,如果只開啟了註解:@EnableAspectJAutoProxy ,Spring會根據類是否有介面來判斷是否用jdk動態代理還是cglib動態代理。如果在@EnableAspectJAutoProxy(proxyTargetClass = true) 加上屬性,則就會都優先使用cglib的動態代理。
上面分析了得到代理工廠,代理工廠得到得到代理類是getProxy()。代理工廠兩個:JdkDynamicAopProxy,ObjenesisCglibAopProxy。
JdkDynamicAopProxy#getProxy()
jdk動態代理生成的代理類是實現一些指定介面的代理類,實現那些介面是:AopProxyUtils.completeProxiedInterfaces(this.advised, true); 查詢。
public Object getProxy(@Nullable ClassLoader classLoader) { // this.advised 就是ProxyFactory物件 if (logger.isTraceEnabled()) { logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource()); } // 獲取生成代理物件所需要實現的介面 // 如果通過指定了 proxyFactory.addInterface 指定了介面,則算上一個,如果沒有指定則看targetClass 是不是介面 如果是的話這個介面算上一個 // 最後還會加上Spring 自帶的三個介面 SpringProxy(只是標記介面,標記是個AOP代理類)、Advised(可以管理AOP 的通知,在使用代理類的時候可以強轉為它 進行管理)、 // DecoratingProxy Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true); // 判斷這些介面中有沒有定義equals方法,hashcode方法 findDefinedEqualsAndHashCodeMethods(proxiedInterfaces); // 針對所指定的介面生成代理物件,包括使用者所新增的介面以及SpringProxy、Advised、DecoratingProxy // 所以生成的代理物件可以強制轉換成任意一個介面型別 // 用的也是JDK中的代理方式, 傳入了this物件,也就是JdkDynamicAopProxy implements AopProxy, InvocationHandler // 呼叫代理類方法的時候,就會走 下面的invoke方法 return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this); }
Spring中建立AOP代理的方式
上面建立代理類舉例子是通過ProxyFactory來的,在spring中是底層才用到這個類,在spring中有幾種實用的建立AOP代理的方式。
1:通過BeanNameAutoProxyCreator 這個後置處理器,進行自動代理。
看到它繼承了AbstractAutoProxyCreator,父類實現了SmartInstantiationAwareBeanPostProcessor後置處理器,裡面肯定有個postProcessBeforeInstantiation,postProcessAfterInitialization。
在postProcessBeforeInstantiation邏輯中會有判斷是否需要提前建立代理物件的邏輯。還會判斷是否要跳過當前bean的代理邏輯的處理: this.advisedBeans.put(cacheKey, Boolean.FALSE);
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) { Object cacheKey = getCacheKey(beanClass, beanName); if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) { // advisedBeans中存的是當前這個bean需不需要代理 if (this.advisedBeans.containsKey(cacheKey)) { return null; } // 當前bean是不是不需要進行代理 if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) { this.advisedBeans.put(cacheKey, Boolean.FALSE); return null; } } // 檢視是否需要提前生成代理物件 // Create proxy here if we have a custom TargetSource. // Suppresses unnecessary default instantiation of the target bean: // The TargetSource will handle target instances in a custom fashion. // 判斷當前beanClass和beanName是否會生成一個TargetSource,如果生成了,就進行代理 TargetSource targetSource = getCustomTargetSource(beanClass, beanName); if (targetSource != null) { if (StringUtils.hasLength(beanName)) { this.targetSourcedBeans.add(beanName); } Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource); // 建立一個代理物件 Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource); this.proxyTypes.put(cacheKey, proxy.getClass()); return proxy; } return null; }
一般的AOP代理邏輯處理是在postProcessAfterInitialization中的
// 正常情況進行AOP的地方 public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) { if (bean != null) { Object cacheKey = getCacheKey(bean.getClass(), beanName); // earlyProxyReferences中存的是哪些提前進行了AOP的bean,beanName:AOP之前的物件 // 注意earlyProxyReferences中並沒有存AOP之後的代理物件 BeanPostProcessor if (this.earlyProxyReferences.remove(cacheKey) != bean) { // 沒有提前進行過AOP,則進行AOP return wrapIfNecessary(bean, beanName, cacheKey); } } // 為什麼不返回代理物件呢? return bean; // }
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) { // 在當前targetSourcedBeans中存在的bean,表示在例項化之前就產生了代理物件 if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) { return bean; } // 當前這個bean不用被代理 this.advisedBean 儲存一個bean需不需要被代理 if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) { return bean; } // 先判斷當前bean是不是要進行AOP,比如當前bean的型別是Pointcut、Advice、Advisor AopInfrastructureBean 那就不需要進行AOP // shouldSkip 給子類來實現判斷是否需要進行AOP代理 if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) { this.advisedBeans.put(cacheKey, Boolean.FALSE); return bean; } // Create proxy if we have advice. // 這麼說不對: 獲取當前beanClass所匹配的advisors(PointCut+Advice) 或者Advice // 也是由子類來實現邏輯的 BeanNameAutoProxyCreator // 只是返回一個標記 DO_NOT_PROXY、PROXY_WITHOUT_ADDITIONAL_INTERCEPTORS 看是否需要進行AOP代理 Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null); // 如果匹配的advisors不等於null,那麼則進行代理,並返回代理物件 if (specificInterceptors != DO_NOT_PROXY) { this.advisedBeans.put(cacheKey, Boolean.TRUE); // 基於bean物件和Advisor建立代理物件 Object proxy = createProxy( bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean)); // 存一個代理物件的型別 this.proxyTypes.put(cacheKey, proxy.getClass()); return proxy; } this.advisedBeans.put(cacheKey, Boolean.FALSE); return bean; }
1.1:定義BeanNameAutoProxyCreator
// 自動代理 BeanPost @Bean public BeanNameAutoProxyCreator creator(){ // BeanPostProcessor BeanNameAutoProxyCreator beanNameAutoProxyCreator = new BeanNameAutoProxyCreator(); // 設定要目標bean的beanName,可以配置多個 beanNameAutoProxyCreator.setBeanNames("userService"); // bean==>AOP // 設定攔截器名稱,其實就是Advisor= PointCut+Advice beanNameAutoProxyCreator.setInterceptorNames("myAdvisor"); return beanNameAutoProxyCreator; }
1.2: 定義Advisor
@Component public class MyAdvisor implements PointcutAdvisor { @Override public Pointcut getPointcut() { // 設定切點資訊,通過方法的名字匹配切點 NameMatchMethodPointcut pointcut = new NameMatchMethodPointcut(); // 設定了切點為 方法名是test的方法 pointcut.addMethodName("test"); return pointcut; } @Override public Advice getAdvice() { // 設定Advice 增強的邏輯 return new MethodBeforeAdvice() { @Override public void before(Method method, Object[] args, Object target) throws Throwable { System.out.println("Myadvisor方法執行前"+target.getClass().getName()); } }; } @Override public boolean isPerInstance() { return false; } }
上面的方式配置的AOP邏輯實現了。
2:還有一種通過DefaultAdvisorAutoProxyCreator來進行AOP邏輯查詢匹配的方式。
@Bean public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator(){ DefaultAdvisorAutoProxyCreator creator = new DefaultAdvisorAutoProxyCreator(); return creator; }
DefaultAdvisorAutoProxyCreator 是找Advisor型別的bean,然後進行匹配。就是上面自定義的MyAdvisor。
這個Bean可以替換掉上面的那個BeanNameAutoProxyCreator。但是這種方式也不方便,因為定義Advisor不夠靈活,配置比較麻煩。
3:使用註解,這種方式比較常用。@EnableAspectJAutoProxy
這個註解有proxyTargetClass 屬性預設false(如果為true表示要使用cglib的動態代理),exposeProxy 屬性預設為false。
Advisor是通過如下方式:
@Component @Aspect public class TestAspect { @Before("execution(public void com.luban.service.UserService.test())") public void before(){ System.out.println("註解前置方法執行"); } }
在配置類上加了這個註解之後,這個註解會引入一個類:AspectJAutoProxyRegistrar。和上面的方式相比:
AspectJAutoProxyRegistrar 繼承ImportBeanDefinitionRegistrar ,具有註冊beanDefinition的功能。就是registerBeanDefinitions方法:註冊一個AnnotationAwareAspectJAutoProxyCreator 類。
public void registerBeanDefinitions( AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { // 註冊一個 AnnotationAwareAspectJAutoProxyCreator 的bean AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry); AnnotationAttributes enableAspectJAutoProxy = AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class); if (enableAspectJAutoProxy != null) { if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) { AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry); } if (enableAspectJAutoProxy.getBoolean("exposeProxy")) { AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry); } } }
AnnotationAwareAspectJAutoProxyCreator 的繼承結構如上圖,它不僅可以找到Advisor型別的bean,還可以找@Aspect標註的bean。
這種註解方式的執行流程按照上面的繼承關係重新整理一下如下:
1:AbstractAutoProxyCreator
是個bean的後置處理器,在某個bean的建立過程中,會執行它裡面的postProcessBeforeInstantiation,postProcessAfterInitialization
AbstractAutoProxyCreator#postProcessBeforeInstantiation
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) { Object cacheKey = getCacheKey(beanClass, beanName); if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) { // advisedBeans中存的是當前這個bean需不需要代理 if (this.advisedBeans.containsKey(cacheKey)) { return null; } // 當前bean是不是不需要進行代理 裡面的兩個方法都可以被子類實現,作為自己不同場景下的判斷 if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) { this.advisedBeans.put(cacheKey, Boolean.FALSE); return null; } } // 檢視是否需要提前生成代理物件 // Create proxy here if we have a custom TargetSource. // Suppresses unnecessary default instantiation of the target bean: // The TargetSource will handle target instances in a custom fashion. // 判斷當前beanClass和beanName是否會生成一個TargetSource,如果生成了,就進行代理 TargetSource targetSource = getCustomTargetSource(beanClass, beanName); if (targetSource != null) { if (StringUtils.hasLength(beanName)) { this.targetSourcedBeans.add(beanName); } Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource); // 建立一個代理物件 Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource); this.proxyTypes.put(cacheKey, proxy.getClass()); return proxy; } return null; }
上面有兩個方法isInfrastructureClass,shouldSkip可以由子類來判斷一個bean要不要進行代理。
AnnotationAwareAspectJAutoProxyCreator #isInfrastructureClass
protected boolean isInfrastructureClass(Class<?> beanClass) { // Previously we setProxyTargetClass(true) in the constructor, but that has too // broad an impact. Instead we now override isInfrastructureClass to avoid proxying // aspects. I'm not entirely happy with that as there is no good reason not // to advise aspects, except that it causes advice invocation to go through a // proxy, and if the aspect implements e.g the Ordered interface it will be // proxied by that interface and fail at runtime as the advice method is not // defined on the interface. We could potentially relax the restriction about // not advising aspects in the future. // 呼叫父類的過濾方法,如果父類沒有過濾掉,呼叫自己增加的增加的過濾方法(過濾掉@Aspect註解標註的bean,因為這是作為Advisor集合的bean) return (super.isInfrastructureClass(beanClass) || (this.aspectJAdvisorFactory != null && this.aspectJAdvisorFactory.isAspect(beanClass))); }
父類中AbstractAutoProxyCreator#isInfrastructureClass
protected boolean isInfrastructureClass(Class<?> beanClass) { // 過濾掉一些 和AOP相關的bean boolean retVal = Advice.class.isAssignableFrom(beanClass) || Pointcut.class.isAssignableFrom(beanClass) || Advisor.class.isAssignableFrom(beanClass) || AopInfrastructureBean.class.isAssignableFrom(beanClass); if (retVal && logger.isTraceEnabled()) { logger.trace("Did not attempt to auto-proxy infrastructure class [" + beanClass.getName() + "]"); } return retVal; }
AspectJAwareAdvisorAutoProxyCreator#shouldSkip
protected boolean shouldSkip(Class<?> beanClass, String beanName) { // TODO: Consider optimization by caching the list of the aspect names // 得到型別為Advisor的bean,以及被@Aspect註解修飾了的類中所定義的@Before等 List<Advisor> candidateAdvisors = findCandidateAdvisors(); // 如果當前beanName是AspectJPointcutAdvisor,那麼則跳過 for (Advisor advisor : candidateAdvisors) { if (advisor instanceof AspectJPointcutAdvisor && ((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) { return true; } } // 呼叫父類的的shouldSkip 方法 return super.shouldSkip(beanClass, beanName); }
父類中AbstractAutoProxyCreator#shouldSkip
protected boolean shouldSkip(Class<?> beanClass, String beanName) { return AutoProxyUtils.isOriginalInstance(beanName, beanClass); }
static boolean isOriginalInstance(String beanName, Class<?> beanClass) { if (!StringUtils.hasLength(beanName) || beanName.length() != beanClass.getName().length() + AutowireCapableBeanFactory.ORIGINAL_INSTANCE_SUFFIX.length()) { return false; } return (beanName.startsWith(beanClass.getName()) && beanName.endsWith(AutowireCapableBeanFactory.ORIGINAL_INSTANCE_SUFFIX)); }
在AspectJAwareAdvisorAutoProxyCreator#shouldSkip中有一個findCandidateAdvisors 的方法,找到所有候選者Advisor
它由子類重寫了,AnnotationAwareAspectJAutoProxyCreator#findCandidateAdvisors如下
protected List<Advisor> findCandidateAdvisors() { // Add all the Spring advisors found according to superclass rules. // 先去呼叫父類的 findCandidateAdvisors 方法 // Advisor=Pointcut+Advice (切點加建議) ,獲得到所有Advisor型別的bean List<Advisor> advisors = super.findCandidateAdvisors(); // Build Advisors for all AspectJ aspects in the bean factory. // 找的是通過AspectJ的方式定義的Advisor if (this.aspectJAdvisorsBuilder != null) { advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors()); } return advisors; }
假如上面例項化之前的那個方法沒有進行Aop代理,那麼正常AOP代理物件是在postProcessAfterInitialization中產生的。
AbstractAutoProxyCreator#postProcessAfterInitialization
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) { if (bean != null) { Object cacheKey = getCacheKey(bean.getClass(), beanName); // earlyProxyReferences中存的是哪些提前進行了AOP的bean,beanName:AOP之前的物件 // 注意earlyProxyReferences中並沒有存AOP之後的代理物件 BeanPostProcessor if (this.earlyProxyReferences.remove(cacheKey) != bean) { // 沒有提前進行過AOP,則進行AOP return wrapIfNecessary(bean, beanName, cacheKey); } } // 為什麼不返回代理物件呢? return bean; // }
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) { // 在當前targetSourcedBeans中存在的bean,表示在例項化之前就產生了代理物件 if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) { return bean; } // 當前這個bean不用被代理 this.advisedBean 儲存一個bean需不需要被代理 if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) { return bean; } // 先判斷當前bean是不是要進行AOP,比如當前bean的型別是Pointcut、Advice、Advisor AopInfrastructureBean 那就不需要進行AOP // shouldSkip 給子類來實現判斷是否需要進行AOP代理 if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) { this.advisedBeans.put(cacheKey, Boolean.FALSE); return bean; } // Create proxy if we have advice. // 這麼說不對: 獲取當前beanClass所匹配的advisors(PointCut+Advice) 或者Advice // 也是由子類來實現邏輯的 BeanNameAutoProxyCreator // 只是返回一個標記 DO_NOT_PROXY、PROXY_WITHOUT_ADDITIONAL_INTERCEPTORS 看是否需要進行AOP代理 Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null); // 如果匹配的advisors不等於null,那麼則進行代理,並返回代理物件 if (specificInterceptors != DO_NOT_PROXY) { this.advisedBeans.put(cacheKey, Boolean.TRUE); // 基於bean物件和Advisor建立代理物件 Object proxy = createProxy( bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean)); // 存一個代理物件的型別 this.proxyTypes.put(cacheKey, proxy.getClass()); return proxy; } this.advisedBeans.put(cacheKey, Boolean.FALSE); return bean; }
AbstractAdvisorAutoProxyCreator#getAdvicesAndAdvisorsForBean
protected Object[] getAdvicesAndAdvisorsForBean( Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) { // 針對當前bean查詢合格的Advisor List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName); if (advisors.isEmpty()) { return DO_NOT_PROXY; } return advisors.toArray(); }
// 查詢合格的Advisor(和beanClass匹配) protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) { // 得到所有的Advisor List<Advisor> candidateAdvisors = findCandidateAdvisors(); // 進行篩選 篩選和beanClass匹配的Advisor List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName); // 提供給子類去額外的新增advisor extendAdvisors(eligibleAdvisors); if (!eligibleAdvisors.isEmpty()) { // 按order進行排序 eligibleAdvisors = sortAdvisors(eligibleAdvisors); } // 返回匹配的Advisor return eligibleAdvisors; }
protected List<Advisor> findCandidateAdvisors() { // Add all the Spring advisors found according to superclass rules. // 先去呼叫父類的 findCandidateAdvisors 方法 // Advisor=Pointcut+Advice (切點加建議) ,獲得到所有Advisor型別的bean List<Advisor> advisors = super.findCandidateAdvisors(); // Build Advisors for all AspectJ aspects in the bean factory. // 找的是通過AspectJ的方式定義的Advisor 找到@Aspect註解標註的類 if (this.aspectJAdvisorsBuilder != null) { advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors()); } return advisors; }
進行建立代理的邏輯:createProxy
protected Object createProxy(Class<?> beanClass, @Nullable String beanName, @Nullable Object[] specificInterceptors, TargetSource targetSource) { if (this.beanFactory instanceof ConfigurableListableBeanFactory) { AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass); } ProxyFactory proxyFactory = new ProxyFactory(); proxyFactory.copyFrom(this); // 複製配置引數 // 是否指定了必須用cglib進行代理 if (!proxyFactory.isProxyTargetClass()) { // 如果沒有指定,那麼則判斷是不是應該進行cglib代理(判斷BeanDefinition中是否指定了要用cglib) if (shouldProxyTargetClass(beanClass, beanName)) { proxyFactory.setProxyTargetClass(true); } else { // 是否進行jdk動態代理,如果當前beanClass實現了某個介面,那麼則會使用JDK動態代理 evaluateProxyInterfaces(beanClass, proxyFactory); // 判斷beanClass有沒有實現介面 } } // 將commonInterceptors和specificInterceptors整合再一起 Advisor[] advisors = buildAdvisors(beanName, specificInterceptors); proxyFactory.addAdvisors(advisors); // 向ProxyFactory中新增advisor proxyFactory.setTargetSource(targetSource); // 被代理的物件 customizeProxyFactory(proxyFactory); proxyFactory.setFrozen(this.freezeProxy); // if (advisorsPreFiltered()) { proxyFactory.setPreFiltered(true); } // 生成代理物件 return proxyFactory.getProxy(getProxyClassLoader()); }
首先建立ProxyFactory物件,開頭已經介紹過這個類了。
public void copyFrom(ProxyConfig other) { Assert.notNull(other, "Other ProxyConfig object must not be null"); this.proxyTargetClass = other.proxyTargetClass; // 是否開啟cglib this.optimize = other.optimize; this.exposeProxy = other.exposeProxy; // 是否將生成的代理物件設定到AopContext中去,後面可以通過AopContext.currentProxy()拿到 this.frozen = other.frozen; this.opaque = other.opaque; }
從上面可以看出,是否要用cglib進行代理,不止是看目標物件是否實現了某個介面,還和proxyTargetClass屬性有關,這個屬性在 @EnableAspectJAutoProxy中有設定,注入AnnotationAwareAspectJAutoProxyCreator的時候賦值進去的,然而看上面的邏輯,就算是
沒有設定,還會判斷當前bean對應的BeanDefinition中是否有設定一個名為:org.springframework.aop.framework.autoproxy.AutoProxyUtils.preserveTargetClass=true的屬性,如果有的話也會設定為true。
getProxy中,會先判斷使用JDK代理工廠還是使用cglib的代理工廠
public Object getProxy(@Nullable ClassLoader classLoader) { // 根據不同的情況得到不同的動態代理工廠,cglib或jdk動態代理 return createAopProxy().getProxy(classLoader); }
protected final synchronized AopProxy createAopProxy() { if (!this.active) { activate(); } // 預設用的就是DefaultAopProxyFactory return getAopProxyFactory().createAopProxy(this); }
AopProxy有兩種,一種是JdkDynamicAopProxy,一種是CglibAopProxy
JdkDynamicAopProxy#getProxy
public Object getProxy(@Nullable ClassLoader classLoader) { // this.advised 就是ProxyFactory物件 if (logger.isTraceEnabled()) { logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource()); } // 獲取生成代理物件所需要實現的介面 // 如果通過指定了 proxyFactory.addInterface 指定了介面,則算上一個,如果沒有指定則看targetClass 是不是介面 如果是的話這個介面算上一個 // 最後還會加上Spring 自帶的三個介面 SpringProxy(只是標記介面,標記是個AOP代理類)、Advised(可以管理AOP 的通知,在使用代理類的時候可以強轉為它 進行管理)、 // DecoratingProxy Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true); // 判斷這些介面中有沒有定義equals方法,hashcode方法 findDefinedEqualsAndHashCodeMethods(proxiedInterfaces); // 針對所指定的介面生成代理物件,包括使用者所新增的介面以及SpringProxy、Advised、DecoratingProxy // 所以生成的代理物件可以強制轉換成任意一個介面型別 // 用的也是JDK中的代理方式, 傳入了this物件,也就是JdkDynamicAopProxy implements AopProxy, InvocationHandler // 呼叫代理類方法的時候,就會走 下面的invoke方法 return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this); }
JdkDynamicAopProxy 本身是一個InvocationHandler,所以當呼叫目標物件的方法時就會執行JdkDynamicAopProxy#invoke方法。
裡面主要的邏輯如下:
上面的 this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);,會得到那些在@Aspect中定義的Advice。這些Advice根據@Before,@After等等的不同,分為AspectJAroundAdvice等等。
然後把這個執行鏈,還有代理物件,目標物件封裝成 ReflectiveMethodInvocation,然後執行其proceed方法,這個方法是個遞迴呼叫。
public Object proceed() throws Throwable { // We start with an index of -1 and increment early. // this.currentInterceptorIndex 預設=-1 if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
// 最後執行method本身的邏輯 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. // 呼叫 AspectJAroundAdvice,AspectJAfterReturningAdvice 等 return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this); } }
以MethodBeforeAdviceInterceptor#invoke為例子
public Object invoke(MethodInvocation mi) throws Throwable {
// 先執行@Aspect中@Before標註的方法 this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
// 然後繼續呼叫下一個Advice方法 return mi.proceed(); // methodinter target.test(); }
在ReflectiveAspectJAdvisorFactory#getAdvisor 中把上面@Aspect的類中的方法封裝成Advisor物件。
public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrderInAspect, String aspectName) { validate(aspectInstanceFactory.getAspectMetadata().getAspectClass()); // 得到當前candidateAdviceMethod方法上的所定義的expression表示式,也就是切點 AspectJExpressionPointcut expressionPointcut = getPointcut( candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass()); if (expressionPointcut == null) { return null; } // 構造一個Advisor,封裝了切點表示式和當前方法 return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod, this, aspectInstanceFactory, declarationOrderInAspect, aspectName); }
不同的Advice對應的不同的類,就是上面說的MethodInterceptor.