日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

Spring Aop 组件概述

發布時間:2025/3/15 javascript 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Spring Aop 组件概述 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
  • Spring Aop 概述
  • AOP(Aspect-Oriented Programming) 面向切面編程, 這種編程模型是在 OOP(Object-Oriented Programming) 的基礎上誕生的一種編程模型, 我們可以簡單的將其理解為: 在程序中具有公共特性的某些類/某些方法上進行攔截, 在方法執行的前面/后面/執行結果返回后 增加執行一些方法 (PS: 對, 就這么簡單, 最起碼 Spring 中是這樣的); 在 Spring 中主要通過了CGLib|動態代理來實現 -> CGLib(通過實現一個子類來控制對原始類的方法調用) 與 Proxy(創建一個 Proxy 類, 內部通過反射來調用原始類) 來實現 <-- 這兩個實現類都可以通過 HSDB 來獲取! , 對于 aop 主要有以下組件

  • Spring Aop 組件 -> Pointcut
  • Pointcut: 這個類位于 “org.springframework.aop” 包中, 它的主要作用還是定義切面的匹配點, 在 Spring Aop 中匹配的點主要是 class 與 method 這兩個方面, 分別為 ClassFilter 與 MethodFilter

    // 由 ClassFilter 與 MethodMatcher 組成的 pointcut public interface Pointcut {// 類過濾器, 可以知道哪些類需要攔截ClassFilter getClassFilter();// 方法匹配器, 可以知道哪些方法需要攔截MethodMatcher getMethodMatcher();// 匹配所有對象的 PointcutPointcut TRUE = TruePointcut.INSTANCE; }

    上面的接口中定義了 Pointcut 的主要方法, 從中我們可以看出, Pointcut 的匹配主要是根據 class 與 method 來進行匹配的; 在 Spring 中主要有以下幾類:

  • NameMatchMethodPointcut: 通過正則表達式匹配方法名字的 Pointcut (PS: 其中 ClassFilter = ClassFilter.TRUE)
  • ControlFlowPointcut: 根據在當前線程的堆棧信息中的方法名來決定是否切入某個方法
  • ComposablePointcut: 組合模式的 Pointcut, 主要分成兩種: 1.組合中所有都匹配算成功 2. 組合中都不匹配才算成功
  • TransactionAttributeSourcePointcut: 通過 TransactionAttributeSource 在 類的方法上提取事務注解的屬性 @Transactional 來判斷是否匹配, 提取到則說明匹配, 提取不到則說明匹配不成功
  • AnnotationJCacheOperationSource: 通過 AnnotationJCacheOperationSource 在方法上提取注解 CacheResult, CachePut,CacheRemove, CacheRemoveAll 來判斷是否匹配成功 (PS: 這與TransactionAttributeSourcePointcut相似 )
  • AspectJExpressionPointcut: 通過 AspectJ 包中的組件進行方法的匹配
  • JdkRegexpMethodPointcut: 通過 正則表達式來匹配方法 上述中的TransactionAttributeSourcePointcut 其實就是Spring注解式事務的 Pointcut, 通過匹配方法上
    @Transactional 標簽來確定方法是否匹配; 而 AspectJExpressionPointcut 其實就是 AspectJ
    包中的工具類來進行匹配
  • Spring Aop 組件 -> Advice
  • Advice: 建議忠告, 勸告, 通知, 這其實最開始是 aopalliance 包中的一個空接口, 接口的存在主要是為了標示對應類為 Advice; 而在Spring Aop 中 Advice 其實表示的是在 Pointcut 點上應該執行的方法, 而這個方法可以在 Pointcut 的前面/后面/包裹 Pointcut/Pointcut拋出異常時/整個 Pointcut 執行成功返回時執行 <- 有時語言不能完全解釋代碼所想表達的意思, 那我們直接來看代碼吧!

    • Advice: 其主要分成兩類: 普通advice 與 Interceptor/MethodInterceptor,
    • 通常Spring是將被AspectJ 標注的方法解析成各種 Advice(BeforeAdvice, AfterAdvice, ThrowingAdvice, AfterReturingAdvice 或 AspectJMethodBeforeAdvice, AspectJAfterAdvice,
      AspectJAfterReturningAdvice, AspectJAfterThrowingAdvice, AspectJAroundAdvice)
    1. Advice: 1.1 MethodBeforeAdvice: 在切面方法之前前執行的方法, 主要有以下類別CountingBeforeAdvice: 它是MethodCounter的子類,MethodCounter中通過 Map 來統計方法執行的次數, 是其最簡單的一個實現;AspectJMethodBeoreAdvice:這是通過解析被 org.aspectj.lang.annotation.Before 注解注釋的方法時解析成的Advice1.2 AfterReturningAdvice: 在切面方法執行后(這里的執行后指不向外拋異常, 否則的話就應該是 AspectJAfterThrowingAdvice 這種 Advice); 主要有以下幾種類型CountingAfterReturningAdvice: 是最簡單的 ReturningAdvice(PS: CountingAfterReturningAdviceMethodCounter的子類,MethodCounter中通過 Map 來統計方法執行的次數)AspectJAfterAdvice: 解析 AspectJ 中的 After 屬性來生成的 Advice(PS: 在java中的實現其實就是在 finally 方法中調用以下對應要執行的方法)AspectJAfterReturningAdvice: 解析 AspectJ 中的 AfterReturning 屬性來生成的 Advice(PS: 若切面方法拋出異常, 則這里的方法就將不執行)AspectJAfterThrowingAdvice: 解析 AspectJ 中的 AfterThrowing 屬性來生成的 Advice(PS: 若切面方法拋出異常, 則這里的方法就執行)1.3 AspectJAroundAdvice: 將執行類 MethodInvocation(MethodInvocation其實就是Pointcut) 進行包裹起來, 并控制其執行的 Advice (其中 Jdk中中 Proxy 使用 ReflectiveMethodInvocation,Cglib 則使用 CglibMethodInvocation)(PS: 注意上面只是 Advice, 而在 JdkDynamicProxy中執行的是 MethodInterceptor, 對于這層接口的適配則都是交給 AdvisorAdapter -> 將 advice 適配成 MethodInterceptor)2. MethodInterceptor: 2.1 ExposeInvocationInterceptor: 將當前 MethodInvocation 放到當前線程對應的 ThreadLoadMap 里面的, 這是一個默認的 Interceptor,AspectJAwareAdvisorAutoProxy獲取何時的 Advisor 時會調用自己的 extendAdvisors 方法, 從而將 ExposeInvocationInterceptor 方法執行鏈表的第一位2.2 SimpleTraceInterceptor:MethodInvocation 的信息寫入 日志的 MethodInterceptor2.3 AfterReturningAdviceInterceptor: 這個類其實就是將 AfterReturningAdvice 包裹成 MethodInterceptor 的適配類, 而做對應適配工作的就是 AfterReturningAdviceAdapter2.4 MethodBeforeAdviceInterceptor: 這個類其實就是將 MethodBeforeAdvice 包裹成 MethodInterceptor 的適配類, 而做對應適配工作的就是 MethodBeforeAdviceAdapter2.5 NopInterceptor: 非常簡單的 MethodInterceptor, 其進行方法調用的統計技術這樣的工作2.6 ThrowsAdviceInterceptor: 這個類其實就是將 ThrowsAdvice 包裹成 MethodInterceptor 的適配類, 而做對應適配工作的就是 ThrowsAdviceAdapter2.7 TransactionInterceptor: 這個類就是大名鼎鼎的注解式事務的工具類, 這個類通過獲取注解在方法上的 @Transactional 注解的信息來決定是否開啟事務的 MethodInterceptor (PS: 在注解式事務編程中將詳細敘述)

    上面的 Advice 類別概述, 而又有以下說明:

  • 無論通過aop命名空間/AspectJ注解注釋的方法, 其最終都將解析成對應的 Advice
  • 所有解析的 Advice 最終都將適配成 MethodInterceptor, 并在 JdkDynamicAopProxy/CglibAopProxy中進行統一調用
  • Spring Aop 組件 -> Advisor
  • Advisor 其實它就是 Pointcut 與 Advice 的組合, Advice 是執行的方法, 而要知道方法何時執行, 則 Advice 必需與 Pointcut 組合在一起, 這就誕生了 Advisor 這個類(PS: 你可以嘗試這樣理解 -> Advice表示建議,Pointcut表示建議的地點, Advisor表示建議者, 建議的者擁有建議的功能, 并且知道在哪兒建議 <- 純屬于歪歪), 主要有以下幾個類:

  • PointcutAdvisor: 我們在 Spring 中常用的 Advisor, 包含一個 Pointcut 與一個 advice
  • AspectJPointcutAdvisor: 這個是 Spring 解析 aop 命名空間時生成的 Advisor(與之對應的 Advice 是 AspectJMethodBeforeAdvice, AspectJAfterAdvice,
    AspectJAfterReturningAdvice, AspectJAfterThrowingAdvice,
    AspectJAroundAdvice, Pointcut 則是AspectJExpressionPointcut), 對于這個類的解析是在
    ConfigBeanDefinitionParser
  • InstantiationModelAwarePointcutAdvisorImpl: 這個Advisor是在Spring解析被 @AspectJ注解注釋的類時生成的 Advisor, 而這個 Advisor中的 Pointcut與Advice都是由
    ReflectiveAspectJAdvisorFactory 來解析生成的(與之對應的 Advice 是
    AspectJMethodBeforeAdvice, AspectJAfterAdvice,
    AspectJAfterReturningAdvice, AspectJAfterThrowingAdvice,
    AspectJAroundAdvice, Pointcut 則是AspectJExpressionPointcut), 解析的步驟是:
    AnnotationAwareAspectJAutoProxyCreator.findCandidateAdvisors() ->
    BeanFactoryAspectJAdvisorsBuilder.buildAspectJAdvisors() ->
    ReflectiveAspectJAdvisorFactory.getAdvisors() ->
    ReflectiveAspectJAdvisorFactory.getAdvisor() 最終生成了
    InstantiationModelAwarePointcutAdvisorImpl (當然包括里面的 Pointcut 與 advice
    也都是由 ReflectiveAspectJAdvisorFactory 解析生成的)
  • TransactionAttributeSourceAdvisor: 一個基于 MethodInterceptor(其實是 TransactionInterceptor)與 TransactionAttributeSourcePointcut 的Advisor,而這個類最常與 TransactionProxyFactoryBean使用
  • DefaultPointcutAdvisor: 最常用的 Advisor, 在使用編程式aop時, 很多時候會將 Advice / MethodInterceptor 轉換成 DefaultPointcutAdvisor
  • NameMatchMethodPointcutAdvisor: 這個是在使用 NameMatchPointcutAdvisor時創建的 Advisor, 主要是通過 方法名來匹配是否執行 Advice
  • RegexpMethodPointcutAdvisor: 基于正則表達式來匹配 Pointcut 的 Advisor, 其中的 Pointcut 默認是 JdkRegexpMethodPointcut
  • DefaultBeanFactoryPointcutAdvisor: Spring 中解析 <aop:advisor> 時生成的 Advisor, 見 ConfigBeanDefinitionParser.parseAdvisor
  • BeanFactoryTransactionAttributeSourceAdvisor: 在注解式事務編程時, 主要是由 BeanFactoryTransactionAttributeSourceAdvisor,
    AnnotationTransactionAttributeSource, TransactionInterceptor
    組合起來進行事務的操作(PS: AnnotationTransactionAttributeSource 主要是解析方法上的
    @Transactional注解, TransactionInterceptor 是個 MethodInterceptor,
    是正真操作事務的地方, 而BeanFactoryTransactionAttributeSourceAdvisor其實起著組合它們的作用); 與之相似的還有 BeanFactoryCacheOperationSourceAdvisor
  • Spring Aop 組件 -> Advised
  • Advised: 已經被建議的對象(主要是代理生成的對象與AdvisedSupport), 其中蘊含了:

    // 這個 Advised 接口的實現著主要是代理生成的對象與AdvisedSupport (Advised的支持器) public interface Advised extends TargetClassAware {// 這個 frozen 決定是否 AdvisedSupport 里面配置的信息是否改變boolean isFrozen();// 是否代理指定的類, 而不是一些 Interfaceboolean isProxyTargetClass();// 返回代理的接口Class<?>[] getProxiedInterfaces();// 判斷這個接口是否是被代理的接口boolean isInterfaceProxied(Class<?> intf);// 設置代理的目標對象void setTargetSource(TargetSource targetSource);// 獲取代理的對象TargetSource getTargetSource();// 判斷是否需要將 代理的對象暴露到 ThreadLocal中, 而獲取對應的代理對象則通過 AopContext 獲取void setExposeProxy(boolean exposeProxy);// 返回是否應該暴露 代理對象boolean isExposeProxy();// 設置 Advisor 是否已經在前面過濾過是否匹配 Pointcut (極少用到)void setPreFiltered(boolean preFiltered);// 獲取 Advisor 是否已經在前面過濾過是否匹配 Pointcut (極少用到)boolean isPreFiltered();// 獲取所有的 AdvisorAdvisor[] getAdvisors();// 增加 Advisor 到鏈表的最后void addAdvisor(Advisor advisor) throws AopConfigException;// 在指定位置增加 Advisorvoid addAdvisor(int pos, Advisor advisor) throws AopConfigException;// 刪除指定的 Advisorboolean removeAdvisor(Advisor advisor);// 刪除指定位置的 Advisorvoid removeAdvisor(int index) throws AopConfigException;// 返回 Advisor 所在位置de indexint indexOf(Advisor advisor);// 將指定的兩個 Advisor 進行替換boolean replaceAdvisor(Advisor a, Advisor b) throws AopConfigException;// 增加 Advice <- 這個Advice將會包裹成 DefaultPointcutAdvisorvoid addAdvice(Advice advice) throws AopConfigException;// 在指定 index 增加 Advice <- 這個Advice將會包裹成 DefaultPointcutAdvisorvoid addAdvice(int pos, Advice advice) throws AopConfigException;// 刪除給定的 Adviceboolean removeAdvice(Advice advice);// 獲取 Advice 的索引位置int indexOf(Advice advice);// 將 ProxyConfig 通過 String 形式返回String toProxyConfigString(); }

    其實它主要完成的是以下幾點:

    1. Proxy代理的Interface 2. 代理的對象 TargetSource 3. 包裹這個 AdvisedAdvisor, 以及對它的增刪 4.Advice 的增刪 而其主要的實現者是:1. AdvisedSupport: 這個類內部是 List<Advisor>, Advisor[], interfaces, DefaultAdvisorChainFactory(判斷 Advisor 是否適合當前的方法), targetSource 2. ProxyCreatorSupport: 這個類繼承 AdvisedSupport, 但是在這個類中主要還是通過 AopProxyFactory 來完成代理對象的創建,ProxyCreatorSupport.createAopProxy() 3. ProxyFactory: 這個類通過構造函數中的 proxyInterface/interceptor/targetSource 來創建代理對象(這個類是編程式 AOP 中最常用的對象) 4. ProxyFactoryBean: 這個類是基于 FactoryBeanProxy創建形式, 其通過代理的 Interface, targetSource 與指定的 interceptorNames 來創建對應的AopProxy, 最后生成對應的代理對象 5. AspectJProxyFactory: 將一個被 @AspectJ 注解標示的類丟入其中, 變創建了對應的代理對象 (這個類現在已經很少用了, 關于如何使用, 可以看這里(http://elim.iteye.com/blog/2397922))
  • Spring Aop 組件 -> TargetSource
  • TargetSource: 這個類的概念其實是動態代理作用的對象, 在 Spring 中又可以分為:

    1. HotSwappableTargetSource: 進行線程安全的熱切換到對另外一個對象實施動態代理操作 2. AbstractPoolingTargetSource: 每次進行生成動態代理對象時都返回一個新的對象 3. ThreadLocalTargetSource: 為每個進行請求的線程維護一個對象的 TargetSource 4. SingletonTargetSource: 最普遍最基本的單例 TargetSource,Spring 中生成動態代理對象, 一般都是用這個 TargetSource
  • Spring Aop 組件 -> AdvisorChainFactory
  • AdvisorChainFactory: 這個接口主要定義了從 Advised中獲取 Advisor 并判斷其是否與 對應的 Method 相匹配, 最終返回的是MethodInterceptor; 其中對 Advisor 轉化成 MethodInterceptor 的工作都是交由 DefaultAdvisorAdapterRegistry 來完成, 下面就是其主邏輯:

    // 獲取匹配 targetClass 與 method 的所有切面的通知 @Override public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Advised config, Method method, Class<?> targetClass) {// This is somewhat tricky... We have to process introductions first,// but we need to preserve order in the ultimate list.List<Object> interceptorList = new ArrayList<Object>(config.getAdvisors().length); // PS: 這里 config.getAdvisors 獲取的是 advisors 是數組Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());boolean hasIntroductions = hasMatchingIntroductions(config, actualClass); // 判斷是有 IntroductionAdvisor 匹配到// 下面這個適配器將通知 [Advice] 包裝成攔截器 [MethodInterceptor]; 而 DefaultAdvisorAdapterRegistry則是適配器的默認實現AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();for (Advisor advisor : config.getAdvisors()) { // 獲取所有的 Advisorif (advisor instanceof PointcutAdvisor) { // advisor 是 PointcutAdvisor 的子類// Add it conditionally.PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;// 判斷此切面 [advisor] 是否匹配 targetClass (PS: 這里是類級別的匹配)if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {/** 通過對適配器將通知 [Advice] 包裝成 MethodInterceptor, 這里為什么是個數組? 因為一個通知類* 可能同時實現了前置通知[MethodBeforeAdvice], 后置通知[AfterReturingAdvice], 異常通知接口[ThrowsAdvice]* 環繞通知 [MethodInterceptor], 這里會將每個通知統一包裝成 MethodInterceptor*/MethodInterceptor[] interceptors = registry.getInterceptors(advisor);MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();// 是否匹配 targetClass 類的 method 方法 (PS: 這里是方法級別的匹配)if (MethodMatchers.matches(mm, method, actualClass, hasIntroductions)) {if (mm.isRuntime()) { // 看了對應的所有實現類, 只有 ControlFlowPointcut 與 AspectJExpressionPointcut 有可能 返回 true// 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)); // 里面裝的是 Advise 與 MethodMatcher}}else {interceptorList.addAll(Arrays.asList(interceptors));}}}}else if (advisor instanceof IntroductionAdvisor) { // 這里是 IntroductionAdvisor// 如果是引入切面的話則判斷它是否適用于目標類, Spring 中默認的引入切面實現是 DefaultIntroductionAdvisor 類// 默認的引入通知是 DelegatingIntroductionInterceptor 它實現了 MethodInterceptor 接口sIntroductionAdvisor 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; }
  • Spring Aop 組件 -> DefaultAdvisorAdapterRegistry
  • DefaultAdvisorAdapterRegistry: 這里類里面存在著 MethodBeforeAdviceAdapter, AfterReturningAdviceAdapter, ThrowsAdviceAdapter 。 這三個類是將 Advice適配成MethodInterceptor 的適配類; 而其本身具有兩個重要的功能:

  • 將 Advice/MethodInterceptor 包裹成 DefaultPointcutAdvisor
  • 通過上面的三個適配類將 Advisor 中的 Advice 適配成對應的MethodInterceptor (PS: 在代理對象執行時, 執行的都是MethodInterceptor, 當然在進行配置時既可以配置 Advice, MethodInterceptor, Advisor)
  • Spring Aop 組件 -> AopProxyFactory
  • AopProxyFactory: 這個接口中定義了根據 AdvisedSupport 中配置的信息來生成合適的AopProxy (主要分為 基于Java 動態代理的 JdkDynamicAopProxy 與基于 Cglib 的ObjenesisCglibAopProxy), 主邏輯如下:

    public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {// 啟用了 優化配置(原因就是 cglib 的性能比 JDK Proxy 要好) || 啟用了直接代理目標類模式 || 沒有指定要代理的接口(除了 接口SpringProxy)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.");}// 代理的對象是否是接口 或 targetClass 是否是 java.lang.reflect.Proxy 的子類if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) { return new JdkDynamicAopProxy(config);}// 創建 cglib 代理的工廠對象return new ObjenesisCglibAopProxy(config);}else {// 返回創建 JDK 代理的工廠對象return new JdkDynamicAopProxy(config);} }

    PS: 這里補充個知識點 Cglib 生成代理類的速度比 Proxy 生成的慢(幾乎到10倍數), 但其執行速度是 Proxy 的 10倍 (可能基于不同版本的 jar 包測出的數據會稍有不同),而在我們日常使用中 JdkDynamicAopProxy 是最常使用的, 下面直接看一下其執行的主邏輯

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {MethodInvocation invocation;Object oldProxy = null;boolean setProxyContext = false;// 目標對象的包裝類, 通過 AdvisedSupport的setTarget方法設置的會自動封閉成 TargetSource 的實現 SingletonTargetSourceTargetSource targetSource = this.advised.targetSource;Class<?> targetClass = null;Object target = null;try {// 被代理的接口中沒有定義 equals 方法且目前方法是 equals 方法, 則調用 equals 方法比較兩代對象所代理的接口if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {// The target does not implement the equals(Object) method itself.// 如果目標對象沒有實現 object 類的基礎方法 euqalsreturn equals(args[0]);}// hashCode 方法的處理else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {// The target does not implement the hashCode() method itself.// 如果目標對象沒有實現 object 類的基礎方法 hashCodereturn hashCode();}// 如果調用的方法是 DecoratingProxy聲明的else if (method.getDeclaringClass() == DecoratingProxy.class) {// There is only getDecoratedClass() declared -> dispatch to proxy config.return AopProxyUtils.ultimateTargetClass(this.advised);}/*** Class類的 isAssignableFrom(Class cls) 方法:* 自身類.class.isAssignableFrom(自身類或子類.class) 返回 true** 對 Advised 接口或者子接口中的方法的調用不經過任何攔截器, 直接委托給Advised 對象中的方法* (此 if 塊 的目的是實現將 advised 對象引入代理對象), this.advised.opaque 默認情況下是 false(它只是一個開關* 選項, 控制代理對象是否可以操作 advised)*/else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&method.getDeclaringClass().isAssignableFrom(Advised.class)) {// Service invocations on ProxyConfig with the proxy config...// 調用 advised 的method 方法return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);}Object retVal;// 當目標對象內部的自我調用無法實施切面中的增強則需要增強則需要通過此屬性暴露代理if (this.advised.exposeProxy) {// 把當前代理對象放到 AopContext 中(其內部使用 ThreadLocal 存著), 并返回上下文中原來的代理對象, 并且保留之前暴露設置的代理// Make invocation available if necessary.oldProxy = AopContext.setCurrentProxy(proxy);setProxyContext = true;}// May be null. Get as late as possible to minimize the time we "own" the target,// in case it comes from a pool.// 得到目標對象target = targetSource.getTarget();if (target != null) {targetClass = target.getClass();}// 獲取當前方法的攔截器鏈// Get the interception chain for this method.List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);// Check whether we have any advice. If we don't, we can fallback on direct// reflective invocation of the target, and avoid creating a MethodInvocation.// 檢測是否含有 MethodInterceptorif (chain.isEmpty()) {// 沒有任何攔截器需要執行則直接執行目標對象方法// We can skip creating a MethodInvocation: just invoke the target directly// Note that the final invoker must be an InvokerInterceptor so we know it does// nothing but a reflective operation on the target, and no hot swapping or fancy proxying.Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);}else {/*** 如果有攔截器的設定, 那么需要調用攔截器之后才調用目標對象的相應方法* 通過 構造一個 ReflectiveMethodInvocation 來實現, 下面會看* 這個 ReflectiveMethodInvocation 類的具體實現*/// We need to create a method invocation...invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);// Proceed to the joinpoint through the interceptor chain.// 執行攔截器鏈retVal = invocation.proceed();}// Massage return value if necessary.Class<?> returnType = method.getReturnType();// 處理返回目標對象本身的情況, 也許某些方法是返回this引用, 此時需要返回代理對象而不是目標對象if (retVal != null && retVal == target &&returnType != Object.class && returnType.isInstance(proxy) &&!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {// Special case: it returned "this" and the return type of the method// is type-compatible. Note that we can't help if the target sets// a reference to itself in another returned object.retVal = proxy;}else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) { // 從這里我們可以發現, 攔截器的返回值若設定的不是 null, 但是 你主動設置為 null, 則將會報出異常throw new AopInvocationException("Null return value from advice does not match primitive return type for: " + method);}return retVal;}finally {if (target != null && !targetSource.isStatic()) {// Must have come from TargetSource.// 如果此 targetSource 不是一個靜態的 targetSource, 那么釋放此 target, 默認的 SingletonTargetSource.isStatic 方法是 true 的targetSource.releaseTarget(target);}if (setProxyContext) {// Restore old proxy.// 還原之前的代理對象AopContext.setCurrentProxy(oldProxy);}} }
  • Spring Aop 組件 -> Joinpoint的子類 MethodInvocation
  • MethodInvocation 是進行 invoke 對應方法/MethodInterceptor的類, 其主要分成用于 Proxy 的 ReflectiveMethodInvocation, 與用于 Cglib 的 CglibMethodInvocation; ReflectiveMethodInvocation 其實就是遞歸的調用 MethodInterceptor, 當沒有 MethodInterceptor可以調用時, 則執行對應的切面點的方法, 如下:

    /*** 實現前置增強在目標方法前調用, 后置增強在目標方法后調用*/ @Override public Object proceed() throws Throwable {// 執行完所有增強執行切點方法// currentInterceptorIndex 默認等于 -1 的, 它記錄著當前執行到了哪個攔截器// interceptorsAndDynamicMethodMatchers 代表著匹配了的 MethodInterceptor// We start with an index of -1 and increment early.if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {// 如果所有的 攔截器都執行完了的話, 則調用 invokeJoinPoint 方法去執行目標對象的目標方法 (反射)return invokeJoinpoint();}// 得到當前要執行的攔截器(攔截器是順序執行的 )Object interceptorOrInterceptionAdvice =this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);// 下面判斷當前攔截器是不是一個動態攔截器if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) { // 其實在 Spring 中 主要的實現類是 AspectJExpressionPointcut// 動態 匹配 方法 攔截// Evaluate dynamic method matcher here: static part will already have// been evaluated and found to match.InterceptorAndDynamicMethodMatcher dm =(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;// 這里調用 MethodMatcher 類中帶3個參數的 matches 方法if (dm.methodMatcher.matches(this.method, this.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 {// 將 this作為參數(MehtodInvocation)傳遞以保證當前實例中調用鏈的執行// 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);} }
  • Spring Aop 組件 -> AbstractAutoProxyCreator
  • AbstractAutoProxyCreator: 這個類是聲明式 Aop 編程中非常重要的一個角色, 我們可以從以下幾點來解析它:

    1. AbstractAutoProxyCreator繼承了 ProxyProcessorSupport, 所以它具有了ProxyConfig中動態代理應該具有的配置屬性 2. AbstractAutoProxyCreator 實現了 SmartInstantiationAwareBeanPostProcessor(包括實例化的前后置函數, 初始化的前后置函數) 并進行了實現 3. 實現了 創建代理類的主方法 createProxy 方法 4. 定義了抽象方法 getAdvicesAndAdvisorsForBean(獲取 Bean對應的 Advisor) AbstractAutoProxyCreator 中等于是構建了創建 Aop 對象的主邏輯, 而其子類 AbstractAdvisorAutoProxyCreator 實現了getAdvicesAndAdvisorsForBean 方法, 并且通過工具類 BeanFactoryAdvisorRetrievalHelper(PS: 它的方法findAdvisorBeans中實現類獲取容器中所有 Advisor 的方法) 來獲取其對應的 Advisor;

    AbstractAutoProxyCreator 的子類中主要有以下幾個:

    1. AspectJAwareAdvisorAutoProxyCreator: 通過解析 aop 命名空間的配置信息時生成的 AdvisorAutoProxyCreator, 主要通過ConfigBeanDefinitionParser.parse() -> ConfigBeanDefinitionParser.configureAutoProxyCreator() -> AopNamespaceUtils.registerAspectJAutoProxyCreatorIfNecessary() -> AopNamespaceUtils.registerAspectJAutoProxyCreatorIfNecessary(); 與之對應的 PointcutAspectJExpressionPointcut, AdvisorAspectJPointcutAdvisor, Advice 則是 AspectJAfterAdvice, AspectJAfterReturningAdvice, AspectJAfterThrowingAdvice, AspectJAroundAdvice 2. AnnotationAwareAspectJAutoProxyCreator: 這是基于 @AspectJ注解生成的 切面類的一個 AbstractAutoProxyCreator, 解析額工作交給了 AspectJAutoProxyBeanDefinitionParser, 步驟如下AspectJAutoProxyBeanDefinitionParser.parse() -> AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary() -> AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary() 3. DefaultAdvisorAutoProxyCreator: 這個類也是 AbstractAutoProxyCreator的子類, 它帥選作用的類時主要是根據其中的 advisorBeanNamePrefix(類名前綴)配置進行判斷 4. BeanNameAutoProxyCreator: 通過類的名字來判斷是否作用(正則匹配)
  • 總結
    本篇主要介紹了 Spring-Aop 中的主要構建, 并進行相應的說明, 單純的講 aop 這個概念其實不復雜, 而在 Spring 中, 主要表現在如下幾點:
  • 1. 涉及的組件多 -> Pointcut, Advice, MethodInterceptor, Advised, Advisor, TargetSource, AopProxyFactory, MethodInvocation, AbstractAutoProxyCreator, 這也造成掌握 Spring-aop 的難度 2. 實現aop需要多個基礎功能的支持(AspectJ中的注解及注解解析, Cglib, java中的 Proxy, Asm字節碼(主要式解析方法中的參數名)) 3. 結合了 BeanPostProcessorBean的實例化/初始化階段就進行生成對應的代理類(比如 AspectJAwareAdvisorAutoProxyCreatorAnnotationAwareAspectJAutoProxyCreator

    https://www.jianshu.com/p/de624a4190c6

    總結

    以上是生活随笔為你收集整理的Spring Aop 组件概述的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。