您好,登錄后才能下訂單哦!
這篇文章主要介紹“Spring如何實現(xiàn)AOP”,在日常操作中,相信很多人在Spring如何實現(xiàn)AOP問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”Spring如何實現(xiàn)AOP”的疑惑有所幫助!接下來,請跟著小編一起來學(xué)習(xí)吧!
最近工作中我都是基于注解實現(xiàn)AOP功能,常用的開啟AOP的注解是@EnableAspectJAutoProxy,我們就從它入手。
上面的動圖的流程的步驟就是:
@EnableAspectJAutoProxy
--> AspectJAutoProxyRegistrar
-->AopConfigUtils .registerAspectJAnnotationAutoProxyCreatorIfNecessary
-->AnnotationAwareAspectJAutoProxyCreator.class
AnnotationAwareAspectJAutoProxyCreator查看其中文注釋(如下),確定它就是AOP的核心類!--溫安適 20191020
/** 1.AspectJAwareAdvisorAutoProxyCreator的子類 ,用于處理當(dāng)前應(yīng)用上下文中的注解切面 2.任何被AspectJ注解的類將自動被識別。 3.若SpringAOP代理模式可以識別,優(yōu)先使用Spring代理模式。 4.它覆蓋了方法執(zhí)行連接點 5.如果使用<aop:include>元素, 則只有名稱與include模式匹配的@aspectj bean才被視為切面 ,并由spring自動代理。 6. Spring Advisors的處理請查閱, org.springframework.aop .framework.autoproxy.AbstractAdvisorAutoProxyCreator */ @SuppressWarnings("serial") public class AnnotationAwareAspectJAutoProxyCreator extends AspectJAwareAdvisorAutoProxyCreator { //...省略實現(xiàn) }注解切面
雖然找到了核心類,但是并沒有找到核心方法!下面我們嘗試畫類圖確定核心方法。
AnnotationAwareAspectJAutoProxyCreator的部分類圖。
從類圖看到了AnnotationAwareAspectJAutoProxyCreator實現(xiàn)了BeanPostProcessor,而AOP功能應(yīng)該在創(chuàng)建完Bean之后執(zhí)行,猜測AnnotationAwareAspectJAutoProxyCreator實現(xiàn)BeanPostProcessor的postProcessAfterInitialization(實例化bean后處理)是核心方法。 查看AnnotationAwareAspectJAutoProxyCreator實現(xiàn)的postProcessAfterInitialization方法,實際該方法在其父類AbstractAutoProxyCreator中。
//AbstractAutoProxyCreator中的postProcessAfterInitialization實現(xiàn) @Override public Object postProcessAfterInitialization(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; }
發(fā)現(xiàn)發(fā)現(xiàn)疑似方法wrapIfNecessary,查看其源碼如下,發(fā)現(xiàn)createProxy方法。確定找對了地方。
protected Object wrapIfNecessary (Object bean, String beanName, Object cacheKey) { if (beanName != null && this.targetSourcedBeans.contains(beanName)) { return bean; } if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) { return bean; } if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) { this.advisedBeans.put(cacheKey, Boolean.FALSE); return bean; } // 創(chuàng)建代理 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; } this.advisedBeans.put(cacheKey, Boolean.FALSE); return bean; }
即AnnotationAwareAspectJAutoProxyCreator實現(xiàn)BeanPostProcessor的postProcessAfterInitialization方法,在該方法中由wrapIfNecessary實現(xiàn)了AOP的功能。 wrapIfNecessary中有2個和核心方法
getAdvicesAndAdvisorsForBean獲取當(dāng)前bean匹配的增強器
createProxy為當(dāng)前bean創(chuàng)建代理
要想明白核心流程還需要分析這2個方法。
查看源碼如下,默認(rèn)實現(xiàn)在AbstractAdvisorAutoProxyCreator中。
@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(); }
查閱findEligibleAdvisors方法,就干了3件事
找所有增強器,也就是所有@Aspect注解的Bean
找匹配的增強器,也就是根據(jù)@Before,@After等注解上的表達(dá)式,與當(dāng)前bean進行匹配,暴露匹配上的。
對匹配的增強器進行擴展和排序,就是按照@Order或者PriorityOrdered的getOrder的數(shù)據(jù)值進行排序,越小的越靠前。
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) { //找所有增強器 List<Advisor> candidateAdvisors = findCandidateAdvisors(); //找所有匹配的增強器 List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName); extendAdvisors(eligibleAdvisors); if (!eligibleAdvisors.isEmpty()) { //排序 eligibleAdvisors = sortAdvisors(eligibleAdvisors); } return eligibleAdvisors; }
AnnotationAwareAspectJAutoProxyCreator 重寫了findCandidateAdvisors,下面我們看看具體實現(xiàn)了什么
@Override protected List<Advisor> findCandidateAdvisors() { // Add all the Spring advisors found according to superclass rules. List<Advisor> advisors = super.findCandidateAdvisors(); // Build Advisors for all AspectJ aspects in the bean factory. if (this.aspectJAdvisorsBuilder != null) { //@Aspect注解的類在這里除了 advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors()); } return advisors; }
從該方法我們可以看到處理@Aspect注解的bean的方法是:this.aspectJAdvisorsBuilder.buildAspectJAdvisors()。 這個方法如下:
public List<Advisor> buildAspectJAdvisors() { List<String> aspectNames = this.aspectBeanNames; if (aspectNames == null) { synchronized (this) { aspectNames = this.aspectBeanNames; if (aspectNames == null) { List<Advisor> advisors = new ArrayList<>(); aspectNames = new ArrayList<>(); //找到所有BeanName String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors( this.beanFactory, Object.class, true, false); for (String beanName : beanNames) { if (!isEligibleBean(beanName)) { continue; } // 必須注意,bean會提前暴露,并被Spring容器緩存,但是這時還不能織入。 Class<?> beanType = this.beanFactory.getType(beanName); if (beanType == null) { continue; } if (this.advisorFactory.isAspect(beanType)) { //找到所有被@Aspect注解的類 aspectNames.add(beanName); AspectMetadata amd = new AspectMetadata(beanType, beanName); if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) { MetadataAwareAspectInstanceFactory factory = new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName); //解析封裝為Advisor返回 List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory); if (this.beanFactory.isSingleton(beanName)) { this.advisorsCache.put(beanName, classAdvisors); } else { this.aspectFactoryCache.put(beanName, factory); } advisors.addAll(classAdvisors); } else { // Per target or per this. if (this.beanFactory.isSingleton(beanName)) { throw new IllegalArgumentException("Bean with name '" + beanName + "' is a singleton, but aspect instantiation model is not singleton"); } MetadataAwareAspectInstanceFactory factory = new PrototypeAspectInstanceFactory(this.beanFactory, beanName); this.aspectFactoryCache.put(beanName, factory); advisors.addAll(this.advisorFactory.getAdvisors(factory)); } } } this.aspectBeanNames = aspectNames; return advisors; } } } if (aspectNames.isEmpty()) { return Collections.emptyList(); } List<Advisor> advisors = new ArrayList<>(); for (String aspectName : aspectNames) { List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName); if (cachedAdvisors != null) { advisors.addAll(cachedAdvisors); } else { MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName); advisors.addAll(this.advisorFactory.getAdvisors(factory)); } } return advisors; }
這個方法可以概括為:
找到所有BeanName
根據(jù)BeanName篩選出被@Aspect注解的類
針對類中被Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class注解的方法,先按上邊的注解順序排序后按方法名稱排序,每一個方法對應(yīng)一個Advisor。
眾所周知,創(chuàng)建代理的常用的2種方式是:JDK創(chuàng)建和CGLIB,下面我們就看看這2中創(chuàng)建代理的例子。
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class JDKProxyMain { public static void main(String[] args) { JDKProxyTestInterface target = new JDKProxyTestInterfaceImpl(); // 根據(jù)目標(biāo)對象創(chuàng)建代理對象 JDKProxyTestInterface proxy = (JDKProxyTestInterface) Proxy .newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new JDKProxyTestInvocationHandler(target)); // 調(diào)用代理對象方法 proxy.testProxy(); } interface JDKProxyTestInterface { void testProxy(); } static class JDKProxyTestInterfaceImpl implements JDKProxyTestInterface { @Override public void testProxy() { System.out.println("testProxy"); } } static class JDKProxyTestInvocationHandler implements InvocationHandler { private Object target; public JDKProxyTestInvocationHandler(Object target){ this.target=target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("執(zhí)行前"); Object result= method.invoke(this.target,args); System.out.println("執(zhí)行后"); return result; } }
import org.springframework.cglib.proxy.Enhancer; import org.springframework.cglib.proxy.MethodInterceptor; import org.springframework.cglib.proxy.MethodProxy; import java.lang.reflect.Method; public class CglibProxyTest { static class CglibProxyService { public CglibProxyService(){ } void sayHello(){ System.out.println(" hello !"); } } static class CglibProxyInterceptor implements MethodInterceptor{ @Override public Object intercept(Object sub, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("before hello"); Object object = methodProxy.invokeSuper(sub, objects); System.out.println("after hello"); return object; } } public static void main(String[] args) { // 通過CGLIB動態(tài)代理獲取代理對象的過程 Enhancer enhancer = new Enhancer(); // 設(shè)置enhancer對象的父類 enhancer.setSuperclass(CglibProxyService.class); // 設(shè)置enhancer的回調(diào)對象 enhancer.setCallback(new CglibProxyInterceptor()); // 創(chuàng)建代理對象 CglibProxyService proxy= (CglibProxyService)enhancer.create(); System.out.println(CglibProxyService.class); System.out.println(proxy.getClass()); // 通過代理對象調(diào)用目標(biāo)方法 proxy.sayHello(); } }
類型 | jdk創(chuàng)建動態(tài)代理 | cglib創(chuàng)建動態(tài)代理 |
---|---|---|
原理 | java動態(tài)代理是利用反射機制生成一個實現(xiàn)代理接口的匿名類,在調(diào)用具體方法前調(diào)用InvokeHandler來處理 | cglib動態(tài)代理是利用asm開源包,對代理對象類的class文件加載進來,通過修改其字節(jié)碼生成子類來處理 |
核心類 | Proxy 創(chuàng)建代理利用反射機制生成一個實現(xiàn)代理接口的匿名類InvocationHandler 方法攔截器接口,需要實現(xiàn)invoke方法 | net.sf.cglib.proxy.Enhancer:主要增強類,通過字節(jié)碼技術(shù)動態(tài)創(chuàng)建委托類的子類實例net.sf.cglib.proxy.MethodInterceptor:方法攔截器接口,需要實現(xiàn)intercept方法 |
局限性 | 只能代理實現(xiàn)了接口的類 | 不能對final修飾的類進行代理,也不能處理final修飾的方法 |
Spring的選擇選擇如何代理時在DefaultAopProxyFactory 中。
public class DefaultAopProxyFactory implements AopProxyFactory, Serializable { @Override public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException { 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."); } if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) { return new JdkDynamicAopProxy(config); } return new ObjenesisCglibAopProxy(config); } else { return new JdkDynamicAopProxy(config); } } //... }
config.isOptimize() 查看源碼注釋時發(fā)現(xiàn),這個是配置使用cglib代理時,是否使用積極策略。這個值一般不建議使用!
config.isProxyTargetClass() 就是@EnableAspectJAutoProxy中的proxyTargetClass屬性。
//exposeProxy=true AopContext 可以訪問,proxyTargetClass=true CGLIB生成代理 @EnableAspectJAutoProxy(exposeProxy=true,proxyTargetClass=true)
hasNoUserSuppliedProxyInterfaces 是否存在可代理的接口
總結(jié)下Spring如何選擇創(chuàng)建代理的方式:
如果設(shè)置了proxyTargetClass=true,一定是CGLIB代理
如果proxyTargetClass=false,目標(biāo)對象實現(xiàn)了接口,走JDK代理
如果沒有實現(xiàn)接口,走CGLIB代理
Spring如何實現(xiàn)AOP?,您可以這樣說:
AnnotationAwareAspectJAutoProxyCreator是AOP核心處理類
AnnotationAwareAspectJAutoProxyCreator實現(xiàn)了BeanProcessor,其中postProcessAfterInitialization是核心方法。
核心實現(xiàn)分為2步
getAdvicesAndAdvisorsForBean獲取當(dāng)前bean匹配的增強器 createProxy為當(dāng)前bean創(chuàng)建代理
getAdvicesAndAdvisorsForBean核心邏輯如下
a. 找所有增強器,也就是所有@Aspect注解的Bean
b. 找匹配的增強器,也就是根據(jù)@Before,@After等注解上的表達(dá)式,與當(dāng)前bean進行匹配,暴露匹配上的。
c. 對匹配的增強器進行擴展和排序,就是按照@Order或者PriorityOrdered的getOrder的數(shù)據(jù)值進行排序,越小的越靠前。
createProxy有2種創(chuàng)建方法,JDK代理或CGLIB
a. 如果設(shè)置了proxyTargetClass=true,一定是CGLIB代理
b. 如果proxyTargetClass=false,目標(biāo)對象實現(xiàn)了接口,走JDK代理
c. 如果沒有實現(xiàn)接口,走CGLIB代理
到此,關(guān)于“Spring如何實現(xiàn)AOP”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識,請繼續(xù)關(guān)注億速云網(wǎng)站,小編會繼續(xù)努力為大家?guī)砀鄬嵱玫奈恼拢?/p>
免責(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)容。