概述
在之前的文章中,我們已經對 SpringAOP 的關鍵組件進行了描述,並且瞭解了其基本操作和流程。在本文中,我們將進一步深入源碼,揭示 SpringAOP 的內部實現細節,理解其運行機制的每個環節,包括切面的織入方式、代理對象的創建過程、連接點的定位與匹配等。通過對完整運行流程的深入研究,我們能夠更全面地理解 SpringAOP 的工作原理,並且能夠更好地利用和擴展這一功能。
本專題共三篇文章,這是第二篇:
- 深入理解 SpringAOP(一):AOP 組件概述
- 深入理解 SpringAOP(二):AOP的執行流程;
- 深入理解 SpringAOP(三):AspectJ支持;
一、代理生效時機
在前文,我們提到了代理基於 AbstractAutoProxyCreator
的子類生效,因此直接觀察該類,我們可以注意到 AbstractAutoProxyCreator
中實現了 SmartInstantiationAwareBeanPostProcessor
,說明他可能在三個關鍵節點觸發代理:
InstantiationAwareBeanPostProcessor
:在實例化階段,即 bean 實例化前後;SmartInstantiationAwareBeanPostProcessor
:早期引用創建階段,即在循環依賴中,當 bean 已實例化而未被初始化時,被其他依賴它的 bean 通過getEarlyBeanReference
方法從一級緩存中獲取;BeanPostProcessor
:在初始化階段,即 bean 完成初始化後,進行依賴注入與各種聲明週期回調前後;
1、在實例化階段
InstantiationAwareBeanPostProcessor
分別提供了 postProcessBeforeInstantiation
和 postProcessAfterInstantiation
兩個方法用於介入 bean 的實例化流程,其中 AbstractAutoProxyCreator
實現了前者:
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;
}
}
// 如果用戶指定的自定義的目標源,則嘗試獲取目標源並根據其創建代理
// 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;
}
protected Object getCacheKey(Class<?> beanClass, @Nullable String beanName) {
// 如果有 beanName,則使用 beanName 作爲 key
if (StringUtils.hasLength(beanName)) {
return (FactoryBean.class.isAssignableFrom(beanClass) ?
BeanFactory.FACTORY_BEAN_PREFIX + beanName : beanName);
}
// 否則使用類型作爲 key
else {
return beanClass;
}
}
這段代碼的作用是在實例化Bean之前進行處理。它檢查Bean是否需要被代理:
- 如果需要,根據自定義目標源創建代理對象,並返回代理對象;
- 如果不需要代理或者不存在自定義目標源,則直接返回
null
,即走正常的 bean 實例化邏輯;
它主要是用來在更靈活的創建代理目標的,一般我們並不會用到,因此這裏瞭解即可。
2、作爲早期引用被創建時
SmartInstantiationAwareBeanPostProcessor
提供了三個方法,AbstractAutoProxyCreator
實現了兩個:
predictBeanType
:確認 bean 的類型,這裏會直接獲取代理對象的類型;getEarlyBeanReference
:獲取對象早期引用,這裏會通過wrapIfNecessary
嘗試爲 bean 創建代理對象;
在開始前,我們需要明確,什麼是早期引用:
一般情況下,Spring 會在 bean 初始化完畢後纔會基於該 bean 實例創建代理對象,但是在循環引用時,比如 beanA 依賴 beanB 依賴 beanA 的情況下,由於後創建的 beanB 需要依賴先創建的 beanA,而在此時先創建的 beanA 並未完成初始化,則此時後創建的 beanB 會通過一級緩存中的 ObjectFactory
,也就是 () → getEarlyBeanReference
方法提前獲得基於 beanB 創建的代理對象(如果不需要代理則就是 beanA 本身),這就是早期引用。
不過,雖然是早期引用階段,但是實際上在這裏創建代理對象的邏輯是與正常的初始化後創建代理對象的邏輯基本一致的:
public Object getEarlyBeanReference(Object bean, String beanName) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
this.earlyProxyReferences.put(cacheKey, bean);
return wrapIfNecessary(bean, beanName, cacheKey);
}
後文我們需要重點關注 wrapIfNecessary
方法,不過目前我們知道在這一步會創建代理對象即可。
3、在初始化階段
SmartInstantiationAwareBeanPostProcessor
提供了兩個方法,AbstractAutoProxyCreator
只實現了其中的 postProcessBeforeInstantiation
,在初始化前,它將爲 bean 生成代理對象:
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;
}
與 getEarlyBeanReference
基本一致,都是基於 wrapIfNecessary
完成的,只不過是時機不同。正常需要代理的 bean 會在這裏被替換爲代理對象。
二、創建代理對象前的準備
知道了代理對象在何時被創建,也大概瞭解了相關的基本組件,現在我們需要真正的瞭解代理對象是如何被創建的,通知、切點和通知器這些組件將會在這個過程中扮演怎樣的角色。
而 wrapIfNecessary
方法則是入口,在這個方法中,spring 會確認 bean 是否需要被代理,如果是就爲其創建代理對象:
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;
}
// 爲 bean 獲取需要的通知器
// Create proxy if we have advice.
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
// 註明該 bean 已經被代理
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;
}
1、爲 bean 獲取通知器
當獲得一個 bean 時,spring 會通過 getAdvicesAndAdvisorsForBean
方法爲這個 bean 獲得它需要的通知器與通知,在 AbstractAutoProxyCreator
它是個空實現,AbstractAdvisorAutoProxyCreator
實現了
@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();
}
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
// 獲取 spring 容器中所有的 Advisor
List<Advisor> candidateAdvisors = findCandidateAdvisors();
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}
// 獲取 spring 容器中所有的 Advisor
// 就是字面意思,從 BeanFactory 中實例化所有 Advisor 並返回
protected List<Advisor> findCandidateAdvisors() {
Assert.state(this.advisorRetrievalHelper != null, "No BeanFactoryAdvisorRetrievalHelper available");
return this.advisorRetrievalHelper.findAdvisorBeans();
}
protected List<Advisor> findAdvisorsThatCanApply(
List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {
// 一個類似 TransactionSynchronizationManager 的上下文,用於記錄當前正在創建代理對象的 bean 的一些信息
ProxyCreationContext.setCurrentProxiedBeanName(beanName);
try {
return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
}
finally {
// 將其從上下文中移除
ProxyCreationContext.setCurrentProxiedBeanName(null);
}
}
整體邏輯比較直觀,總共就三步:
- 從
BeanFactory
加載並獲取所有的Advisor
; - 從這些
Advisor
中篩選出 bean 需要的部分; - 將這些
Advisor
按@Order
或者Ordered
接口排序;
值得一提的是,在 AnnotationAwareAspectJAutoProxyCreator
中,它對 findCandidateAdvisors
進行了重寫,在原有邏輯的基礎上添加了基於 AspectJ
生成的 Advisor
,這裏暫且先知道即可。
2、篩選匹配通知器
這裏我們額外的看一下 AopUtils.findAdvisorsThatCanApply
方法,它揭露了通知器 Advisor
是如何判斷是否需要爲這個 bean 應用切點的:
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;
}
public static boolean canApply(Advisor advisor, Class<?> targetClass) {
return canApply(advisor, targetClass, false);
}
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 pca) {
return canApply(pca.getPointcut(), targetClass, hasIntroductions);
}
else {
// It doesn't have a pointcut so we assume it applies.
return true;
}
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;
}
Set<Class<?>> classes = new LinkedHashSet<>();
if (!Proxy.isProxyClass(targetClass)) {
classes.add(ClassUtils.getUserClass(targetClass));
}
classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass));
for (Class<?> clazz : classes) {
// 獲取這個 bean 中直接聲明的方法
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;
}
這裏大體處理了兩類匹配邏輯:
- 如果通知器是
IntroductionAdvisor
類型,則通過通知器的ClassFilter
進行類型匹配; - 如果通知器是
PointcutAdvisor
類型,則通過通知器的Pointcut
切點中的ClassFilter
與MethodMatcher
分別對類型和類中的方法進行匹配。不過,針對MethodMatcher
又分兩種情況:MethodMatcher
是IntroductionAwareMethodMatcher
類型,說明支持同時根據方法和 bean 的類型進行匹配;- 如果不是,則說明只支持根據方法進行匹配;
3、確認代理類型
讓我們回到 wrapIfNecessary
,現在我們得到了所有可以作用於 bean 上的 Advisor
,接下來就需要根據這些 Advisor
去創建代理對象:
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
// ... ...
// 獲取可作用於 bean 的 Advisor
// 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;
}
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);
}
// 根據 ProxyConfig(就是 AbstractAutoProxyCreator 本身)創建代理工廠
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this);
// 如果需要基於目標類而不是其接口代理(即這個代理類沒實現接口)
// 並且他們已經被 jdk 代理了(比如 Annotation 或者 Mybatis 的 Mapper),或者是根據 lambda 生成的匿名內部類
// 那麼生成的代理類需要實現這些接口類型
if (proxyFactory.isProxyTargetClass()) {
// Explicit handling of JDK proxy targets and lambdas (for introduction advice scenarios)
if (Proxy.isProxyClass(beanClass) || ClassUtils.isLambdaClass(beanClass)) {
// Must allow for introductions; can't just set interfaces to the proxy's interfaces only.
for (Class<?> ifc : beanClass.getInterfaces()) {
proxyFactory.addInterface(ifc);
}
}
}
// 其他情況下,根據 beanDefinition 中的 preserveTargetClass 屬性
// 判斷是否要直接基於這個類而不是其接口創建代理對象,簡而言之,就是要不要走 CGLib 代理
else {
// No proxyTargetClass flag enforced, let's apply our default checks...
if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
}
// 否則直接從這個類實現的接口中尋找可以用於代理的接口
else {
evaluateProxyInterfaces(beanClass, proxyFactory);
}
}
// 創建 Advisor
// 一般情況下,這裏就是各種 Advisor,不過也可能混有用於支持 AspectJ 的特殊對象,因此需要在這裏統一處理
// 轉爲 Advisor
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
proxyFactory.addAdvisors(advisors);
proxyFactory.setTargetSource(targetSource);
customizeProxyFactory(proxyFactory);
// 是否要啓用 advisor 的預過濾,在 AbstractAutoProxyCreator 中總是返回 false
// 因此我們可以認爲總是爲 true
proxyFactory.setFrozen(this.freezeProxy);
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}
// 獲取類加載器,然後創建代理對象
// Use original ClassLoader if bean class not locally loaded in overriding class loader
ClassLoader classLoader = getProxyClassLoader();
if (classLoader instanceof SmartClassLoader && classLoader != beanClass.getClassLoader()) {
classLoader = ((SmartClassLoader) classLoader).getOriginalClassLoader();
}
return proxyFactory.getProxy(classLoader);
}
protected void evaluateProxyInterfaces(Class<?> beanClass, ProxyFactory proxyFactory) {
Class<?>[] targetInterfaces = ClassUtils.getAllInterfacesForClass(beanClass, getProxyClassLoader());
boolean hasReasonableProxyInterface = false;
for (Class<?> ifc : targetInterfaces) {
// 確認接口是否滿足下列條件,如果是那就使用它作爲代理接口:
// 1、是否不爲 Aware 這樣的 Spring 回調接口
// 2、是否不爲 cglib.proxy.Factory 這樣的內部接口
// 3、是否有定義抽象方法(如果沒有抽象方法那自然也沒必要代理了)
if (!isConfigurationCallbackInterface(ifc) && !isInternalLanguageInterface(ifc) &&
ifc.getMethods().length > 0) {
hasReasonableProxyInterface = true;
break;
}
}
// 如果找到了代理接口,說明需要基於接口代理
// 那就讓代理對象實現所有的接口
if (hasReasonableProxyInterface) {
// Must allow for introductions; can't just set interfaces to the target's interfaces only.
for (Class<?> ifc : targetInterfaces) {
proxyFactory.addInterface(ifc);
}
}
// 如果沒有找到代理接口,那就讓他基於對象本身的類型生成代理
else {
proxyFactory.setProxyTargetClass(true);
}
}
暫且忽略代理工廠 ProxyFactory
中的邏輯,這裏主要做了這麼個判斷:
- 如果
proxyFactory
設置了proxyTargetClass
標誌爲true
,則說明要使用目標類(target class)作爲代理的基礎。在這種情況下,如果目標類是JDK動態代理的代理類或者是 Lambda 表達式生成的匿名內部類,則需要特殊處理,即通過遍歷目標類的接口,將這些接口添加到代理工廠中,以保證代理對象具備這些接口的方法; - 如果
proxyFactory
的proxyTargetClass
標誌沒有設置爲true
,則執行下面的邏輯。這表示沒有顯式要求使用目標類作爲代理基礎,並且可以根據一些默認規則進行判斷:
a. 如果根據默認規則確定應該使用目標類作爲代理基礎,則將proxyTargetClass
標誌設置爲true
,即需要進行 CGLib 代理;
b. 如果不滿足使用目標類作爲代理基礎的條件,則根據目標類的接口情況來設置代理工廠的接口。通過調用evaluateProxyInterfaces(beanClass, proxyFactory)
方法,根據目標類的接口信息,將適合的接口添加到代理工廠中;
4、適配通知器
另外,在 createProxy
中,會調用 buildAdvisors
去適配通知器,這是雖然一般情況下輸入的 specificInterceptors
大部分都是 Advisor
,不過也可能有一些其他的類型需要特殊處理,比如大家都很熟悉的 MethodInterceptor
,它只實現了 Advice
接口,因此需要在這裏被適配爲 DefaultPointcutAdvisor
。
總而言之,在創建代理對象前,需要調用適配器將裏面入參的 Object
類型的數組 specificInterceptors
,全部確保轉爲 Advisor
:
protected Advisor[] buildAdvisors(@Nullable String beanName, @Nullable Object[] specificInterceptors) {
// 有些攔截器是直接通過把 beanName 設置到 AbstractAutoProxyCreator 註冊的
// 因此此處需要將他們直接取出來
// Handle prototypes correctly...
Advisor[] commonInterceptors = resolveInterceptorNames();
// 收集所有可用的攔截器
List<Object> allInterceptors = new ArrayList<>();
if (specificInterceptors != null) {
if (specificInterceptors.length > 0) {
// specificInterceptors may equal PROXY_WITHOUT_ADDITIONAL_INTERCEPTORS
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");
}
// 調用通知器適配器註冊表 advisorAdapterRegistry,嘗試將所有的攔截器對象適配爲通知器
Advisor[] advisors = new Advisor[allInterceptors.size()];
for (int i = 0; i < allInterceptors.size(); i++) {
advisors[i] = this.advisorAdapterRegistry.wrap(allInterceptors.get(i));
}
return advisors;
}
private Advisor[] resolveInterceptorNames() {
BeanFactory bf = this.beanFactory;
ConfigurableBeanFactory cbf = (bf instanceof ConfigurableBeanFactory ? (ConfigurableBeanFactory) bf : null);
List<Advisor> advisors = new ArrayList<>();
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]);
}
這裏我們需要看一下 AdvisorAdapterRegistry
的唯一一個實現類 DefaultAdvisorAdapterRegistry
的 wrap
方法:
@Override
public Advisor wrap(Object adviceObject) throws UnknownAdviceTypeException {
// 已經是 Advisor 了,直接返回
if (adviceObject instanceof Advisor) {
return (Advisor) adviceObject;
}
// 沒有實現 Advice 接口,直接拋異常
if (!(adviceObject instanceof Advice advice)) {
throw new UnknownAdviceTypeException(adviceObject);
}
// 是方法攔截器,這是最常見的實現
if (advice instanceof MethodInterceptor) {
// So well-known it doesn't even need an adapter.
return new DefaultPointcutAdvisor(advice);
}
// 不是上述兩者,則調用 AdvisorAdapter 鏈嘗試將其適配爲 Advisor
for (AdvisorAdapter adapter : this.adapters) {
// Check that it is supported.
if (adapter.supportsAdvice(advice)) {
return new DefaultPointcutAdvisor(advice);
}
}
throw new UnknownAdviceTypeException(advice);
}
這裏的邏輯還是比較直白的:
- 如果已經是
Advisor
了,就直接返回; - 如果不是
Advisor
,那必須是Advice
,否則直接拋異常; - 如果它是
MethodInterceptor
,那就將其適配爲DefaultPointcutAdvisor
(可能是考慮到 spring 中幾乎九成九的 AOP 都是基於MethodInterceptor
實現的,因此這裏直接專門提出來了); - 如果是其他情況,就調用適配器鏈,找到一個支持處理這個攔截器的
AdvisorAdapter
去對它做適配;
三、創建代理對象
經歷了一番波折,現在我們得到了所有最終可用的 Advisor
,以及在 ProxyFactory
設置好了代理類要實現哪些類型,現在我們看看 ProxyFactory.getProxy
是如何創建代理對象的:
public Object getProxy(@Nullable ClassLoader classLoader) {
return createAopProxy().getProxy(classLoader);
}
protected final synchronized AopProxy createAopProxy() {
if (!this.active) {
activate();
}
// 獲取 AOP 代理工廠,默認爲 DefaultAopProxyFactory
return getAopProxyFactory()
.createAopProxy(this);
}
1、確認代理方式
在默認情況下,getAopProxyFactory
會獲得一個 DefaultAopProxyFactory
實例,在 createAopProxy
方法中,會根據各種條件決定要使用何種方式生成代理:
public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {
private static final long serialVersionUID = 7930414337282325166L;
@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
if (!NativeDetector.inNativeImage() &&
(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.");
}
// 如果在上文獲取到的代理類型,若滿足下述任意條件,則使用 JDK 代理:
// 1、代理的目標類是接口;
// 2、代理的目標類本身就是個代理類
// 3、代理的目標類是基於 Lambda 表達式生成的匿名內部類
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass) || ClassUtils.isLambdaClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
// 否則基於 Cglib 代理
return new ObjenesisCglibAopProxy(config);
}
else {
return new JdkDynamicAopProxy(config);
}
}
/**
* Determine whether the supplied {@link AdvisedSupport} has only the
* {@link org.springframework.aop.SpringProxy} interface specified
* (or no proxy interfaces specified at all).
*/
private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) {
Class<?>[] ifcs = config.getProxiedInterfaces();
return (ifcs.length == 0 || (ifcs.length == 1 && SpringProxy.class.isAssignableFrom(ifcs[0])));
}
}
這裏主要做了這三層判斷:
- 如果應用程序運行在 Native Image環境中(即原生鏡像化環境,例如 GraalVM 的 Native Image 模式),則直接返回使用JDK動態代理
JdkDynamicAopProxy
。 - 如果配置中設置了優化標誌
optimize
,或者配置中設置了proxyTargetClass
標誌,或者沒有提供用戶自定義的代理接口(即沒有明確指定要代理的接口),則需要進一步判斷:
a. 如果目標類targetClass
爲空,則拋出AopConfigException
異常,提示無法確定目標類;
b. 如果目標類是接口類型targetClass.isInterface()
,或者是JDK動態代理的代理類Proxy.isProxyClass(targetClass)
,或者是Lambda表達式生成的類ClassUtils.isLambdaClass(targetClass)
,則返回使用JDK動態代理;
c. 如果以上條件都不滿足,即目標類既不是接口也不是代理類,那麼返回使用CGLIB動態代理ObjenesisCglibAopProxy
。 - 如果以上條件都不滿足,則默認使用JDK動態代理
JdkDynamicAopProxy
;
簡而言之,僅當代理的目標類沒有接口,且不是代理類的時候,纔會使用 Cglib
基於子類生成代理對象,這也是爲什麼即使我們的 bean 沒有實現任何接口,Spring 依然能夠生成代理的原因。
2、創建代理類
現在,通過 ProxyFactory
中的 AopProxyFactory
,我們可能獲得 JdkDynamicAopProxy
或者 ObjenesisCglibAopProxy
對象,我們以比較常見的 JdkDynamicAopProxy
爲例,看看它是如何真正的創建代理對象的:
@Override
public Object getProxy(@Nullable ClassLoader classLoader) {
if (logger.isTraceEnabled()) {
logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
}
return Proxy.newProxyInstance(classLoader, this.proxiedInterfaces, this);
}
這裏平平無奇的直接調用了 Proxy.newProxyInstance
,那麼顯然一切的奧祕都在最後作爲 InvocationHandler
傳入的這個 this
,也就是 JdkDynamicAopProxy
本身。
先看看它的成員變量和構造函數:
final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {
// 代理對象的生成配置,即 AbstractAutoProxyCreator 本身
// 此處保存有該 bean 的 Advisor 與代理方法的映射關係,以及該代理對象實現的接口類型
// 本身也是一個 Advised,當我通過代理對象調用 Advised 接口中聲明的方法時,都會轉發到這裏
private final AdvisedSupport advised;
// 代理對象要實現哪些接口
private final Class<?>[] proxiedInterfaces;
// 是否有重寫 hashCode 或者 equals 方法
private boolean equalsDefined;
private boolean hashCodeDefined;
/**
* Construct a new JdkDynamicAopProxy for the given AOP configuration.
* @param config the AOP configuration as AdvisedSupport object
* @throws AopConfigException if the config is invalid. We try to throw an informative
* exception in this case, rather than let a mysterious failure happen later.
*/
public JdkDynamicAopProxy(AdvisedSupport config) throws AopConfigException {
Assert.notNull(config, "AdvisedSupport must not be null");
if (config.getAdvisorCount() == 0 && config.getTargetSource() == AdvisedSupport.EMPTY_TARGET_SOURCE) {
throw new AopConfigException("No advisors and no TargetSource specified");
}
this.advised = config;
// 確認是否有重新 hashCode 或者 equals 放方法
this.proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
findDefinedEqualsAndHashCodeMethods(this.proxiedInterfaces);
}
}
在創建代理前,它會先添加一些默認的接口:
static Class<?>[] completeProxiedInterfaces(AdvisedSupport advised, boolean decoratingProxy) {
Class<?>[] specifiedInterfaces = advised.getProxiedInterfaces();
if (specifiedInterfaces.length == 0) {
// No user-specified interfaces: check whether target class is an interface.
Class<?> targetClass = advised.getTargetClass();
if (targetClass != null) {
if (targetClass.isInterface()) {
advised.setInterfaces(targetClass);
}
else if (Proxy.isProxyClass(targetClass) || ClassUtils.isLambdaClass(targetClass)) {
advised.setInterfaces(targetClass.getInterfaces());
}
specifiedInterfaces = advised.getProxiedInterfaces();
}
}
// 添加 SpringProxy、Advised 接口
List<Class<?>> proxiedInterfaces = new ArrayList<>(specifiedInterfaces.length + 3);
for (Class<?> ifc : specifiedInterfaces) {
// Only non-sealed interfaces are actually eligible for JDK proxying (on JDK 17)
if (!ifc.isSealed()) {
proxiedInterfaces.add(ifc);
}
}
if (!advised.isInterfaceProxied(SpringProxy.class)) {
proxiedInterfaces.add(SpringProxy.class);
}
if (!advised.isOpaque() && !advised.isInterfaceProxied(Advised.class)) {
proxiedInterfaces.add(Advised.class);
}
// 如果通知器 DecoratingProxy,就讓代理對象也實現 DecoratingProxy
if (decoratingProxy && !advised.isInterfaceProxied(DecoratingProxy.class)) {
proxiedInterfaces.add(DecoratingProxy.class);
}
return ClassUtils.toClassArray(proxiedInterfaces);
}
3、代理方法
InvocationHandler.invoke
是代理對象攔截待執行方法的關鍵,在 JdkDynamicAopProxy
中,它區分了五類方法,並做了不同的處理,這裏我們主要關注後續通過 getInterceptorsAndDynamicInterceptionAdvice
獲取通知調用鏈的部分:
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 {
// 調用 eqlues 方法
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
// The target does not implement the equals(Object) method itself.
return equals(args[0]);
}
// 調用 hashCode 方法
else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
// The target does not implement the hashCode() method itself.
return hashCode();
}
// 如果調用的方法來自於 DecoratingProxy 接口
else if (method.getDeclaringClass() == DecoratingProxy.class) {
// There is only getDecoratedClass() declared -> dispatch to proxy config.
return AopProxyUtils.ultimateTargetClass(this.advised);
}
// 如果這個方法來自於 Advised 接口,那就調用 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);
}
// 真正的調用的進行增強,即調用 AOP 植入的各種前置和後置放阿飛
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);
}
}
}
4、獲取攔截器鏈
通過 AdvisedSupport
(其實就是 ProxyFactory
)的 getInterceptorsAndDynamicInterceptionAdvice
方法,可以獲得由所有的實際要執行方法的攔截器鏈:
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;
}
其中,AdvisorChainFactory
默認只有 DefaultAdvisorChainFactory
一個實現類,因此我們直接看它的 getInterceptorsAndDynamicInterceptionAdvice
方法即可:
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) {
// 1、如果基於方法切點攔截,則根據方法切點判斷通知是否生效
if (advisor instanceof PointcutAdvisor pointcutAdvisor) {
// 由於 isPreFiltered 必定爲 true,因此這裏實際上就是看看方法切點是否支持處理這個類型的 bean
// Add it conditionally.
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);
// 如果這個方法檢查器是動態的,即每次調用的時候才檢查是否生效,那就將其包裝爲 InterceptorAndDynamicMethodMatcher
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));
}
}
}
}
// /2、如果基於類攔截,則基於類確認該通知是否生效
else if (advisor instanceof IntroductionAdvisor ia) {
if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}
// 3、其他的情況,比如基於 AspectJ,直接將其包裝爲 MethodInterceptor
else {
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}
return interceptorList;
}
可以看到,這裏主要是檢查將各種不同類型的 Advisor
是否支持處理該類型的 bean,如果是,就將其轉爲 MethodInterceptor
,然後收集所有的攔截器湊成鏈後,返回給代理對象:
- 如果當前的
Advisor
是一個PointcutAdvisor
,即基於切點的通知器,那麼:- 先根據切點的
ClassFilter
判斷是否匹配成功,然後再根據節點的MethodMatcher
的類型,覺得要根據方法還是同時根據方法與類進行匹配; - 如果匹配成功,再判斷
MethodMatcher
是否根據方法調用情況動態的決定是否匹配,若是則將其包裝爲InterceptorAndDynamicMethodMatcher
並添加到攔截器鏈;
- 先根據切點的
- 如果當前的
Advisor
是一個IntroductionAdvisor
,即引介增強器,那麼根據類過濾器的匹配規則判斷是否需要將它添加到攔截器鏈中; - 如果當前的
Advisor
不是上述兩種類型,直接將它的攔截器數組添加到攔截器鏈中;
5、執行攔截器鏈
回到 invoke
方法,現在我們通過 getInterceptorsAndDynamicInterceptionAdvice
方法獲取調用鏈後,就該真正的執行它的:
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// ... ...
// 真正的調用的進行增強,即調用 AOP 植入的各種前置和後置放阿飛
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();
}
// ... ...
}
執行上下文
其中,ReflectiveMethodInvocation
是一個包含了本次調用信息的一個執行上下文,它將在攔截器鏈中流轉以完成全部的流程:
public class ReflectiveMethodInvocation implements ProxyMethodInvocation, Cloneable {
// 代理對象
protected final Object proxy;
// 原始對象與代理的方法
@Nullable
protected final Object target;
protected final Method method;
// 本次調用的參數
protected Object[] arguments;
// 調用對象的類型
@Nullable
private final Class<?> targetClass;
// 一些特殊的參數
@Nullable
private Map<String, Object> userAttributes;
// 攔截器鏈
protected final List<?> interceptorsAndDynamicMethodMatchers;
// 當前調用的攔截器鏈的下標
private int currentInterceptorIndex = -1;
protected ReflectiveMethodInvocation(
Object proxy, @Nullable Object target, Method method, @Nullable Object[] arguments,
@Nullable Class<?> targetClass, List<Object> interceptorsAndDynamicMethodMatchers) {
this.proxy = proxy;
this.target = target;
this.targetClass = targetClass;
this.method = BridgeMethodResolver.findBridgedMethod(method); // 如果代理的是橋接方法,那就找到它的原始方法
this.arguments = AopProxyUtils.adaptArgumentsIfNecessary(method, arguments); // 這裏會根據方法入參類型適配一下入參
this.interceptorsAndDynamicMethodMatchers = interceptorsAndDynamicMethodMatchers; // 攔截器鏈
}
}
調用攔截器鏈
當我們調用 ReflectiveMethodInvocation.proceed
方法的時候,實際上是會先調用攔截器鏈:
public Object proceed() throws Throwable {
// 如果沒有攔截器,直接調用方法本身
// We start with an index of -1 and increment early.
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
// 獲取攔截器,並讓 currentInterceptorIndex + 1
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
// 如果是動態攔截器,就根據當前的調用參數判斷是否要應用它
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher dm) {
// Evaluate dynamic method matcher here: static part will already have
// been evaluated and found to match.
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);
}
}
protected Object invokeJoinpoint() throws Throwable {
return AopUtils.invokeJoinpointUsingReflection(this.target, this.method, this.arguments);
}
這個地方稍微有點繞,大概意思是這樣的:
- 首先,
ReflectiveMethodInvocation
在內部維護了一個成員變量currentInterceptorIndex
,代表了當前調用到第幾個攔截器; - 每當調用了一個攔截器後,都會使
currentInterceptorIndex
加一,也就是說,每當調用一次proceed
方法,都相當於執行了一個攔截器; - 當
currentInterceptorIndex
等於攔截器鏈的長度減一時,意味着所有的攔截器都調用完畢,此時真正的調用被攔截的方法;
在這個基礎上,每次調用攔截器前,都會做一次判斷,如果攔截器是動態攔截器,就根據方法參數判斷是否要調用它,否則就直接調用 processed
跳過這個攔截器。
這也就意味着,我們在攔截器中完成攔截操作後,是需要主動的調用 ReflectiveMethodInvocation.processed
方法的,這個時候就體現出了這種設計的精妙之處:
- 允許主動中斷:只有調用
proceed
時,攔截器鏈纔會繼續往下走,否則可以直接中斷整個調用流程; - 可以攔截調用結果:當調用
proceed
後,實際上會形成遞歸,這使得所有的攔截器都可以獲取並處理方法的返回值;
總結
1、代理的創建時機
- 實例化前後:依靠
InstantiationAwareBeanPostProcessor
完成,不太常見; - 初始化後:依靠
BeanPostProcessor
完成,如果沒有因爲循環依賴導致 bean 被提前實例化,那麼正常情況 bean 會在這時被代理; - 獲取早期引用時:依靠
SmartInstantiationAwareBeanPostProcessor
完成,當需要被代理的 bean 由於循環依賴導致初始化前就要被其他 bean 獲取時,會在這時被提前完成代理;
其中,後兩者最終都會通過 AbstractAutoProxyCreator.wrapIfNecessary
完成代理對象的創建。
2、通知器的獲取
當進入 wrapIfNecessary
方法後,在真正的創建代理對象前,需要通過AbstractAutoProxyCreator.getAdvicesAndAdvisorsForBean
方法獲取可應用於代理對象的通知器。
該方法的具體實現位於 AbstractAdvisorAutoProxyCreator
中:
- 調用
findEligibleAdvisors
用於查出是否有可用的通知器; - 在
findEligibleAdvisors
方法中,通過findCandidateAdvisors
加載 spring 容器中的所有Advisor
,在AnnotationAwareAspectJAutoProxyCreator
中通過重寫該方法,額外加載了一些基於AspectJ
的通知器; - 再調用
findAdvisorsThatCanApply
從所有的Advisor
中篩選出可應用於當前 bean 的通知器:- 如果通知器是
IntroductionAdvisor
類型,則通過通知器的ClassFilter
進行類型匹配; - 如果通知器是
PointcutAdvisor
類型,則通過通知器的Pointcut
切點中的ClassFilter
與MethodMatcher
分別對類型和類中的方法進行匹配。其中,若MethodMatcher
類型爲IntroductionAwareMethodMatcher
,則支持同時根據方法與其類型進行匹配; - 如果通知器不是上述兩者,則認爲其必定可應用與當前 bean;
- 如果通知器是
經過上述流程後若當前 bean 沒有任何可用的通知器,則說明其無需代理,否則需要通過通知器進行代理增強。
3、代理前的準備
獲得可用的通知器後,將會調用 createProxy
方法真正的進入創建代理對象的邏輯中。
- 創建一個
ProxyFactory
用於後續創建代理對象; - 嘗試推斷代理對象的類型:
- 若
proxyFactory
設置了proxyTargetClass
標誌爲true
,則說明要使用目標類(target class)作爲代理的基礎。在這種情況下,如果目標類是 JDK 動態代理的代理類(比如Annotation
)或者是 Lambda 表達式生成的匿名內部類,則需要遍歷目標類的接口,將這些接口添加到代理工廠中,以保證代理對象具備這些接口的方法; - 如果
proxyFactory
的proxyTargetClass
標誌沒有設置爲true
,則執行下面的邏輯。這表示沒有顯式要求使用目標類作爲代理基礎,則:
a.應該使用目標類作爲代理基礎,則將proxyTargetClass
標誌設置爲true
,即需要進行 CGLib 代理;
b.不滿足使用目標類作爲代理基礎的條件,則調用evaluateProxyInterfaces
方法,根據目標類的接口信息,將適合的接口添加到代理工廠中;
- 若
- 適配通知器:在這一步,大部分的
Advisor
都以及被蒐集到了,不過仍有一些通知器需要在buildAdvisors
方法中進行適配或者特殊的處理:- 收集通用通知器:處了在容器中註冊的通知器外,有另一部分通用通知器直接通過直接在
AbstractAutoProxyCreator
中登記beanName
的方法設置,此時需要根據beanName
將其從容器中取出; - 適配通知器:此時,已收集的通知器中混有多種類型的對象,因此需要通過
AdvisorAdapterRegistry.wrap
**方法將其中非Advisor
對象進行適配:- 如果已經是
Advisor
了,就直接返回; - 如果不是
Advisor
,那必須是Advice
,否則直接拋異常; - 如果它是
MethodInterceptor
,那就將其適配爲DefaultPointcutAdvisor
; - 如果是其他類型的
Advice
,就調用適配器鏈,找到一個支持處理這個攔截器的AdvisorAdapter
去對它做適配;
- 如果已經是
- 收集通用通知器:處了在容器中註冊的通知器外,有另一部分通用通知器直接通過直接在
4、創建代理對象
- 當在
ProxyFactory
中配置好了代理對象的類型、需要實現的接口類型、需要應用的通知器及其他配置後; ProxyFactory
將會在createAopProxy
方法中獲取一個AopProxyFactory
(默認爲DefaultAopProxyFactory
);- 接着調用
DefaultAopProxyFactory
的createAopProxy
方法,根據情況去創建一個AopProxy
對象:- 如果需要基於目標類代理,那麼就使用 CGLib 代理,返回一個
ObjenesisCglibAopProxy
; - 如果需要基於接口代理,那麼使用 JDK 的動態代理,返回一個
JdkDynamicAopProxy
;
- 如果需要基於目標類代理,那麼就使用 CGLib 代理,返回一個
- 接着我們調用
AopProxy
的getProxy
方法,該方法將會真正的創建一個代理對象。
5、方法代理
對於 JDK 動態代理來說,用於生成代理的 InvocationHandler
即爲 JdkDynamicAopProxy
本身,當我們調用代理對象的方法時,將會統一經過 invoke
方法。
其中,根據方法類型又分爲三種類型:
equals
和hashCode
方法:若兩方法沒有在接口中重新定義,則直接按JdkDynamicAopProxy
去進行比較/獲取哈希值;- 如果方法是
DecoratingProxy
或Advised
接口中聲明的方法,則直接通過當前代理對象內部持有的相應實例進行調用; - 如果是普通方法,則在調用前後一次調用通知器中的
Advice
增強邏輯;
其中,對於普通方法,在首次調用 invoke
的時候,將會:
- 通過內部持有的
AdvisedSupport
對象(即Advised
的默認實現)的getInterceptorsAndDynamicInterceptionAdvice
方法獲取相應的方法攔截器; - 然後
AdvisedSupport
將會通過內部的AdvisorChainFactory
(默認爲DefaultAdvisorChainFactory
)的getInterceptorsAndDynamicInterceptionAdvice
方法創建方法攔截器鏈; - 在
DefaultAdvisorChainFactory
中,將會:- 先取出
AdvisedSupport
中存放的所有可應用於當前 bean 的通知器,然後遍歷它們:- 如果當前的
Advisor
是一個PointcutAdvisor
,即基於切點的通知器,那麼根據其持有的切點Pointcut
中的ClassFilter
與MethodMatcher
進行匹配; - 如果當前的
Advisor
是一個IntroductionAdvisor
,即引介增強器,那麼根據類過濾器的匹配規則判斷是否需要將它添加到攔截器鏈中; - 如果當前的
Advisor
不是上述兩種類型,直接將它的攔截器數組添加到攔截器鏈中;
- 如果當前的
- 在獲得的可用的通知器後,通過
AdvisorAdapterRegistry.getInterceptors
(此處的適配器註冊表在上文也用於適配Advisor
)方法將其全部適配爲MethodInterceptor
;
- 先取出
- 通過
DefaultAdvisorChainFactory
獲取方法攔截器鏈後,將會將攔截器鏈與要增強的代理方法封裝爲一個方法調用對象MethodInvocation
(默認爲ReflectiveMethodInvocation
); - 然後調用
MethodInvocation.processed
方法,此時將會調用鏈首的攔截器,接着攔截器再繼續調用processed
方法,遞歸此步驟,直到整個調用鏈完成或者中斷爲止;