Spring AOP解析(2)--AOP的實現原理及原始碼解析
前言:
上一篇對於AOP的使用做了簡單的介紹,本文開始著重對於AOP的實現原理進行解析,AOP的使用主要是通過自定義標籤<aop:aspectj-autoproxy>開啟,所以就需要通過該標籤入手開始探尋AOP的奧祕
一、<aop:aspectj-autoproxy>標籤的解析
Spring的標籤分為預設的標籤和自定義的標籤,自定義的標籤都需要自定義解析器來對標籤進行解析,所以可以先從該標籤的解析器入手。全域性搜尋aspectj-autoproxy,可以發現Spring-Aop包中果然存在一個aspectj-autoproxy的解析器,在AopNamespaceHandler的初始化方法中定義,註冊了一個標籤解析器AspectJAutoProxyBeanDefinitionParser,原始碼如下:
1 public class AopNamespaceHandler extends NamespaceHandlerSupport { 2 3 @Override 4 public void init() { 5 // In 2.0 XSD as well as in 2.1 XSD. 6 registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser()); 7 registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());8 registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator()); 9 10 // Only in 2.0 XSD: moved to context namespace as of 2.1 11 registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser()); 12 } 13 14 }
AspectJAutoProxyBeanDefinitionParser主要需要執行parser方法,原始碼如下:
1 @Override 2 @Nullable 3 public BeanDefinition parse(Element element, ParserContext parserContext) { 4 AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element); 5 extendBeanDefinition(element, parserContext); 6 return null; 7 }
其中核心邏輯線上第4行,用於註冊AnnotationAwareAutoProxyCreator,首先是建立一個該類的BeanDefintion,然後是解析<aop:aspectj-autoproxy>標籤的兩個屬性proxy-target-class和expose-proxy,最後註冊該BeanDefinition,原始碼如下:
1 public static void registerAspectJAnnotationAutoProxyCreatorIfNecessary( 2 ParserContext parserContext, Element sourceElement) { 3 /** 獲取org.springframework.aop.config.internalAutoProxyCreator類的BeanDefinition物件*/ 4 BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary( 5 parserContext.getRegistry(), parserContext.extractSource(sourceElement)); 6 /** 用於解析 proxy-target-class屬性 和 expose-proxy屬性*/ 7 useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement); 8 /** 註冊AnnotationAutoProxyCreator元件*/ 9 registerComponentIfNecessary(beanDefinition, parserContext); 10 }
目前可以得出結論,AOP的實現功能或者說<aop:aspectj-autoproxy/>標籤的功能實現是通過AnnotationAwareAutoProxyCreator來實現的,而上面的步驟都是在建立和註冊AnnotationAwareAutoProxyCreator的bean的定義的過程。
二、AnnotationAwareAutoProxyCreator的原始碼解析
AnnotationAwareAutoProxyCreator類實現了很多的介面,分別實現了Orderd、BeanPostProcessor的子介面、BeanFactoryAware、BeanClassLoaderAware等介面,而既然實現了BeanPostProcessor介面,很顯然在bean載入時就會執行BeanPostProcessor的postProcessorBeforeInstantiation方法和postProcessAfterInitialization方法,其中postProcessBeforeInstantiation方法是在bean例項化之前執行,而postProcessAfterInitialization是在bean執行了init方法之後執行,均是在父類AbstarctAutoProxyCreator中實現。
方法postProcessorBeforeInstantiation原始碼解析:
1 /** 目標物件源bean集合*/ 2 private final Set<String> targetSourcedBeans = Collections.newSetFromMap(new ConcurrentHashMap<>(16)); 3 4 /** 提前曝光的代理引用集合*/ 5 private final Map<Object, Object> earlyProxyReferences = new ConcurrentHashMap<>(16); 6 7 /** 代理型別集合*/ 8 private final Map<Object, Class<?>> proxyTypes = new ConcurrentHashMap<>(16); 9 10 /** 增強bean集合,Advice、PointCut、Advisor、AopInfrastructureBean等類的bean會加入該集合*/ 11 private final Map<Object, Boolean> advisedBeans = new ConcurrentHashMap<>(256); 12 13 @Override 14 public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) { 15 /** 16 * 1.根據beanClass和beanName獲取快取的key 17 * 如果是工廠bean則key = &beanName 18 * 如果不是工廠bean則key = beanName 19 * */ 20 Object cacheKey = getCacheKey(beanClass, beanName); 21 22 /** 23 * 2.如果targetSourcedBeans中不包含當前bean則進行判斷 24 * */ 25 if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) { 26 if (this.advisedBeans.containsKey(cacheKey)) { 27 return null; 28 } 29 /** 30 * 3.isInfrastructureClass方法是判斷當前beanClass是否是AOP增強相關的介面 31 * 判斷beanClass是否是Advice、PointCut、Advisor、AopInfrastructureBean等介面的實現類 32 * 如果是則加入到advisedBeans集合中 33 * */ 34 if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) { 35 this.advisedBeans.put(cacheKey, Boolean.FALSE); 36 return null; 37 } 38 } 39 40 /** 41 * 4.根據beanClass和beanName獲取自定義的TargetSource例項,如果存在的話則建立代理,如果不存在則直接跳過 42 * TargetSource例項相當於就是目標物件bean的封裝例項 43 * */ 44 TargetSource targetSource = getCustomTargetSource(beanClass, beanName); 45 if (targetSource != null) { 46 if (StringUtils.hasLength(beanName)) { 47 this.targetSourcedBeans.add(beanName); 48 } 49 /** 4.1.獲取當前bean所有的增強陣列 */ 50 Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource); 51 /** 4.2.根據增強陣列為目標物件建立代理物件 */ 52 Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource); 53 this.proxyTypes.put(cacheKey, proxy.getClass()); 54 /** 4.3.返回代理bean*/ 55 return proxy; 56 } 57 return null; 58 }
例項化前置方法邏輯不多,主要是判斷有沒有自定義的TargetSource物件,如果有自定義的則直接獲取增強建立代理,如果不是則直接返回null
其中核心步驟之一
方法postProcessAfterInitialization原始碼解析
1 @Override 2 public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) { 3 if (bean != null) { 4 Object cacheKey = getCacheKey(bean.getClass(), beanName); 5 if (this.earlyProxyReferences.remove(cacheKey) != bean) { 6 /** 呼叫wrapIfNecessary方法為當前bean建立代理*/ 7 return wrapIfNecessary(bean, beanName, cacheKey); 8 } 9 } 10 return bean; 11 } 12 13 protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) { 14 /** 15 * 第一步:判斷當前bean是否已經存在targetSourcedBeans集合和advisedBeans中,並且如果是Advise相關bean則加入到advisedBeans集合中 16 * */ 17 if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) { 18 return bean; 19 } 20 if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) { 21 return bean; 22 } 23 if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) { 24 this.advisedBeans.put(cacheKey, Boolean.FALSE); 25 return bean; 26 } 27 28 /** 29 * 第二步:獲取當前bean所有的增強陣列,也就是Advisor陣列 30 * */ 31 Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null); 32 if (specificInterceptors != DO_NOT_PROXY) { 33 this.advisedBeans.put(cacheKey, Boolean.TRUE); 34 /** 35 * 第三步:將目標bean封裝成TargetSource物件,然後根據增強陣列建立目標物件的代理物件 36 * */ 37 Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean)); 38 this.proxyTypes.put(cacheKey, proxy.getClass()); 39 return proxy; 40 } 41 42 this.advisedBeans.put(cacheKey, Boolean.FALSE); 43 return bean; 44 }
初始化後置方法邏輯和例項化前置方法邏輯基本上差不多,同樣是先獲取當前bean的所有增強陣列,然後將增強陣列織入到bean中建立一個代理物件
總結這兩個方法可以看出建立代理的流程一共可以分成三步:
第一步:將當前的bean封裝成TargetSource物件,如果自定義優先使用自定義的TargetSource;如果沒有自定義則使用預設的SingletonTargetSource物件
第二步:獲取當前bean需要增強的所有Advisor陣列,也就是需要在這個bean上需要織入的增強物件陣列
第三步:根據目標物件的封裝物件TargetSource物件 和 增強陣列Advisor陣列 給當前的bean建立一個代理物件
第一步很好理解,實際就是建立一個TargetSource物件,TargetSource物件中持有目標bean的引用,通過TargetSource物件可以訪問到目標物件bean
第二步是獲取當前bean需要織入的所有增強陣列,通過呼叫getAdvicesAndAdvisorForBean方法實現,而getAdvicesAndAdvisorForBean方法是通過子類AbstractAdvisorAutoProxyCreator類實現,原始碼如下:
1 /** 2 * 獲取當前bean所有的增強 3 * */ 4 @Override 5 @Nullable 6 protected Object[] getAdvicesAndAdvisorsForBean( 7 Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) { 8 9 /** 呼叫findEligibleAdvisors方法獲取Advisor列表*/ 10 List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName); 11 if (advisors.isEmpty()) { 12 return DO_NOT_PROXY; 13 } 14 return advisors.toArray(); 15 }
直接呼叫了內部的findEligibleAdvisors方法,繼續檢視原始碼:
1 /** 查詢Advisor列表*/ 2 protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) { 3 /** 4 * 1、查詢所有定義的Advisor列表 5 * 實現邏輯就是從BeanFactory根據Advisor型別查詢所有的Advisor例項,一種是實現來Advisor介面的,一種是被@Aspectj註解修飾的轉化成Advisor 6 * */ 7 List<Advisor> candidateAdvisors = findCandidateAdvisors(); 8 /** 9 * 2、根據bean來篩選出需要在當前bean上增強的Advisor列表 10 * 11 * */ 12 List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName); 13 extendAdvisors(eligibleAdvisors); 14 if (!eligibleAdvisors.isEmpty()) { 15 /** 3、對所有Advisor進行排序 */ 16 eligibleAdvisors = sortAdvisors(eligibleAdvisors); 17 } 18 return eligibleAdvisors; 19 }
該方法分成了三步,第一步是從BeanFactory中找到所有的Advisor集合,有的是實現了Advisor介面定義的,有的是通過@AspectJ註解定義轉化來的;第二步是找出匹配當前bean的所有Advisor;最後一步是對匹配的Advisor列表進行排序
可以發現第一步邏輯應該還比較清楚,就是從容器中找到所有的Advisor,第三步排序也比較好理解,核心是第二步匹配邏輯比較複雜,所以接下來就著重檢視Advisor是如何針對bean進行匹配的,方法為findAdvisorsThatCanApply,原始碼如下:
1 /** 2 * 查詢指定beanClass和beanName中需要增強的Advisor列表 3 * */ 4 protected List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) { 5 6 ProxyCreationContext.setCurrentProxiedBeanName(beanName); 7 try { 8 /** 直接呼叫AopUtils的findAdvisorThatCanApply方法*/ 9 return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass); 10 } 11 finally { 12 ProxyCreationContext.setCurrentProxiedBeanName(null); 13 } 14 }
直接呼叫了AopUtils工具類的findAdvisorsThatCanApply方法,原始碼如下:
1 public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) { 2 if (candidateAdvisors.isEmpty()) { 3 return candidateAdvisors; 4 } 5 List<Advisor> eligibleAdvisors = new ArrayList<>(); 6 /** 7 * 1、遍歷所有的Advisor, 呼叫canApply方法判斷當前的bean和當前的advisor是否匹配 8 * */ 9 for (Advisor candidate : candidateAdvisors) { 10 /** 11 * 2、首先判斷當前增強是否是引介增強,如果是執行canApply方法判斷是否匹配 12 * */ 13 if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) { 14 eligibleAdvisors.add(candidate); 15 } 16 } 17 boolean hasIntroductions = !eligibleAdvisors.isEmpty(); 18 for (Advisor candidate : candidateAdvisors) { 19 if (candidate instanceof IntroductionAdvisor) { 20 // already processed 21 continue; 22 } 23 /** 24 * 3、如果不是引介增強,則執行canApply方法判斷是否匹配 25 * */ 26 if (canApply(candidate, clazz, hasIntroductions)) { 27 eligibleAdvisors.add(candidate); 28 } 29 } 30 return eligibleAdvisors; 31 }
該方法的功能是從Advisor列表中篩選出所有和clazz匹配的增強列表,根據當前增強是否是引介增強(IntroductionAdvisor介面實現)分別呼叫過載的canApply方法進行判斷當前Advisor和當前的clazz是否匹配,所以判斷是否匹配的邏輯就在canApply方法中。
canApply方法原始碼如下:
1 /** 2 * 判斷當前增強advisor是否匹配當前的目標類targetClass 3 * */ 4 public static boolean canApply(Advisor advisor, Class<?> targetClass) { 5 //呼叫內部canApply方法 6 return canApply(advisor, targetClass, false); 7 } 8 9 /** 10 * 功能同上 11 * @param advisor:增強物件 12 * @param targetClass:目標類 13 * @param hasIntroductions:是否有引介增強 14 * */ 15 public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) { 16 if (advisor instanceof IntroductionAdvisor) { 17 /** 18 * 如果是引介增強,則呼叫IntroductionAdvisor的getClassFilter.matches方法判斷是否匹配 19 * */ 20 return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass); 21 } 22 else if (advisor instanceof PointcutAdvisor) { 23 /** 24 * 如果是普通增強,呼叫canApply方法判斷是否匹配 25 * */ 26 PointcutAdvisor pca = (PointcutAdvisor) advisor; 27 return canApply(pca.getPointcut(), targetClass, hasIntroductions); 28 } 29 else { 30 // It doesn't have a pointcut so we assume it applies. 31 return true; 32 } 33 }
1 public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) { 2 Assert.notNull(pc, "Pointcut must not be null"); 3 if (!pc.getClassFilter().matches(targetClass)) { 4 return false; 5 } 6 7 MethodMatcher methodMatcher = pc.getMethodMatcher(); 8 if (methodMatcher == MethodMatcher.TRUE) { 9 // No need to iterate the methods if we're matching any method anyway... 10 return true; 11 } 12 13 IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null; 14 if (methodMatcher instanceof IntroductionAwareMethodMatcher) { 15 introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher; 16 } 17 18 Set<Class<?>> classes = new LinkedHashSet<>(); 19 if (!Proxy.isProxyClass(targetClass)) { 20 classes.add(ClassUtils.getUserClass(targetClass)); 21 } 22 classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass)); 23 24 for (Class<?> clazz : classes) { 25 Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz); 26 for (Method method : methods) { 27 if (introductionAwareMethodMatcher != null ? 28 introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) : 29 methodMatcher.matches(method, targetClass)) { 30 return true; 31 } 32 } 33 } 34 35 return false; 36 }
通過第一步和第二步已經得到了需要織入增強的目標物件TargetSource和需要織入的所有增強Advisor陣列,最後一步就是呼叫createProxy方法將這兩者合併起來建立一個目標物件的代理過程,createProxy方法原始碼如下:
1 /** 2 * 建立代理 3 * */ 4 protected Object createProxy(Class<?> beanClass, @Nullable String beanName, @Nullable Object[] specificInterceptors, TargetSource targetSource) { 5 6 if (this.beanFactory instanceof ConfigurableListableBeanFactory) { 7 AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass); 8 } 9 10 /** 11 * 1.建立代理工廠類,並複製當前類的屬性 12 * */ 13 ProxyFactory proxyFactory = new ProxyFactory(); 14 proxyFactory.copyFrom(this); 15 16 if (!proxyFactory.isProxyTargetClass()) { 17 if (shouldProxyTargetClass(beanClass, beanName)) { 18 proxyFactory.setProxyTargetClass(true); 19 } 20 else { 21 evaluateProxyInterfaces(beanClass, proxyFactory); 22 } 23 } 24 25 /** 26 * 2.設定代理工廠屬性,將增強陣列advisors和目標物件targetSource加入到代理工廠中 27 * */ 28 Advisor[] advisors = buildAdvisors(beanName, specificInterceptors); 29 proxyFactory.addAdvisors(advisors); 30 proxyFactory.setTargetSource(targetSource); 31 customizeProxyFactory(proxyFactory); 32 33 proxyFactory.setFrozen(this.freezeProxy); 34 if (advisorsPreFiltered()) { 35 proxyFactory.setPreFiltered(true); 36 } 37 /** 38 * 3.呼叫代理工廠類的getProxy方法建立代理物件 39 * */ 40 return proxyFactory.getProxy(getProxyClassLoader()); 41 }
從原始碼可以看出,主要邏輯就是構建了一個ProxyFactory物件,然後是給ProxyFactory物件的屬性進行賦值,並且將增強屬性和目標物件都傳到代理工廠ProxyFactory中,而建立代理的過程最終是呼叫了ProxyFactory的getProxy方法進行建立,邏輯如下:
1 /** 建立代理物件*/ 2 public Object getProxy(@Nullable ClassLoader classLoader) { 3 //建立AopProxy物件,然後呼叫AopProxy物件的getProxy方法 4 return createAopProxy().getProxy(classLoader); 5 } 6 7 /** 建立AopProxy物件 */ 8 protected final synchronized AopProxy createAopProxy() { 9 if (!this.active) { 10 activate(); 11 } 12 //先獲取AopProxy工廠,然後建立AopProxy物件 13 return getAopProxyFactory().createAopProxy(this); 14 } 15 16 @Override 17 public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException { 18 /** 19 * 判斷條件選取是採用 JDK動態代理還是CGLIB代理 20 * isOptimize: 判斷是否採用優化策略,只有CGLIB代理才有效 21 * isProxyTargetClass: 該屬性對於<aop:aspectj-autoproxy/>標籤中的proxy-target-class屬性的值. 22 * 表示是否代理目標類本身,而不是目標類的介面 23 * 比如當前目標類為 GoodsServiceImpl 實現類 GoodsService介面 24 * 如果該屬性為false時,則建立的代理是代理的GoodsService介面,需要用JDK動態代理 25 * 如果該屬性為true時,則建立的代理是代理的GoodsServiceImpl本身,所以必須採用CGLIB來建立代理 26 * hasNoUserSuppliedProxyInterfaces :判斷是否存在代理介面 27 * */ 28 if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) { 29 Class<?> targetClass = config.getTargetClass(); 30 if (targetClass == null) { 31 throw new AopConfigException("TargetSource cannot determine target class: " + 32 "Either an interface or a target is required for proxy creation."); 33 } 34 if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) { 35 /** 如果目標物件是一個介面,則建立JDK動態代理物件 */ 36 return new JdkDynamicAopProxy(config); 37 } 38 /** 39 * 如果目標物件不是一個介面,則建立 CGLIB代理物件 40 * */ 41 return new ObjenesisCglibAopProxy(config); 42 } 43 else { 44 /** 建立 JDK動態代理物件 */ 45 return new JdkDynamicAopProxy(config); 46 } 47 }
該方法中對於AOP的引數進行了判斷,判斷當前的物件是採用JDK動態代理還是CGLIB代理,則分別建立不同的代理物件AopProxy實現類,至於如何選擇JDK動態代理還是CGLIB代理,大致規則如下:
(*** 重點 ***)
1、如果目標物件實現了介面,預設情況下會採用JDK動態代理;但是可以通過配置 proxy-target-class屬性的值為true強制使用CGLIB代理,則代理的是目標物件的本身
2、如果目標物件沒有實現介面,那麼必須採用CGLIB建立代理物件
到目前為止已經知道了如何一步一步建立的代理了,接下來就是不同型別的代理來對目標物件建立代理物件的邏輯了,主要是通過呼叫AopProxy物件的getProxy方法建立,不同型別的實現分別如下:
1、JDK動態代理建立代理物件
JDK動態代理建立物件是通過代理JdkDynamicAopProxy實現的,而JdkDynamicAopProxy實現了InvocationHandler介面
1 /** 2 * JDK動態代理建立代理物件 3 * */ 4 @Override 5 public Object getProxy() { 6 //呼叫內部過載方法getProxy 7 return getProxy(ClassUtils.getDefaultClassLoader()); 8 } 9 10 @Override 11 public Object getProxy(@Nullable ClassLoader classLoader) { 12 13 Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true); 14 findDefinedEqualsAndHashCodeMethods(proxiedInterfaces); 15 //建立代理例項,並且代理實現就是JdkDynamicAopProxy本身 16 return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this); 17 }
最終通過Proxy.newProxyInstance方法建立了代理物件,而代理執行者就是this,也就是JdkDynamicAopProxy本身,所以目標物件的所有方法執行都會執行到JdkDynamicAopProxy物件的invoke方法
注:此處涉及到Java的動態代理技術,不懂的同學可以參考文章:Java技術整理--反射機制及動態代理詳解
既然目標物件的方法執行最終都會執行JdkDynamicAopProxy的invoke方法,所以核心就在於該方法的實現,原始碼如下:(以下是AOP動態代理最終的核心邏輯)
1 @Override 2 @Nullable 3 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 4 Object oldProxy = null; 5 boolean setProxyContext = false; 6 7 /** 獲取目標物件 */ 8 TargetSource targetSource = this.advised.targetSource; 9 Object target = null; 10 11 try { 12 //處理equals方法 13 if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) { 14 return equals(args[0]); 15 } 16 //處理hash方法 17 else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) { 18 return hashCode(); 19 } 20 //如果目標物件是DecoratingProxy型別,則返回目標物件的最終物件型別 21 else if (method.getDeclaringClass() == DecoratingProxy.class) { 22 return AopProxyUtils.ultimateTargetClass(this.advised); 23 } 24 /** 25 * 如果目標物件是Advice介面型別,則直接使用反射進行呼叫 26 * */ 27 else if (!this.advised.opaque && method.getDeclaringClass().isInterface() && 28 method.getDeclaringClass().isAssignableFrom(Advised.class)) { 29 return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args); 30 } 31 32 Object retVal; 33 34 /** 35 * 判斷是否暴露代理物件,通過<aop:aspectj-autoproxy expose-proxy="true"/>設定 36 * 當exposeProxy為true時,AopContext會在ThreadLocal中就將代理物件設定進去,就可以通過AopContext.getCurrentProxy方法獲取當前的代理物件 37 * 主要是用來解決目標物件內部呼叫無法織入增強的問題 38 * */ 39 if (this.advised.exposeProxy) { 40 // Make invocation available if necessary. 41 oldProxy = AopContext.setCurrentProxy(proxy); 42 setProxyContext = true; 43 } 44 45 //獲取目標物件 46 target = targetSource.getTarget(); 47 //獲取目標物件的Class物件 48 Class<?> targetClass = (target != null ? target.getClass() : null); 49 50 /** 獲取當前方法上的攔截器鏈*/ 51 List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); 52 53 if (chain.isEmpty()) { 54 //通過反射直接呼叫目標物件的方法 55 Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args); 56 retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse); 57 } 58 else { 59 //將攔截器鏈封裝到MethodInvocation物件中 60 MethodInvocation invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain); 61 /** 然後執行攔截器鏈 */ 62 retVal = invocation.proceed(); 63 } 64 65 //獲取方法返回結果的型別 66 Class<?> returnType = method.getReturnType(); 67 if (retVal != null && retVal == target && 68 returnType != Object.class && returnType.isInstance(proxy) && 69 !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) { 70 // Special case: it returned "this" and the return type of the method 71 // is type-compatible. Note that we can't help if the target sets 72 // a reference to itself in another returned object. 73 retVal = proxy; 74 } 75 else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) { 76 throw new AopInvocationException( 77 "Null return value from advice does not match primitive return type for: " + method); 78 } 79 return retVal; 80 } 81 finally { 82 if (target != null && !targetSource.isStatic()) { 83 // Must have come from TargetSource. 84 targetSource.releaseTarget(target); 85 } 86 if (setProxyContext) { 87 // 88 AopContext.setCurrentProxy(oldProxy); 89 } 90 } 91 } 92 93 @Override 94 @Nullable 95 public Object proceed() throws Throwable { 96 /** 97 * 當前所以的增強方法執行完畢後,通過反射執行目標物件的方法 98 * */ 99 if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) { 100 return invokeJoinpoint(); 101 } 102 103 Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex); 104 if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) { 105 // Evaluate dynamic method matcher here: static part will already have 106 // been evaluated and found to match. 107 InterceptorAndDynamicMethodMatcher dm = 108 (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice; 109 Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass()); 110 if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) { 111 return dm.interceptor.invoke(this); 112 } 113 else { 114 // Dynamic matching failed. 115 // Skip this interceptor and invoke the next in the chain. 116 return proceed(); 117 } 118 } 119 else { 120 /** 121 * 執行普通攔截器的邏輯 122 * */ 123 return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this); 124 } 125 }
總結代理物件執行目標物件方法的邏輯:
1、 將所有增強封裝成方法攔截器MethodInterceptor物件,生成攔截器鏈
2、按順序依次執行攔截器鏈上所有的攔截器邏輯,直到所有的攔截器邏輯通過反射執行完成,最終會通過反射執行目標物件的方法
3、攔截器的執行順序是先執行後置增強攔截器、再執行環繞增強攔截器、然後再執行前置增強攔截器、最終才是執行目標物件的方法
後置增強攔截器處理邏輯是先執行其他攔截器邏輯,在finally中執行後置攔截器的本身邏輯,程式碼如下:
1 @Override 2 public Object invoke(MethodInvocation mi) throws Throwable { 3 try { 4 /** 5 * 繼續執行其他方法攔截器 6 * */ 7 return mi.proceed(); 8 } 9 finally { 10 /** 11 * 最終通過反射執行後置增強攔截器本身的邏輯 12 * */ 13 invokeAdviceMethod(getJoinPointMatch(), null, null); 14 } 15 }
異常增強攔截器處理邏輯是通過try/catch捕獲攔截器鏈的執行,一旦拋異常就通過反射執行本身的邏輯,程式碼如下:
1 @Override 2 public Object invoke(MethodInvocation mi) throws Throwable { 3 try { 4 /** 5 * 執行攔截器鏈方法 6 * */ 7 return mi.proceed(); 8 } 9 catch (Throwable ex) { 10 if (shouldInvokeOnThrowing(ex)) { 11 /** 12 * 如果攔截器鏈方法拋異常,則通過反射執行異常增強本身方法 13 * */ 14 invokeAdviceMethod(getJoinPointMatch(), null, ex); 15 } 16 throw ex; 17 } 18 }
環繞增強攔截器處理邏輯是執行通過反射執行環繞增強攔截器的邏輯,而在環繞增強邏輯中會執行 JoinPoint的proceed()繼續執行攔截器鏈路的方法,程式碼如下:
1 @Override 2 public Object invoke(MethodInvocation mi) throws Throwable { 3 if (!(mi instanceof ProxyMethodInvocation)) { 4 throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi); 5 } 6 ProxyMethodInvocation pmi = (ProxyMethodInvocation) mi; 7 ProceedingJoinPoint pjp = lazyGetProceedingJoinPoint(pmi); 8 JoinPointMatch jpm = getJoinPointMatch(pmi); 9 /** 通過反射執行環繞增強的邏輯*/ 10 return invokeAdviceMethod(pjp, jpm, null, null); 11 }
前置增強攔截器處理邏輯是先執行前置攔截器本身的邏輯,然後再執行攔截器鏈的其他方法,程式碼如下:
1 @Override 2 public Object invoke(MethodInvocation mi) throws Throwable { 3 /** 通過反射先執行前置增強的本身邏輯*/ 4 this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis()); 5 /** 繼續執行攔截器鏈路的其他邏輯 */ 6 return mi.proceed(); 7 }
所以如果有多個前置處理器,先執行invoke方法的前置處理器會先後執行橫切邏輯;而如果有多個後置處理器,先執行invoke方法的後置處理器,會後執行本身的橫切邏輯
2、CGLIB動態代理建立代理物件
CGLIb代理建立代理物件是通過ObjenesisCglibAopProxy物件實現,ObjenesisCglibAopProxy繼承於CglibAopProxy,獲取代理的方法同樣也是getProxy,實現邏輯如下:
1 @Override 2 public Object getProxy() { 3 /** 呼叫內部過載方法getProxy*/ 4 return getProxy(null); 5 } 6 7 @Override 8 public Object getProxy(@Nullable ClassLoader classLoader) { 9 10 try { 11 /** 獲取目標物件的Class物件*/ 12 Class<?> rootClass = this.advised.getTargetClass(); 13 Class<?> proxySuperClass = rootClass; 14 if (rootClass.getName().contains(ClassUtils.CGLIB_CLASS_SEPARATOR)) { 15 proxySuperClass = rootClass.getSuperclass(); 16 Class<?>[] additionalInterfaces = rootClass.getInterfaces(); 17 for (Class<?> additionalInterface : additionalInterfaces) { 18 this.advised.addInterface(additionalInterface); 19 } 20 } 21 22 23 /** 24 * 構造Enhancer物件,並設定Enhancer物件的各種屬性 25 * */ 26 Enhancer enhancer = createEnhancer(); 27 if (classLoader != null) { 28 enhancer.setClassLoader(classLoader); 29 if (classLoader instanceof SmartClassLoader && 30 ((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) { 31 enhancer.setUseCache(false); 32 } 33 } 34 enhancer.setSuperclass(proxySuperClass); 35 enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised)); 36 enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE); 37 enhancer.setStrategy(new ClassLoaderAwareGeneratorStrategy(classLoader)); 38 39 Callback[] callbacks = getCallbacks(rootClass); 40 Class<?>[] types = new Class<?>[callbacks.length]; 41 for (int x = 0; x < types.length; x++) { 42 types[x] = callbacks[x].getClass(); 43 } 44 // fixedInterceptorMap only populated at this point, after getCallbacks call above 45 enhancer.setCallbackFilter(new ProxyCallbackFilter( 46 this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset)); 47 enhancer.setCallbackTypes(types); 48 49 /** 呼叫createProxyClassAndInstance方法建立代理物件 */ 50 return createProxyClassAndInstance(enhancer, callbacks); 51 } 52 catch (CodeGenerationException | IllegalArgumentException ex) { 53 throw new AopConfigException("Could not generate CGLIB subclass of " + this.advised.getTargetClass() + 54 ": Common causes of this problem include using a final class or a non-visible class", 55 ex); 56 } 57 catch (Throwable ex) { 58 throw new AopConfigException("Unexpected AOP exception", ex); 59 } 60 } 61 62 protected Object createProxyClassAndInstance(Enhancer enhancer, Callback[] callbacks) { 63 enhancer.setInterceptDuringConstruction(false); 64 enhancer.setCallbacks(callbacks); 65 /** 執行Enhancer的create方法建立代理物件*/ 66 return (this.constructorArgs != null && this.constructorArgTypes != null ? 67 enhancer.create(this.constructorArgTypes, this.constructorArgs) : 68 enhancer.create()); 69 } 70 71 public Object create() { 72 classOnly = false; 73 argumentTypes = null; 74 return createHelper(); 75 } 76 77 private Object createHelper() { 78 preValidate(); 79 Object key = KEY_FACTORY.newInstance((superclass != null) ? superclass.getName() : null, 80 ReflectUtils.getNames(interfaces), 81 filter == ALL_ZERO ? null : new WeakCacheKey<CallbackFilter>(filter), 82 callbackTypes, 83 useFactory, 84 interceptDuringConstruction, 85 serialVersionUID); 86 this.currentKey = key; 87 Object result = super.create(key); 88 return result; 89 } 90 91 protected Object create(Object key) { 92 try { 93 ClassLoader loader = getClassLoader(); 94 Map<ClassLoader, ClassLoaderData> cache = CACHE; 95 ClassLoaderData data = cache.get(loader); 96 if (data == null) { 97 synchronized (AbstractClassGenerator.class) { 98 cache = CACHE; 99 data = cache.get(loader); 100 if (data == null) { 101 Map<ClassLoader, ClassLoaderData> newCache = new WeakHashMap<ClassLoader, ClassLoaderData>(cache); 102 data = new ClassLoaderData(loader); 103 newCache.put(loader, data); 104 CACHE = newCache; 105 } 106 } 107 } 108 this.key = key; 109 Object obj = data.get(this, getUseCache()); 110 if (obj instanceof Class) { 111 return firstInstance((Class) obj); 112 } 113 return nextInstance(obj); 114 } 115 catch (RuntimeException | Error ex) { 116 throw ex; 117 } 118 catch (Exception ex) { 119 throw new CodeGenerationException(ex); 120 } 121 }
CGLIB 是一套強大的高效能的程式碼生成工具包,底層通過位元組碼生成技術ASM框架來實現,由於直接實現ASM需要熟悉JVM內部結構以及Class檔案格式和指令集,所以不推薦直接使用ASM,而CGLIB就是在ASM框架基礎之上的封裝。所以在繼續分析CGLIB實現AOP邏輯原理之前可以先熟悉下CGLIB的用法。
2.1、CGLIB的使用案例
第一步:定義目標類
1 public class UserService { 2 3 public void addUser(){ 4 System.out.println("新增新使用者"); 5 } 6 7 public void getUser(){ 8 System.out.println("查詢使用者資訊"); 9 } 10 }
定義UserService類,注意這裡是類而不是介面,因為CGLIB是原理是給目標類生成子類,而不是實現介面
第二步:定義Callback,或者說是方法攔截器,或者說就是AOP中的增強邏輯
1 package com.lucky.test.spring.cglib; 2 3 import org.springframework.cglib.proxy.MethodInterceptor; 4 import org.springframework.cglib.proxy.MethodProxy; 5 import java.lang.reflect.Method; 6 7 /** 8 * 自定義方法攔截器 9 */ 10 public class CglibMethodInterceptor implements MethodInterceptor { 11 @Override 12 public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { 13 14 System.out.println("前置增強方法執行"); 15 16 /** 執行父類方法 */ 17 Object result = methodProxy.invokeSuper(o, objects); 18 19 System.out.println("後置增強方法執行"); 20 return result; 21 } 22 }
自定義方法攔截器實現了CGLIB包中的MethodInterceotor介面,該介面繼承之Callback介面,在實現中插入了前置增強和後置增強邏輯,並且在實現中通過MethodProxy.invokeSuper方法執行了父類的方法
第三步:建立子類
1 /** 建立目標類的子類例項*/ 2 public static Object getInstance(Class superClass, Callback callback){ 3 Enhancer enhancer = new Enhancer(); 4 //設定父類 5 enhancer.setSuperclass(superClass); 6 //設定回撥,MethodInterceptor就是繼承的Callback介面 7 enhancer.setCallback(callback); 8 //通過位元組碼生成技術,建立目標類superClass的子類例項 9 return enhancer.create(); 10 }
CGLIB建立目標類子類是通過Enhancer類的create方法建立的,所以在建立之前需要先構造一個Enhancer物件,然後設定父類、callback等屬性,最後通過ASM框架的位元組碼生成技術建立目標類的子類
第四步:測試程式碼如下:
1 public static void main(String[] args){ 2 3 //新建方法攔截器物件 4 MethodInterceptor callback = new CglibMethodInterceptor(); 5 //構造目標類的子類 6 UserService userService = (UserService)getInstance(UserService.class, callback); 7 //執行目標類方法,實際執行的是子類的方法 8 userService.addUser(); 9 }
先建立Callback實現類MethodInterceptor的例項,然後呼叫getInstance方法傳入目標類UserService.class和方法攔截器CglibMethodInterceptor物件獲取目標類的子類例項,最好執行子類方法,結果如下:
1 前置增強方法執行 2 新增新使用者 3 後置增強方法執行
通過CGLIB建立子類的方式,成功實現了AOP的增強邏輯織入。
2.2、Spring AOP 的CGLIB生成代理的實現邏輯總結
(**重點*)
1、獲取到目標物件的Class物件
2、獲取所有的增強Advisor列表,並全部封裝成Callback實現類MethodIncetor物件
3、構造Enhancer物件,並設定屬性將目標類和需要新增的Callback全部設定為Enhancer的屬性
4、通過呼叫Enhancer物件的create方法通過底層ASM框架的位元組碼生成技術建立目標物件的子類
5、獲取到目標物件的子類,通過子類的方法,在子類方法中相當於也是執行了Callback的鏈,和JDK的方法攔截器流程類似
6、每次執行子類方法,都會執行鏈路上的所有Callback的intercept方法,在方法內部執行增強邏輯,並執行invokeSuper方法執行父類(目標類)的方法