文章目錄
前言
上一篇看了Spring IOC源碼,猿猿們都知道,有IOC就有AOP,那這篇就結合例子來看一下AOP的源碼。
基本概念
AOP(Aspect Oriented Programming),即面向切面編程,可以說是OOP(Object Oriented Programming,面向對象編程)的補充和完善。OOP引入封裝、繼承、多態等概念來建立一種對象層次結構,用於模擬公共行爲的一個集合。不過OOP允許開發者定義縱向的關係,但並不適合定義橫向的關係,例如日誌功能。日誌代碼往往橫向地散佈在所有對象層次中,而與它對應的對象的核心功能毫無關係對於其他類型的代碼,如安全性、異常處理和透明的持續性也都是如此,這種散佈在各處的無關的代碼被稱爲橫切(cross cutting),在OOP設計中,它導致了大量代碼的重複,而不利於各個模塊的重用。
AOP技術恰恰相反,它利用一種稱爲"橫切"的技術,剖解開封裝的對象內部,並將那些影響了多個類的公共行爲封裝到一個可重用模塊,並將其命名爲"Aspect",即切面。所謂"切面",簡單說就是那些與業務無關,卻爲業務模塊所共同調用的邏輯或責任封裝起來,便於減少系統的重複代碼,降低模塊之間的耦合度,並有利於未來的可操作性和可維護性。
使用"橫切"技術,AOP把軟件系統分爲兩個部分:核心關注點和橫切關注點。業務處理的主要流程是核心關注點,與之關係不大的部分是橫切關注點。橫切關注點的一個特點是,他們經常發生在覈心關注點的多處,而各處基本相似,比如權限認證、日誌、事物。AOP的作用在於分離系統中的各種關注點,將核心關注點和橫切關注點分離開來。
橫切關注點
即對哪些方法進行切入,對哪些方法進行攔截,攔截後怎麼處理,這些關注點稱之爲橫切關注點。
切面(Aspect)
把原來糅雜在業務邏輯代碼中的非業務代碼抽取出來,把功能相同的放在一個類中形成一個切面。類是對物體特徵的抽象,切面就是對橫切關注點的抽象。
連接點(JoinPoint)
需要切入的點、被攔截到的點,因爲Spring只支持方法類型的連接點,所以在Spring中連接點指的就是被攔截到的方法,實際上連接點還可以是字段或者構造器。
切入點(PointCut)
對連接點進行攔截的定義。
通知(Advice)
所謂通知指的就是指攔截到連接點之後要執行的代碼,通知分爲前置、後置、異常、最終、環繞通知五種。
目標對象(Target)
代理的目標對象。
織入(Weave)
將切面應用到目標對象並導致代理對象創建的過程。
引入(Introduction)
在不修改代碼的前提下,引入可以在運行期爲類動態地添加一些方法或字段。
基本概念網上有很多,就不細說了。這裏要提一下AOP是一種思想,它的實現主要有Spring AOP和AspectJ,Spring實現AOP的底層相當複雜,所以藉助了AspectJ的語法來實現,即使用了@Aspect註解來實現。
Spring AOP是在運行期進行織入的,而AspectJ是在編譯期進行織入。
類結構體系
示例代碼
配置類
@Configuration
@ComponentScan(value = "com.ambition")
/**
* Spring AOP 默認使用 JDK 動態代理
*
* proxyTargetClass = true 時則代理目標對象時強制使用 CGLIB 代理
* @see DefaultAopProxyFactory#createAopProxy(org.springframework.aop.framework.AdvisedSupport)
*
* exposeProxy = true 暴露代理對象,這樣就可以使用 AopContext.currentProxy() 方法獲取當前代理的對象
* @see AopContext#currentProxy
* @see JdkDynamicAopProxy#invoke(java.lang.Object, java.lang.reflect.Method, java.lang.Object[])
*
* 可以解決在方法裏面調方法,或者用 this 關鍵字調方法,而無法被代理的情況
**/
@EnableAspectJAutoProxy(proxyTargetClass = true, exposeProxy = true)
public class AopConfig {
}
切面類
@Aspect
@Component
public class AmbitionAop {
@Pointcut("execution(* com.ambition.service.CalculateImpl.*(..))")
public void pointCut() { }
@Before(value = "pointCut()")
public void methodBefore(JoinPoint joinPoint) {
String methodName = joinPoint.getSignature().getName();
System.out.println("執行目標方法【" + methodName + "】之前執行<前置通知>, 入參" + Arrays.asList(joinPoint.getArgs()));
}
@After(value = "pointCut()")
public void methodAfter(JoinPoint joinPoint) {
String methodName = joinPoint.getSignature().getName();
System.out.println("執行目標方法【" + methodName + "】之前執行<後置通知>, 入參" + Arrays.asList(joinPoint.getArgs()));
}
@AfterReturning(value = "pointCut()")
public void methodReturning(JoinPoint joinPoint) {
String methodName = joinPoint.getSignature().getName();
System.out.println("執行目標方法【" + methodName + "】之前執行<返回通知>, 入參" + Arrays.asList(joinPoint.getArgs()));
}
@AfterThrowing(value = "pointCut()")
public void methodAfterThrowing(JoinPoint joinPoint) {
String methodName = joinPoint.getSignature().getName();
System.out.println("執行目標方法【" + methodName + "】之前執行<異常通知>, 入參" + Arrays.asList(joinPoint.getArgs()));
}
}
目標對象
@Component
public class CalculateImpl implements Calculate {
@Override
public int add(int numA, int numB) {
// System.out.println(1 / 0);
return numA + numB;
}
@Override
public int reduce(int numA, int numB) {
return numA - numB;
}
@Override
public int div(int numA, int numB) {
return numA / numB;
}
@Override
public int multi(int numA, int numB) {
return numA * numB;
}
}
測試類
public static void main(String[] args) {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(AopConfig.class);
Calculate calculate = context.getBean(Calculate.class);
int result = calculate.add(1, 2);
System.out.println("運算結果:" + result);
}
沒有異常時的打印結果
發生異常時的打印結果
產生過程
先來看一下它是如何被Spring IOC容器初始化並生成代理對象的,順便說一下上一篇沒有具體說明的部分,再說它的執行過程。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
boolean proxyTargetClass() default false;
boolean exposeProxy() default false;
}
可以看到這個註解上面導入了一個AspectJAutoProxyRegistrar類,它實現了ImportBeanDefinitionRegistrar,解析IOC源碼的時候,我們看到Spring會將這種類型的組件放到一個集合中,然後統一調用registerBeanDefinitions()
方法,委託其進行BeanDefinition的註冊。
class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
BeanDefinitionRegistry registry) {
// 註冊 AspectJ 相關的處理組件
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
AnnotationAttributes enableAspectJAutoProxy =
AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
if (enableAspectJAutoProxy != null) {
if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}
if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
}
}
}
}
可以看到主要代碼就是AopConfigUtils的registerAspectJAnnotationAutoProxyCreatorIfNecessary()
方法。
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) {
return registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry, null);
}
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry,
@Nullable Object source) {
return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
}
private static BeanDefinition registerOrEscalateApcAsRequired(Class<?> cls,
BeanDefinitionRegistry registry,
@Nullable Object source) {
// 容器中已經包含 "org.springframework.aop.config.internalAutoProxyCreator"
if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
// 獲取 BeanDefinition
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;
}
/**
* 封裝 AnnotationAwareAspectJAutoProxyCreator 爲 RootBeanDefinition
*
* 名稱爲{@link AopConfigUtils#AUTO_PROXY_CREATOR_BEAN_NAME}
**/
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;
}
這裏Spring容器已經解析到剛剛導入的類了,然後會調用上面那個方法進行註冊。
其實就是往Spring容器中註冊一個AnnotationAwareAspectJAutoProxyCreator組件,很多EnableXXX註解都是這樣將需要的組件註冊到IOC容器,然後委託初始化過程來實現功能的擴展。
protected Object createBean(String beanName,
RootBeanDefinition mbd,
@Nullable Object[] args) throws BeanCreationException {
RootBeanDefinition mbdToUse = mbd;
......
try {
/**
* Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
* 給 BeanPostProcessors 一個返回代理而不是目標 Bean 實例的機會【重要】
* 但此時還沒有創建代理對象,此時沒有對象,只有 BeanDefinition
*
* 第一次調用後置處理器【跟 AOP 有關】
* @see org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#postProcessAfterInitialization(java.lang.Object, java.lang.String)
*
* InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
* Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
*
* 此時對象還沒有實例化,只有 BeanDefinition
* 無法進行代理,只是將切面找出來進行緩存
*/
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
}
catch (Throwable ex) {
throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
"BeanPostProcessor before instantiation of bean failed", ex);
}
try {
/**
* 實例化 Bean
**/
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
if (logger.isTraceEnabled()) {
logger.trace("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
}
catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanCreationException(
mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
}
}
然後來看看Spring是怎麼將代理對象創建出來的,之前說resolveBeforeInstantiation()
方法將切面找出來進行緩存,那麼是怎麼緩存的呢,方法跟進去看一下。
protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
Object bean = null;
if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
Class<?> targetType = determineTargetType(beanName, mbd);
if (targetType != null) {
bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
if (bean != null) {
bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
}
}
}
mbd.beforeInstantiationResolved = (bean != null);
}
return bean;
}
這裏第一次調用InstantiationAwareBeanPostProcessor類型的後置處理器的postProcessBeforeInstantiation()
方法,第二次調用BeanPostProcessor類型的後置處理器的postProcessAfterInitialization()
方法,一般只會調用第一個方法。
從上面的類體系結構圖中可以看到,AbstractAutoProxyCreator是InstantiationAwareBeanPostProcessor的子類,所以會調用它重寫的postProcessBeforeInstantiation()
方法。
先說一下AbstractAdvisorAutoProxyCreator繼承了AbstractAutoProxyCreator,而它又實現了BeanFactoryAware,IOC容器在初始化過程中會回調setBeanFactory()
方法,AbstractAdvisorAutoProxyCreator有一個BeanFactoryAdvisorRetrievalHelper屬性,在Spring回調的時候,會實例化爲BeanFactoryAdvisorRetrievalHelperAdapter,它繼承了BeanFactoryAdvisorRetrievalHelper,這個類在後面會有很大用處。
AnnotationAwareAspectJAutoProxyCreator繼承了AspectJAwareAdvisorAutoProxyCreator,它在Spring回調的時候,實例化了一個ReflectiveAspectJAdvisorFactory類,它繼承了AbstractAspectJAdvisorFactory,它又實現了AspectJAdvisorFactory,和另一個BeanFactoryAspectJAdvisorsBuilderAdapter類,
它繼承了BeanFactoryAspectJAdvisorsBuilder。
不用委託Spring注入,回調的時候進行實例化,Get了一項新技能,就是費頭髮。
看圖更清晰一點:
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
Object cacheKey = getCacheKey(beanClass, beanName);
if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
// 已經被代理過則返回
if (this.advisedBeans.containsKey(cacheKey)) {
return null;
}
// 不應代理 或者 應該跳過
if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return null;
}
}
TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
if (targetSource != null) {
if (StringUtils.hasLength(beanName)) {
this.targetSourcedBeans.add(beanName);
}
// 獲取所有合格的增強器
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
// 創建 AOP 代理
Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
// 存入緩存
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
return null;
}
這裏shouldSkip()
方法就是緩存切面通知的地方。
protected boolean shouldSkip(Class<?> beanClass, String beanName) {
// 查找所有候選的通知
List<Advisor> candidateAdvisors = findCandidateAdvisors();
for (Advisor advisor : candidateAdvisors) {
/**
* 是 AspectJPointcutAdvisor 的子類 並且 切面名稱是 beanName
*
* 一般是 InstantiationModelAwarePointcutAdvisorImpl
**/
if (advisor instanceof AspectJPointcutAdvisor &&
((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) {
return true;
}
}
return super.shouldSkip(beanClass, beanName);
}
protected List<Advisor> findCandidateAdvisors() {
// 之前回調的時候實例化的 BeanFactoryAdvisorRetrievalHelperAdapter
this.advisorRetrievalHelper.findAdvisorBeans();
}
主要的方法就是findCandidateAdvisors()
方法,查找所有候選的通知。這裏會先走父類的查找方法,再走子類的查找方法,主要是子類的方法。
protected List<Advisor> findCandidateAdvisors() {
/**
* 添加根據超類規則找到的所有 Spring Advisors
*
* 查找要在自動代理中使用的所有候選 Advisor【找 Spring AOP 的 Advisor】
**/
List<Advisor> advisors = super.findCandidateAdvisors();
/**
* 構建 BeanFactory 中所有 AspectJ 方面的 Advisors
**/
if (this.aspectJAdvisorsBuilder != null) {
/**
* 查找帶有 AspectJ 註解的 Aspect bean【不同的註解對應不同的切面類】【找 AspectJ 的 Advisor】
*
* aspectJAdvisorsBuilder 是之前回調的時候實例化的 BeanFactoryAspectJAdvisorsBuilderAdapter
**/
advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
}
return advisors;
}
用之前Spring回調時初始化的BeanFactoryAspectJAdvisorsBuilderAdapter組件來構建 AspectJ 的通知。代碼如下:
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;
}
Class<?> beanType = this.beanFactory.getType(beanName);
if (beanType == null) {
continue;
}
// 是切面【具有 @Aspect 註解並且不是由 ajc 編譯】
if (this.advisorFactory.isAspect(beanType)) {
aspectNames.add(beanName);
AspectMetadata amd = new AspectMetadata(beanType, beanName);
// AspectJ支持的不同子句(切面實例化模型)是單例的
if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
MetadataAwareAspectInstanceFactory factory =
new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
/**
* 獲取 AspectJ 註解對應的切面增強處理類
**/
List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
// 是單例則存入 Map<String, List<Advisor>> 緩存
if (this.beanFactory.isSingleton(beanName)) {
this.advisorsCache.put(beanName, classAdvisors);
}
// 否則存入 Map<String, MetadataAwareAspectInstanceFactory> 緩存
else {
this.aspectFactoryCache.put(beanName, factory);
}
advisors.addAll(classAdvisors);
}
else {
if (this.beanFactory.isSingleton(beanName)) {
throw new IllegalArgumentException();
}
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;
}
主要方法就是ReflectiveAspectJAdvisorFactory的getAdvisors()
方法。代碼如下:
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
// 獲取切面類
Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
// 獲取切面類名稱
String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
// 校驗
validate(aspectClass);
/**
* 用裝飾器包裝 MetadataAwareAspectInstanceFactory,使其僅實例化一次
**/
MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);
List<Advisor> advisors = new ArrayList<>();
// 遍歷所有的除標註 @Pointcut 註解的通知方法
for (Method method : getAdvisorMethods(aspectClass)) {
// 獲取對應的增強器
Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName);
if (advisor != null) {
advisors.add(advisor);
}
}
......
return advisors;
}
getAdvisor()
方法獲取對應的增強器,代碼如下:
public Advisor getAdvisor(Method candidateAdviceMethod,
MetadataAwareAspectInstanceFactory aspectInstanceFactory,
int declarationOrderInAspect,
String aspectName) {
// 校驗
validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());
// 獲取切點表達式
AspectJExpressionPointcut expressionPointcut = getPointcut(
candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
if (expressionPointcut == null) {
return null;
}
// 獲取對應的增強器【重要】
return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
}
public InstantiationModelAwarePointcutAdvisorImpl(AspectJExpressionPointcut declaredPointcut,
Method aspectJAdviceMethod,
AspectJAdvisorFactory aspectJAdvisorFactory,
MetadataAwareAspectInstanceFactory aspectInstanceFactory,
int declarationOrder,
String aspectName) {
this.declaredPointcut = declaredPointcut;
this.declaringClass = aspectJAdviceMethod.getDeclaringClass();
this.methodName = aspectJAdviceMethod.getName();
this.parameterTypes = aspectJAdviceMethod.getParameterTypes();
this.aspectJAdviceMethod = aspectJAdviceMethod;
this.aspectJAdvisorFactory = aspectJAdvisorFactory;
this.aspectInstanceFactory = aspectInstanceFactory;
this.declarationOrder = declarationOrder;
this.aspectName = aspectName;
// 惰性實例化
if (aspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
Pointcut preInstantiationPointcut = Pointcuts.union(
aspectInstanceFactory.getAspectMetadata().getPerClausePointcut(), this.declaredPointcut);
this.pointcut = new PerTargetInstantiationModelPointcut(
this.declaredPointcut, preInstantiationPointcut, aspectInstanceFactory);
this.lazy = true;
}
else {
this.pointcut = this.declaredPointcut;
this.lazy = false;
// 實例化對相應的增強器
this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);
}
}
private Advice instantiateAdvice(AspectJExpressionPointcut pointcut) {
// 由不同的切面註解獲取不同的增強器
Advice advice = this.aspectJAdvisorFactory.getAdvice(
this.aspectJAdviceMethod,
pointcut,
this.aspectInstanceFactory,
this.declarationOrder,
this.aspectName
);
return (advice != null ? advice : EMPTY_ADVICE);
}
這裏調用的是ReflectiveAspectJAdvisorFactory的getAdvice()
方法,主要就是由切面註解實例化不同的通知類。
public Advice getAdvice(Method candidateAdviceMethod,
AspectJExpressionPointcut expressionPointcut,
MetadataAwareAspectInstanceFactory aspectInstanceFactory,
int declarationOrder,
String aspectName) {
// 獲取切面類
Class<?> candidateAspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
// 校驗
validate(candidateAspectClass);
// 獲取切面方法上的通知類型
AspectJAnnotation<?> aspectJAnnotation =
AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
if (aspectJAnnotation == null) {
return null;
}
......
AbstractAspectJAdvice springAdvice;
// 由註解類型實例化不同的增強器
switch (aspectJAnnotation.getAnnotationType()) {
case AtPointcut:
if (logger.isDebugEnabled()) {
logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");
}
return null;
// @Around
case AtAround:
springAdvice = new AspectJAroundAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
// @Before
case AtBefore:
springAdvice = new AspectJMethodBeforeAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
// @After
case AtAfter:
springAdvice = new AspectJAfterAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
// @AfterReturning
case AtAfterReturning:
springAdvice = new AspectJAfterReturningAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();
if (StringUtils.hasText(afterReturningAnnotation.returning())) {
springAdvice.setReturningName(afterReturningAnnotation.returning());
}
break;
// @AfterThrowing
case AtAfterThrowing:
springAdvice = new AspectJAfterThrowingAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();
if (StringUtils.hasText(afterThrowingAnnotation.throwing())) {
springAdvice.setThrowingName(afterThrowingAnnotation.throwing());
}
break;
default:
throw new UnsupportedOperationException();
}
// 配置屬性
springAdvice.setAspectName(aspectName);
springAdvice.setDeclarationOrder(declarationOrder);
String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod);
if (argNames != null) {
springAdvice.setArgumentNamesFromStringArray(argNames);
}
// 綁定參數
springAdvice.calculateArgumentBindings();
return springAdvice;
}
這個方法執行完,可以看到將帶有切面註解的方法都轉換爲對應的通知方法了。
創建過程
那麼前期的準備工作就執行完了,創建工作從AbstractAutowireCapableBeanFactory的initializeBean()
開始。
protected Object initializeBean(final String beanName,
final Object bean,
@Nullable RootBeanDefinition mbd) {
// 回調 Aware 及其實現類的方法
if (System.getSecurityManager() != null) {
AccessController.doPrivileged(
(PrivilegedAction<Object>) () -> {
invokeAwareMethods(beanName, bean);
return null;
},
getAccessControlContext());
}
else {
invokeAwareMethods(beanName, bean);
}
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
/**
* 關鍵字:執行
* 執行 BeanPostProcessor 直接實現類的 postProcessBeforeInitialization() 方法
*
* @PostConstruct 註解是在這裏面進行處理的
*/
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
/**
* 執行 Bean 生命週期回調中的 init 方法
*
* 實現 InitializingBean 接口並重寫 afterPropertiesSet() 方法是在這裏面進行處理的
*/
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
if (mbd == null || !mbd.isSynthetic()) {
/**
* 關鍵字:改變
* 執行 BeanPostProcessor 直接實現類的 postProcessAfterInitialization() 方法
*
* 產生 AOP 代理,事務的代理等
*/
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
applyBeanPostProcessorsAfterInitialization()
方法跟進去,發現其調用了BeanPostProcessor類型的後置處理器的postProcessAfterInitialization()
方法,這裏就會進到AbstractAutoProxyCreator的postProcessAfterInitialization()
方法。
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
// 如果需要則進行包裝
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
主要代碼就是wrapIfNecessary()
方法了,跟進去:
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))) {
return bean;
}
// 是不應代理的基礎結構類 或者 需要跳過
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
/**
* 獲取所有合格的增強器
*
* 通過註解方式和 XML【<aop: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;
}
// 否則標記爲未代理
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
getAdvicesAndAdvisorsForBean()
方法,有一部分代碼跟之前的一樣,主要多了查找可以應用於指定Bean的增強器這一過程,就不細說了,主要說createProxy()
創建代理對象方法:
protected Object createProxy(Class<?> beanClass,
@Nullable String beanName,
@Nullable Object[] specificInterceptors,
TargetSource targetSource) {
// beanFactory【DefaultListableBeanFactory】 是 ConfigurableListableBeanFactory 的子類
if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
/**
* 暴露目標對象
*
* 設置 originalTargetClass 屬性值爲 beanClass
**/
AutoProxyUtils.exposeTargetClass(
(ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass
);
}
// 代理工廠
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this);
/**
* proxyTargetClass 屬性值是否爲 False,默認爲 False
**/
if (!proxyFactory.isProxyTargetClass()) {
/**
* 確定是否應使用給定的 Bean 替代其目標類而不是其接口
*
* preserveTargetClass 屬性值爲 True
**/
if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
}
else {
evaluateProxyInterfaces(beanClass, proxyFactory);
}
}
// 構建增強器
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
proxyFactory.addAdvisors(advisors);
proxyFactory.setTargetSource(targetSource);
// 空方法
customizeProxyFactory(proxyFactory);
proxyFactory.setFrozen(this.freezeProxy);
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}
// 獲取代理對象【重要】
return proxyFactory.getProxy(getProxyClassLoader());
}
跟進去,最後執行的是DefaultAopProxyFactory的createAopProxy
方法:
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
// 需要優化【默認爲False】 或者 proxyTargetClass屬性值爲True【默認爲False】 或者 沒有用戶提供的代理接口
if (config.isOptimize() || config.isProxyTargetClass()
|| hasNoUserSuppliedProxyInterfaces(config)) {
// 目標類
Class<?> targetClass = config.getTargetClass();
if (targetClass == null) {
throw new AopConfigException();
}
// 是接口 或者 是代理的類
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
// 使用 JDK 動態代理
return new JdkDynamicAopProxy(config);
}
// 使用 CGLIB 代理
return new ObjenesisCglibAopProxy(config);
}
// 默認使用 JDK 動態代理
else {
return new JdkDynamicAopProxy(config);
}
}
這裏實例化代理對象的時候,傳了一個AdvisedSupport參數,後面調用的時候轉換爲攔截器會用到它的方法。
傳入後置處理器邏輯執行完之後,就可以看到創建的代理對象被織入了切面信息,感覺就像一個尋寶的過程,猿猿的生活就是這麼樸實無華且枯燥。
執行過程
因爲目標對象是一個JDK代理對象,所以執行目標方法會被上面實例化的JdkDynamicAopProxy代理對象的invoke()
方法攔截:
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
MethodInvocation invocation;
Object oldProxy = null;
boolean setProxyContext = false;
TargetSource targetSource = this.advised.targetSource;
Object target = null;
try {
// 代理接口沒有定義 equals 方法 且 調用的是目標對象的 equals 方法
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
// 目標對象沒有自己實現 equals 方法
return equals(args[0]);
}
// 代理接口沒有定義 hashCode 方法 且 調用的是目標對象的 hashCode 方法
else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
// 目標對象沒有自己實現 hashCode 方法
return hashCode();
}
// 聲明類型是 DecoratingProxy
else if (method.getDeclaringClass() == DecoratingProxy.class) {
return AopProxyUtils.ultimateTargetClass(this.advised);
}
// 透明 且 聲明類型是個接口 且 聲明類型是 Advised
else if (!this.advised.opaque && method.getDeclaringClass().isInterface()
&& method.getDeclaringClass().isAssignableFrom(Advised.class)) {
return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
}
Object retVal;
/**
* 如果設置了 exposeProxy = true 則將代理對象設置到線程本地變量中
*
* @see org.springframework.context.annotation.EnableAspectJAutoProxy#exposeProxy()
**/
if (this.advised.exposeProxy) {
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
target = targetSource.getTarget();
Class<?> targetClass = (target != null ? target.getClass() : null);
/**
* 獲取此方法的攔截鏈
**/
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
/**
* 檢查是否有其他通知
* 如果沒有,可以依靠目標直接反射調用,並避免創建 MethodInvocation
**/
if (chain.isEmpty()) {
/**
* 我們可以跳過創建 MethodInvocation 的操作:僅直接調用目標
* 請注意,最終的調用者必須是 InvokerInterceptor
**/
// 使給定參數適應給定方法中的目標籤名
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
// 通過反射調用給定目標
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
/**
* 創建一個 ReflectiveMethodInvocation
**/
invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
/**
* 通過攔截器鏈進入連接點【責任鏈模式】
**/
retVal = invocation.proceed();
}
Class<?> returnType = method.getReturnType();
if (retVal != null && retVal == target && returnType != Object.class
&& returnType.isInstance(proxy)
&& !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
retVal = proxy;
}
else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
throw new AopInvocationException();
}
return retVal;
}
finally {
if (target != null && !targetSource.isStatic()) {
targetSource.releaseTarget(target);
}
if (setProxyContext) {
AopContext.setCurrentProxy(oldProxy);
}
}
}
現在我們已經將通知織入到目標方法中去了,但是是如何執行這些通知方法的呢,getInterceptorsAndDynamicInterceptionAdvice()
方法看一下:
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method,
@Nullable Class<?> targetClass) {
// 目標對象方法的緩存鍵
// public abstract int com.ambition.service.Calculate.add(int,int)
MethodCacheKey cacheKey = new MethodCacheKey(method);
// 先去緩存中獲取
List<Object> cached = this.methodCache.get(cacheKey);
if (cached == null) {
// 緩存中沒有,則進行邏輯解析
cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
this, method, targetClass);
// 放入緩存中
this.methodCache.put(cacheKey, cached);
}
return cached;
}
Spring的設計思路很多操作都是先去緩存中獲取,獲取不到再進行復雜耗時的邏輯解析,然後放入緩存中,下次就直接獲取到了,優化了性能,敲黑板。
AdvisedSupport類有一個AdvisorChainFactory屬性,實例化了DefaultAdvisorChainFactory,由它進行邏輯解析。
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Advised config,
Method method,
@Nullable Class<?> targetClass) {
// 獲取 DefaultAdvisorAdapterRegistry 實例
AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
// 獲取通知
Advisor[] advisors = config.getAdvisors();
// 攔截器集合
List<Object> interceptorList = new ArrayList<>(advisors.length);
// 目標類
Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
Boolean hasIntroductions = null;
for (Advisor advisor : advisors) {
// 是 PointcutAdvisor 切點通知類型,DefaultPointcutAdvisor 和 InstantiationModelAwarePointcutAdvisorImpl 都符合條件
if (advisor instanceof PointcutAdvisor) {
PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
// 代理配置以預先過【默認爲False】 或者 切面與目標類匹配
if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
// 獲取 TrueMethodMatcher 或 AspectJExpressionPointcut 方法匹配器
MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
boolean match;
// TrueMethodMatcher 不是 IntroductionAwareMethodMatcher 的子類,AspectJExpressionPointcut 是
if (mm instanceof IntroductionAwareMethodMatcher) {
if (hasIntroductions == null) {
hasIntroductions = hasMatchingIntroductions(advisors, actualClass);
}
match = ((IntroductionAwareMethodMatcher) mm).matches(method, actualClass, hasIntroductions);
}
else {
match = mm.matches(method, actualClass);
}
// 匹配
if (match) {
// 轉換爲攔截器
MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
if (mm.isRuntime()) {
for (MethodInterceptor interceptor : interceptors) {
// 封裝爲 InterceptorAndDynamicMethodMatcher
interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
}
}
else {
interceptorList.addAll(Arrays.asList(interceptors));
}
}
}
}
// 是 IntroductionAdvisor 類型
else if (advisor instanceof IntroductionAdvisor) {
IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}
else {
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}
return interceptorList;
}
主要功能就是將通知類轉換爲攔截器類,執行完後可以看到AspectJAfterReturningAdvice轉換爲了AfterReturningAdviceInterceptor,AspectJMethodBeforeAdvice轉換爲了MethodBeforeAdviceInterceptor,AspectJAfterAdvice、AspectJAroundAdvice和AspectJAfterThrowingAdvice本身就是攔截器。
如果沒有攔截器,則直接反射調用目標方法。有的話則封裝爲ReflectiveMethodInvocation對象,調用它的proceed()
方法進行攔截處理。
public Object proceed() throws Throwable {
/**
* 從索引 -1 開始並提前增加【通過遞歸調用】
* 確保所有的責任者都完成處理邏輯
**/
// 是最後一個攔截器
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
// 直接通過反射調用目標方法
return invokeJoinpoint();
}
/**
* 獲取下一個責任者
*
* ExposeInvocationInterceptor
* AspectJAfterThrowingAdvice
* AfterReturningAdviceInterceptor
* AspectJAfterAdvice
* AspectJAroundAdvice
* MethodBeforeAdviceInterceptor
**/
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
/**
* 是 InterceptorAndDynamicMethodMatcher 類型
* 這裏都不是這個類型
**/
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);
}
}
這裏的設計使用了一個currentInterceptorIndex
從 -1 開始的索引下標,通過遞歸調用,如果是最後一個攔截器,則直接反射調用目標方法,如果不是,則獲取下一個攔截器,很巧妙,給大佬Orz了。
最後看一下各個攔截器的調用方法。
ExposeInvocationInterceptor的invoke()
方法:
public Object invoke(MethodInvocation mi) throws Throwable {
MethodInvocation oldInvocation = invocation.get();
invocation.set(mi);
try {
// 返回
return mi.proceed();
}
finally {
invocation.set(oldInvocation);
}
}
主要是用ThreadLocal將當前MethodInterceptor進行暴露。
AspectJAfterThrowingAdvice的invoke()
方法:
public Object invoke(MethodInvocation mi) throws Throwable {
try {
// 返回
return mi.proceed();
}
catch (Throwable ex) {
// 拋異常則調用
if (shouldInvokeOnThrowing(ex)) {
invokeAdviceMethod(getJoinPointMatch(), null, ex);
}
throw ex;
}
}
這個攔截器主要是處理異常的,有異常就做事,沒有異常就什麼也不幹。之後的調用處理拋了異常,都會被這裏捕獲。
AfterReturningAdviceInterceptor的invoke()
方法:
public Object invoke(MethodInvocation mi) throws Throwable {
Object retVal = mi.proceed();
// 如果發生異常,則返回通知不執行,返回到異常通知邏輯,被捕獲
this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
return retVal;
}
AspectJAfterAdvice的invoke()
方法:
public Object invoke(MethodInvocation mi) throws Throwable {
try {
// 返回
return mi.proceed();
}
finally {
// 返回通知一定會執行是因爲放在 finally 塊中
invokeAdviceMethod(getJoinPointMatch(), null, null);
}
}
AspectJAroundAdvice的invoke()
方法:
public Object invoke(MethodInvocation mi) throws Throwable {
// ReflectiveMethodInvocation 是 ProxyMethodInvocation
if (!(mi instanceof ProxyMethodInvocation)) {
throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi);
}
ProxyMethodInvocation pmi = (ProxyMethodInvocation) mi;
ProceedingJoinPoint pjp = lazyGetProceedingJoinPoint(pmi);
JoinPointMatch jpm = getJoinPointMatch(pmi);
// 調用環繞通知方法
return invokeAdviceMethod(pjp, jpm, null, null);
}
protected Object invokeAdviceMethod(@Nullable JoinPointMatch jpMatch,
@Nullable Object returnValue,
@Nullable Throwable ex) throws Throwable {
// 用給定的參數調用通知方法
return invokeAdviceMethodWithGivenArgs(argBinding(getJoinPoint(), jpMatch, returnValue, ex));
}
protected Object invokeAdviceMethod(JoinPoint jp,
@Nullable JoinPointMatch jpMatch,
@Nullable Object returnValue,
@Nullable Throwable t) throws Throwable {
return invokeAdviceMethodWithGivenArgs(argBinding(jp, jpMatch, returnValue, t));
}
protected Object invokeAdviceMethodWithGivenArgs(Object[] args) throws Throwable {
// 處理調用參數
Object[] actualArgs = args;
if (this.aspectJAdviceMethod.getParameterCount() == 0) {
actualArgs = null;
}
try {
// 使給定的方法可訪問,並在必要時明確將其設置爲可訪問
ReflectionUtils.makeAccessible(this.aspectJAdviceMethod);
/**
* 反射調用增強處理方法
*
* @see AopUtils#invokeJoinpointUsingReflection(java.lang.Object, java.lang.reflect.Method, java.lang.Object[])
**/
return this.aspectJAdviceMethod.invoke(this.aspectInstanceFactory.getAspectInstance(), actualArgs);
}
catch (IllegalArgumentException ex) {
throw new AopInvocationException();
}
catch (InvocationTargetException ex) {
throw ex.getTargetException();
}
}
MethodBeforeAdviceInterceptor的invoke()
方法:
public Object invoke(MethodInvocation mi) throws Throwable {
// 前置通知邏輯
this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
// 返回
return mi.proceed();
}
所以可以看到,攔截器的執行順序是:
這就是爲什麼在沒有環繞通知的情況下,沒有異常的執行順序是先執行前置通知,再執行後置通知,最後執行返回通知。
有異常的情況下,先執行前置通知,再執行後置通知,最後執行異常通知。
並且後置通知只要有就一定會執行。