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

歡迎訪問 生活随笔!

生活随笔

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

javascript

跟着小马哥学系列之 Spring AOP(AbstractAutoProxyCreator 详解)

發布時間:2024/3/13 javascript 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 跟着小马哥学系列之 Spring AOP(AbstractAutoProxyCreator 详解) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

學成路更寬,吊打面試官。 ——小馬哥

版本修訂

  • 2021.5.19:去除目錄

簡介

大家好,我是小馬哥成千上萬粉絲中的一員!2019年8月有幸在叩丁狼教育舉辦的猿圈活動中知道有這么一位大咖,從此結下了不解之緣!此系列在多次學習極客時間《小馬哥講Spring AOP 編程思想》基礎上形成的個人一些總結。希望能幫助各位小伙伴, 祝小伙伴早日學有所成。

AbstractAutoProxyCreator 功能

從命名可知這個抽象類主要功能就是自動創建代理,怎么實現自動?這就得與 Spring IoC 容器打通。所以此抽象類實現了 SmartInstantiationAwareBeanPostProcessor 和 BeanFactoryAware

  • 使用 AOP 代理包裝每個合格 bean 用 BeanPostProcessor 實現,在調用 bean 本身之前將委托給指定的攔截器。
  • 這個類區分了公共的攔截器(為它創建的所有代理共享)以及 特定的攔截器(每個 bean 實例都是唯一的)。如果有公共的攔截器,則使用 interceptorNames 屬性設置它們(與 ProxyFactoryBean 一樣,使用當前工廠中的攔截器名稱而不是 bean 引用來允許正確處理原型 advisor 和攔截器)
  • 如果有大量 bean 需要用類似的代理進行包裝,即委托給相同的攔截器,那么這種自動代理特別有用。您可以向 bean 工廠注冊一個這樣的后處理程序來實現相同的效果,而不是為 x 個目標 bean 重復定義 x 個代理。
  • 子類可以應用任何策略(子類可以實現 getAdvicesAndAdvisorsForBean 方法)來決定一個 bean 是否要被代理,例如根據類型、名稱、定義細節等。它們還可以返回應該只應用于特定 bean 實例的額外攔截器。一個簡單的具體實現是 BeanNameAutoProxyCreator,它通過給定的名稱標識要代理的 bean。
  • 任意的 TargetSourceCreator 實現都可以用于創建自定義目標源:例如,將原型對象池化。即使沒有 advice,只要 TargetSourceCreator 指定了自定義 TargetSource,也會發生自動代理。如果沒有設置 TargetSourceCreators ,或者沒有匹配的,默認情況下將使用 SingletonTargetSource 來包裝目標 bean 實例。

AbstractAutoProxyCreator 類圖

相關類介紹

AopInfrastructureBean

標記接口,用于識別 Spring AOP 基礎結構一部分的 bean,避免當 Pointcut 匹配時生成代理對象。

ProxyConfig

用于創建代理時配置的便利超類,以確保所有代理創建器具有一致的屬性。

