Spring AOP源碼深入分析
1. 前言
Spring除了IOC和DI,還有另一個殺手锏功能——Spring AOP。AOP是一種面向切面的編程思想,它的關(guān)注點是橫向的,不同于OOP的縱向。面向?qū)ο缶幊虝r,如果我們要給多個類引入同一個行為,唯一的方式就是使用繼承,否則就要在這些類里面加入大量重復(fù)的代碼,如此一來程序?qū)⒉焕诰S護(hù)。于是,AOP橫空出世,它彌補(bǔ)了OOP編程的弊端。Spring內(nèi)部也有大量特性是通過AOP來實現(xiàn)的,比如我們熟知的數(shù)據(jù)庫事務(wù)。
2. 術(shù)語
查看源碼前,先了解一下AOP的相關(guān)術(shù)語。
連接點(Joinpoint)
Advice執(zhí)行的位置,比如:方法前、方法后、發(fā)生異常時等等,Spring僅支持方法的連接點。
切點(Pointcut)
連接點的過濾條件,AOP通過切點定位到具體的連接點。
增強(qiáng)/通知(Advice)
應(yīng)用在連接點的行為,增強(qiáng)的邏輯代碼,分為:前置、后置、環(huán)繞、異常增強(qiáng)。
增強(qiáng)器(Advisor)
通知器由一個切點(Pointcut)和一個增強(qiáng)(Advice)組成。
切面(Aspect)
由切點(Pointcut)和增強(qiáng)(Advice)組成。
織入(Weaving)
將增強(qiáng)應(yīng)用到目標(biāo)連接點的過程,可以靜態(tài)織入,也可以運行時織入。
目標(biāo)(Target)
被增強(qiáng)的對象(方法)。
代理(Proxy)
向Target應(yīng)用Advice之后創(chuàng)建的代理對象。
3. 示例
Spring AOP使用起來非常簡單,這里提供一個小示例。
1、定義切面
@Aspect
@Component
public class MyAspectConfig {
@Pointcut("execution(* com.javap.aop.*.*(..))")
public void pointCut() {
}
/**
* 每一個增強(qiáng)方法,都會被封裝成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,也就是需要被增強(qiáng)的目標(biāo)對象
@Component
public class Person {
public String say() {
System.err.println("say...");
return "aabbccdd";
}
/**
* final方法,子類無法重寫,因此不能被增強(qiáng)
*/
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呢???
答案當(dāng)然要在注解本身找了,該注解上有一個@Import注解,引入了AspectJAutoProxyRegistrar類。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
/**
* 是否強(qiáng)制使用類代理模式: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的擴(kuò)展點之一,Spring在實例化bean實例后,會觸發(fā)該擴(kuò)展點,對bean做擴(kuò)展和增強(qiáng),也就是返回織入了Advice后的代理對象。

5. AbstractAutoProxyCreator
AnnotationAwareAspectJAutoProxyCreator既然實現(xiàn)了BeanPostProcessor接口,那么必然要重寫postProcessAfterInitialization()方法來返回增強(qiáng)后的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) {
// 生成增強(qiáng)后的代理對象,如果有需要
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
Spring會調(diào)用wrapIfNecessary()方法來返回增強(qiáng)后的bean。**所有的bean都會被BeanPostProcessor處理,但并不是所有的bean都需要增強(qiáng),Spring會根據(jù)切點表達(dá)式判斷beanClass是否需要被增強(qiáng)。**這個判斷過程是比較耗時的,因為要解析beanClass所有的方法去和切點表達(dá)式進(jìn)行匹配,所以Spring加了一個Map緩存解析過的beanClass。
判斷bean是否要增強(qiáng)也很簡單,通過getAdvicesAndAdvisorsForBean()方法去解析能應(yīng)用到beanClass的所有增強(qiáng)器Advisor,如果沒有增強(qiáng)器可用于該beanClass,也就不需要增強(qiáng),直接原樣返回bean即可,否則基于Advisor去創(chuàng)建增強(qiáng)后的代理對象。
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
// 已增強(qiáng)
return bean;
}
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
// 已經(jīng)解析過beanClass,且判定為無需增強(qiáng)
return bean;
}
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
// 無需增強(qiáng)
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,無需增強(qiáng)
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
6. 構(gòu)建Advisor
bean是否要增強(qiáng),是通過beanClass是否有可用的Advisor來判斷的。那么,Advisor是怎么來的呢?
查找bean可用的Advisor的方法在AbstractAdvisorAutoProxyCreator#findEligibleAdvisors(),先從容器內(nèi)找出所有的Advisor,也就是我們在@Aspect類里定義的各種增強(qiáng)方法,然后根據(jù)切點表達(dá)式過濾出可以應(yīng)用到當(dāng)前beanClass的Advisor。然后將一個特殊的攔截器ExposeInvocationInterceptor插入到首位,最后將攔截器排個序返回。
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
/**
* 查找容器內(nèi)所有的Advisor:@Aspect類里定義的各種增強(qiáng)方法
*/
List<Advisor> candidateAdvisors = findCandidateAdvisors();
/**
* 根據(jù)切點表達(dá)式,過濾出可以應(yīng)用到beanClass的Advisor
*/
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
/**
* 將ExposeInvocationInterceptor攔截器插入到第一個
*/
extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}
構(gòu)建Advisor的職責(zé)交給了BeanFactoryAspectJAdvisorsBuilder類的buildAspectJAdvisors()方法,它首先從容器內(nèi)找出所有加了@Aspect注解的bean,然后解析bean所有加了@Pointcut、@Around、@Before、@After、@AfterReturning、@AfterThrowing注解的方法,將它們封裝成Advisor對象。
/** *將bean里面加了指定注解的方法封裝成對應(yīng)的Advice *@Before -> AspectJMethodBeforeAdvice * Around -> AspectJAroundAdvice *@After -> AspectJAfterAdvice *....... */ List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
容器內(nèi)的Advisor對象并不能都應(yīng)用到目標(biāo)bean對象,所以Spring還會調(diào)用findAdvisorsThatCanApply()方法過濾出當(dāng)前beanClass可用的Advisor。
7. 創(chuàng)建代理對象
如果當(dāng)前bean有可用的Advisor,也就意味著需要對bean做增強(qiáng),此時會調(diào)用createProxy()方法創(chuàng)建增強(qiáng)后的代理對象。
問題:使用JDK代理還是CGLIB代理?
我們可以通過屬性proxyTargetClass強(qiáng)制使用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)建子類對象來增強(qiáng)目標(biāo)bean,生成的子類默認(rèn)會實現(xiàn)org.springframework.aop.SpringProxy接口用來標(biāo)記它是一個Spring生成的代理類。我們重點看給Enhancer對象設(shè)置的Callback,因為它會對方法做攔截,也就是說,我們調(diào)用子類的增強(qiáng)方法,其實就是在調(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增強(qiáng)邏輯就在DynamicAdvisedInterceptor#intercept()里。
// Choose an "aop" interceptor (used for AOP calls). Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised);
8. DynamicAdvisedInterceptor
調(diào)用CGLIB增強(qiáng)子類的方法,其實會觸發(fā)DynamicAdvisedInterceptor#intercept()方法,看看Spring增強(qiáng)的邏輯。
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;
}
/**
* 獲取目標(biāo)Bean實例
* 如果是prototype 此時會創(chuàng)建新的實例
*/
target = targetSource.getTarget();
Class<?> targetClass = (target != null ? target.getClass() : null);
/**
* 獲取方法能應(yīng)用到的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
- 獲取方法能應(yīng)用到的Advice,構(gòu)建攔截器調(diào)用鏈
- 觸發(fā)攔截器調(diào)用鏈
如果方法沒有可用的Advice,也就不需要增強(qiáng),直接調(diào)用父類方法即可。反之方法需要增強(qiáng),Spring會new一個CglibMethodInvocation對象,觸發(fā)攔截器調(diào)用鏈。
9. CglibMethodInvocation
CglibMethodInvocation#proceed()方法會觸發(fā)攔截器調(diào)用鏈,Spring通過一個int變量currentInterceptorIndex來記錄當(dāng)前執(zhí)行的攔截器索引,通過和總的攔截器數(shù)量判斷是否調(diào)用完所有的攔截器,如果是則通過invokeJoinpoint()方法去調(diào)用目標(biāo)方法,反之則去執(zhí)行Advice增強(qiáng)。
public Object proceed() throws Throwable {
/**
* currentInterceptorIndex 當(dāng)前執(zhí)行的攔截器索引
* interceptorsAndDynamicMethodMatchers.size() 所有攔擊器個數(shù)
* 執(zhí)行完最后一個攔截器,就要執(zhí)行目標(biāo)方法了
*/
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
// 最終反射調(diào)用目標(biāo)方法
return invokeJoinpoint();
}
// 觸發(fā)Advice增強(qiáng)
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增強(qiáng),分別是通過@Around、@Before、@After、@AfterReturning、@AfterThrowing注解標(biāo)記的方法。這五種Advice分別對應(yīng)五個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ā)當(dāng)前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();
}
到此這篇關(guān)于Spring AOP源碼深入分析的文章就介紹到這了,更多相關(guān)Spring AOP內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Spring的refresh()方法相關(guān)異常解析
這篇文章主要介紹了Spring的refresh()方法相關(guān)異常解析,具有一定參考價值,需要的朋友可以了解下。2017-11-11
spring為java.util.Properties類型的屬性進(jìn)行賦值過程解析
這篇文章主要介紹了spring為java.util.Properties類型的屬性進(jìn)行賦值過程解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-01-01

