今天我們來看下 spring aop 模塊的核心流程。
1. 簡單的 spring aop 例子
先看一個 aop 例子。如下代碼,先定義一個切面
package example.scannable;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import java.util.Arrays;
/**
* 打印日誌的切面
*/
@Component
@Aspect
public class MyLogAspect {
@Pointcut("execution(* example.scannable.MyLogService.*(..))")
public void pointCut() {
}
/**
* 方法前置通知
*
* @param joinPoint
*/
@Before(value = "pointCut()")
public void methodBefore(JoinPoint joinPoint) {
String methodName = joinPoint.getSignature().getName();
System.out.println(
"執行目標方法【" + methodName + "】之前執行<前置通知>,入參" + Arrays.asList(joinPoint.getArgs()));
}
/**
* 方法後置通知
*
* @param joinPoint
*/
@After(value = "pointCut()")
public void methodAfter(JoinPoint joinPoint) {
String methodName = joinPoint.getSignature().getName();
System.out.println(
"執行目標方法【" + methodName + "】之前執行<後置通知>,入參" + Arrays.asList(joinPoint.getArgs()));
}
/**
* 方法返回通知
*
* @param joinPoint
*/
@AfterReturning(value = "pointCut()")
public void methodReturning(JoinPoint joinPoint) {
String methodName = joinPoint.getSignature().getName();
System.out.println(
"執行目標方法【" + methodName + "】之前執行<返回通知>,入參" + Arrays.asList(joinPoint.getArgs()));
}
/**
* 方法異常通知
*
* @param joinPoint
*/
@AfterThrowing(value = "pointCut()")
public void methodAfterThrowing(JoinPoint joinPoint) {
String methodName = joinPoint.getSignature().getName();
System.out.println(
"執行目標方法【" + methodName + "】之前執行<異常通知>,入參" + Arrays.asList(joinPoint.getArgs()));
}
}
這是一個自定義的切面,創建了方法切點、方法前置通知、方法後置通知、方法返回通知、方法異常通知。
我們再創建一個基礎的 service:
package example.scannable;
import org.springframework.stereotype.Service;
public interface MyLogService {
String sayHello(String name);
}
package example.scannable;
import org.springframework.stereotype.Service;
@Service
public class MyLogServiceImpl implements MyLogService {
@Override
public String sayHello(String name) {
String result = "hello " + name + "!";
System.out.println(result);
return result;
}
}
這是一個基礎的類,它有一個方法,打印一個字符串,並返回參數。
我們再創建單元測試啓動類:
public class EnableAspectJAutoProxyTests {
@Test
public void withJdkProxy() {
ApplicationContext ctx = new AnnotationConfigApplicationContext(ConfigWithJdkProxy.class);
MyLogService fooService = ctx.getBean(MyLogService.class);
fooService.sayHello("spring");
}
@ComponentScan("example.scannable")
@EnableAspectJAutoProxy
static class ConfigWithJdkProxy {
}
}
執行結果如下:
執行目標方法【sayHello】之前執行<前置通知>,入參[spring]
hello spring!
執行目標方法【sayHello】之前執行<返回通知>,入參[spring]
執行目標方法【sayHello】之前執行<後置通知>,入參[spring]
可以看到在執行 MyLogService 類的 sayHello 方法的前後,執行了切面類中的各個方法。
這個是一個 spring aop 切面的基本用法。
那它是如何做到的呢?下面我們進入 spring aop 模塊的源代碼中一探究竟!
2. EnableAspectJAutoProxy 註解
可以看到我們的配置類上使用了 @EnableAspectJAutoProxy 註解,它目就啓動了 aop 的切面功能。它是怎麼做到呢?我看看它的源代碼:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
/**
* 指示是否基於標準 Java 接口代理相反的,創建基於子類的 CGLIB 代理。默認是 false
*
* Indicate whether subclass-based (CGLIB) proxies are to be created as opposed
* to standard Java interface-based proxies. The default is {@code false}.
*/
boolean proxyTargetClass() default false;
/**
* 表明代理對象應該通過 AOP 框架以一個從線程本地化來恢復 AopContext 類變量的方式被暴露出來。
* 默認情況下是關閉的,即,不保證 AopContext 訪問能正常工作。
*
* Indicate that the proxy should be exposed by the AOP framework as a {@code ThreadLocal}
* for retrieval via the {@link org.springframework.aop.framework.AopContext} class.
* Off by default, i.e. no guarantees that {@code AopContext} access will work.
* @since 4.3.1
*/
boolean exposeProxy() default false;
}
這個類上邊又使用了 @Import(AspectJAutoProxyRegistrar.class) ,它是把 AspectJAutoProxyRegistrar 類導入到了 spring 容器中。繼續看它的源代碼:
package org.springframework.context.annotation;
import org.springframework.aop.config.AopConfigUtils;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.type.AnnotationMetadata;
/**
* Registers an {@link org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator
* AnnotationAwareAspectJAutoProxyCreator} against the current {@link BeanDefinitionRegistry}
* as appropriate based on a given @{@link EnableAspectJAutoProxy} annotation.
*
* @author Chris Beams
* @author Juergen Hoeller
* @since 3.1
* @see EnableAspectJAutoProxy
*/
class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
/**
* Register, escalate, and configure the AspectJ auto proxy creator based on the value
* of the @{@link EnableAspectJAutoProxy#proxyTargetClass()} attribute on the importing
* {@code @Configuration} class.
*/
@Override
public void registerBeanDefinitions(
AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
// 註冊一個 AnnotationAwareAspectJAutoProxyCreator 類到 bean 工廠
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
// 解析 EnableAspectJAutoProxy 類註解
AnnotationAttributes enableAspectJAutoProxy =
AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
if (enableAspectJAutoProxy != null) {
if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
// 強制使用 CGLIB 代理
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}
if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
// 強制暴露代理對象
AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
}
}
}
}
我們發現,這個類是 ImportBeanDefinitionRegistrar 類型,即導入 bean 定義註冊器,看下它的類圖:
我在上一篇文章 spring ioc 容器核心流程分析中,講過這個類型,它是在 spring 容器 的 refresh() 刷新方法中的 invokeBeanFactoryPostProcessors() 方法中執行的,它是通過調用 org.springframework.context.annotation.ConfigurationClassPostProcessor 的 postProcessBeanDefinitionRegistry() 方法執行處理 bean 定義註冊器,最後調用到 org.springframework.context.annotation.ConfigurationClassPostProcessor 類的 postProcessBeanDefinitionRegistry() 方法中,接着,通過創建 ConfigurationClassParser 類,解析 @Configuration 類,最終處理 @Import 註解時,判斷 bean 的類型是否爲 ImportBeanDefinitionRegistrar 類型(即 AspectJAutoProxyRegistrar 類),然後實例化它並且保存到配置類 ConfigurationClass 上,最後再通過 ConfigurationClassBeanDefinitionReader 類型,配置類 bean 定義讀取器,去執行配置類中的導入 bean 註冊器的 registerBeanDefinitions() 方法。
這個方法中最主要的是 AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry); 方法,看它的名字應該可以猜測到,它是往容器中註冊一個切面註解自動代理創建器。
@Nullable
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) {
// 創建一個切面註解自動代理創建器
return registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry, null);
}
@Nullable
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(
BeanDefinitionRegistry registry, @Nullable Object source) {
// 註冊一個 AnnotationAwareAspectJAutoProxyCreator 類
return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
}
果然,就是註冊了一個 AnnotationAwareAspectJAutoProxyCreator 類到容器中。同樣看下它的類圖:
可以看到它實現了 BeanPostProcessor、InstantiationAwareBeanPostProcessor 接口。
其中它實現了 BeanPostProcessor 的 postProcessAfterInitialization() 方法,這個方法是在 createBean 創建 bean 方法中執行的,如下面的方法調用棧。
# 執行 AbstractAutoProxyCreator 類的實例化之前的後置處理方法
postProcessBeforeInstantiation(Class, String):257, AbstractAutoProxyCreator (org.springframework.aop.framework.autoproxy), AbstractAutoProxyCreator.java
# 在實例化之前應用 bean 後置處理器
applyBeanPostProcessorsBeforeInstantiation(Class, String):1202, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support), AbstractAutowireCapableBeanFactory.java
# bean 實例化之前的解析
resolveBeforeInstantiation(String, RootBeanDefinition):1175, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support), AbstractAutowireCapableBeanFactory.java
# 委派到 createBean 方法
createBean(String, RootBeanDefinition, Object[]):550, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support), AbstractAutowireCapableBeanFactory.java
lambda$doGetBean$0(String, RootBeanDefinition, Object[]):364, AbstractBeanFactory (org.springframework.beans.factory.support), AbstractBeanFactory.java
# 調用 ObjectFactory 個 getObject() 方法
getObject():-1, 424732838 (org.springframework.beans.factory.support.AbstractBeanFactory$$Lambda$384), Unknown Source
# 獲取單例
getSingleton(String, ObjectFactory):262, DefaultSingletonBeanRegistry (org.springframework.beans.factory.support), DefaultSingletonBeanRegistry.java
# 獲取 bean
doGetBean(String, Class, Object[], boolean):361, AbstractBeanFactory (org.springframework.beans.factory.support), AbstractBeanFactory.java
# 獲取 bean
getBean(String):218, AbstractBeanFactory (org.springframework.beans.factory.support), AbstractBeanFactory.java
# 預處理單例實例
preInstantiateSingletons():957, DefaultListableBeanFactory (org.springframework.beans.factory.support), DefaultListableBeanFactory.java
# 實例化剩餘單例
finishBeanFactoryInitialization(ConfigurableListableBeanFactory):982, AbstractApplicationContext (org.springframework.context.support), AbstractApplicationContext.java
# 刷新方法
refresh():613, AbstractApplicationContext (org.springframework.context.support), AbstractApplicationContext.java
...省略
它的方法具體流程,我們稍後詳細再看。
還有,它實現了 InstantiationAwareBeanPostProcessor 接口的 postProcessBeforeInstantiation() 方法,對 bean 實例化之前執行處理操作。它是在創建 bean 之後,對 bean 進行初始化的時候調用的,如下方法的調用棧:
# 執行 AbstractAutoProxyCreator 的 postProcessAfterInitialization 方法
postProcessAfterInitialization(Object, String):305, AbstractAutoProxyCreator (org.springframework.aop.framework.autoproxy), AbstractAutoProxyCreator.java
# 應用 bean 初始化後的後置處理
applyBeanPostProcessorsAfterInitialization(Object, String):468, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support), AbstractAutowireCapableBeanFactory.java
# 初始化 bean
initializeBean(String, Object, RootBeanDefinition):1923, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support), AbstractAutowireCapableBeanFactory.java
# 創建 bean
doCreateBean(String, RootBeanDefinition, Object[]):654, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support), AbstractAutowireCapableBeanFactory.java
# 委派到 createBean 方法
createBean(String, RootBeanDefinition, Object[]):562, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support),
...同上...
doGetBean(String, Class, Object[], boolean):361, AbstractBeanFactory (org.springframework.beans.factory.support), AbstractBeanFactory.java
getBean(String):218, AbstractBeanFactory (org.springframework.beans.factory.support), AbstractBeanFactory.java
preInstantiateSingletons():957, DefaultListableBeanFactory (org.springframework.beans.factory.support), DefaultListableBeanFactory.java
finishBeanFactoryInitialization(ConfigurableListableBeanFactory):982, AbstractApplicationContext (org.springframework.context.support), AbstractApplicationContext.java
refresh():613, AbstractApplicationContext (org.springframework.context.support), AbstractApplicationContext.java
...省略無關的調用
我們重點看下這兩個方法。
3. bean 實例化之前的後置處理
下面,我們開始着重看 AbstractAutoProxyCreator#postProcessBeforeInstantiation 這個方法,源碼附上:
/**
* 實例化之前的後置處理,創建代理對象
*
* @param beanClass the class of the bean to be instantiated
* @param beanName the name of the bean
* @return
*/
@Override
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;
}
}
// 如果我們一個自定義的目標源,那就創建代理對象。
// 禁止目標 bean 不必要的初始化。
// 這個目標源將會以自定義的方式處理目標實例。
// Create proxy here if we have a custom TargetSource.
// Suppresses unnecessary default instantiation of the target bean:
// The TargetSource will handle target instances in a custom fashion.
TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
if (targetSource != null) {
if (StringUtils.hasLength(beanName)) {
this.targetSourcedBeans.add(beanName);
}
// 獲取類的增強器
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
// 創建代理對象,這裏決定創建 jdk 代理或者是 cglib 代理對象
Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
// 放入緩存
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
return null;
}
postProcessBeforeInstantiation 這個方法的主要的邏輯是:
- 判斷 bean 是否爲基礎的類;
- 通過獲取容器中所有的增強器,並且加入到緩存中,判斷增強器是否應該被跳過;
- 如果有自定義的目標源,那就創建代理對象並返回對象,沒有的話則返回 null;
我們看下 isInfrastructureClass() 方法,判斷是否爲基礎類,我們看下它的實現:org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#isInfrastructureClass
// 判斷是否爲基礎類
protected boolean isInfrastructureClass(Class<?> beanClass) {
boolean retVal = Advice.class.isAssignableFrom(beanClass) ||
Pointcut.class.isAssignableFrom(beanClass) ||
Advisor.class.isAssignableFrom(beanClass) ||
AopInfrastructureBean.class.isAssignableFrom(beanClass);
if (retVal && logger.isTraceEnabled()) {
logger.trace("Did not attempt to auto-proxy infrastructure class [" + beanClass.getName() + "]");
}
return retVal;
}
這個方法的邏輯是,判斷這個類是不是一個 Advice、Pointcut、Advisor、AopInfrastructureBean 類型;
3.1 shouldSkip 是否需要跳過
下面看重點的 shouldSkip 方法:org.springframework.aop.aspectj.autoproxy.AspectJAwareAdvisorAutoProxyCreator#shouldSkip
/**
* 判斷是否跳過指定的類型和 bean
*
* @param beanClass the class of the bean
* @param beanName the name of the bean
* @return
*/
@Override
protected boolean shouldSkip(Class<?> beanClass, String beanName) {
// TODO: Consider optimization by caching the list of the aspect names
// 找到候選的增強器,創建的時候也把它們放入緩存中
List<Advisor> candidateAdvisors = findCandidateAdvisors();
for (Advisor advisor : candidateAdvisors) {
if (advisor instanceof AspectJPointcutAdvisor &&
((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) {
return true;
}
}
return super.shouldSkip(beanClass, beanName);
}
3.1.1 findCandidateAdvisors 查找候選的增強器
這裏邊是先找候選的增強器,繼續看看它的邏輯:org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator#findCandidateAdvisors
@Override
protected List<Advisor> findCandidateAdvisors() {
// spring tx 事務模塊實現了 Advisor 接口
// 從 bean 工廠中找 Advisor 類型的候選 bean
// 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) {
// 使用切面增強器構建器,進行構建增強器
advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
}
return advisors;
}
先調用父類的方法,然後在調用自己的構建切面增強器。看看父類的方法是什麼樣的邏輯:
/**
* 找使用了自動代理的候選增強器
* Find all candidate Advisors to use in auto-proxying.
* @return the List of candidate Advisors
*/
protected List<Advisor> findCandidateAdvisors() {
Assert.state(this.advisorRetrievalHelper != null, "No BeanFactoryAdvisorRetrievalHelper available");
// 使用增強器恢復工具類去找增強器
return this.advisorRetrievalHelper.findAdvisorBeans();
}
org.springframework.aop.framework.autoproxy.BeanFactoryAdvisorRetrievalHelper#findAdvisorBeans
/**
* 從當前 bean 工廠中查找合格的增強器 beans,忽略工廠 bean 和當前正被創建的 bean
*
* Find all eligible Advisor beans in the current bean factory,
* ignoring FactoryBeans and excluding beans that are currently in creation.
* @return the list of {@link org.springframework.aop.Advisor} beans
* @see #isEligibleBean
*/
public List<Advisor> findAdvisorBeans() {
// 找增強器的 bean 名稱
// Determine list of advisor bean names, if not cached already.
String[] advisorNames = this.cachedAdvisorBeanNames;
if (advisorNames == null) {
// Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let the auto-proxy creator apply to them!
advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Advisor.class, true, false);
this.cachedAdvisorBeanNames = advisorNames;
}
if (advisorNames.length == 0) {
return new ArrayList<>();
}
List<Advisor> advisors = new ArrayList<>();
for (String name : advisorNames) {
// 是否一個合格的 bean
if (isEligibleBean(name)) {
// 顧慮當前被創建的 bean
if (this.beanFactory.isCurrentlyInCreation(name)) {
if (logger.isTraceEnabled()) {
logger.trace("Skipping currently created advisor '" + name + "'");
}
}
else {
try {
// 從 bean 工廠中查找 Advisor 類型的 bean
advisors.add(this.beanFactory.getBean(name, Advisor.class));
}
catch (BeanCreationException ex) {
Throwable rootCause = ex.getMostSpecificCause();
if (rootCause instanceof BeanCurrentlyInCreationException) {
BeanCreationException bce = (BeanCreationException) rootCause;
String bceBeanName = bce.getBeanName();
if (bceBeanName != null && this.beanFactory.isCurrentlyInCreation(bceBeanName)) {
if (logger.isTraceEnabled()) {
logger.trace("Skipping advisor '" + name +
"' with dependency on currently created bean: " + ex.getMessage());
}
// Ignore: indicates a reference back to the bean we're trying to advise.
// We want to find advisors other than the currently created bean itself.
continue;
}
}
throw ex;
}
}
}
}
return advisors;
}
這裏的主要做的事情就是從 bean 工廠中獲取 Advisor 類型的 beans 返回。spring tx 模塊的源碼,就是在這裏進行查找的。
3.1.2 buildAspectJAdvisors 構建切面增強器
接着回來看下 this.aspectJAdvisorsBuilder.buildAspectJAdvisors() 這個方法,它實際上是 org.springframework.aop.aspectj.annotation.BeanFactoryAspectJAdvisorsBuilder#buildAspectJAdvisors 的方法:
/**
* 從當前 bean 工廠中查找 AspectJ 註解的切面,返回一個 spring aop 增強器的列表。
* 爲每個切面的 advice 方法創建一個 spring 增強器
*
* Look for AspectJ-annotated aspect beans in the current bean factory,
* and return to a list of Spring AOP Advisors representing them.
* <p>Creates a Spring Advisor for each AspectJ advice method.
* @return the list of {@link org.springframework.aop.Advisor} beans
* @see #isEligibleBean
*/
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<>();
// 從 bean 工廠中找出全部的 bean 名稱
String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Object.class, true, false);
for (String beanName : beanNames) {
if (!isEligibleBean(beanName)) {
continue;
}
// 我們需要小心不要讓這些 bean 過早的實例化,這種情況下它們將會被 spring 容器緩存,但不會被編織。
// We must be careful not to instantiate beans eagerly as in this case they
// would be cached by the Spring container but would not have been weaved.
// 根據 bean 名稱獲取類型
Class<?> beanType = this.beanFactory.getType(beanName, false);
if (beanType == null) {
continue;
}
// 判斷是否有 @Aspect 註解
if (this.advisorFactory.isAspect(beanType)) {
aspectNames.add(beanName);
// 切面元數據
AspectMetadata amd = new AspectMetadata(beanType, beanName);
if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
// 必須是單例的才能創建切面
MetadataAwareAspectInstanceFactory factory =
new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
// 獲取全部的增強器,重要的方法
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;
}
@Override
public boolean isAspect(Class<?> clazz) {
return (hasAspectAnnotation(clazz) && !compiledByAjc(clazz));
}
private boolean hasAspectAnnotation(Class<?> clazz) {
return (AnnotationUtils.findAnnotation(clazz, Aspect.class) != null);
}
/**
* We need to detect this as "code-style" AspectJ aspects should not be
* interpreted by Spring AOP.
*/
private boolean compiledByAjc(Class<?> clazz) {
// The AJTypeSystem goes to great lengths to provide a uniform appearance between code-style and
// annotation-style aspects. Therefore there is no 'clean' way to tell them apart. Here we rely on
// an implementation detail of the AspectJ compiler.
for (Field field : clazz.getDeclaredFields()) {
if (field.getName().startsWith(AJC_MAGIC)) {
return true;
}
}
return false;
}
這裏主要做了幾件事情:
- 遍歷所有的 bean;
- 通過 org.springframework.aop.aspectj.annotation.AbstractAspectJAdvisorFactory#isAspect 方法判斷類是否一個切面,使用 @Aspect 註解標記的類;
- 根據bean 的 scope 類型創建對應的切面實例工廠,通過工廠獲取增強器。單例類型對應的工廠是 BeanFactoryAspectInstanceFactory,否則使用 PrototypeAspectInstanceFactory 工廠;
- 收集把所有的增強器,並且將它們添加到緩存中,最後返回增強器集合。
其中第 3 步中,兩個切面實例工廠都是繼承了 org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory 類,它的 getAdvisors 如下:
/**
* 獲取增強器
*
* @param aspectInstanceFactory the aspect instance factory
* (not the aspect instance itself in order to avoid eager instantiation)
* @return
*/
@Override
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
// 切面類型
Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
// 切面名稱
String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
// 校驗
validate(aspectClass);
// We need to wrap the MetadataAwareAspectInstanceFactory with a decorator
// so that it will only instantiate once.
MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);
List<Advisor> advisors = new ArrayList<>();
// 獲取類上的所有增強器方法
for (Method method : getAdvisorMethods(aspectClass)) {
// Prior to Spring Framework 5.2.7, advisors.size() was supplied as the declarationOrderInAspect
// to getAdvisor(...) to represent the "current position" in the declared methods list.
// However, since Java 7 the "current position" is not valid since the JDK no longer
// returns declared methods in the order in which they are declared in the source code.
// Thus, we now hard code the declarationOrderInAspect to 0 for all advice methods
// discovered via reflection in order to support reliable advice ordering across JVM launches.
// Specifically, a value of 0 aligns with the default value used in
// AspectJPrecedenceComparator.getAspectDeclarationOrder(Advisor).
// 開始獲取增強器,增強器實現了方法攔截器接口,用於執行時進行調用
Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, 0, aspectName);
if (advisor != null) {
advisors.add(advisor);
}
}
// If it's a per target aspect, emit the dummy instantiating aspect.
if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
advisors.add(0, instantiationAdvisor);
}
// 查找介紹的字段
// Find introduction fields.
for (Field field : aspectClass.getDeclaredFields()) {
Advisor advisor = getDeclareParentsAdvisor(field);
if (advisor != null) {
advisors.add(advisor);
}
}
return advisors;
}
主要的邏輯爲:
- 獲取切面的類型、名稱,進行校驗;
- 獲取切面類的所有的除了 @Pointcut 註解標記的所有方法,並進行排序;
- 根據方法獲取切面註解(Pointcut.class, Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class),然後創建切點表達式端點類 AspectJExpressionPointcut,最後創建一個實例化模型切點增強器實例 InstantiationModelAwarePointcutAdvisorImpl 返回
- 獲取切面類上聲明的字段,過濾出標記有 @DeclareParents 註解的字段,創建 DeclareParentsAdvisor 類返回。
4. bean 初始化之後的後置處理
接着,該看 org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#postProcessAfterInitialization 類方法了:
/**
* 初始化之後的後置處理,如果 bean 被標識爲被子類代理的類,那就用配置的攔截器創建一個代理對象。
*
* Create a proxy with the configured interceptors if the bean is
* identified as one to proxy by the subclass.
* @see #getAdvicesAndAdvisorsForBean
*/
@Override
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 方法:
/**
* 必要的時候包裝給定的 bean,比如是否需要被代理。
*
* Wrap the given bean if necessary, i.e. if it is eligible for being proxied.
* @param bean the raw bean instance
* @param beanName the name of the bean
* @param cacheKey the cache key for metadata access
* @return a proxy wrapping the bean, or the raw bean instance as-is
*/
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;
}
// 創建代理對象,如果有增強器
// Create proxy if we have advice.
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;
}
它的主要流程:
- 判斷bean 是否基礎類,是否應該跳過(這一步已經在上面的 postProcessBeforeInstantiation 方法執行過了);
- 執行 getAdvicesAndAdvisorsForBean() 方法,爲目標 bean 獲取的通知和增強器;
- 增強器不爲空,則代理創建代理對象;
- 返回創建的代理對象;
我們重點看下 getAdvicesAndAdvisorsForBean 獲取通知和增強器邏輯和創建代理對象邏輯。
4.1 getAdvicesAndAdvisorsForBean 獲取通知和增強器
它是實現在 org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#getAdvicesAndAdvisorsForBean:
@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() 方法:
/**
* Find all eligible Advisors for auto-proxying this class.
* @param beanClass the clazz to find advisors for
* @param beanName the name of the currently proxied bean
* @return the empty List, not {@code null},
* if there are no pointcuts or interceptors
* @see #findCandidateAdvisors
* @see #sortAdvisors
* @see #extendAdvisors
*/
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;
}
做了三件事:
- 執行 findCandidateAdvisors() 查找候選增強器(這一步同樣也是在上面的 3.1.1 節講過了);
- 執行 findAdvisorsThatCanApply() 繼續查找能應用的增強器;
- 執行 extendAdvisors() 擴展增強器;
- 返回可以用的增強器。
4.1.1 findAdvisorsThatCanApply 查找可以應用的增強器
我們看下 org.springframework.aop.support.AopUtils#findAdvisorsThatCanApply 方法:
/**
* 從給定的類中選擇一個候選增強器,這個列表要適用於給定的類
*
* Determine the sublist of the {@code candidateAdvisors} list
* that is applicable to the given class.
* @param candidateAdvisors the Advisors to evaluate
* @param clazz the target class
* @return sublist of Advisors that can apply to an object of the given class
* (may be the incoming List as-is)
*/
public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
if (candidateAdvisors.isEmpty()) {
return candidateAdvisors;
}
List<Advisor> eligibleAdvisors = new ArrayList<>();
for (Advisor candidate : candidateAdvisors) {
// 判斷是否可以應用
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;
}
if (canApply(candidate, clazz, hasIntroductions)) {
eligibleAdvisors.add(candidate);
}
}
return eligibleAdvisors;
}
這裏主要執行了 canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) 方法:
public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {
if (advisor instanceof IntroductionAdvisor) {
// 介紹類的增強器
return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);
}
else if (advisor instanceof PointcutAdvisor) {
// 切點增強器
PointcutAdvisor pca = (PointcutAdvisor) advisor;
return canApply(pca.getPointcut(), targetClass, hasIntroductions);
}
else {
// It doesn't have a pointcut so we assume it applies.
return true;
}
}
這裏判斷增強器的類型,一般是 InstantiationModelAwarePointcutAdvisorImpl 類型,它實現了 PointcutAdvisor 接口,執行 canApply(pca.getPointcut(), targetClass, hasIntroductions) 方法:
/**
* 給定的切點可以全部應用到這個類上嗎?這是一個非常重要的測試,因爲它用於優化一個類的切點。
。 *
* Can the given pointcut apply at all on the given class?
* <p>This is an important test as it can be used to optimize
* out a pointcut for a class.
* @param pc the static or dynamic pointcut to check
* @param targetClass the class to test
* @param hasIntroductions whether or not the advisor chain
* for this bean includes any introductions
* @return whether the pointcut can apply on any method
*/
public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
Assert.notNull(pc, "Pointcut must not be null");
if (!pc.getClassFilter().matches(targetClass)) {
return false;
}
// 方法匹配器
MethodMatcher methodMatcher = pc.getMethodMatcher();
if (methodMatcher == MethodMatcher.TRUE) {
// No need to iterate the methods if we're matching any method anyway...
return true;
}
IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
}
// 獲取目標類的 Class 類型
Set<Class<?>> classes = new LinkedHashSet<>();
if (!Proxy.isProxyClass(targetClass)) {
// 獲取原始類
classes.add(ClassUtils.getUserClass(targetClass));
}
// 獲取類的所有接口
classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass));
for (Class<?> clazz : classes) {
// 獲取類上聲明的方法
Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
for (Method method : methods) {
// 遍歷每個方法,判斷是否匹配
if (introductionAwareMethodMatcher != null ?
introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) :
methodMatcher.matches(method, targetClass)) {
return true;
}
}
}
return false;
}
這裏主要做了一下幾件事情:
- 獲取增強器中的切點的方法匹配器;
- 獲取目標類的原始類、所有的接口信息;
- 遍歷類和接口,獲取其上的聲明的方法;
- 根據匹配與方法機型匹配;
- 返回匹配結果。
4.1.2 extendAdvisors 擴展增強器
對應的是 org.springframework.aop.aspectj.autoproxy.AspectJAwareAdvisorAutoProxyCreator#extendAdvisors 方法:
/**
* Add an {@link ExposeInvocationInterceptor} to the beginning of the advice chain.
* <p>This additional advice is needed when using AspectJ pointcut expressions
* and when using AspectJ-style advice.
*/
@Override
protected void extendAdvisors(List<Advisor> candidateAdvisors) {
// 如果需要的話,設置增強器調用器鏈,添加一個暴露方法執行器的執行攔截器
AspectJProxyUtils.makeAdvisorChainAspectJCapableIfNecessary(candidateAdvisors);
}
繼續看它的實現:
/**
* Add special advisors if necessary to work with a proxy chain that contains AspectJ advisors:
* concretely, {@link ExposeInvocationInterceptor} at the beginning of the list.
* <p>This will expose the current Spring AOP invocation (necessary for some AspectJ pointcut
* matching) and make available the current AspectJ JoinPoint. The call will have no effect
* if there are no AspectJ advisors in the advisor chain.
* @param advisors the advisors available
* @return {@code true} if an {@link ExposeInvocationInterceptor} was added to the list,
* otherwise {@code false}
*/
public static boolean makeAdvisorChainAspectJCapableIfNecessary(List<Advisor> advisors) {
// Don't add advisors to an empty list; may indicate that proxying is just not required
if (!advisors.isEmpty()) {
boolean foundAspectJAdvice = false;
for (Advisor advisor : advisors) {
// Be careful not to get the Advice without a guard, as this might eagerly
// instantiate a non-singleton AspectJ aspect...
if (isAspectJAdvice(advisor)) {
foundAspectJAdvice = true;
break;
}
}
if (foundAspectJAdvice && !advisors.contains(ExposeInvocationInterceptor.ADVISOR)) {
// 添加一個暴露執行的攔截器
advisors.add(0, ExposeInvocationInterceptor.ADVISOR);
return true;
}
}
return false;
}
這個方法的邏輯是:
- 先從所有的增強器中一個切面通知;
- 判斷是否找到,並且這些增強器其中不包含 ExposeInvocationInterceptor.ADVISOR 常量;
- 如果符合條件,那麼添加 ExposeInvocationInterceptor.ADVISOR 常量,並且把它放入這些增強器的首尾。
4.2 createProxy 創建代理對象
接着看 org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#createProxy 創建代理對象方法:
/**
* 爲給定的 bean 創建一個代理對象
*
* Create an AOP proxy for the given bean.
* @param beanClass the class of the bean
* @param beanName the name of the bean
* @param specificInterceptors the set of interceptors that is
* specific to this bean (may be empty, but not null)
* @param targetSource the TargetSource for the proxy,
* already pre-configured to access the bean
* @return the AOP proxy for the bean
* @see #buildAdvisors
*/
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 proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this);
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);
proxyFactory.setFrozen(this.freezeProxy);
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}
// 創建代理對象
return proxyFactory.getProxy(getProxyClassLoader());
}
這裏主要進行的邏輯:
- 創建一個代理工廠 ProxyFactory;
- 設置代理工廠屬性,綁定增強器;
- 通過代理工廠來創建代理對象。
4.2.1 創建 AOP 代理對象
代理工廠創建代理對象 org.springframework.aop.framework.ProxyFactory#getProxy(java.lang.ClassLoader):
public Object getProxy(@Nullable ClassLoader classLoader) {
// 創建一個 Aop 代理,通過 DefaultAopProxyFactory 來創建一個 aop 代理,來獲取代理對象
return createAopProxy().getProxy(classLoader);
}
它會創建一個 aop 代理:
/**
* 子類應該調用這個來返回一個新的 AOP 代理,不應該用 this 作爲參數來創建一個 AOP 代理對象
*
* Subclasses should call this to get a new AOP proxy. They should <b>not</b>
* create an AOP proxy with {@code this} as an argument.
*/
protected final synchronized AopProxy createAopProxy() {
if (!this.active) {
activate();
}
// 通過代理工廠創建代理類
return getAopProxyFactory().createAopProxy(this);
}
然後會獲取一個 aop 代理工廠來創建 aop 代理:org.springframework.aop.framework.DefaultAopProxyFactory#createAopProxy
/**
* 創建代理對象
*
* @param config the AOP configuration in the form of an
* AdvisedSupport object
* @return
* @throws AopConfigException
*/
@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
if (!IN_NATIVE_IMAGE &&
(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)) {
// 代理對象是一個接口,或者它是一個 jdk 自帶的 Proxy 類,那就創建 jdk 的動態代理對象
return new JdkDynamicAopProxy(config);
}
// 否則就創建一個 cglib 代理對象
return new ObjenesisCglibAopProxy(config);
}
else {
return new JdkDynamicAopProxy(config);
}
}
這裏可以看到它會根據條件創建 jdk 代理或者 cglib 代理:
- 目標類是一個接口或者目標類已經是一個jdk原生的代理對象(Proxy.class 之類),那麼就創建 JdkDynamicAopProxy 類對象;
- 否則創建一個 ObjenesisCglibAopProxy 類型對象返回。
4.3 JdkDynamicAopProxy 創建代理對象
我們重點看下 JdkDynamicAopProxy 代理對象的實現。它的 getProxy 方法如下:
@Override
public Object getProxy(@Nullable ClassLoader classLoader) {
if (logger.isTraceEnabled()) {
logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
}
// 使用 JDK 自帶的動態代理對象進行代理
return Proxy.newProxyInstance(classLoader, this.proxiedInterfaces, this);
}
看到這個,是不是感覺非常熟悉,用的就是 jdk 自身的動態代理 API。通過調用 Proxy 的 newProxyInstance() 方法,來創建一個動態代理對象,其中這個方法的第三個參數類型是一個 InvocationHandler 類型,傳遞的實例就是 JdkDynamicAopProxy 類實例本身。
Proxy 動態代理對象創建代理對象的時候,實際上是使用到了 java.lang.reflect.ProxyGenerator#generateClassFile 方法來生成目標類實例,它是在內存中通過直接寫入字節碼對應的數據。
我們來看看 JdkDynamicAopProxy 它實現的 InvocationHandler 接口的 invoke() 方法:
/**
* 執行代理
*
* Implementation of {@code InvocationHandler.invoke}.
* <p>Callers will see exactly the exception thrown by the target,
* unless a hook method throws an exception.
*/
@Override
@Nullable
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
TargetSource targetSource = this.advised.targetSource;
Object target = null;
try {
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
// equals 方法
// The target does not implement the equals(Object) method itself.
return equals(args[0]);
}
else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
// The target does not implement the hashCode() method itself.
return hashCode();
}
else if (method.getDeclaringClass() == DecoratingProxy.class) {
// There is only getDecoratedClass() declared -> dispatch to proxy config.
return AopProxyUtils.ultimateTargetClass(this.advised);
}
else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
method.getDeclaringClass().isAssignableFrom(Advised.class)) {
// Service invocations on ProxyConfig with the proxy config...
return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
}
Object retVal;
// 如果設置了暴露代理對象,就將其放入當前線程本地化中
if (this.advised.exposeProxy) {
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// Get as late as possible to minimize the time we "own" the target,
// in case it comes from a pool.
target = targetSource.getTarget();
Class<?> targetClass = (target != null ? target.getClass() : null);
// 獲取攔截器和動態攔截器通知
// Get the interception chain for this method.
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
// Check whether we have any advice. If we don't, we can fallback on direct
// reflective invocation of the target, and avoid creating a MethodInvocation.
if (chain.isEmpty()) {
// We can skip creating a MethodInvocation: just invoke the target directly
// Note that the final invoker must be an InvokerInterceptor so we know it does
// nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
// 創建一個方法執行器
// We need to create a method invocation...
MethodInvocation invocation =
new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// Proceed to the joinpoint through the interceptor chain.
// 執行方法,重點方法,使用了責任鏈調用模式
retVal = invocation.proceed();
}
// Massage return value if necessary.
Class<?> returnType = method.getReturnType();
if (retVal != null && retVal == target &&
returnType != Object.class && returnType.isInstance(proxy) &&
!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
// Special case: it returned "this" and the return type of the method
// is type-compatible. Note that we can't help if the target sets
// a reference to itself in another returned object.
retVal = proxy;
}
else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
throw new AopInvocationException(
"Null return value from advice does not match primitive return type for: " + method);
}
return retVal;
}
finally {
if (target != null && !targetSource.isStatic()) {
// Must have come from TargetSource.
targetSource.releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}
我們梳理下它的流程:
- 對一些基礎方法和 DecoratingProxy 類型、Advised 類型直接返回,比如 equals、hashCode等;
- 如果設置了暴露代理對象,就將其放入當前線程本地化中;
- 獲取攔截器和動態攔截器通知(非常重要的方法);org.springframework.aop.framework.AdvisedSupport#getInterceptorsAndDynamicInterceptionAdvice
- 創建一個方法執行器 ReflectiveMethodInvocation,執行方法(非常重要的方法,內部使用了責任鏈調用模式);
- 返回生成的代理對象。
4.3.1 獲取攔截器和動態攔截通知
這個邏輯對應上面 invoke 流程中的第 3 步,是非常重要的方法。先看下它的源碼:org.springframework.aop.framework.AdvisedSupport#getInterceptorsAndDynamicInterceptionAdvice
/**
* 從給定的方法和目標類中,根據增強器的通知來創建對應的攔截器和冬天攔截器通知。
*
* Determine a list of {@link org.aopalliance.intercept.MethodInterceptor} objects
* for the given method, based on this configuration.
* @param method the proxied method
* @param targetClass the target class
* @return a List of MethodInterceptors (may also include InterceptorAndDynamicMethodMatchers)
*/
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) {
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;
}
它又繼續調用了增強器鏈工廠的方法:org.springframework.aop.framework.DefaultAdvisorChainFactory#getInterceptorsAndDynamicInterceptionAdvice
/**
* 獲取增強器的通知,並且將它轉成方法攔截器
*
* @param config the AOP configuration in the form of an Advised object
* @param method the proxied method
* @param targetClass the target class (may be {@code null} to indicate a proxy without
* target object, in which case the method's declaring class is the next best option)
* @return
*/
@Override
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
Advised config, Method method, @Nullable Class<?> targetClass) {
// 增強器適配器註冊器
// This is somewhat tricky... We have to process introductions first,
// but we need to preserve order in the ultimate list.
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) {
if (advisor instanceof PointcutAdvisor) {
// 基本上屬於 InstantiationModelAwarePointcutAdvisorImpl 這個類
// Add it conditionally.
PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
// 獲取方法匹配器
MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
boolean match;
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()) {
// Creating a new object instance in the getInterceptors() method
// isn't a problem as we normally cache created chains.
for (MethodInterceptor interceptor : interceptors) {
// 攔截器和動態方法匹配器
interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
}
}
else {
interceptorList.addAll(Arrays.asList(interceptors));
}
}
}
}
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;
}
這個可是最核心的方法了,梳理下它的調用流程:
- 獲取一個增強器適配器註冊表對象 AdvisorAdapterRegistry,實際上是一個 DefaultAdvisorAdapterRegistry 類型的對象;
- 獲取所有的增強器進行遍歷;
- 根據增強器所屬類型(主要是 PointcutAdvisor 類型),進行判斷是否匹配目標(獲取切點上的方法匹配器與目標方法進行匹配);
- 從增強器適配器註冊表 DefaultAdvisorAdapterRegistry 中,根據增強器來獲取攔截器;
- 返回攔截器集合。
4.3.1.1 從增強器適配器註冊表中獲取攔截器
我們看下第 4 步,從增強器適配器註冊表中獲取攔截器:org.springframework.aop.framework.adapter.DefaultAdvisorAdapterRegistry#getInterceptors
/**
* 從給定的增強器中獲取方法攔截器
*
* @param advisor the Advisor to find an interceptor for
* @return
* @throws UnknownAdviceTypeException
*/
@Override
public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
List<MethodInterceptor> interceptors = new ArrayList<>(3);
// 獲取增強器上的通知
Advice advice = advisor.getAdvice();
if (advice instanceof MethodInterceptor) {
// 方法攔截器接口,環繞通知、後置通知、異常通知
interceptors.add((MethodInterceptor) advice);
}
for (AdvisorAdapter adapter : this.adapters) {
// 三個適配器:前置通知、返回通知、異常通知(一般不創建這個異常通知)
if (adapter.supportsAdvice(advice)) {
interceptors.add(adapter.getInterceptor(advisor));
}
}
if (interceptors.isEmpty()) {
throw new UnknownAdviceTypeException(advisor.getAdvice());
}
return interceptors.toArray(new MethodInterceptor[0]);
}
// 增強器適配器
private final List<AdvisorAdapter> adapters = new ArrayList<>(3);
/**
* 創建一個增強器適配器註冊器,註冊已知的適配器。
*
* Create a new DefaultAdvisorAdapterRegistry, registering well-known adapters.
*/
public DefaultAdvisorAdapterRegistry() {
// 註冊前置通知適配器
registerAdvisorAdapter(new MethodBeforeAdviceAdapter());
// 註冊返回通知適配器
registerAdvisorAdapter(new AfterReturningAdviceAdapter());
// 註冊異常通知適配器
registerAdvisorAdapter(new ThrowsAdviceAdapter());
}
@Override
public void registerAdvisorAdapter(AdvisorAdapter adapter) {
this.adapters.add(adapter);
}
那麼它的流程是:
- 獲取增強器上的通知;
- 判斷通知是否屬於 MethodInterceptor 類型,屬於就直接放入集合保存起來;
- 遍歷註冊表中的所有的適配器(MethodBeforeAdviceAdapter 前置通知適配器、AfterReturningAdviceAdapter 返回通知適配器、ThrowsAdviceAdapter 異常通知適配器),判斷通知是否支持,支持的話就從對應的適配器中獲取攔截器(分別對應 MethodBeforeAdviceInterceptor 前置通知攔截器、AfterReturningAdviceInterceptor 後置通知攔截器、ThrowsAdviceInterceptor 異常通知攔截器)保存到集合;
- 返回保存的攔截器集合。
4.3.2 ReflectiveMethodInvocation 方法執行器
下面,我們該看執行方法的邏輯了。它是通過創建一個方法執行器 ReflectiveMethodInvocation 對象,看它的 proceed() 方法:
/**
* 執行方法調用
*
* @return
* @throws Throwable
*/
@Override
@Nullable
public Object proceed() throws Throwable {
// 從索引爲 -1 開始調用
// We start with an index of -1 and increment early.
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
// 當前索引 == 攔截器集合中最後一個攔截器時,纔會進行執行真正的方法調用
return invokeJoinpoint();
}
// 根據索引遞增的順序獲取攔截器
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
// Evaluate dynamic method matcher here: static part will already have
// been evaluated and found to match.
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 {
// 動態匹配失敗,跳過這個攔截器。進入下一個鏈
// Dynamic matching failed.
// Skip this interceptor and invoke the next in the chain.
return proceed();
}
}
else {
// It's an interceptor, so we just invoke it: The pointcut will have
// been evaluated statically before this object was constructed.
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
它的邏輯是:
- 判斷當前 currentInterceptorIndex 變量(從 -1 開始)是否等於攔截器鏈長度減一的值,如果符合,則執行 invokeJoinpoint() 方法,真正執行目標方法調用(通過反反射調用);
- 使用 currentInterceptorIndex 變量遞增,從攔截器鏈中獲取攔截器;
- 執行攔截器的 invoke 方法,並傳入當前對象(攔截器中會根據它的類型來決定)。
先看下 MethodInterceptor 攔截器接口的實現圖:
上面的方法攔截器實現依次是:前置通知、異常通知、返回通知、後置通知、環繞通知攔截器。
這裏的調用流程非常有必要打斷點走一遍,在目標方法 example.scannable.MyLogService#sayHello 上打斷點,看下它的方法調用棧:
# 最後執行目標方法 MyLogServiceImpl 的 sayHello 方法
sayHello(String):11, MyLogServiceImpl (example.scannable), MyLogServiceImpl.java
invoke0(Method, Object, Object[]):-1, NativeMethodAccessorImpl (jdk.internal.reflect), NativeMethodAccessorImpl.java
invoke(Object, Object[]):62, NativeMethodAccessorImpl (jdk.internal.reflect), NativeMethodAccessorImpl.java
invoke(Object, Object[]):43, DelegatingMethodAccessorImpl (jdk.internal.reflect), DelegatingMethodAccessorImpl.java
# 執行 Method 的的 invoke 方法,反射
invoke(Object, Object[]):566, Method (java.lang.reflect), Method.java
# 最後執行 AopUtils類的 invokeJoinpointUsingReflection 方法
invokeJoinpointUsingReflection(Object, Method, Object[]):359, AopUtils (org.springframework.aop.support), AopUtils.java
# 最後執行 ReflectiveMethodInvocation 類的 invokeJoinpoint 方法
invokeJoinpoint():217, ReflectiveMethodInvocation (org.springframework.aop.framework), ReflectiveMethodInvocation.java
# 再執行 ReflectiveMethodInvocation 類的 proceed 方法
proceed():177, ReflectiveMethodInvocation (org.springframework.aop.framework), ReflectiveMethodInvocation.java
# 執行第三個攔截器 AspectJAfterThrowingAdvice 異常通知攔截器的 invoke 方法
invoke(MethodInvocation):67, AspectJAfterThrowingAdvice (org.springframework.aop.aspectj), AspectJAfterThrowingAdvice.java
# 再執行 ReflectiveMethodInvocation 類的 proceed 方法
proceed():205, ReflectiveMethodInvocation (org.springframework.aop.framework), ReflectiveMethodInvocation.java
# 執行第三個攔截器 AfterReturningAdviceInterceptor 返回通知攔截器的 invoke 方法
invoke(MethodInvocation):58, AfterReturningAdviceInterceptor (org.springframework.aop.framework.adapter), AfterReturningAdviceInterceptor.java
# 再執行 ReflectiveMethodInvocation 類的 proceed 方法
proceed():205, ReflectiveMethodInvocation (org.springframework.aop.framework), ReflectiveMethodInvocation.java
# 執行第二個攔截器 AspectJAfterAdvice 後置通知攔截器的 invoke 方法
invoke(MethodInvocation):52, AspectJAfterAdvice (org.springframework.aop.aspectj), AspectJAfterAdvice.java
# 再執行 ReflectiveMethodInvocation 類的 proceed 方法
proceed():205, ReflectiveMethodInvocation (org.springframework.aop.framework), ReflectiveMethodInvocation.java
# 執行第二個攔截器 MethodBeforeAdviceInterceptor 前置通知攔截器的 invoke 方法
invoke(MethodInvocation):60, MethodBeforeAdviceInterceptor (org.springframework.aop.framework.adapter), MethodBeforeAdviceInterceptor.java
# 再執行 ReflectiveMethodInvocation 類的 proceed 方法
proceed():205, ReflectiveMethodInvocation (org.springframework.aop.framework), ReflectiveMethodInvocation.java
# 執行第一個攔截器 ExposeInvocationInterceptor 的 invoke 方法
invoke(MethodInvocation):99, ExposeInvocationInterceptor (org.springframework.aop.interceptor), ExposeInvocationInterceptor.java
# 執行 ReflectiveMethodInvocation 類的 proceed 方法
proceed():205, ReflectiveMethodInvocation (org.springframework.aop.framework), ReflectiveMethodInvocation.java
# 執行 JdkDynamicAopProxy 的 invoke 方法
invoke(Object, Method, Object[]):222, JdkDynamicAopProxy (org.springframework.aop.framework), JdkDynamicAopProxy.java
# 執行代理對象 Proxy 的 sayHello 方法
sayHello(String):-1, $Proxy50 (com.sun.proxy), Unknown Source
aspectIsApplied1(ApplicationContext):67, EnableAspectJAutoProxyTests (org.springframework.context.annotation), EnableAspectJAutoProxyTests.java
# 調用 EnableAspectJAutoProxyTests 測試類的 withJdkProxy 方法
withJdkProxy():44, EnableAspectJAutoProxyTests (org.springframework.context.annotation), EnableAspectJAutoProxyTests.java
...省略無關調用棧
從上面的方法執行調用鏈以及方法執行源代碼看,它是使用了責任鏈模式 + 遞歸的方式進行調用,先從攔截器鏈中一個個的執行攔截器,最後再調用目標方法,形成一個攔截器調用鏈棧,最後執行完目標方法之後,依次返回攔截器執行剩餘的方法邏輯,最後結束。
這個過程在很多地方都用到了,比如 Java web 中的 filter 過濾器鏈,和 spring mvc 中的方法攔截器鏈,都是同一個套路。web 服務器 Tomcat 中每次接收處理一個請求時,也是會創建了一個 org.apache.catalina.core.ApplicationFilterChain 過濾器鏈,這過濾器鏈中也是持有一組過濾器,然後通過一個變量從 0 開始,遞增的獲取過濾器,然後進行執行目標方法。
5. 總結
以上就是 spring aop 的源碼核心流程,我們來稍微的回顧下:
- 通過在類上使用 @EnableAspectJAutoProxy 註解,開啓 spring aop 功能;
- 這個註解引入了 AnnotationAwareAspectJAutoProxyCreator 類,它是一個 bean 後置處理器,分別主要是負責在創建 bean 時進行解析其類上的切面、通知信息,以及通過使用 jdk 動態代理或者 cglib 動態代理來創建目標;
- 然後在執行一個動態代理的 bean 的方法時,通過將解析出來的切面、切點來創建對應的方法攔截器鏈,以遞歸 + 責任鏈的方式執行攔截器和目標方法。