您好,登錄后才能下訂單哦!
本篇內(nèi)容主要講解“如何理解AOP中JDK代理實現(xiàn)的原理”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學(xué)習(xí)“如何理解AOP中JDK代理實現(xiàn)的原理”吧!
動態(tài)代理技術(shù)在Spring AOP中分為兩種:
提供一種在運行時創(chuàng)建一個實現(xiàn)了一組接口的新類。由于Java是不支持實例化接口的,因此JDK會在運行期間生成一個代理類對給定的接口進行實現(xiàn),在調(diào)用該代理類接口的時候,將實現(xiàn)邏輯轉(zhuǎn)發(fā)到調(diào)用處理器中(Invocation handler)。
JDK進行動態(tài)代理的類必須實現(xiàn)接口
代理類是java.lang.reflect.Proxy子類,類名以$Proxy開始。
CGLIB(Code Generation Library)是基于ASM(對Java字節(jié)碼進行操作的框架)的類庫。
Spring AOP中,如果被代理類(targetObject)沒有實現(xiàn)接口,即無法通過JDK的動態(tài)代理生成代理類,那么就會選擇CGLIB來進行代理。
CGLIB動態(tài)代理的原理:創(chuàng)建一個targetObject的子類,覆蓋掉需要父類的方法,在覆蓋的方法中對功能進行增強。
注意,由于是采用繼承覆蓋的方式,所以由final方法修飾的類無法使用CGLIB進行代理。
JDK動態(tài)代理要求被代理類實現(xiàn)接口,切面類需要實現(xiàn)InvocationHandler。
CGLIB采用繼承+方法覆蓋實現(xiàn)切面,重寫方法將邏輯委托給MethodInterceptor#intercept。
CGLIB對代理類基本沒有限制,但是需要注意被代理的類不可以被final修飾符和private修飾,因為Java無法重寫final類/private的方法。
@EnableAspectJAutoProxy注解是Spring AOP開啟的標(biāo)志,在啟動類標(biāo)記此注解,即啟用可加載對應(yīng)的切面類邏輯。此注解的ElementType為TYPE,表示標(biāo)記在類上。
同時用 @Retention(RetentionPolicy.RUNTIME) 聲明了注解在運行時得到保留。此外最重要的是使用了 @Import(AspectJAutoProxyRegistrar.class) 來注冊AOP的。
@EnableAspectJAutoProxy注解正是通過@Import的方式來將 AspectJAutoProxyRegistrar類注冊成Spring的Bean,以便在容器解析切面類時派上用場。那么AspectJAutoProxyRegistrar類的作用是什么?
@Import(AspectJAutoProxyRegistrar.class)
@EnableAspectJAutoProxy支持處理標(biāo)有AspectJ的@Aspect批注的組件,用戶可以主動聲明proxyTargetClass來指定Spring AOP使用哪種動態(tài)代理方式來創(chuàng)建代理類(默認使用基于實現(xiàn)接口的JDK動態(tài)代理方式)。
使用CGLIB動態(tài)代理來創(chuàng)建代理類
@Configuration @EnableAspectJAutoProxy(proxyTargetClass=true) @ComponentScan("com.libo") public class AppConfig { // ... }
為了解決一些由于代理引發(fā)的切面失效問題,Spring AOP在Spring 4.3.1后引入了AopContext類來將代理類的引用存儲在ThreadLocal中,通過AopContext可以快速獲取當(dāng)前類的代理類。
默認為不支持,如果聲明為true,即可使用AopContext獲取代理類,同時,為了使用AspectJ,需要確保當(dāng)前jar倉庫存在aspectjweaver。
通過@Import注冊AspectJAutoProxyRegistrar,通常情況下,我們的啟動類本身也是一個Bean,Spring支持使用 @Import來導(dǎo)入一個沒有標(biāo)記任何Spring注解 的類來將該Java類注冊成Spring的Bean。
Registers an AnnotationAwareAspectJAutoProxyCreator against the current BeanDefinitionRegistry as appropriate based on a given @EnableAspectJAutoProxy annotation.
根據(jù)當(dāng)前BeanDefinitionRegistry在適當(dāng)?shù)奈恢米訟nnotationAwareAspectJAutoProxyCreator。
用來導(dǎo)入一些特殊的BeanDefinition,Spring在處理 @Configuration 時,會去掃描是否有通過 @Import 標(biāo)簽導(dǎo)入的類,對ImportBeanDefinitionRegistrar這類接口,還會執(zhí)行其中的registerBeanDefinitions方法。
AspectJAutoProxyRegistrar:實現(xiàn)了ImportBeanDefinitionRegistrar接口,用來注冊AspectJAnnotationAutoProxyCreator,也就是支持注解驅(qū)動(同時兼容XML)解析的AspectJ自動代理創(chuàng)建器。
class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar { @Override public void registerBeanDefinitions( AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { // 向容器注冊AspectJAnnotationAutoProxyCreator AopConfigUtils. registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry); AnnotationAttributes enableAspectJAutoProxy = AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class); // 如果@EnableAspectJAutoProxy上存在標(biāo)簽內(nèi)容 if (enableAspectJAutoProxy != null) { // proxyTargetClass為true,則強制指定AutoProxyCreator使用CGLIB進行代理 if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) { AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry); } // 是否開啟exposeProxy特性 if (enableAspectJAutoProxy.getBoolean("exposeProxy")) { AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry); } } } }
向容器注冊AspectJAnnotationAutoProxyCreator
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
隨后解析 @EnableAspectJAutoProxy 注解上的元數(shù)據(jù)來決定是否開啟上述我們講到的proxyTargetClass和exposeProxy特性.
為了了解registerBeanDefinitions方法的執(zhí)行鏈路和調(diào)用時機,我們使用IDE的debug來查看調(diào)用棧分析執(zhí)行流程。
org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader#loadBeanDefinitionsForConfigurationClass(configClass.getImportBeanDefinitionRegistrars())
這行代碼,從代碼的語義上我們可以大致可以猜出來,這是解析當(dāng)前配置類上是否存在通過@Import導(dǎo)入的實現(xiàn)了ImportBeanDefinitionRegistrar的類。
最終會調(diào)用AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary方法,注冊一個AnnotationAwareAspectJAutoProxyCreator,該類屬于AOP的核心類。
執(zhí)行AspectJAutoProxyRegistrar#registerBeanDefinitions方法。
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
@Nullable public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary( BeanDefinitionRegistry registry, @Nullable Object source) { return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source); }
從上面的代碼可以看出來AnnotationAwareAspectJAutoProxyCreator這個類作為實際操作者,查看該類的繼承關(guān)系圖。(省略一些不必要的類)。
首先看第一個接口,BeanPostProcessor,這個接口作為頂層接口,肯定不會被外部直接調(diào)用,所以大概率是底下的幾個具體實現(xiàn)類被調(diào)用,然后通過判斷是不是InstantiationAwareBeanPostProcessor接口的類型,再執(zhí)行相應(yīng)邏輯,帶著這個疑惑,來看源碼。
AbstractAutoProxyCreator通過postProcessAfterInitialization實現(xiàn)AOP功能。
// 在實例化之后進行操作容器對象 @Override public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) throws BeansException { if (bean != null) { Object cacheKey = getCacheKey(bean.getClass(), beanName); if (!this.earlyProxyReferences.contains(cacheKey)) { return wrapIfNecessary(bean, beanName, cacheKey); } } return bean; } protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) { // beanName不為空,并且存在于targetSourcedBeans中,也就是自定義的 // TargetSource被解析過了 if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) { return bean; } // 如果Bean為advisedBeans,也不需要被代理 if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) { return bean; } // isInfrastructureClass和shouldSkip的作用: // 識別切面類,加載切面類成advisors // 為什么又執(zhí)行一次是因為存在循環(huán)依賴的情況下無法加載advisor if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) { this.advisedBeans.put(cacheKey, Boolean.FALSE); return bean; } // Create proxy if we have advice. // 返回匹配當(dāng)前Bean的所有Advice、Advisor、Interceptor Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null); if (specificInterceptors != DO_NOT_PROXY) { this.advisedBeans.put(cacheKey, Boolean.TRUE); // 創(chuàng)建Bean對應(yīng)的代理,SingletonTargetSource用于封裝實現(xiàn)類的信息 Object proxy = createProxy( bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean)); this.proxyTypes.put(cacheKey, proxy.getClass()); return proxy; } // 下次代理不需要重復(fù)生成了 this.advisedBeans.put(cacheKey, Boolean.FALSE); return bean; }
判斷緩存中是否存在當(dāng)前Bean或者是當(dāng)前Bean已經(jīng)被代理過了,那么直接返回bean.
嘗試再次加載advisor,避免由于循環(huán)依賴導(dǎo)致advisor加載不完整.
獲取當(dāng)前bean符合的advisor數(shù)組.
創(chuàng)建代理類.
本文來分析getAdvicesAndAdvisorsForBean方法是如何在所有的advisors中找到匹配的advisor的.
@Override @Nullable protected Object[] getAdvicesAndAdvisorsForBean( Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) { List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName); if (advisors.isEmpty()) { return DO_NOT_PROXY; } return advisors.toArray(); } //這里調(diào)用了findEligibleAdvisors來尋找合適的advisors,如果返回的集合為空,那么 // 最后返回null. // 如果返回了advisors,將其數(shù)組化返回. protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) { //BeanFactory 中所有 Advisor 的實現(xiàn) List<Advisor> candidateAdvisors = findCandidateAdvisors(); // 有資格的 Advisor List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName); extendAdvisors(eligibleAdvisors); if (!eligibleAdvisors.isEmpty()) { eligibleAdvisors = sortAdvisors(eligibleAdvisors); } return eligibleAdvisors; } //首先獲取之前解析過的advisors列表-candidateAdvisors,這里是所有的切面類解析成的advisors. //在candidateAdvisors中找到當(dāng)前Bean匹配的advisor-findAdvisorsThatCanApply. //將獲取到的eligibleAdvisors進行排序. protected List<Advisor> findCandidateAdvisors() { Assert.state(this.advisorRetrievalHelper != null, "No BeanFactoryAdvisorRetrievalHelper available"); return this.advisorRetrievalHelper.findAdvisorBeans(); } protected List<Advisor> findAdvisorsThatCanApply( List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) { ProxyCreationContext.setCurrentProxiedBeanName(beanName); try { return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass); } finally { ProxyCreationContext.setCurrentProxiedBeanName(null); } } public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) { if (candidateAdvisors.isEmpty()) { return candidateAdvisors; } // 存儲最終匹配的Advisor集合 List<Advisor> eligibleAdvisors = new ArrayList<>(); for (Advisor candidate : candidateAdvisors) { // 當(dāng)前advisor對象是否實現(xiàn)了IntroductionAdvisor接口 if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) { eligibleAdvisors.add(candidate); } } boolean hasIntroductions = !eligibleAdvisors.isEmpty(); for (Advisor candidate : candidateAdvisors) { if (candidate instanceof IntroductionAdvisor) { // already processed continue; } // canApply->判斷當(dāng)前的advisor的pointcut表達式是否匹配當(dāng)前class if (canApply(candidate, clazz, hasIntroductions)) { eligibleAdvisors.add(candidate); } } return eligibleAdvisors; } //最終是調(diào)用了AopUtils.findAdvisorsThatCanApply來篩選匹配Bean的Advisors.
ProxyFactory 對象中有要代理的bean和這個Bean上的advisor
Bean使用哪種代理
當(dāng)Bean實現(xiàn)接口時,Spring就會用JDK的動態(tài)代理。 當(dāng)Bean沒有實現(xiàn)接口時,Spring會自動使用CGlib實現(xiàn),但是前提是項目中導(dǎo)入了CGlib的相關(guān)依賴,否則Spring只能使用JDK來代理那些沒有實現(xiàn)接口的類,這樣生成的代理類會報錯。 AopProxy有兩個實現(xiàn)類JdkDynamicAopProxy和CglibAopProxy。都是構(gòu)造 ReflectiveMethodInvocation.proceed()。
JdkDynamicAopProxy
invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain); retVal = invocation.proceed();
CglibAopProxy
// CglibMethodInvocation 繼承于 ReflectiveMethodInvocation retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
ReflectiveMethodInvocation.proceed()
public Object proceed() throws Throwable { // 當(dāng)所有攔截器都執(zhí)行后,調(diào)用目標(biāo)類的目標(biāo)方法 if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) { return invokeJoinpoint(); } Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex); if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) { // 動態(tài)攔截器 InterceptorAndDynamicMethodMatcher dm = (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice; 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 { // MethodInterceptor的實現(xiàn)類在處理完自己的邏輯后,還是會調(diào)用procee(),傳入this就是為了達到這個目的 return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this); } }
Spring用來處理應(yīng)用上下文中被@AspectJ注解標(biāo)記的類的。繼續(xù)進入registerOrEscalateApcAsRequired方法中看看注冊流程.
org.springframework.aop.config.AopConfigUtils#registerOrEscalateApcAsRequired private static BeanDefinition registerOrEscalateApcAsRequired( Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) { Assert.notNull(registry, "BeanDefinitionRegistry must not be null"); // 當(dāng)前容器是否包含 org.springframework.aop.config.internalAutoProxyCreator if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) { BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME); if (!cls.getName().equals(apcDefinition.getBeanClassName())) { int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName()); int requiredPriority = findPriorityForClass(cls); if (currentPriority < requiredPriority) { apcDefinition.setBeanClassName(cls.getName()); } } return null; } // 將傳入的class包裝成BeanDefinition,然后注冊到容器中,并講其order的執(zhí)行順序 //調(diào)整為最優(yōu)。 // 在aop中,這里會注冊AnnotationAwareAspectJAutoProxyCreator.class這個類 RootBeanDefinition beanDefinition = new RootBeanDefinition(cls); beanDefinition.setSource(source); beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE); beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition); return beanDefinition; }
首先查看當(dāng)前容器中是否包含
org.springframework.aop.config.internalAutoProxyCreator的BeanDefiniton.
如果沒有,將傳入的class(在此處傳入了AnnotationAwareAspectJAutoProxyCreator.class)包裝成RootBeanDefinition,然后注冊到容器中.
設(shè)置proxyTargetClass與exposeProxy
我們看一下如何設(shè)置proxyTargetClass即可,大體上設(shè)置proxyTargetClass與exposeProxy的邏輯都是相通的.
// 如果@EnableAspectJAutoProxy上存在標(biāo)簽內(nèi)容 if (enableAspectJAutoProxy != null) { // 如果proxyTargetClass為true,則強制指定AutoProxyCreator使用CGLIB進行代理 if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) { AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry); } // 是否開啟exposeProxy特性 if (enableAspectJAutoProxy.getBoolean("exposeProxy")) { AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry); } }
進入AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry); AopConfigUtils#forceAutoProxyCreatorToUseClassProxying public static void forceAutoProxyCreatorToUseClassProxying(BeanDefinitionRegistry registry) { // 如果容器中包含 org.springframework.aop.config.internalAutoProxyCreator if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) { // 取出 org.springframework.aop.config.internalAutoProxyCreator的BeanDefinition BeanDefinition definition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME); // 設(shè)置proxyTargetClass為true definition.getPropertyValues().add("proxyTargetClass", Boolean.TRUE); } }
如容器中包含名org.springframework.aop.config.internalAutoProxyCreator,那么取出該BeanDefinition,設(shè)置proxyTargetClass為true。
Spring為了兼容不同的BeanDefinition持有不同的屬性值,將它們都抽象成了MutablePropertyValues,definition.getPropertyValues().add("proxyTargetClass", Boolean.TRUE),就跟我們平時JavaBean中的set方法是一樣的.
簡單理解 @Import 和ImportBeanDefinitionRegistrar,下面我們通過兩個用例來理解@Import和ImportBeanDefinitionRegistrar
通過@Import導(dǎo)入類讓Spring進行管理
public class NeedImportBean { public void doSomething(){ Logger.getGlobal().info("Through @Import registry to a bean "); } }
在啟動類中將NeedImportBean導(dǎo)入
/** * @author jaymin * 2020/11/30 20:13 */ @Configuration @ComponentScan(value = "com.xjm") @Import(NeedImportBean.class) @EnableAspectJAutoProxy public class ApplicationConfig { public static AnnotationConfigApplicationContext getApplicationContext() { return new AnnotationConfigApplicationContext(ApplicationConfig.class); } } //對NeedImportBean做getBean public class BeanFactoryDemo { public static void main(String[] args) throws Exception { AnnotationConfigApplicationContext applicationContext = ApplicationConfig.getApplicationContext(); NeedImportBean needImportBean = applicationContext.getBean(NeedImportBean.class); } }
NeedImportBean實現(xiàn)ImportBeanDefinitionRegistrar接口,然后驗證兩個點:
是否會回調(diào)registerBeanDefinitions方法。
通過getBean是否能獲取NeedImportBean
public class NeedImportBean implements ImportBeanDefinitionRegistrar{ @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { Logger.getGlobal().info("Through implements ImportBeanDefinitionRegistrar and @Import to callback me."); } public void doSomething(){ Logger.getGlobal().info("Through @Import registry to a bean "); } }
refresh中激活后置處理器ConfigurationClassPostProcessor加載@Configuration上的元數(shù)據(jù)
首先容器會加載refresh方法。
執(zhí)行invokeBeanFactoryPostProcessors(beanFactory);激活工廠級別的后置處理器。
由于啟動類都是被 @Configuration 標(biāo)記的,Spring會使用ConfigurationClassPostProcessor來解析被 @Configuration 的類。
使用ConfigurationClassBeanDefinitionReader來加載配置類解析成BeanDefinition。
到此,相信大家對“如何理解AOP中JDK代理實現(xiàn)的原理”有了更深的了解,不妨來實際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進入相關(guān)頻道進行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。