文章目錄
一、前言
本文是筆者閱讀Spring源碼的記錄文章,由於本人技術水平有限,在文章中難免出現錯誤,如有發現,感謝各位指正。在閱讀過程中也創建了一些衍生文章,衍生文章的意義是因爲自己在看源碼的過程中,部分知識點並不瞭解或者對某些知識點產生了興趣,所以爲了更好的閱讀源碼,所以開設了衍生篇的文章來更好的對這些知識點進行進一步的學習。
全集目錄:Spring源碼分析:全集整理
本文衍生篇:
Spring 源碼分析衍生篇九 : AOP源碼分析 - 基礎篇
本文後篇:
Spring源碼分析十二:@AspectJ方式的AOP 之 getAdvicesAndAdvisorsForBean
二、簡介
Aop 即面向切面編程,而 Aspect 是Aop 思想的一種實現。
並不是所有的AOP框架都相同,它們在連接點模型上可能有強弱之分,有些允許在字段修飾符級別的應用通知,有些只支持方法調用相關的連接點。需要注意的是 Spring 只支持方法級別的連接點。
Spring 提供了4種類型的AOP支持
- 基於代理的經典Spring Aop
- 純Pojo切面
- @AspectJ註解驅動的切面
- 注入式的Aspectj的切面
前三種都是Spring Aop 實現的變體,Spring Aop 構建在動態代理之上,因此Spring 對Aop的支持侷限於方法攔截。
本文分析的是 基於 @AspectJ 註解的 Aop 源碼。
1. Spring Aop 和 AspectJ 的關係
AspectJ 是一套AOP框架,是對java語言語法和語義的擴展,所以他自己提供了一套關鍵字,這也就是說,如果在沒有安裝 AspectJ的情況下,是無法使用 AspectJ 的。而Spring Aop 依賴的是Spring,僅僅能做到方法級別的攔截。所以在Spring中使用 @AspectJ 註解實現的AOP 功能,其底層實現還是 Spring Aop。
2. @ApsectJ 的啓用 - @EnableAspectJAutoProxy
在使用AspectJ AOP 功能時,我們需要使用註解 @EnableAspectJAutoProxy(proxyTargetClass = true)
來開啓Aop 功能。那麼我們的分析入口自然是從這個註解開始。
但實際上,啓用AOP功能並不需要我們手動去聲明。因爲在只要我們引入了 SpringAop 對應的依賴,Spring就自動幫我們啓用 Aop功能。其原因在 org.springframework.boot.autoconfigure.aop.AopAutoConfiguration
類中,如下,Spring 會將 AopAutoConfiguration
加載作爲配置類,其內部類也會加載,默認加載 CglibAutoProxyConfiguration
。CglibAutoProxyConfiguration
上有 @EnableAspectJAutoProxy(proxyTargetClass = true)
註解,也就達到了默認開始AOP的功能。
@Configuration(proxyBeanMethods = false)
@ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true)
public class AopAutoConfiguration {
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(Advice.class)
static class AspectJAutoProxyingConfiguration {
@Configuration(proxyBeanMethods = false)
@EnableAspectJAutoProxy(proxyTargetClass = false)
@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false",
matchIfMissing = false)
static class JdkDynamicAutoProxyConfiguration {
}
@Configuration(proxyBeanMethods = false)
@EnableAspectJAutoProxy(proxyTargetClass = true)
@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true",
matchIfMissing = true)
static class CglibAutoProxyConfiguration {
}
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingClass("org.aspectj.weaver.Advice")
@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true",
matchIfMissing = true)
static class ClassProxyingConfiguration {
ClassProxyingConfiguration(BeanFactory beanFactory) {
if (beanFactory instanceof BeanDefinitionRegistry) {
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}
}
}
}
不過我們仍舊可以知道,AOP的功能入口在於@EnableAspectJAutoProxy
註解。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
boolean proxyTargetClass() default false;
boolean exposeProxy() default false;
}
分析了這麼久的源碼,從上面我們可以看到 @EnableAspectJAutoProxy
註解 中使用了 @Import(AspectJAutoProxyRegistrar.class)
註解引入了AspectJAutoProxyRegistrar
類,因此我們下面來看看 AspectJAutoProxyRegistrar
類的實現。
二、 AspectJAutoProxyRegistrar
AspectJAutoProxyRegistrar
實現了 ImportBeanDefinitionRegistrar
接口,那麼我們自然要看看他的registerBeanDefinitions
方法了。(Spring 在 ConfigurationClassPostProcessor 中完成了對 ImportBeanDefinitionRegistrar 接口的處理,主要功能還是將BeanDefinition注入到Spring容器中。具體可以看 :Spring 源碼分析衍生篇七 :ConfigurationClassPostProcessor 上篇)。
/**
* 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) {
// 如有必要,註冊Aspect J註釋自動代理創建器
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
// 獲取 @EnableAspectJAutoProxy 註解
AnnotationAttributes enableAspectJAutoProxy =
AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
if (enableAspectJAutoProxy != null) {
// 解析 proxyTargetClass 屬性
if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}
// 解析 exposeProxy 屬性
if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
}
}
}
從上面代碼我們可以看到,registerBeanDefinitions
方法最主要的功能就是自動代理創建器的註冊。(所謂的自動代理創建器,顧名思義就是可以用來自動創建代理的"機器",可以簡單理解成Spring 封裝的一個創建代理對象的工具類,具有多種實現方式,這個下面會講。這裏使用AOP的實現方式,因此我們來看他的註冊過程, 即 AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
方法 。
其中 registerAspectJAnnotationAutoProxyCreatorIfNecessary
方法在經歷數次跳轉後最終調用了 AopConfigUtils#registerOrEscalateApcAsRequired
方法。
上面我們說到自動代理創建器有多種實現方式,但是實際使用只能選擇其中一種,所以需要根據優先級來判斷使用哪一種。
public static final String AUTO_PROXY_CREATOR_BEAN_NAME =
"org.springframework.aop.config.internalAutoProxyCreator";
private static final List<Class<?>> APC_PRIORITY_LIST = new ArrayList<>(3);
static {
// Set up the escalation list...
// 事務使用
APC_PRIORITY_LIST.add(InfrastructureAdvisorAutoProxyCreator.class);
APC_PRIORITY_LIST.add(AspectJAwareAdvisorAutoProxyCreator.class);
// Spring aop 使用
APC_PRIORITY_LIST.add(AnnotationAwareAspectJAutoProxyCreator.class);
}
// 這裏的 cls 是 AnnotationAwareAspectJAutoProxyCreator.class
private static BeanDefinition registerOrEscalateApcAsRequired(
Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
// 如果有註冊,則判斷優先級,將優先級的高的保存
// 如果已經純在了自動代理創建器,且存在的自動代理創建器與現在的並不一致,那麼需要根據優先級來判斷到底要使用哪個
if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
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) {
// 改變bean所對應的className 屬性
apcDefinition.setBeanClassName(cls.getName());
}
}
// 如果已經存在自動代理創建器,並且與將要創建的一致,那麼無需再次創建
return null;
}
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;
}
...
// 可以看到,所謂的優先級順序實際上是在 APC_PRIORITY_LIST 集合的順序
public static void forceAutoProxyCreatorToUseClassProxying(BeanDefinitionRegistry registry) {
if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
BeanDefinition definition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
// 設置 proxyTargetClass 屬性
definition.getPropertyValues().add("proxyTargetClass", Boolean.TRUE);
}
}
...
public static void forceAutoProxyCreatorToExposeProxy(BeanDefinitionRegistry registry) {
if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
BeanDefinition definition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
// 設置 exposeProxy 屬性
definition.getPropertyValues().add("exposeProxy", Boolean.TRUE);
}
}
這裏可以看到,整體是註冊了一個beanName爲“org.springframework.aop.config.internalAutoProxyCreator”
的bean,Bean 類型爲 AnnotationAwareAspectJAutoProxyCreator
。到這裏我們就可以知道Aop的功能完成肯定是在 AnnotationAwareAspectJAutoProxyCreator
中完成的,因此下面我們開始分析 AnnotationAwareAspectJAutoProxyCreator
的代碼。
注:
-
這裏之所以 beanName (
AUTO_PROXY_CREATOR_BEAN_NAME
) 和 bean的類型並不相同,是因爲這個beanName 特指內部的自動代理創建器
,但是自動創建代理器會對應多種不同的實現方式。比如在默認的事務中,注入的bean類型卻爲InfrastructureAdvisorAutoProxyCreator
,而AOP的實現卻是AnnotationAwareAspectJAutoProxyCreator
。 -
關於優先級的問題,我們可以看到
APC_PRIORITY_LIST
集合的順序,下標越大,優先級越高。因此可以得知優先級的順序應該是
InfrastructureAdvisorAutoProxyCreator
<AspectJAwareAdvisorAutoProxyCreator
<AnnotationAwareAspectJAutoProxyCreator
三、AnnotationAwareAspectJAutoProxyCreator
上面我們可以看到,整個過程就是將 AnnotationAwareAspectJAutoProxyCreator
註冊到 Spring 中並且設置一些屬性。
那麼我們來看看 AnnotationAwareAspectJAutoProxyCreator
,其主要邏輯實際上還是在其父類 AbstractAutoProxyCreator
中完成。(包括事務的實現邏輯也主要在 AbstractAutoProxyCreator
中,這一點後續關於事務的源碼分析會詳細解讀)
AnnotationAwareAspectJAutoProxyCreator
實現了 SmartInstantiationAwareBeanPostProcessor
接口的方法,SmartInstantiationAwareBeanPostProcessor
接口方法穿插在 Bean初始化的過程中,轉念一想,Spring Aop的核心思想就是動態代理,那麼必然會在bean初始化的時候"做手腳"。因此我們下面的重心就放在 SmartInstantiationAwareBeanPostProcessor
的方法分析上。
注:關於 後處理器SmartInstantiationAwareBeanPostProcessor
的內容 具體請參考 Spring源碼分析衍生篇四:後處理器 BeanPostProcessor。
上面也說了,其主要邏輯在AbstractAutoProxyCreator
中實現,這裏是在AbstractAutoProxyCreator
中實現的 SmartInstantiationAwareBeanPostProcessor
方法,所以我們下面看的實際是 AbstractAutoProxyCreator
類,
四、AbstractAutoProxyCreator
這裏額外提一下,Spring事務的實現也依賴於 AbstractAutoProxyCreator
類,並且邏輯與Aop 的實現基本一致,因爲事務的實現的方式也是Aop代理。後面新篇講到事務時會相信解讀。
下面是AbstractAutoProxyCreator
中 SmartInstantiationAwareBeanPostProcessor
的一些實現方法的實現
@Override
@Nullable
public Class<?> predictBeanType(Class<?> beanClass, String beanName) {
// 從代理換緩存中獲取代理類型
if (this.proxyTypes.isEmpty()) {
return null;
}
Object cacheKey = getCacheKey(beanClass, beanName);
return this.proxyTypes.get(cacheKey);
}
@Override
@Nullable
public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, String beanName) {
return null;
}
@Override
public Object getEarlyBeanReference(Object bean, String beanName) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
this.earlyProxyReferences.put(cacheKey, bean);
return wrapIfNecessary(bean, beanName, cacheKey);
}
@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;
}
// 是基礎設施類 || 是被 @AspectJ 註解修飾的類。則跳過 Aop代理
if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return null;
}
}
// 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);
// 創建代理類
Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
return null;
}
@Override
public boolean postProcessAfterInstantiation(Object bean, String beanName) {
return true;
}
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
return pvs;
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
return 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;
}
我們可以根據 SmartInstantiationAwareBeanPostProcessor
方法的調用順序進行分析。如果想要生成代理,可以在bean初始化之後。也就是 postProcessBeforeInstantiation
方法中。在 postProcessBeforeInstantiation
方法中我們可以看到關鍵方法是在於 wrapIfNecessary
。不過在此之前我們先來看看 postProcessBeforeInstantiation
方法中的一段分析
1. 是否跳過代理
我們這一部分主要是用來分析AbstractAutoProxyCreator#postProcessBeforeInstantiation
中的這一段代碼:
// 是基礎設施類 || 是被 @AspectJ 註解修飾的類。則跳過 Aop代理
if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return null;
}
這段代碼將在bean加載前判斷bean是否交由Aop代理,亦或者換一種說法 : 判斷將該Bean交由Spring容器創建還是交由Aop 創建。在實際創建bean代理時候,Spring會根據cacheKey 獲取到值,爲false則不需要代理。
我們可以看到關鍵的判斷條件就是下面兩個:
1.1. isInfrastructureClass(beanClass)
這裏我們可以很清楚的看到,如果當前bean是基礎類(Advice
、Pointcut
、Advisor
、AopInfrastructureBean
及其子類),則返回true。
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;
}
1.2. shouldSkip(beanClass, beanName)
protected boolean shouldSkip(Class<?> beanClass, String beanName) {
// TODO: Consider optimization by caching the list of the aspect names
// 尋找所有候選代理增強點。關於這個方法,在後面關於 getAdvicesAndAdvisorsForBean 的文章中會詳細分析,這裏就不分析
List<Advisor> candidateAdvisors = findCandidateAdvisors();
for (Advisor advisor : candidateAdvisors) {
// 從前面的代碼分析可以看出,如果是Aop 的動態封裝都是基於 InstantiationModelAwarePointcutAdvisorImpl 也就是 InstantiationModelAwarePointcutAdvisor,自然是繼承PointcutAdvisor
// 如果 代理類基於 AspectJPointcutAdvisor && aspectName==beanName,即當前初始化的類是ApspectJ類本身。則返回true,跳過代理
if (advisor instanceof AspectJPointcutAdvisor &&
((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) {
return true;
}
}
// 父類shouldSkip 判斷了文件是否是 .ORIGINAL 後綴,是則跳過。
return super.shouldSkip(beanClass, beanName);
}
關於if語句判斷條件:
-
advisor instanceof AspectJPointcutAdvisor
基礎篇有講過。Advisor
兩個子接口PointcutAdvisor
、IntroductionAdvisor
。IntroductionAdvisor與PointcutAdvisor
最本質上的區別就是,IntroductionAdvisor
只能應用於類級別的攔截,只能使用Introduction型的Advice。而不能像PointcutAdvisor
那樣,可以使用任何類型的Pointcut,以及幾乎任何類型的Advice。而通過 Spring Aop 動態注入的是 Advisor 默認都是
InstantiationModelAwarePointcutAdvisorImpl
都滿此條件。所以這裏爲false 的情況只有硬編碼注入時IntroductionAdvisor
類型的Advisor
,所以這裏基本都會返回true。 -
((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName))
: 這裏就是判斷beanName 是否是 @AspectJ 註解修飾的bean的name。那麼就可以看出,這裏返回ture的條件是 @ApsectJ 修飾的 AspectJPointcutAdvisor 類。即 被 @ApsectJ 修飾的類會跳過代理
綜上,跳過Aop代理的條件就是:Aop基礎設施類或者 被@AspectJ修飾的類
2. AbstractAutoProxyCreator#wrapIfNecessary
postProcessAfterInitialization
方法中我們可看到關鍵方法 wrapIfNecessary。
wrapIfNecessary
主要是用來判斷當前bean是否需要代理,如果需要,則進行bean封裝。
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
// 如果已經處理過
if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
// 無需增強。這個在postProcessBeforeInstantiation 方法中對 cacheKey 進行了判斷緩存,this.advisedBeans.get(cacheKey) 的返回值代表當前bean是否需要aop代理。
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
// 給定的bean類是否是一個基礎設施類(Advice、Pointcut、Advisor、AopInfrastructureBean) || 配置了指定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;
}
可以很明顯的發現下面兩個方法是關鍵。
// 獲取適配的增強點
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
// 根據增強點創建對象
Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
2.1. 獲取代理增強點 - getAdvicesAndAdvisorsForBean
篇幅所限,新開文章:Spring源碼分析十二:@AspectJ方式的AOP 之 getAdvicesAndAdvisorsForBean
2.2. 創建代理類 - createProxy
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);
// 判斷當前bean 是使用 TargetClass 代理還是接口代理
if (!proxyFactory.isProxyTargetClass()) {
// 檢查 proxyTargeClass設置以及preservetargetClass 屬性
if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
}
else {
evaluateProxyInterfaces(beanClass, proxyFactory);
}
}
// 將攔截器 Interceptors 封裝成增強器 Advisor
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());
}
代碼中已經有詳細的註釋了,可以看到代理類的創建Spring委託給 ProxyFactory 去處理,而在此函數中主要是對 ProxyFactory 的初始化操作:
- 獲取當前類的屬性
- 添加代理接口
- 封裝Advisor 並加入到ProxyFactory 中
- 設置要代理的類
- 通過customizeProxyFactory定製代理類 ,對ProxyFactory 進一步封裝
- 進行獲取代理操作
我們下面主要下面兩個方法:
2.2.1. buildAdvisors(beanName, specificInterceptors);
需要注意的是:這裏的參數 就是 Object[] specificInterceptors
就是 getAdvicesAndAdvisorsForBean
方法返回的 Advisor,通過對 getAdvicesAndAdvisorsForBean 方法的分析我們可以得知, specificInterceptors 應該全是 InstantiationModelAwarePointcutAdvisorImpl 類型。
protected Advisor[] buildAdvisors(@Nullable String beanName, @Nullable Object[] specificInterceptors) {
// Handle prototypes correctly...
// 解析註冊的所有 Interceptor Name。即我們可以手動添加一些 攔截器,這裏將手動添加的攔截器保存到commonInterceptors 中
Advisor[] commonInterceptors = resolveInterceptorNames();
List<Object> allInterceptors = new ArrayList<>();
if (specificInterceptors != null) {
// 加入攔截器
allInterceptors.addAll(Arrays.asList(specificInterceptors));
if (commonInterceptors.length > 0) {
if (this.applyCommonInterceptorsFirst) {
allInterceptors.addAll(0, Arrays.asList(commonInterceptors));
}
else {
allInterceptors.addAll(Arrays.asList(commonInterceptors));
}
}
}
if (logger.isTraceEnabled()) {
int nrOfCommonInterceptors = commonInterceptors.length;
int nrOfSpecificInterceptors = (specificInterceptors != null ? specificInterceptors.length : 0);
logger.trace("Creating implicit proxy for bean '" + beanName + "' with " + nrOfCommonInterceptors +
" common interceptors and " + nrOfSpecificInterceptors + " specific interceptors");
}
Advisor[] advisors = new Advisor[allInterceptors.size()];
for (int i = 0; i < allInterceptors.size(); i++) {
// 攔截器進行轉化爲 Advisor
advisors[i] = this.advisorAdapterRegistry.wrap(allInterceptors.get(i));
}
return advisors;
}
...
// this.interceptorNames 是自己通過set設置的屬性。在基礎篇中Advice 有過類似的設置。我們這裏是沒有的
private Advisor[] resolveInterceptorNames() {
BeanFactory bf = this.beanFactory;
ConfigurableBeanFactory cbf = (bf instanceof ConfigurableBeanFactory ? (ConfigurableBeanFactory) bf : null);
List<Advisor> advisors = new ArrayList<>();
// 將 interceptorNames 獲取到的攔截器保存起來,並返回。
for (String beanName : this.interceptorNames) {
if (cbf == null || !cbf.isCurrentlyInCreation(beanName)) {
Assert.state(bf != null, "BeanFactory required for resolving interceptor names");
Object next = bf.getBean(beanName);
advisors.add(this.advisorAdapterRegistry.wrap(next));
}
}
return advisors.toArray(new Advisor[0]);
}
我們下面來看一下 this.advisorAdapterRegistry.wrap(allInterceptors.get(i));
的實現
public Advisor wrap(Object adviceObject) throws UnknownAdviceTypeException {
// 如果 adviceObject 本身就是 Advisor則不需進一步操作
if (adviceObject instanceof Advisor) {
return (Advisor) adviceObject;
}
// 此封裝方法只能處理Advisor 和 Advice兩種類型,如果不是將不能封裝
if (!(adviceObject instanceof Advice)) {
throw new UnknownAdviceTypeException(adviceObject);
}
Advice advice = (Advice) adviceObject;
if (advice instanceof MethodInterceptor) {
// So well-known it doesn't even need an adapter.
// 如果是MethodInterceptor 類型則使用 DefaultPointcutAdvisor 封裝
return new DefaultPointcutAdvisor(advice);
}
// 如果存在 Advisor 的適配器則同樣需要進行封裝。
for (AdvisorAdapter adapter : this.adapters) {
// Check that it is supported.
if (adapter.supportsAdvice(advice)) {
return new DefaultPointcutAdvisor(advice);
}
}
throw new UnknownAdviceTypeException(advice);
}
DefaultAdvisorAdapterRegistry#wrap 方法也很簡單,就是將 adviceObject 包裝成 Advisor 。
2.2.2. proxyFactory.getProxy(getProxyClassLoader());
上述代碼中 proxyFactory.getProxy(getProxyClassLoader());
會繼續調用到 DefaultAopProxyFactory#createAopProxy
因此我們來看 DefaultAopProxyFactory#createAopProxy
首先我們來看一下 proxyFactory.getProxy 方法。
public Object getProxy(@Nullable ClassLoader classLoader) {
return createAopProxy().getProxy(classLoader);
}
顯然意見我們需要將這個內容分爲兩步: createAopProxy() 和 getProxy(classLoader)
2.2.2.1 createAopProxy()
ProxyCreatorSupport#createAopProxy
會調用 DefaultAopProxyFactory#createAopProxy
。因此,這裏我們來看 DefaultAopProxyFactory#createAopProxy
的實現
@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
Class<?> targetClass = config.getTargetClass();
if (targetClass == null) {
throw new AopConfigException("TargetSource cannot determine target class: " +
"Either an interface or a target is required for proxy creation.");
}
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
return new ObjenesisCglibAopProxy(config);
}
else {
return new JdkDynamicAopProxy(config);
}
}
在這個方法中我們可以看到 Aop代理使用了 JDK動態代理和 Cglib動態代理兩種動態代理模式,並根據某些參數來進行選擇代理方式
從 createAopProxy
代碼中我們可以看到幾個參數:
optimize
: 用來控制通過CGlib 創建的代理是否使用激進的優化策略,一般默認false,對JDK動態代理無效。proxyTargetClass
:若爲true,則目標類本身被代理,而不是代理目標類的接口,創建 cglib代理。hasNoUserSuppliedProxyInterfaces
:是否存在代理接口
即:
- 如果目標對象實現了接口,默認會採用JDK動態代理實現AOP
- 如果目標對象實現了接口,可以強制使用CGLIB動態代理實現AOP
- 如果目標對象沒有實現接口,必須採用CGLIB代理,Spring會自動在JDK動態代理和CGLIB代理之前切換。
2.2.2.2 getProxy(classLoader)
首先我們需要知道的是,調用這個方法的是 createAopProxy()
方法的返回值,那麼就可能是JdkDynamicAopProxy.getProxy
或者 ObjenesisCglibAopProxy.getProxy
。這裏就不再具體分析其代理類生成過程了,就是和Cglib代理和Jdk代理的基本流程。
五、總結
總結一下整體邏輯和思想,寫的並不嚴謹。
- 服務啓動時,通過
@EnableAspectJAutoProxy
開始aop功能,引入AnnotationAwareAspectJAutoProxyCreator
自動創建配置器 - 在
AnnotationAwareAspectJAutoProxyCreator
中。會在bean創建過程中判斷bean是否需要被切入,判斷的方式是是否有滿足的Advisor
,這其中有一部分是編碼直接注入的(比如事務的BeanFactoryTransactionAttributeSourceAdvisor
),但是在Spring Aop 中,由於匹配規則的衆多,需要動態生成Advisor
。 - 如果需要切入,則創建bean 的代理。代理的方式有jdk代理和cglib代理,根據情況選擇代理方式。
- 如果不需要切入,則什麼也不做。
至此,@AspectJ方式的AOP 的源碼分析結束。
以上:內容部分參考
《Spring實戰》
《Spring源碼深度解析》
https://www.cnblogs.com/cheng21553516/p/12190008.html
https://blog.csdn.net/wyl6019/article/details/80136000
如有侵擾,聯繫刪除。 內容僅用於自我記錄學習使用。如有錯誤,歡迎指正