主要配置:

  • proxyTargetClass:同 @EnableAspectJAutoProxy 中的屬性 proxyTargetClass 一樣語義,是否使用 CGLIB 代理,默認是 false 使用 JDK 基于接口的動態代理
  • optimize:設置代理是否應該執行主動優化。主動優化的確切含義在不同的代理之間是不同的,但通常會有一些權衡。默認設置是 false。例如,優化通常意味著在創建代理之后通知更改不會生效。因此,優化在默認情況下是禁用的。如果其他設置排除了優化,那么“true”的優化值可能會被忽略;例如,如果 exposeProxy 被設置為 true,而這與優化不兼容。
  • opaque:默認值是 false,任何 AOP 代理都可以強制轉換為 Advised。
  • exposeProxy:同 @EnableAspectJAutoProxy 中的屬性 exposeProxy 一樣語義,是否將代理對象暴露在 AopContext 類中。
  • frozen:設置該配置是否應該被凍結。當一個配置被凍結時,不能做出任何 Advice 更改。這對于優化很有用,當我們不希望調用方能夠在強制轉換為 Adviced 后操作配置時也很有用。
  • ProxyProcessorSupport

    具有代理處理器通用功能的基類,特別是 ClassLoader 管理和 evaluateProxyInterfaces 算法。

    管理 ClassLoader

    通過屬性 boolean classLoaderConfigured 管理屬性 proxyClassLoader 只允許設置一次

    evaluateProxyInterfaces() 方法解讀

    檢查給定 bean 類上的接口,并將它們應用到 ProxyFactory(如果可用的話)。調用 isConfigurationCallbackInterface(Class<?>) 和 sInternalLanguageInterface(Class<?>) 來過濾合理的代理接口。如果沒有可用接口則使用 CGLIB 代理。

    protected void evaluateProxyInterfaces(Class<?> beanClass, ProxyFactory proxyFactory) {// 獲取類中的所有接口,如果是接口返回它自己Class<?>[] targetInterfaces = ClassUtils.getAllInterfacesForClass(beanClass, getProxyClassLoader());boolean hasReasonableProxyInterface = false;/*** 獲取的接口列表,只要接口列表滿足一個不是 Spring 框架 InitializingBean、DisposableBean、Aware 接口擴展接口和* 不是 Jdk 中 AutoCloseable 和 Closeable 接口并且不是內部語言接口(接口名稱是 groovy.lang.GroovyObject* 或者是以 .cglib.proxy.Factory 結尾或者 .bytebuddy.MockAccess 結尾)并且不是空接口*/for (Class<?> ifc : targetInterfaces) {if (!isConfigurationCallbackInterface(ifc) && !isInternalLanguageInterface(ifc) &&ifc.getMethods().length > 0) {hasReasonableProxyInterface = true;break;}}// 如果有可代理的接口添加到代理工廠中if (hasReasonableProxyInterface) {for (Class<?> ifc : targetInterfaces) {proxyFactory.addInterface(ifc);}}else {// 沒有接口就設置 CGLIB 代理proxyFactory.setProxyTargetClass(true);} }

    BeanFactoryAware

    實現 setBeanFactory((BeanFactory beanFactory) 方法。并且該實現類交由 Spring IoC 管理。則由 Spring IoC 容器在填充普通 bean 屬性之后,但在初始化回調(如 iinitializingBean.afterPropertiesSet() 或自定義初始化方法之前調用。

    BeanPostProcessor

    Bean 的后置處理器,可以通過實現此接口覆寫 postProcessBeforeInitialization 和 postProcessAfterInitialization 方法對 bean 進行修改,比如 AbstractAutoProxyCreato 就是通過覆寫 postProcessAfterInitialization 返回代理對象

    InstantiationAwareBeanPostProcessor

    BeanPostProcessor 的子接口,它添加了一個實例化之前的回調函數和一個實例化之后但在顯式屬性設置或自動裝配發生之前的回調函數。通常用于抑制特定目標 bean 的默認實例化,例如創建帶有特殊 targetsource 的代理(池化目標、延遲初始化目標等),或者實現額外的注入策略,如字段注入。

    SmartInstantiationAwareBeanPostProcessor

    此接口擴展了 InstantiationAwareBeanPostProcessor接口,添加一個 predictBeanType 回調,用于預測已處理 bean 的最終類型。

    AopProxy

    通過委派已配置的 Aop 代理接口,創建實際的代理對象。Spring AOP 通過 DefaultAopProxyFactory 提供了開箱即用 的 JDK 動態代理(JdkDynamicAopProxy) 和 CGLIB 代理(ObjenesisCglibAopProxy)

    • 通過 getProxy方法獲取代理對象(默認的 ClassLoader)
    • 通過指定 ClassLoader 的 getProxy(@Nullable ClassLoader classLoader) 方法獲取代理對象

    AopProxyFactory

    基于 AdvisedSupport 配置對象新增 AOP 代理的工廠接口

    代理應該遵守以下契約:

    • 應該實現配置的所有接口
    • 實現 Advised 接口
    • 實現 equals 方法用于比較代理接口、advice 和 目標對象
    • 如果所有的 advisor 和 目標對象都是可序列化的,代理對象應該也是可序列化的
    • 如果 advisor 和目標對象是線程安全的則代理對象也應該是線程安全的

    唯一實現:DefaultAopProxyFactory#createAopProxy(AdvisedSupport config) 方法分析

    AopProxyFactory 默認實現,創建不是 JDK 動態代理就是 CGLIB 代理。

    @Override public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {/*** 對于給定的 AdvisedSupport 實例,如果滿足以下任意條件,則創建一個 CGLIB 代理:* 1. 優化標志被設置* 2. proxyTargetClass 標志被設置(即使設置了如果被代理對象是接口還是使用 JDK 動態代理)* 3. 沒有指定代理接口*/ 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.");}// 目標對象是接口或者是已經被 JDK 動態代理代理過的對象則創建 JDK 動態代理if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {return new JdkDynamicAopProxy(config);}return new ObjenesisCglibAopProxy(config);}else {return new JdkDynamicAopProxy(config);} }

    AbstractAutoProxyCreator 簡介

    AdvisorAdapterRegistry 管理

    • 通過 advisorAdapterRegistry 屬性管理 AdvisorAdapterRegistry 默認是 GlobalAdvisorAdapterRegistry(DefaultAdvisorAdapterRegistry),
    • 可以通過 setAdvisorAdapterRegistry() 方法進行設置

    TargetSourceCreator 使用

    在前面 AbstractAutoProxyCreator 功能介紹最后一條中介紹即使沒有 Advice,只要 TargetSourceCreator 指定了自定義 TargetSource,也會發生自動代理,將會在 postProcessBeforeInstantiation 介紹

    • 可以通過 setCustomTargetSourceCreators(TargetSourceCreator… targetSourceCreators) 方法設置

    公共攔截器管理

    • 通過 interceptorNames 屬性管理公共攔截器
    • 通過 setInterceptorNames(String... interceptorNames)方法進行設置
    • 通過 setApplyCommonInterceptorsFirst(boolean applyCommonInterceptorsFirst) 方法設置公共攔截器與特殊攔截的先后順序

    BeanFactory 管理

    由于 AbstractAutoProxyCreator 實現了 BeanFactoryAware 便于底層 IoC 打通,具有依賴查找的能力

    • 通過 getBeanFactory() 獲取 BeanFactory
    • setBeanFactory 方法由 Spring IoC 容器回調

    SmartInstantiationAwareBeanPostProcessor 實現

    @Override@Nullablepublic Class<?> predictBeanType(Class<?> beanClass, String beanName) {// 如果代理類型緩存為空則跳過if (this.proxyTypes.isEmpty()) {return null;}/*** 如果 bean 名稱為空則 cacheKey 則是類對象;* 如果有 bean 類型是 FactoryBean 則 cacheKey 則是 &beanName;* 否則 cacheKey 就是 beanName*/Object cacheKey = getCacheKey(beanClass, beanName);// 通過 cacheKey 去代理類型緩存獲取return this.proxyTypes.get(cacheKey);}@Override@Nullablepublic Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, String beanName) {return null;}@Overridepublic Object getEarlyBeanReference(Object bean, String beanName) {/*** 如果 bean 名稱為空把 bean Class 對象作為 cacheKey ;* 如果有 bean 類型是 FactoryBean 則 cacheKey 則是 &beanName;* 否則 cacheKey 就是 beanName*/Object cacheKey = getCacheKey(bean.getClass(), beanName);// 緩存早期代理引用this.earlyProxyReferences.put(cacheKey, bean);// 根據條件生成代理return wrapIfNecessary(bean, beanName, cacheKey);}

    獲取代理對象

    wrapIfNecessary() 方法分析

    protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {// 如果通過了自定義 TargetSourceCreator 方式處理過目標實例則不需要代理if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {return bean;}// 內部基礎 bean 或者不需要代理的 bean 則不代理if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {return bean;}/*** 是否是基礎設施(默認規則 Advice、Pointcut、Advisor、AopInfrastructureBean)* 或者不需要進行代理(默認規則是否是類名與 bean 名稱長度必須相同并且 bean 名稱以類名開頭以 .ORIGINAL)則不代理。并放入 advisedBeans 緩存中*/if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) { // 方入 advisedBean 緩存以便重復創建 bean 時提供性能this.advisedBeans.put(cacheKey, Boolean.FALSE);return bean;}// 根據子類實現不同的規則獲取 Advice/Advisor.Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);// 滿足生成代理對象條件if (specificInterceptors != DO_NOT_PROXY) {// 放入緩存this.advisedBeans.put(cacheKey, Boolean.TRUE);// 生成代理對象(子類可覆寫)Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));// 放入代理類型緩存this.proxyTypes.put(cacheKey, proxy.getClass());return proxy;}// 如果沒有符合條件的 advice 則不生成代理并緩存this.advisedBeans.put(cacheKey, Boolean.FALSE);return bean; }

    createProxy() 方法分析

    protected Object createProxy(Class<?> beanClass, @Nullable String beanName,@Nullable Object[] specificInterceptors, TargetSource targetSource) {/*** 獲取 beanName 的 BeanDefinition 并設置一個* 屬性名為 org.springframework.aop.framework.autoproxy.AutoProxyUtils.originalTargetClass 值為 beanClass 屬性*/if (this.beanFactory instanceof ConfigurableListableBeanFactory) {AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);}// 通過 ProxyFactory 來創建代理對象ProxyFactory proxyFactory = new ProxyFactory();proxyFactory.copyFrom(this);// 使用 JDK 動態代理if (!proxyFactory.isProxyTargetClass()) {/*** 通過 beanName 的 BeanDefinition 獲取屬性名 * org.springframework.aop.framework.autoproxy.AutoProxyUtils.originalTargetClass.preserveTargetClass* 的屬性值是否為 true 如果是 true 即使 proxyFactory.isProxyTargetClass() 是 false 還是會使用 CGLIB 動態代理*/if (shouldProxyTargetClass(beanClass, beanName)) {proxyFactory.setProxyTargetClass(true);}else {// 父類 ProxyProcessorSupport#evaluateProxyInterfaces 方法在上面已經分析過了evaluateProxyInterfaces(beanClass, proxyFactory);}}// 構建 Advisor(后面分析)Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);proxyFactory.addAdvisors(advisors);proxyFactory.setTargetSource(targetSource);// 空方法留給子類擴展customizeProxyFactory(proxyFactory);// 是否凍結代理對象(默認是 false)proxyFactory.setFrozen(this.freezeProxy);// 是否對 Advisor 預過濾(默認是 false 留給子類擴展 AbstractAdvisorAutoProxyCreator 是 true)if (advisorsPreFiltered()) {proxyFactory.setPreFiltered(true);}// 通過代理工廠根據 ClassLoader 獲取代理對象 return proxyFactory.getProxy(getProxyClassLoader()); }

    buildAdvisors() 方法分析

    確定給定 bean 的 Advisor,包括特定的攔截器和公共攔截器,然后把這些攔截器都適配成 Advisor 對象。

    protected Advisor[] buildAdvisors(@Nullable String beanName, @Nullable Object[] specificInterceptors) {/*** 根據內部關聯 BeanFactory 通過 IoC 根據公共的攔截器的 bean 名稱獲取 bean * 然后再通過內部關聯的 DefaultAdvisorAdapterRegistry 包裝成類型為`DefaultPointcutAdvisor` 的 Advisor*/Advisor[] commonInterceptors = resolveInterceptorNames();List<Object> allInterceptors = new ArrayList<>();// 特定的攔截器不為空再根據是否設置了公共攔截器在前,合并這些攔截器if (specificInterceptors != null) {allInterceptors.addAll(Arrays.asList(specificInterceptors));if (commonInterceptors.length > 0) {if (this.applyCommonInterceptorsFirst) {allInterceptors.addAll(0, Arrays.asList(commonInterceptors));}else {allInterceptors.addAll(Arrays.asList(commonInterceptors));}}}Advisor[] advisors = new Advisor[allInterceptors.size()];for (int i = 0; i < allInterceptors.size(); i++) {// 通過內部關聯的 DefaultAdvisorAdapterRegistry 把攔截器包裝成 Advisoradvisors[i] = this.advisorAdapterRegistry.wrap(allInterceptors.get(i));}return advisors; }

    子類

    AbstractAdvisorAutoProxyCreator

    自動構建 Advisor 代理列表,子類覆寫 findCandidateAdvisors() 獲取 Advisor 列表。也可以通過覆寫 AbstractAutoProxyCreator.shouldSkip(java.lang.Class<?>, java.lang.String) 方法跳過自動代理。 通過 @Order 注解或者實現 Ordered 接口來控制 Adivosr/Advice。通過 AnnotationAwareOrderComparator 來排序 Advisor/Advice。沒有 @Order 注釋或沒有實現 Ordered 接口的 Advisor 將被認為是無序的;它們將以未定義的順序出現在 Advisor 鏈的末尾。

    方法

    getAdvicesAndAdvisorsForBean() 方法

    實現 AbstractAutoProxyCreator#getAdvicesAndAdvisorsForBean 方法,委派給本類 findEligibleAdvisors() 方法(子類可以覆寫)

    @Override @Nullable protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {// 委派給 findEligibleAdvisors() 方法(子類可以覆寫)List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);if (advisors.isEmpty()) {return DO_NOT_PROXY;}return advisors.toArray(); }
    findEligibleAdvisors() 方法
    protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {// 通過 IoC 容器獲取所有 Advisor 實例List<Advisor> candidateAdvisors = findCandidateAdvisors();/*** 如果 Advisor 類型是 IntroductionAdvisor 獲取關聯的 ClassFilter 進行匹配* 如果 Advisor 類型是 PointcutAdvisor 獲取關聯的 ClassFilter 進行匹配,如果匹配成功再獲取 MethodMatcher 進行靜態匹配(2個參數 matches() 方法 )*/List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);// 擴展接口子類實現extendAdvisors(eligibleAdvisors);if (!eligibleAdvisors.isEmpty()) {// 進行排序eligibleAdvisors = sortAdvisors(eligibleAdvisors);}return eligibleAdvisors; }

    AspectJAwareAdvisorAutoProxyCreator

    AbstractAdvisorAutoProxyCreator 子類,它暴露 AspectJ 的調用上下文,并在多個 advice 來自相同的 aspect 時推斷 AspectJ 的 advice 優先級規則(AspectJPrecedenceComparator 比較器)。

    主要覆蓋方法

    • extendAdvisors:通過 ExposeInvocationInterceptor 把 MethodInvocation 暴露到上下文,以便在 AspectJ 中操作(例如 AbstractAspectJAdvice#currentJoinPoint 方法和 AspectJExpressionPointcut#matches(Method method, Class<?> targetClass, Object… args) 方法)
    • shouldSkip:通過定義的 Aspect
    • sortAdvisors:通過 PartiallyComparableAdvisorHolder 中關聯的AnnotationAwareOrderComparator 進行排序

    AnnotationAwareAspectJAutoProxyCreator

    AspectJAwareAdvisorAutoProxyCreator 子類,它處理當前應用上下文用中所有的 AspectJ 中 @Aspect 注解 以及 Spring Advisor ,通過 ReflectiveAspectJAdvisorFactory 和 BeanFactoryAspectJAdvisorsBuilderAdapter 相互搭配實現

    主要覆蓋方法

    findCandidateAdvisors() 方法
    @Override protected List<Advisor> findCandidateAdvisors() {// 通過 Spring IoC 容器獲取所有 Advisor BeanList<Advisor> advisors = super.findCandidateAdvisors();// 通過 Spring IoC 容器獲取所有標注 @AspectJ 注解的 Bean,再獲取標注 AspectJ 注解(除了@Pointcut 其他的注解 @After、@Before、@AfterReturning 等)的方法if (this.aspectJAdvisorsBuilder != null) {advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());} return advisors; }

    總結

    自動代理創建主要利用 Spring IoC 的 BeanPostProcessor#postProcessAfterInitialization 方法進行擴展,再利用 getAdvicesAndAdvisorsForBean 模板方法根據不同規則獲取 Advice/Advisor(比如 Bean 名稱,Bean 類型以及 AspectJ ),然后由 ProxyFactory 委派給 DefaultAopProxyFactory(默認,也可以替換)獲取代理對象

    總結

    以上是生活随笔為你收集整理的跟着小马哥学系列之 Spring AOP(AbstractAutoProxyCreator 详解)的全部內容,希望文章能夠幫你解決所遇到的問題。

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