Spring AOP源碼深入分析
1. 前言
Spring除了IOC和DI,還有另一個殺手锏功能——Spring AOP。AOP是一種面向切面的編程思想,它的關注點是橫向的,不同于OOP的縱向。面向?qū)ο缶幊虝r,如果我們要給多個類引入同一個行為,唯一的方式就是使用繼承,否則就要在這些類里面加入大量重復的代碼,如此一來程序?qū)⒉焕诰S護。于是,AOP橫空出世,它彌補了OOP編程的弊端。Spring內(nèi)部也有大量特性是通過AOP來實現(xiàn)的,比如我們熟知的數(shù)據(jù)庫事務。
2. 術語
查看源碼前,先了解一下AOP的相關術語。
連接點(Joinpoint)
Advice執(zhí)行的位置,比如:方法前、方法后、發(fā)生異常時等等,Spring僅支持方法的連接點。
切點(Pointcut)
連接點的過濾條件,AOP通過切點定位到具體的連接點。
增強/通知(Advice)
應用在連接點的行為,增強的邏輯代碼,分為:前置、后置、環(huán)繞、異常增強。
增強器(Advisor)
通知器由一個切點(Pointcut)和一個增強(Advice)組成。
切面(Aspect)
由切點(Pointcut)和增強(Advice)組成。
織入(Weaving)
將增強應用到目標連接點的過程,可以靜態(tài)織入,也可以運行時織入。
目標(Target)
被增強的對象(方法)。
代理(Proxy)
向Target應用Advice之后創(chuàng)建的代理對象。
3. 示例
Spring AOP使用起來非常簡單,這里提供一個小示例。
1、定義切面
@Aspect @Component public class MyAspectConfig { @Pointcut("execution(* com.javap.aop.*.*(..))") public void pointCut() { } /** * 每一個增強方法,都會被封裝成Advisor對象 * * @see Advisor */ @Before("pointCut()") public void before() { System.err.println("before"); } @After("pointCut()") public void after() { System.err.println("after"); } @Around("pointCut()") public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { System.err.println("Around before"); Object result = proceedingJoinPoint.proceed(proceedingJoinPoint.getArgs()); System.err.println("Around after"); return result; } @AfterReturning(value = "pointCut()", returning = "result") public void afterReturning(JoinPoint joinPoint, String result) throws Throwable { System.err.println("afterReturning: " + result); } @AfterThrowing(value = "pointCut()", throwing = "e") public void afterThrowing(Exception e) throws Throwable { System.err.println("afterThrowing: " + e.getMessage()); } }
2、定義bean,也就是需要被增強的目標對象
@Component public class Person { public String say() { System.err.println("say..."); return "aabbccdd"; } /** * final方法,子類無法重寫,因此不能被增強 */ public final void eat() { System.err.println("eat..."); } }
3、加上@EnableAspectJAutoProxy
注解,就可以啟用AOP了。
@Configuration @ComponentScan("com.javap.aop") @EnableAspectJAutoProxy public class AopApplication { public static void main(String[] args) { ApplicationContext context = new AnnotationConfigApplicationContext(AopApplication.class); Person person = context.getBean(Person.class); person.say(); person.eat(); } }
控制臺輸出:
Around before
before
say...
Around after
after
afterReturning: aabbccdd
eat...
4. @EnableAspectJAutoProxy
問題:為什么在啟動類上,加上**@EnableAspectJAutoProxy**
注解就可以開啟AOP呢???
答案當然要在注解本身找了,該注解上有一個@Import
注解,引入了AspectJAutoProxyRegistrar
類。
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Import(AspectJAutoProxyRegistrar.class) public @interface EnableAspectJAutoProxy { /** * 是否強制使用類代理模式:CGLIB代理 */ boolean proxyTargetClass() default false; /** * 是否暴露代理對象,以通過AopContext獲取 */ boolean exposeProxy() default false; }
AspectJAutoProxyRegistrar
類實現(xiàn)了Spring提供的ImportBeanDefinitionRegistrar
接口并重寫了registerBeanDefinitions()
方法,如此一來Spring在啟動時,就會觸發(fā)AspectJAutoProxyRegistrar#registerBeanDefinitions()
方法,該方法會向容器內(nèi)注冊一個特別重要的類AnnotationAwareAspectJAutoProxyCreator
。
class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar { @Override public void registerBeanDefinitions( AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { /** * 注冊AnnotationAwareAspectJAutoProxyCreator類 */ AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry); // 獲取注解信息 AnnotationAttributes enableAspectJAutoProxy = AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class); if (enableAspectJAutoProxy != null) { /** * 將注解屬性寫入到BeanDefinition * proxyTargetClass:是否通過CGLIB類代理模式 * exposeProxy:是否暴露代理類,以通過AopContext獲取 */ if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) { AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry); } if (enableAspectJAutoProxy.getBoolean("exposeProxy")) { AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry); } } } }
AnnotationAwareAspectJAutoProxyCreator實現(xiàn)了BeanPostProcessor接口,屬于Spring的擴展點之一,Spring在實例化bean實例后,會觸發(fā)該擴展點,對bean做擴展和增強,也就是返回織入了Advice后的代理對象。
5. AbstractAutoProxyCreator
AnnotationAwareAspectJAutoProxyCreator既然實現(xiàn)了BeanPostProcessor接口,那么必然要重寫postProcessAfterInitialization()
方法來返回增強后的bean,重寫方法在父類AbstractAutoProxyCreator里。
@Override public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) { if (bean != null) { Object cacheKey = getCacheKey(bean.getClass(), beanName); // 循環(huán)依賴,提前暴露bean時,代理對象可能已經(jīng)生成 if (this.earlyProxyReferences.remove(cacheKey) != bean) { // 生成增強后的代理對象,如果有需要 return wrapIfNecessary(bean, beanName, cacheKey); } } return bean; }
Spring會調(diào)用wrapIfNecessary()
方法來返回增強后的bean。**所有的bean都會被BeanPostProcessor處理,但并不是所有的bean都需要增強,Spring會根據(jù)切點表達式判斷beanClass是否需要被增強。**這個判斷過程是比較耗時的,因為要解析beanClass所有的方法去和切點表達式進行匹配,所以Spring加了一個Map緩存解析過的beanClass。
判斷bean是否要增強也很簡單,通過getAdvicesAndAdvisorsForBean()
方法去解析能應用到beanClass的所有增強器Advisor,如果沒有增強器可用于該beanClass,也就不需要增強,直接原樣返回bean即可,否則基于Advisor去創(chuàng)建增強后的代理對象。
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) { if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) { // 已增強 return bean; } if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) { // 已經(jīng)解析過beanClass,且判定為無需增強 return bean; } if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) { // 無需增強 this.advisedBeans.put(cacheKey, Boolean.FALSE); return bean; } /** * 獲取beanClass可用的Advisor */ Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null); if (specificInterceptors != DO_NOT_PROXY) { this.advisedBeans.put(cacheKey, Boolean.TRUE); // 基于Advisor,創(chuàng)建代理對象 Object proxy = createProxy( bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean)); this.proxyTypes.put(cacheKey, proxy.getClass()); return proxy; } // beanClass無可用的Advice,無需增強 this.advisedBeans.put(cacheKey, Boolean.FALSE); return bean; }
6. 構建Advisor
bean是否要增強,是通過beanClass是否有可用的Advisor來判斷的。那么,Advisor是怎么來的呢?
查找bean可用的Advisor的方法在AbstractAdvisorAutoProxyCreator#findEligibleAdvisors()
,先從容器內(nèi)找出所有的Advisor,也就是我們在@Aspect
類里定義的各種增強方法,然后根據(jù)切點表達式過濾出可以應用到當前beanClass的Advisor。然后將一個特殊的攔截器ExposeInvocationInterceptor插入到首位,最后將攔截器排個序返回。
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) { /** * 查找容器內(nèi)所有的Advisor:@Aspect類里定義的各種增強方法 */ List<Advisor> candidateAdvisors = findCandidateAdvisors(); /** * 根據(jù)切點表達式,過濾出可以應用到beanClass的Advisor */ List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName); /** * 將ExposeInvocationInterceptor攔截器插入到第一個 */ extendAdvisors(eligibleAdvisors); if (!eligibleAdvisors.isEmpty()) { eligibleAdvisors = sortAdvisors(eligibleAdvisors); } return eligibleAdvisors; }
構建Advisor的職責交給了BeanFactoryAspectJAdvisorsBuilder
類的buildAspectJAdvisors()
方法,它首先從容器內(nèi)找出所有加了@Aspect注解的bean,然后解析bean所有加了@Pointcut
、@Around
、@Before
、@After
、@AfterReturning
、@AfterThrowing
注解的方法,將它們封裝成Advisor對象。
/** *將bean里面加了指定注解的方法封裝成對應的Advice *@Before -> AspectJMethodBeforeAdvice * Around -> AspectJAroundAdvice *@After -> AspectJAfterAdvice *....... */ List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
容器內(nèi)的Advisor對象并不能都應用到目標bean對象,所以Spring還會調(diào)用findAdvisorsThatCanApply()
方法過濾出當前beanClass可用的Advisor。
7. 創(chuàng)建代理對象
如果當前bean有可用的Advisor,也就意味著需要對bean做增強,此時會調(diào)用createProxy()
方法創(chuàng)建增強后的代理對象。
問題:使用JDK代理還是CGLIB代理?
我們可以通過屬性proxyTargetClass
強制使用CGLIB代理,如果不指定,Spring的規(guī)則是:如果beanClass實現(xiàn)了接口,且接口至少有一個自定義方法,那么就用JDK代理,否則用CGLIB代理。
protected void evaluateProxyInterfaces(Class<?> beanClass, ProxyFactory proxyFactory) { // 獲取beanClass實現(xiàn)的所有接口 Class<?>[] targetInterfaces = ClassUtils.getAllInterfacesForClass(beanClass, getProxyClassLoader()); boolean hasReasonableProxyInterface = false; /** * 遍歷接口 * 1.非配置的回調(diào)接口,即Spring內(nèi)置的接口不算,例如InitializingBean、Aware等接口 * 2.非內(nèi)部語言接口,例如GroovyObject * 3.接口至少有一個自定義方法 */ for (Class<?> ifc : targetInterfaces) { if (!isConfigurationCallbackInterface(ifc) && !isInternalLanguageInterface(ifc) && ifc.getMethods().length > 0) { hasReasonableProxyInterface = true; break; } } if (hasReasonableProxyInterface) { // Must allow for introductions; can't just set interfaces to the target's interfaces only. for (Class<?> ifc : targetInterfaces) { proxyFactory.addInterface(ifc); } } else { // 沒有實現(xiàn)有效接口,使用CGLIB代理 proxyFactory.setProxyTargetClass(true); } }
最終,Spring會通過ProxyFactory去創(chuàng)建代理對象。
protected Object createProxy(Class<?> beanClass, @Nullable String beanName, @Nullable Object[] specificInterceptors, TargetSource targetSource) { if (this.beanFactory instanceof ConfigurableListableBeanFactory) { AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass); } // 基于ProxyFactory創(chuàng)建代理對象 ProxyFactory proxyFactory = new ProxyFactory(); // 屬性賦值給ProxyFactory proxyFactory.copyFrom(this); /** * 判斷使用JDK代理還是CGLIB代理 * 如果beanClass實現(xiàn)了接口,且接口至少有一個自定義方法,則使用JDK代理 * 否則CGLIB代理 */ if (!proxyFactory.isProxyTargetClass()) { if (shouldProxyTargetClass(beanClass, beanName)) { proxyFactory.setProxyTargetClass(true); } else { evaluateProxyInterfaces(beanClass, proxyFactory); } } Advisor[] advisors = buildAdvisors(beanName, specificInterceptors); proxyFactory.addAdvisors(advisors); proxyFactory.setTargetSource(targetSource); customizeProxyFactory(proxyFactory); // 是否凍結(jié),也就是Advisor不可再變更 proxyFactory.setFrozen(this.freezeProxy); if (advisorsPreFiltered()) { proxyFactory.setPreFiltered(true); } // 創(chuàng)建動態(tài)代理 兩種方式 JDK CGlib return proxyFactory.getProxy(getProxyClassLoader()); }
AopProxy有兩種實現(xiàn),分別是**JdkDynamicAopProxy**
和**CglibAopProxy**
**,前者使用JDK動態(tài)代理的方式將Advice織入bean,后者通過CGLIB生成子類的方式將Advice織入bean。**我們以CGLIB為例,創(chuàng)建代理對象的方法是CglibAopProxy#getProxy()
。
@Override public Object getProxy(@Nullable ClassLoader classLoader) { if (logger.isTraceEnabled()) { logger.trace("Creating CGLIB proxy: " + this.advised.getTargetSource()); } try { Class<?> rootClass = this.advised.getTargetClass(); Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy"); Class<?> proxySuperClass = rootClass; if (ClassUtils.isCglibProxyClass(rootClass)) { proxySuperClass = rootClass.getSuperclass(); Class<?>[] additionalInterfaces = rootClass.getInterfaces(); for (Class<?> additionalInterface : additionalInterfaces) { this.advised.addInterface(additionalInterface); } } // Validate the class, writing log messages as necessary. validateClassIfNecessary(proxySuperClass, classLoader); // Configure CGLIB Enhancer... Enhancer enhancer = createEnhancer(); if (classLoader != null) { enhancer.setClassLoader(classLoader); if (classLoader instanceof SmartClassLoader && ((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) { enhancer.setUseCache(false); } } enhancer.setSuperclass(proxySuperClass); /** * 會實現(xiàn)接口 * @see org.springframework.aop.SpringProxy * @see org.springframework.aop.framework.Advised */ enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised)); enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE); enhancer.setStrategy(new ClassLoaderAwareUndeclaredThrowableStrategy(classLoader)); /** * 獲取方法回調(diào),AOP主要看 * @see DynamicAdvisedInterceptor */ Callback[] callbacks = getCallbacks(rootClass); Class<?>[] types = new Class<?>[callbacks.length]; for (int x = 0; x < types.length; x++) { types[x] = callbacks[x].getClass(); } // fixedInterceptorMap only populated at this point, after getCallbacks call above enhancer.setCallbackFilter(new ProxyCallbackFilter( this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset)); enhancer.setCallbackTypes(types); // Generate the proxy class and create a proxy instance. return createProxyClassAndInstance(enhancer, callbacks); } catch (CodeGenerationException | IllegalArgumentException ex) { throw new AopConfigException("Could not generate CGLIB subclass of " + this.advised.getTargetClass() + ": Common causes of this problem include using a final class or a non-visible class", ex); } catch (Throwable ex) { // TargetSource.getTarget() failed throw new AopConfigException("Unexpected AOP exception", ex); } }
Spring會通過Enhancer去創(chuàng)建子類對象來增強目標bean,生成的子類默認會實現(xiàn)org.springframework.aop.SpringProxy
接口用來標記它是一個Spring生成的代理類。我們重點看給Enhancer對象設置的Callback,因為它會對方法做攔截,也就是說,我們調(diào)用子類的增強方法,其實就是在調(diào)用Callback#intercept()
。Spring考慮的比較全面,會針對main
、equals
、hashCode
等方法做處理,針對AOP我們主要看AopInterceptor
即可。
/** * Spring考慮了很多情況, *比如對main、equals、hashCode方法的攔截 *AOP主要看aopInterceptor */ Callback[] mainCallbacks = new Callback[]{ aopInterceptor,ll for normal advice targetInterceptor,// invoke target without considering advice,if optimized new SerializableNo0p(),l/ no override for methods mapped to this targetDispatcher, this.advisedDispatcher, new EqualsInterceptor(this.advised), new HashCodeInterceptor(this.advised) };
aopInterceptor是DynamicAdvisedInterceptor子類對象,用于處理AOP方法調(diào)用,也就是說,AOP增強邏輯就在DynamicAdvisedInterceptor#intercept()
里。
// Choose an "aop" interceptor (used for AOP calls). Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised);
8. DynamicAdvisedInterceptor
調(diào)用CGLIB增強子類的方法,其實會觸發(fā)DynamicAdvisedInterceptor#intercept()
方法,看看Spring增強的邏輯。
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { Object oldProxy = null; boolean setProxyContext = false; Object target = null; TargetSource targetSource = this.advised.getTargetSource(); try { /** * 是否要暴露代理對象,以通過AopContext獲取 * 寫入ThreadLocal */ if (this.advised.exposeProxy) { oldProxy = AopContext.setCurrentProxy(proxy); setProxyContext = true; } /** * 獲取目標Bean實例 * 如果是prototype 此時會創(chuàng)建新的實例 */ target = targetSource.getTarget(); Class<?> targetClass = (target != null ? target.getClass() : null); /** * 獲取方法能應用到的Advice,攔截器調(diào)用鏈 * @see org.springframework.aop.interceptor.ExposeInvocationInterceptor * @see org.springframework.aop.aspectj.AspectJAfterThrowingAdvice * @see org.springframework.aop.framework.adapter.AfterReturningAdviceInterceptor * @see org.springframework.aop.aspectj.AspectJAfterAdvice * @see org.springframework.aop.aspectj.AspectJAroundAdvice * @see org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor */ List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); Object retVal; if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) { /** * 沒有Advice,直接調(diào)用父類方法 */ Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args); retVal = methodProxy.invoke(target, argsToUse); } else { retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed(); } // 處理一下返回結(jié)果的類型 retVal = processReturnType(proxy, target, method, retVal); return retVal; } finally { if (target != null && !targetSource.isStatic()) { targetSource.releaseTarget(target); } if (setProxyContext) { AopContext.setCurrentProxy(oldProxy); } } }
方法攔截器主要做了三件事:
- 判斷是否要暴露代理對象,如果要則寫入ThreadLocal
- 獲取方法能應用到的Advice,構建攔截器調(diào)用鏈
- 觸發(fā)攔截器調(diào)用鏈
如果方法沒有可用的Advice,也就不需要增強,直接調(diào)用父類方法即可。反之方法需要增強,Spring會new一個CglibMethodInvocation對象,觸發(fā)攔截器調(diào)用鏈。
9. CglibMethodInvocation
CglibMethodInvocation#proceed()
方法會觸發(fā)攔截器調(diào)用鏈,Spring通過一個int變量currentInterceptorIndex
來記錄當前執(zhí)行的攔截器索引,通過和總的攔截器數(shù)量判斷是否調(diào)用完所有的攔截器,如果是則通過invokeJoinpoint()
方法去調(diào)用目標方法,反之則去執(zhí)行Advice增強。
public Object proceed() throws Throwable { /** * currentInterceptorIndex 當前執(zhí)行的攔截器索引 * interceptorsAndDynamicMethodMatchers.size() 所有攔擊器個數(shù) * 執(zhí)行完最后一個攔截器,就要執(zhí)行目標方法了 */ if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) { // 最終反射調(diào)用目標方法 return invokeJoinpoint(); } // 觸發(fā)Advice增強 Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex); if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) { InterceptorAndDynamicMethodMatcher dm = (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice; Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass()); if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) { return dm.interceptor.invoke(this); } else { return proceed(); } } else { return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this); } }
10. Advice子類
Spring AOP提供了五種Advice增強,分別是通過@Around
、@Before
、@After
、@AfterReturning
、@AfterThrowing
注解標記的方法。這五種Advice分別對應五個Advice子類實現(xiàn)。
1、AspectJAfterThrowingAdvice
先走下一個攔截器,只有在發(fā)生異常時,才觸發(fā)的Advice。
@Override public Object invoke(MethodInvocation mi) throws Throwable { try { // 先走下一個攔截器 return mi.proceed(); } catch (Throwable ex) { if (shouldInvokeOnThrowing(ex)) { /** * 只有發(fā)生異常了,才會執(zhí)行@AfterThrowing Advice */ invokeAdviceMethod(getJoinPointMatch(), null, ex); } throw ex; } }
2、AfterReturningAdviceInterceptor
走剩下所有的攔截器,拿到返回結(jié)果。正常執(zhí)行完畢才觸發(fā)的Advice,如果發(fā)生異常則不觸發(fā)。
@Override public Object invoke(MethodInvocation mi) throws Throwable { // 直接走剩下的攔截器,拿到返回結(jié)果 Object retVal = mi.proceed(); /** * 正常執(zhí)行完畢,才觸發(fā) @AfterReturning Advice * 如果期間發(fā)生異常,則不觸發(fā) */ this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis()); return retVal; }
3、AspectJAfterAdvice
先走下一個攔截器,執(zhí)行完畢再最終調(diào)用的Advice,不論是否發(fā)生異常。
@Override public Object invoke(MethodInvocation mi) throws Throwable { try { /** * 先走下一個攔截器,執(zhí)行完畢再最終調(diào)用@After Advice */ return mi.proceed(); } finally { /** * 執(zhí)行@After Advice方法 * @After Advice一定會被調(diào)用,不管是否發(fā)生異常,因為在finally */ invokeAdviceMethod(getJoinPointMatch(), null, null); } }
4、AspectJAroundAdvice
直接觸發(fā)Advice,是否繼續(xù)調(diào)用后續(xù)Advice由我們自己決定。
@Override public Object invoke(MethodInvocation mi) throws Throwable { if (!(mi instanceof ProxyMethodInvocation)) { throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi); } /** * 直接觸發(fā)Advice,是否繼續(xù)調(diào)用后續(xù)Advice,由@Around Advice自己決定 */ ProxyMethodInvocation pmi = (ProxyMethodInvocation) mi; ProceedingJoinPoint pjp = lazyGetProceedingJoinPoint(pmi); JoinPointMatch jpm = getJoinPointMatch(pmi); return invokeAdviceMethod(pjp, jpm, null, null); }
5、MethodBeforeAdviceInterceptor
先觸發(fā)當前Advice,再調(diào)用下一個Advice。
@Override public Object invoke(MethodInvocation mi) throws Throwable { /** * 先觸發(fā) @Before Advice * 再調(diào)用下一個Advice */ this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis()); return mi.proceed(); }
到此這篇關于Spring AOP源碼深入分析的文章就介紹到這了,更多相關Spring AOP內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
application.yml的格式寫法和pom.xml讀取配置插件方式
這篇文章主要介紹了application.yml的格式寫法和pom.xml讀取配置插件方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-07-07SpringBoot統(tǒng)計、監(jiān)控SQL運行情況的方法詳解
這篇文章主要給大家介紹了關于SpringBoot統(tǒng)計、監(jiān)控SQL運行情況的相關資料,文中通過實例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2022-02-02在SpringBoot當中使用Thymeleaf視圖解析器的詳細教程
Thymeleaf是一款開源的模板引擎,它允許前端開發(fā)者使用HTML與XML編寫動態(tài)網(wǎng)頁,hymeleaf的主要特點是將表達式語言嵌入到HTML結(jié)構中,它支持Spring框架,使得在Spring MVC應用中集成非常方便,本文給大家介紹了在SpringBoot當中使用Thymeleaf視圖解析器的詳細教程2024-09-09