死磕Spring之AOP篇 – Spring AOP自動代理(三)創建代理對象
- 2021 年 4 月 21 日
- 筆記
- Spring AOP, 死磕Spring之AOP篇, 源碼解析
該系列文章是本人在學習 Spring 的過程中總結下來的,裏面涉及到相關源碼,可能對讀者不太友好,請結合我的源碼注釋 Spring 源碼分析 GitHub 地址 進行閱讀。
Spring 版本:5.1.14.RELEASE
在開始閱讀 Spring AOP 源碼之前,需要對 Spring IoC 有一定的了解,可查看我的 《死磕Spring之IoC篇 – 文章導讀》 這一系列文章
了解 AOP 相關術語,可先查看 《Spring AOP 常見面試題) 》 這篇文章
該系列其他文章請查看:《死磕 Spring 之 AOP 篇 – 文章導讀》
在前面的《Spring AOP 自動代理(一)入口》文章中,分析了 Spring AOP 自動代理的入口是 AbstractAutoProxyCreator 對象,其中自動代理的過程主要分為下面兩步:
- 篩選出能夠應用於當前 Bean 的 Advisor
- 找到了合適 Advisor 則創建一個代理對象, JDK 動態代理或者 CGLIB 動態代理
上一篇《Spring AOP 自動代理(二)篩選合適的通知器》文章分析了上面第 1
步的處理過程,先去解析出當前 IoC 容器所有 Advisor 對象,包括 Advisor 類型的 Bean 和從 @AspectJ
註解的 Bean 解析出來的 Advisor 對象;然後通過通過 ClassFilter 類過濾器和 MethodMatcher 方法匹配器篩選出能夠應用於這個 Bean 的 Advisor 們,最後進行排序;不同的 AspectJ 根據 @Order
排序,同一個 AspectJ 中不同 Advisor 的排序,優先級:AspectJAfterThrowingAdvice > AspectJAfterReturningAdvice > AspectJAfterAdvice > AspectJAroundAdvice > AspectJMethodBeforeAdvice
本文將會分析上面的第 2
的創建過程,如果這個 Bean 有合適的 Advisor,那麼為這個 Bean 創建一個代理對象,我們一起來看看是如何創建代理對象的。
回顧
// AbstractAutoProxyCreator.java
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
/*
* <1> 如果當前 Bean 已經創建過自定義 TargetSource 對象
* 表示在上面的**實例化前置處理**中已經創建代理對象,那麼直接返回這個對象
*/
if (StringUtils.hasLength(beanName)
&& this.targetSourcedBeans.contains(beanName))
{
return bean;
}
// <2> `advisedBeans` 保存了這個 Bean 沒有必要創建代理對象,則直接返回
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
/*
* <3> 不需要創建代理對象,則直接返回當前 Bean
*/
if (isInfrastructureClass(bean.getClass()) // 如果是 Spring 內部的 Bean(Advice、Pointcut、Advisor 或者 AopInfrastructureBean 標記接口)
|| shouldSkip(bean.getClass(), beanName)) // 應該跳過
{
// 將這個 Bean 不需要創建代理對象的結果保存起來
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// Create proxy if we have advice.
// <4> 獲取能夠應用到當前 Bean 的所有 Advisor(已根據 @Order 排序)
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
// <5> 如果有 Advisor,則進行下面的動態代理創建過程
if (specificInterceptors != DO_NOT_PROXY) {
// <5.1> 將這個 Bean 已創建代理對象的結果保存至 `advisedBeans`
this.advisedBeans.put(cacheKey, Boolean.TRUE);
// <5.2> 創建代理對象,JDK 動態代理或者 CGLIB 動態代理
// 這裡傳入的是 SingletonTargetSource 對象,可獲取代理對象的目標對象(當前 Bean)
Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
// <5.3> 將代理對象的 Class 對象(目標類的子類)保存
this.proxyTypes.put(cacheKey, proxy.getClass());
// <5.4> 返回代理對象
return proxy;
}
// <6> 否則,將這個 Bean 不需要創建代理對象的結果保存起來
this.advisedBeans.put(cacheKey, Boolean.FALSE);
// <7> 返回這個 Bean 對象
return bean;
}
在創建代理對象的過程中,上面方法的第 4
步嘗試獲取能夠應用於當前 Bean 的 Advisor,該過程在上一篇文章中進行分析過,如果有 Advisor,則調用 createProxy(..)
方法創建代理對象
注意,這裡傳入的 TargetSource 是一個 SingletonTargetSource 對象,可獲取目標對象,如下:
public class SingletonTargetSource implements TargetSource, Serializable {
private static final long serialVersionUID = 9031246629662423738L;
private final Object target;
public SingletonTargetSource(Object target) {
Assert.notNull(target, "Target object must not be null");
this.target = target;
}
@Override
public Class<?> getTargetClass() {
return this.target.getClass();
}
@Override
public Object getTarget() {
return this.target;
}
@Override
public void releaseTarget(Object target) {
// nothing to do
}
@Override
public boolean isStatic() {
return true;
}
}
創建代理對象的流程
-
創建一個 ProxyFactory 代理工廠對象,設置需要創建的代理類的配置信息,例如 Advisor 數組和 TargetSource 目標類來源
-
藉助 DefaultAopProxyFactory 選擇 JdkDynamicAopProxy(JDK 動態代理)還是 ObjenesisCglibAopProxy(CGLIB 動態代理)
-
當
proxy-target-class
為false
時,優先使用 JDK 動態代理,如果目標類沒有實現可代理的接口,那麼還是使用 CGLIB 動態代理 -
如果為
true
,優先使用 CGLIB 動態代理,如果目標類本身是一個接口,那麼還是使用 JDK 動態代理
-
-
通過 JdkDynamicAopProxy 或者 ObjenesisCglibAopProxy 創建一個代理對象
- JdkDynamicAopProxy 本身是一個 InvocationHandler 實現類,通過 JDK 的
Proxy.newProxyInstance(..)
創建代理對象 - ObjenesisCglibAopProxy 藉助 CGLIB 的 Enhancer 創建代理對象,會設置 Callback 數組和 CallbackFilter 篩選器(選擇合適 Callback 處理對應的方法),整個過程相比於 JDK 動態代理更複雜點,主要的實現在 DynamicAdvisedInterceptor 方法攔截器中
- JdkDynamicAopProxy 本身是一個 InvocationHandler 實現類,通過 JDK 的
AbstractAutoProxyCreator
org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator
:AOP 自動代理的抽象類,完成主要的邏輯實現,提供一些骨架方法交由子類完成
1. createProxy 方法
createProxy(..)
方法,為目標對象創建一個代理對象,如下:
protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
@Nullable Object[] specificInterceptors, TargetSource targetSource) {
if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
// 為目標 Bean 的 BeanDefinition 對象設置一個屬性
// org.springframework.aop.framework.autoproxy.AutoProxyUtils.originalTargetClass -> 目標 Bean 的 Class 對象
AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
}
// <1> 創建一個代理工廠
ProxyFactory proxyFactory = new ProxyFactory();
// <2> 複製當前 ProxyConfig 的一些屬性(例如 proxyTargetClass、exposeProxy)
proxyFactory.copyFrom(this);
/**
* <3> 判斷是否類代理,也就是是否開啟 CGLIB 代理
* 默認配置下為 `false`,參考 {@link org.springframework.context.annotation.EnableAspectJAutoProxy}
*/
if (!proxyFactory.isProxyTargetClass()) {
/*
* <3.1> 如果這個 Bean 配置了進行類代理,則設置為 `proxyTargetClass` 為 `true`
*/
if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
}
else {
/*
* <3.2> 檢測當前 Bean 實現的接口是否包含可代理的接口
* 如沒有實現,則將 `proxyTargetClass` 設為 `true`,表示需要進行 CGLIB 提升
*/
evaluateProxyInterfaces(beanClass, proxyFactory);
}
}
/*
* <4> 對入參的 Advisor 進一步處理,因為其中可能還存在 Advice 類型,需要將他們包裝成 DefaultPointcutAdvisor 對象
* 如果配置了 `interceptorNames` 攔截器,也會添加進來
*/
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
// <5> 代理工廠添加 Advisor 數組
proxyFactory.addAdvisors(advisors);
// <6> 代理工廠設置 TargetSource 對象
proxyFactory.setTargetSource(targetSource);
// <7> 對 ProxyFactory 進行加工處理,抽象方法,目前沒有子類實現
customizeProxyFactory(proxyFactory);
proxyFactory.setFrozen(this.freezeProxy);
// <8> 是否這個 AdvisedSupport 配置管理器已經過濾過目標類(默認為 false)
if (advisorsPreFiltered()) {
// 設置 `preFiltered` 為 `true`
// 這樣 Advisor 們就不會根據 ClassFilter 進行過濾了,而直接通過 MethodMatcher 判斷是否處理被攔截方法
proxyFactory.setPreFiltered(true);
}
// <9> 通過 ProxyFactory 代理工廠創建代理對象
return proxyFactory.getProxy(getProxyClassLoader());
}
該方法的處理過程如下:
- 創建一個 ProxyFactory 代理工廠
proxyFactory
- 複製當前對象的一些屬性給
proxyFactory
(例如 proxyTargetClass、exposeProxy),當前 AbstractAutoProxyCreator 對象繼承了 ProxyConfig - 判斷是否類代理,也就是是否開啟 CGLIB 代理,默認配置下為
false
,如果沒有的話,進行下面處理- 如果這個 Bean 配置了進行類代理,則設置為
proxyTargetClass
為true
- 否則,檢測當前 Bean 實現的接口是否包含可代理的接口,如沒有實現,則將
proxyTargetClass
設為true
,表示需要進行 CGLIB 提升
- 如果這個 Bean 配置了進行類代理,則設置為
- 調用
buildAdvisors(..)
方法,對入參的 Advisor 數組進一步處理,會將不是 Advisor 類型的對象包裝成 DefaultPointcutAdvisor 對象 proxyFactory
代理工廠添加 Advisor 數組proxyFactory
代理工廠設置 TargetSource 對象,用戶獲取目標對象- 對
proxyFactory
進行加工處理,抽象方法,目前沒有子類實現 - 是否這個 AdvisedSupport 配置管理器已經過濾過目標類(默認為
false
)- 是的話設置
preFiltered
為true
,這樣 Advisor 們就不會根據 ClassFilter 進行過濾了,而直接通過 MethodMatcher 判斷是否處理被攔截方法
- 是的話設置
- 調用
proxyFactory
代理工廠的getProxy(@Nullable ClassLoader classLoader)
方法創建代理對象
這個過程不複雜,容易理解,其中第 4
步會再次對 Advisor 數組進一步處理,在第 9
步根據 proxyFactory
創建代理對象
buildAdvisors 方法
buildAdvisors(@Nullable String beanName, @Nullable Object[] specificInterceptors)
方法,對 Advisor 數組進一步處理,如下:
protected Advisor[] buildAdvisors(@Nullable String beanName, @Nullable Object[] specificInterceptors) {
// Handle prototypes correctly...
// <1> 將配置的 `interceptorNames` 轉換成 Advisor 類型(默認沒有)
Advisor[] commonInterceptors = resolveInterceptorNames();
// <2> 將 commonInterceptors 與 specificInterceptors 放入一個集合
List<Object> allInterceptors = new ArrayList<>();
if (specificInterceptors != null) {
allInterceptors.addAll(Arrays.asList(specificInterceptors));
if (commonInterceptors.length > 0) {
// 是否添加至最前面(默認為 true)
if (this.applyCommonInterceptorsFirst) {
allInterceptors.addAll(0, Arrays.asList(commonInterceptors));
}
else {
allInterceptors.addAll(Arrays.asList(commonInterceptors));
}
}
}
Advisor[] advisors = new Advisor[allInterceptors.size()];
/*
* <3> 遍歷 `specificInterceptors` 數組
*/
for (int i = 0; i < allInterceptors.size(); i++) {
// <3.1> 將不是 Advisor 類型的 Advice 或者 MethodInterceptor 包裝成 DefaultPointcutAdvisor 對象
advisors[i] = this.advisorAdapterRegistry.wrap(allInterceptors.get(i));
}
// <4> 返回構建好的 Advisor 數組
return advisors;
}
該方法的處理過程如下:
-
將配置的
interceptorNames
轉換成 Advisor 類型(默認沒有),得到commonInterceptors
數組,如下: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]); }
解析
interceptorNames
中對應的 Bean,並包裝成 Advisor 類型(如果需要的話) -
將上一步獲取到的
commonInterceptors
數組放入入參中的specificInterceptors
數組中 -
遍歷
specificInterceptors
數組-
將不是 Advisor 類型的 Advice 或者 MethodInterceptor 包裝成 DefaultPointcutAdvisor 對象
// DefaultAdvisorAdapterRegistry.java @Override public Advisor wrap(Object adviceObject) throws UnknownAdviceTypeException { if (adviceObject instanceof Advisor) { // Advisor 類型,直接返回 return (Advisor) adviceObject; } if (!(adviceObject instanceof Advice)) { // 非 Advice 接口,拋出異常 throw new UnknownAdviceTypeException(adviceObject); } Advice advice = (Advice) adviceObject; if (advice instanceof MethodInterceptor) { // MethodInterceptor 類型,包裝成 DefaultPointcutAdvisor 對象 // So well-known it doesn't even need an adapter. return new DefaultPointcutAdvisor(advice); } for (AdvisorAdapter adapter : this.adapters) { // Check that it is supported. // 檢查該 Advice 類型是否支持 if (adapter.supportsAdvice(advice)) { // 包裝成 DefaultPointcutAdvisor 對象 返回 return new DefaultPointcutAdvisor(advice); } } throw new UnknownAdviceTypeException(advice); }
-
-
返回構建好的 Advisor 數組
能夠應用於這個 Bean 的 Advisor 們已經準備好了,那麼接下來我們來看看 ProxyFactory 是如何創建代理對象的
2. ProxyFactory
org.springframework.aop.framework.ProxyFactory
,代理工廠,如下:
public Object getProxy(@Nullable ClassLoader classLoader) {
// <1> 先創建一個 AOP 代理類(JdkDynamicAopProxy 或者 ObjenesisCglibAopProxy)
// <2> 根據 AOP 代理為目標 Bean 創建一個代理對象,並返回
return createAopProxy().getProxy(classLoader);
}
過程分為兩步:
-
調用
createAopProxy()
方法,創建一個 AOP 代理類(JdkDynamicAopProxy 或者 ObjenesisCglibAopProxy),如下:protected final synchronized AopProxy createAopProxy() { if (!this.active) { activate(); } // <1> 先獲取 AOP 代理工廠,默認為 DefaultAopProxyFactory,只有這個實現 // <2> 然後通過它根據創建當前 AdvisedSupport 配置管理器創建一個 AOP 代理(JdkDynamicAopProxy 或者 ObjenesisCglibAopProxy) return getAopProxyFactory().createAopProxy(this); }
-
然後調用 AOP 代理類的
getProxy(@Nullable ClassLoader classLoader)
方法獲取代理對象
可以看到選擇 JDK 動態代理還是選擇 CGLIB 動態代理在 DefaultAopProxyFactory 中可以找到答案
3. DefaultAopProxyFactory
org.springframework.aop.framework.DefaultAopProxyFactory
,默認的 AOP 代理工廠,如下:
public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {
@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
/*
* <1> 判斷是否滿足下面三個條件的其中一個
*/
if (config.isOptimize() // 需要優化,默認為 `false`
|| config.isProxyTargetClass() // 使用類代理,也就是使用 CGLIB 動態代理
|| hasNoUserSuppliedProxyInterfaces(config) // 目標類沒有實現接口
) {
// <1.1> 獲取目標類
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.");
}
/*
* <1.2> 如果目標類是一個接口或者是 java.lang.reflect.Proxy 的子類
* 則還是使用 JDK 動態代理,創建一個 JdkDynamicAopProxy 對象,傳入 AdvisedSupport 配置管理器,並返回
*/
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
// <1.3> 使用 CGLIB 動態代理,創建一個 ObjenesisCglibAopProxy 對象,傳入 AdvisedSupport 配置管理器,並返回
return new ObjenesisCglibAopProxy(config);
}
// <2> 否則
else {
// 使用 JDK 動態代理,創建一個 JdkDynamicAopProxy 對象,傳入 AdvisedSupport 配置管理器,並返回
return new JdkDynamicAopProxy(config);
}
}
private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) {
Class<?>[] ifcs = config.getProxiedInterfaces();
return (ifcs.length == 0 || (ifcs.length == 1 && SpringProxy.class.isAssignableFrom(ifcs[0])));
}
}
創建 AOP 代理類的過程如下:
-
判斷是否滿足下面三個條件的其中一個,則進行下面的處理
需要優化,默認為
false
;使用類代理,也就是使用 CGLIB 動態代理,在前面的
AbstractAutoProxyCreator#createProxy(..)
方法中有提到過;目標類沒有實現接口;
- 獲取目標類
- 如果目標類是一個接口或者是
java.lang.reflect.Proxy
的子類,則還是使用JDK 動態代理,創建一個JdkDynamicAopProxy
對象 - 否則,使用 CGLIB 動態代理,創建一個
ObjenesisCglibAopProxy
對象
-
否則,使用JDK 動態代理,創建一個
JdkDynamicAopProxy
對象
我們可以看到JDK 動態代理對應 JdkDynamicAopProxy
對象,CGLIB 動態代理對應 ObjenesisCglibAopProxy
(繼承 CglibAopProxy
)對象,在創建這兩個對象的時候都傳入了一個參數,就是 AdvisedSupport
配置管理器對象。
回到前面的 ProxyFactory#createAopProxy()
方法中,這個 AdvisedSupport
對象就是這個 ProxyFactory
對象,它繼承了 AdvisedSupport
。
再回到 AbstractAutoProxyCreator#createProxy(..)
方法中,這個 ProxyFactory
對象是在這創建的,包含了 TargetSource
目標類來源和能夠應用於當前目標對象的所有 Advisor
。
所以,我們得到的JdkDynamicAopProxy
或者ObjenesisCglibAopProxy
都包含了創建 AOP 代理對象的所有配置信息,可以創建代理對象了。
通過上面的這個方法,我們還可以得出一個結論,關於
proxy-target-class
配置的含義是什麼?首先這個配置表示是否進行類代理,也就是 CGLIB 動態代理,默認是
false
當為
false
時,優先使用 JDK 動態代理,如果目標類沒有實現可代理的接口,那麼還是使用 CGLIB 動態代理如果為
true
,優先使用 CGLIB 動態代理,如果目標類本身是一個接口,那麼還是使用 JDK 動態代理
到這裡,我們知道了使用哪種方式創建代理對象,那麼接下里我們一起來看看兩種方式創建代理對象的過程。
4. JdkDynamicAopProxy
org.springframework.aop.framework.JdkDynamicAopProxy
,JDK 動態代理類,實現了 InvocationHandler 接口,可創建代理對象
構造函數
final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {
/** use serialVersionUID from Spring 1.2 for interoperability. */
private static final long serialVersionUID = 5531744639992436476L;
/** We use a static Log to avoid serialization issues. */
private static final Log logger = LogFactory.getLog(JdkDynamicAopProxy.class);
/** 代理對象的配置信息,例如保存了 TargetSource 目標類來源、能夠應用於目標類的所有 Advisor */
private final AdvisedSupport advised;
/** 目標對象是否重寫了 equals 方法 */
private boolean equalsDefined;
/** 目標對象是否重寫了 hashCode 方法 */
private boolean hashCodeDefined;
public JdkDynamicAopProxy(AdvisedSupport config) throws AopConfigException {
Assert.notNull(config, "AdvisedSupport must not be null");
if (config.getAdvisors().length == 0 // 沒有 Advisor,表示沒有任何動作
&& config.getTargetSource() == AdvisedSupport.EMPTY_TARGET_SOURCE) // 沒有來源
{
throw new AopConfigException("No advisors and no TargetSource specified");
}
this.advised = config;
}
}
4.1 getProxy 方法
getProxy()
方法,獲取一個 JDK 動態代理對象,如下:
@Override
public Object getProxy() { return getProxy(ClassUtils.getDefaultClassLoader()); }
@Override
public Object getProxy(@Nullable ClassLoader classLoader) {
// <1> 獲取需要代理的接口(目標類實現的接口,會加上 Spring 內部的幾個接口,例如 SpringProxy)
Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
// <2> 判斷目標類是否重寫了 `equals` 或者 `hashCode` 方法
// 沒有重寫在攔截到這兩個方法的時候,會調用當前類的實現
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
// <3> 調用 JDK 的 Proxy#newProxyInstance(..) 方法創建代理對象
// 傳入的參數就是當前 ClassLoader 類加載器、需要代理的接口、InvocationHandler 實現類
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
獲取代理對象的過程如下:
-
獲取需要代理的接口(目標類實現的接口,會加上 Spring 內部的幾個接口,例如 SpringProxy)
-
判斷目標類是否重寫了
equals
或者hashCode
方法,沒有重寫在攔截到這兩個方法的時候,會調用當前類的實現private void findDefinedEqualsAndHashCodeMethods(Class<?>[] proxiedInterfaces) { for (Class<?> proxiedInterface : proxiedInterfaces) { Method[] methods = proxiedInterface.getDeclaredMethods(); for (Method method : methods) { if (AopUtils.isEqualsMethod(method)) { this.equalsDefined = true; } if (AopUtils.isHashCodeMethod(method)) { this.hashCodeDefined = true; } if (this.equalsDefined && this.hashCodeDefined) { return; } } } }
-
調用 JDK 的
Proxy#newProxyInstance(..)
方法創建代理對象,入參的 InvocationHandler 實現了就是當前對象
對於上面 JDK 創建代理對象的過程是不是很熟悉,不清楚的小夥伴可以查看我前面 《初識 JDK、CGLIB 兩種動態代理》 這篇文章
AopProxyUtils
org.springframework.aop.framework.AopProxyUtils
工具類,獲取 JDK 創建代理對象時需要實現哪些接口,如下:
static Class<?>[] completeProxiedInterfaces(AdvisedSupport advised, boolean decoratingProxy) {
// <1> 獲取需要代理的接口(目標類實現的接口),放入 `specifiedInterfaces` 中
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)) {
advised.setInterfaces(targetClass.getInterfaces());
}
specifiedInterfaces = advised.getProxiedInterfaces();
}
}
// <2> 判斷目標類實現的接口是否存在 SpringProxy|Advised|DecoratingProxy 接口,不存在需要添加一個
boolean addSpringProxy = !advised.isInterfaceProxied(SpringProxy.class);
boolean addAdvised = !advised.isOpaque() && !advised.isInterfaceProxied(Advised.class);
boolean addDecoratingProxy = (decoratingProxy && !advised.isInterfaceProxied(DecoratingProxy.class));
int nonUserIfcCount = 0;
if (addSpringProxy) {
nonUserIfcCount++;
}
if (addAdvised) {
nonUserIfcCount++;
}
if (addDecoratingProxy) {
nonUserIfcCount++;
}
Class<?>[] proxiedInterfaces = new Class<?>[specifiedInterfaces.length + nonUserIfcCount];
System.arraycopy(specifiedInterfaces, 0, proxiedInterfaces, 0, specifiedInterfaces.length);
int index = specifiedInterfaces.length;
// <3> 如果目標類實現的接口沒有 SpringProxy,則添加一個
// 這樣創建的代理對象就會實現這個接口,就能知道這個代理對象是否由 Spring 創建
if (addSpringProxy) {
proxiedInterfaces[index] = SpringProxy.class;
index++;
}
// 添加一個 Advised 接口
if (addAdvised) {
proxiedInterfaces[index] = Advised.class;
index++;
}
// 添加一個 DecoratingProxy 接口
if (addDecoratingProxy) {
proxiedInterfaces[index] = DecoratingProxy.class;
}
// <4> 返回需要代理的接口
return proxiedInterfaces;
}
該方法的處理過程如下:
- 獲取需要代理的接口(目標類實現的接口),放入
specifiedInterfaces
中 - 判斷目標類實現的接口是否存在 SpringProxy|Advised|DecoratingProxy 接口,不存在需要添加一個
- 通常情況下,上面三個接口都會添加到
specifiedInterfaces
的後面 - 返回
specifiedInterfaces
數組
通過上面這個方法得到的結論:在 Spring 內部通過 JDK 創建的代理對象會實現額外的接口,包括 SpringProxy 標記接口,可區分代理對象是否為 Spring 創建的
4 CglibAopProxy
org.springframework.aop.framework.CglibAopProxy
,CGLIB 動態代理類,可創建代理對象
CGLIB 動態代理比 JDK 動態代理可要複雜得多~
構造函數
class CglibAopProxy implements AopProxy, Serializable {
// Constants for CGLIB callback array indices
// 因為 CGLIB 設置的 Callback 是一個數組,下面定義了數組中固定幾個攔截器的位置
// 進行 AOP 代理的通用攔截器
private static final int AOP_PROXY = 0;
// 執行目標方法的攔截器
private static final int INVOKE_TARGET = 1;
// 空的 Callback 對象,對於 finalize() 方法,不需要進行任何處理
private static final int NO_OVERRIDE = 2;
// 目標對象調度器,用於獲取目標對象
private static final int DISPATCH_TARGET = 3;
// 配置管理器的調度器,會返回一個 AdvisedSupport 對象
private static final int DISPATCH_ADVISED = 4;
// 處理 `equals(Object)` 方法的攔截器
private static final int INVOKE_EQUALS = 5;
// 處理 `hashCode()` 方法的攔截器
private static final int INVOKE_HASHCODE = 6;
/** Logger available to subclasses; static to optimize serialization. */
protected static final Log logger = LogFactory.getLog(CglibAopProxy.class);
/** Keeps track of the Classes that we have validated for final methods. */
private static final Map<Class<?>, Boolean> validatedClasses = new WeakHashMap<>();
/** 代理對象的配置信息,例如保存了 TargetSource 目標類來源、能夠應用於目標類的所有 Advisor */
protected final AdvisedSupport advised;
/** 創建代理對象的構造方法入參 */
@Nullable
protected Object[] constructorArgs;
/** 創建代理對象的構造方法的入參類型 */
@Nullable
protected Class<?>[] constructorArgTypes;
/** Dispatcher used for methods on Advised. 配置管理器的調度器,會返回一個 AdvisedSupport 對象 */
private final transient AdvisedDispatcher advisedDispatcher;
/**
* 緩存方法的調用器數組索引
* key:方法名稱
* value:方法對應的方法調用器在 Callback 數組中的位置
*/
private transient Map<String, Integer> fixedInterceptorMap = Collections.emptyMap();
// 方法調用器在 Callback 數組中的偏移量
private transient int fixedInterceptorOffset;
public CglibAopProxy(AdvisedSupport config) throws AopConfigException {
Assert.notNull(config, "AdvisedSupport must not be null");
if (config.getAdvisors().length == 0 // 沒有 Advisor,表示沒有任何動作
&& config.getTargetSource() == AdvisedSupport.EMPTY_TARGET_SOURCE) // 沒有來源
{
throw new AopConfigException("No advisors and no TargetSource specified");
}
this.advised = config;
this.advisedDispatcher = new AdvisedDispatcher(this.advised);
}
}
上面的每一個屬性都有注釋,都非常重要,在 Spring 的 CGLIB 動態代理創建代理對象時,會設置一個 Callback 數組,上面定義了數組中固定幾個攔截器的位置
數組中前面的幾個 Callback 如下:
0
:進行 AOP 代理的通用攔截器【重點關注】1
:執行目標方法的攔截器2
:空的 Callback 對象,例如finalize()
方法,不需要進行任何處理3
:目標對象調度器,用於獲取目標對象4
:配置管理器的調度器,會返回一個 AdvisedSupport 對象5
:處理equals(Object)
方法的攔截器6
:處理hashCode()
方法的攔截器
4.1 getProxy 方法
getProxy()
方法,獲取一個 CGLIB 動態代理對象,如下:
@Override
public Object getProxy() { return getProxy(null); }
@Override
public Object getProxy(@Nullable ClassLoader classLoader) {
try {
// <1> 獲取目標類
Class<?> rootClass = this.advised.getTargetClass();
Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy");
// <2> 將目標類作為被代理的類
Class<?> proxySuperClass = rootClass;
// <3> 如果目標類已經被 CGLIB 提升(名稱包含 `$$` 符號)
if (ClassUtils.isCglibProxyClass(rootClass)) {
// <3.1> 獲取目標類的父類作為被代理的類
proxySuperClass = rootClass.getSuperclass();
// <3.2> 獲取目標類實現的接口,並添加至當前 AdvisedSupport 配置管理器中
// 例如 `@Configuration` 註解的 Bean 會被 CGLIB 提升,實現了 EnhancedConfiguration 接口
Class<?>[] additionalInterfaces = rootClass.getInterfaces();
for (Class<?> additionalInterface : additionalInterfaces) {
this.advised.addInterface(additionalInterface);
}
}
// Validate the class, writing log messages as necessary.
// <4> 進行校驗,僅打印日誌,例如 final 修飾的方法不能被 CGLIB 提升
validateClassIfNecessary(proxySuperClass, classLoader);
// Configure CGLIB Enhancer...
// <5> 創建 CGLIB 的增強類,並進行接下來的配置
Enhancer enhancer = createEnhancer();
if (classLoader != null) {
enhancer.setClassLoader(classLoader);
// `useCache` 默認為 `true`,可通過 `cglib.useCache` 系統參數指定
if (classLoader instanceof SmartClassLoader &&
((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
enhancer.setUseCache(false);
}
}
// <5.1> 設置被代理的類
enhancer.setSuperclass(proxySuperClass);
// <5.2> 設置需要代理的接口(可能沒有,不過都會加上 Spring 內部的幾個接口,例如 SpringProxy)
enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
// <5.3> 設置命名策略,默認生成的代理對象的名稱中包含 '$$' 和 'BySpringCGLIB'
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
enhancer.setStrategy(new ClassLoaderAwareUndeclaredThrowableStrategy(classLoader));
// <5.4> 獲取回調接口,也就是 MethodInterceptor 方法攔截器
Callback[] callbacks = getCallbacks(rootClass);
Class<?>[] types = new Class<?>[callbacks.length];
for (int x = 0; x < types.length; x++) {
types[x] = callbacks[x].getClass();
}
// fixedInterceptorMap only populated at this point, after getCallbacks call above
// <5.5> 設置 Callback 過濾器,用於篩選出方法對應的 Callback 回調接口
enhancer.setCallbackFilter(new ProxyCallbackFilter(
this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
enhancer.setCallbackTypes(types);
// Generate the proxy class and create a proxy instance.
// <6> 創建代理對象,CGLIG 位元組碼替身,創建目標類的子類
return createProxyClassAndInstance(enhancer, callbacks);
}
catch (CodeGenerationException | IllegalArgumentException ex) {
// 拋出 AopConfigException 異常
}
catch (Throwable ex) {
// 拋出 AopConfigException 異常
}
}
該方法的處理過程如下:
- 獲取目標類
rootClass
- 將目標類作為被代理的類
proxySuperClass
- 如果目標類已經被 CGLIB 提升(名稱包含
$$
符號)- 獲取目標類的父類作為被代理的類
- 獲取目標類實現的接口,並添加至當前 AdvisedSupport 配置管理器中,例如
@Configuration
註解的 Bean 會被 CGLIB 提升,實現了 EnhancedConfiguration 接口
- 進行校驗,僅打印日誌,例如 final 修飾的方法不能被 CGLIB 提升
- 創建 CGLIB 的增強類 Enhancer 對象,並進行接下來的配置
- 設置被代理的類為
proxySuperClass
- 設置需要代理的接口(例如 SpringProxy),在前面講述 JDK 動態代理創建代理對象時已經講過 AopProxyUtils 這個工具類,不同的是 CGLIB 不會添加 DecoratingProxy 這個接口
- 設置命名策略,默認生成的代理對象的名稱中包含
$$
和BySpringCGLIB
- 調用
getCallbacks(Class<?>)
方法,獲取回調數組Callback[] callbacks
,也就是 MethodInterceptor 方法攔截器 - 設置 Callback 過濾器為
ProxyCallbackFilter
,用於篩選出方法使用callbacks
中的哪個 Callback
- 設置被代理的類為
- 調用
createProxyClassAndInstance(Enhancer enhancer, Callback[] callbacks)
方法,創建代理對象,並返回
CGLIB 創建代理對象的過程整體上並不複雜,其中第 5.4
、5.5
和 6
步我們接下來逐步分析
4.2 getCallbacks 方法
getCallbacks(Class<?> rootClass)
方法,獲取代理對象的 Callback 回調數組,如下:
private Callback[] getCallbacks(Class<?> rootClass) throws Exception {
// Parameters used for optimization choices...
// <1> 獲取代理對象的三個配置信息
// `exposeProxy` 是否暴露代理對象,通常為 `false`
boolean exposeProxy = this.advised.isExposeProxy();
// `isFrozen` 配置管理器是否被凍結,通常為 `false`
boolean isFrozen = this.advised.isFrozen();
// `isStatic` 是否是靜態的目標對象,也就是說目標對象是否每次都需要創建,通常為 `true`
boolean isStatic = this.advised.getTargetSource().isStatic();
// Choose an "aop" interceptor (used for AOP calls).
// <2> 【重點】創建目標對象的攔截器,MethodInterceptor 方法攔截器,會對目標對象的方法進行攔截處理,之前篩選出來的 Advisor 會在這個裏面被調用
Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised);
// Choose a "straight to target" interceptor. (used for calls that are
// unadvised but can return this). May be required to expose the proxy.
// <3> 創建目標對象的執行器,用於執行目標方法
Callback targetInterceptor;
// <3.1> 如果需要暴露當前代理對象,則通過 AopContext 進行暴露,放入 ThreadLocal 中,其他的和下面都相同
if (exposeProxy) {
targetInterceptor = (isStatic ?
new StaticUnadvisedExposedInterceptor(this.advised.getTargetSource().getTarget()) :
new DynamicUnadvisedExposedInterceptor(this.advised.getTargetSource()));
}
// <3.2> 否則,不暴露
else {
targetInterceptor = (isStatic ?
// <3.2.1> 用於執行方法代理對象,並對最終的返回結果進一步處理(返回結果是否需要為代理對象,返回結果是否不能為空)
new StaticUnadvisedInterceptor(this.advised.getTargetSource().getTarget()) :
// <3.2.2> 和上者的區別就是,每次攔截都會重新獲取目標對象,結束後釋放該目標對象
new DynamicUnadvisedInterceptor(this.advised.getTargetSource()));
}
// Choose a "direct to target" dispatcher (used for
// unadvised calls to static targets that cannot return this).
// <4> 目標對象調度器,用於獲取目標對象
Callback targetDispatcher = (isStatic ?
// <4.1> 目標對象的調度器,用於獲取當前目標對象
new StaticDispatcher(this.advised.getTargetSource().getTarget()) :
// <4.2> 目標對象的調度器,空的 Callback,不做任何處理
new SerializableNoOp());
// <5> 生成主要的幾個回調接口,也就是上面創建的幾個 Callback,放入 `mainCallbacks` 數組
Callback[] mainCallbacks = new Callback[] {
// 0:進行 AOP 代理的通用攔截器
aopInterceptor, // for normal advice
// 1:執行目標方法的攔截器
targetInterceptor, // invoke target without considering advice, if optimized
// 2:空的 Callback 對象,例如 `finalize()` 方法,不需要進行任何處理
new SerializableNoOp(), // no override for methods mapped to this
// 3:目標對象調度器,用於獲取目標對象
targetDispatcher,
// 4:配置管理器的調度器,會返回一個 AdvisedSupport 對象
// 因為代理對象會實現 Advised 接口,攔截到其裏面的方法時,需要調用當前 AdvisedSupport 的方法
this.advisedDispatcher,
// 5:處理 `equals(Object)` 方法的攔截器
new EqualsInterceptor(this.advised),
// 6:處理 `hashCode()` 方法的攔截器
new HashCodeInterceptor(this.advised)
};
Callback[] callbacks;
// If the target is a static one and the advice chain is frozen,
// then we can make some optimizations by sending the AOP calls
// direct to the target using the fixed chain for that method.
/*
* <6> 如果目標對象不需要每次都創建,且當前 AdvisedSupport 配置管理器被凍結了,性能優化,可暫時忽略
* 那麼在創建代理對象的時候,就可以先將目標對象的每個方法對應的方法調用器解析出來,該過程有點性能損耗,這樣在代理對象執行方法的時候性能有所提升
* 不過由於這裡會解析出許多方法調用器,會佔有一定的內存,以空間換時間
*/
if (isStatic && isFrozen) {
Method[] methods = rootClass.getMethods();
Callback[] fixedCallbacks = new Callback[methods.length];
this.fixedInterceptorMap = new HashMap<>(methods.length);
// TODO: small memory optimization here (can skip creation for methods with no advice)
/*
* <6.1> 遍歷目標對象所有的方法
*/
for (int x = 0; x < methods.length; x++) {
Method method = methods[x];
// <6.1.1> 獲取能夠應用於該方法的所有攔截器(有序)
// 不同的 AspectJ 根據 @Order 排序
// 同一個 AspectJ 中的 Advice 排序:AspectJAfterThrowingAdvice > AfterReturningAdviceInterceptor > AspectJAfterAdvice > AspectJAroundAdvice > MethodBeforeAdviceInterceptor
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, rootClass);
// <6.1.2> 創建一個方法調用器
fixedCallbacks[x] = new FixedChainStaticTargetInterceptor(
chain, this.advised.getTargetSource().getTarget(), this.advised.getTargetClass());
// <6.1.3> 將每個方法的對應的調用器的位置索引緩存起來
this.fixedInterceptorMap.put(methods.toString(), x);
}
// Now copy both the callbacks from mainCallbacks
// and fixedCallbacks into the callbacks array.
callbacks = new Callback[mainCallbacks.length + fixedCallbacks.length];
// <6.2> 將 `mainCallbacks` 複製到 `callbacks` 數組
System.arraycopy(mainCallbacks, 0, callbacks, 0, mainCallbacks.length);
// <6.3> 將 `fixedCallbacks` 複製到 `callbacks` 數組(拼接在後面)
System.arraycopy(fixedCallbacks, 0, callbacks, mainCallbacks.length, fixedCallbacks.length);
// <6.4> 記錄一個已生成的方法調用器的偏移量
this.fixedInterceptorOffset = mainCallbacks.length;
}
// <7> 否則,不進行解析,取上面的幾個主要的 Callback
else {
callbacks = mainCallbacks;
}
// <8> 返回這個目標對象對應的 Callback 數組
return callbacks;
}
該方法的處理過程如下:
-
是獲取代理對象的三個配置信息
exposeProxy
是否暴露代理對象,通常為false
isFrozen
配置管理器是否被凍結,通常為false
isStatic
是否是靜態的目標對象,也就是說目標對象是否每次都需要創建,通常為true
-
【重點】創建目標對象的攔截器,DynamicAdvisedInterceptor 方法攔截器,會對目標對象的方法進行攔截處理,代理對象的處理邏輯都在這裏面完成
-
創建目標對象的執行器,用於執行目標方法
- 如果需要暴露當前代理對象,則通過 AopContext 進行暴露,放入 ThreadLocal 中,其他的和下面都相同
- 否則,不暴露
isStatic
為 true,創建 StaticUnadvisedInterceptor 對象,用於執行方法代理對象,並對最終的返回結果進一步處理(返回結果是否需要為代理對象,返回結果是否不能為空)- 否則,創建 DynamicUnadvisedInterceptor 對象,和上者的區別就是,每次攔截都會重新獲取目標對象,結束後釋放該目標對象
-
目標對象調度器,用於獲取目標對象
isStatic
為 true,創建 StaticDispatcher 對象,目標對象的調度器,用於獲取當前目標對象- 否則,創建 SerializableNoOp 對象,空的 Callback,不做任何處理
-
生成主要的幾個回調接口,也就是上面創建的幾個 Callback,放入
mainCallbacks
數組,可以回到上面的構造函數看看哦😈0
:進行 AOP 代理的通用攔截器1
:執行目標方法的攔截器2
:空的 Callback 對象,例如finalize()
方法,不需要進行任何處理3
:目標對象調度器,用於獲取目標對象4
:配置管理器的調度器,會返回一個 AdvisedSupport 對象,因為代理對象會實現 Advised 接口,攔截到其裏面的方法時,需要調用當前 AdvisedSupport 的方法5
:處理equals(Object)
方法的攔截器6
:處理hashCode()
方法的攔截器 -
如果目標對象不需要每次都創建,且當前 AdvisedSupport 配置管理器被凍結了(默認不會),這一步做了一個性能優化,具體查看上面的代碼
在創建代理對象的時候,就可以先將目標對象的每個方法對應的方法調用器解析出來,該過程有點性能損耗,這樣在代理對象執行方法的時候性能有所提升;不過由於這裡會解析出許多方法調用器,會佔有一定的內存,以空間換時間
-
否則,不進行解析,取上面
mainCallbacks
-
返回這個目標對象對應的 Callback 數組
獲取代理對象的 Callback 過程稍微有點複雜,因為代理對象處理不同的方法使用到的 Callback 也是不同的。不過你要知道的是上面第 2
步,第一個 Callback 就是 DynamicAdvisedInterceptor 對象,該對象用於進行 AOP 代理的通用攔截器,目標類的方法在這個攔截器中進行處理。這個對象和 JDK 動態代理創建的代理對象的實現差不多,所以都放入下一篇文章進行分析😈
4.3 ProxyCallbackFilter
CglibAopProxy 的私有內部靜態類,用於篩選方法出對應的 Callback 對象
private static class ProxyCallbackFilter implements CallbackFilter {
private final AdvisedSupport advised;
private final Map<String, Integer> fixedInterceptorMap;
private final int fixedInterceptorOffset;
public ProxyCallbackFilter(
AdvisedSupport advised, Map<String, Integer> fixedInterceptorMap, int fixedInterceptorOffset) {
this.advised = advised;
this.fixedInterceptorMap = fixedInterceptorMap;
this.fixedInterceptorOffset = fixedInterceptorOffset;
}
/**
* 根據 Method 返回我們需要的 Callback 在數組中的位置
*/
@Override
public int accept(Method method) {
// <1> 如果該方法是 `finalize()`
if (AopUtils.isFinalizeMethod(method)) {
// 返回一個空 Callback 對象,不對該方法做任何處理
return NO_OVERRIDE;
}
// <2> 如果該方法是 Advised 中的方法,也就是需要 AdvisedSupport 來執行
if (!this.advised.isOpaque() && method.getDeclaringClass().isInterface() &&
method.getDeclaringClass().isAssignableFrom(Advised.class)) {
// 返回一個配置管理器的調度器,會返回一個 AdvisedSupport 對象去執行這個方法
return DISPATCH_ADVISED;
}
// We must always proxy equals, to direct calls to this.
// <3> 如果該方法是 `equals(Object)` 方法
if (AopUtils.isEqualsMethod(method)) {
// 返回處理 `equals(Object)` 方法的攔截器去執行該方法
return INVOKE_EQUALS;
}
// We must always calculate hashCode based on the proxy.
// <4> 如果該方法是 `hashCode()` 方法
if (AopUtils.isHashCodeMethod(method)) {
// 返回處理 `hashCode()` 方法的攔截器去執行該方法
return INVOKE_HASHCODE;
}
// <5> 獲取目標類 Class 對象
Class<?> targetClass = this.advised.getTargetClass();
// Proxy is not yet available, but that shouldn't matter.
// <6> 獲取能夠應用於該方法的所有攔截器,僅判斷是否存在 Advice
List<?> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
boolean haveAdvice = !chain.isEmpty();
boolean exposeProxy = this.advised.isExposeProxy();
boolean isStatic = this.advised.getTargetSource().isStatic();
boolean isFrozen = this.advised.isFrozen();
// <7> 如果有 Advice 或者配置沒有被凍結,通常情況都會進入這裡
if (haveAdvice || !isFrozen) {
// If exposing the proxy, then AOP_PROXY must be used.
// <7.1> 如果需要暴露這個代理對象,默認為 `false`
if (exposeProxy) {
// 返回處理 AOP 代理的通用攔截器去執行該方法
return AOP_PROXY;
}
String key = method.toString();
// Check to see if we have fixed interceptor to serve this method.
// Else use the AOP_PROXY.
// <7.2> 如果目標對象是單例的,且配置被凍結,且存在對應的方法調用器
if (isStatic && isFrozen && this.fixedInterceptorMap.containsKey(key)) {
// We know that we are optimizing so we can use the FixedStaticChainInterceptors.
// 返回已經存在的方法調用器
int index = this.fixedInterceptorMap.get(key);
return (index + this.fixedInterceptorOffset);
}
// <7.3> 否則(通常會走到這一步)
else {
// 返回處理 AOP 代理的通用攔截器去執行該方法
return AOP_PROXY;
}
}
// <8> 否則
else {
// <8.1> 如果需要暴露代理對象,或者不是單例模式,默認這兩種情況都不滿足
if (exposeProxy || !isStatic) {
// 則返回執行目標方法的攔截器
return INVOKE_TARGET;
}
Class<?> returnType = method.getReturnType();
// <8.2> 如果該方法需要返回的就是目標類,暫時不清楚這種情況
if (targetClass != null && returnType.isAssignableFrom(targetClass)) {
// 那麼返回執行目標方法的攔截器,返回當前對象
return INVOKE_TARGET;
}
// <8.3> 否則,返回目標對象調度器,用於獲取目標對象,讓目標對象自己去執行這個方法
else {
return DISPATCH_TARGET;
}
}
}
}
我們直接看到實現的 accept(Method method)
方法的處理邏輯:
- 如果該方法是
finalize()
,返回一個空 Callback 對象,不對該方法做任何處理 - 如果該方法是 Advised 中的方法,也就是需要 AdvisedSupport 來執行,返回一個配置管理器的調度器,會返回一個 AdvisedSupport 對象去執行這個方法
- 如果該方法是
equals(Object)
方法,返回處理equals(Object)
方法的攔截器去執行該方法 - 如果該方法是
hashCode()
方法,返回處理hashCode()
方法的攔截器去執行該方法 - 獲取目標類 Class 對象
- 獲取能夠應用於該方法的所有攔截器,僅判斷是否存在 Advice
- 如果有 Advice 或者配置沒有被凍結,通常情況都會進入這裡
- 如果需要暴露這個代理對象,默認為
false
,返回處理 AOP 代理的通用攔截器去執行該方法 - 如果目標對象是單例的,且配置被凍結,且存在對應的方法調用器,返回已經存在的方法調用器
- 否則(通常會走到這一步),返回進行 AOP 代理的通用攔截器去執行該方法
- 如果需要暴露這個代理對象,默認為
- 否則
- 如果需要暴露代理對象,或者不是單例模式,默認這兩種情況都不滿足,返回執行目標方法的攔截器
- 如果該方法需要返回的就是目標類,暫時不清楚這種情況,那麼返回執行目標方法的攔截器,返回當前對象
- 否則,返回目標對象調度器,用於獲取目標對象,讓目標對象自己去執行這個方法
上面的處理過程基本上都根據 Method 進行判斷,然後返回一個 int
數值,這個值代表去取 Callback 數組中的那個 Callback,回看上面講到的幾個方法你就全部理解了。
我們來看到上面的第 7.3
步,返回的是一個 0
,表示使用第一個 Callback 進行處理,對應的就是 DynamicAdvisedInterceptor 對象,這個對象和 JDK 動態代理創建的代理對象的實現差不多,所以都放入下一篇文章進行分析😈
4.4 createProxyClassAndInstance 方法
createProxyClassAndInstance(Enhancer enhancer, Callback[] callbacks)
方法,創建代理對象,如下:
protected Object createProxyClassAndInstance(Enhancer enhancer, Callback[] callbacks) {
// 設置使用構造器期間不進行攔截
enhancer.setInterceptDuringConstruction(false);
// 設置 Callback 數組
enhancer.setCallbacks(callbacks);
// 創建一個代理對象(目標類的子類)
return (this.constructorArgs != null && this.constructorArgTypes != null ?
// 使用指定的構造方法
enhancer.create(this.constructorArgTypes, this.constructorArgs) :
// 使用默認的構造方法
enhancer.create());
}
這個方法在 ObjenesisCglibAopProxy 子類中被重寫了,Spring 內部也是使用 ObjenesisCglibAopProxy 這個類,因為 CGLIB 創建的子類考慮到通過構造器實例化代理對象,可能會存在構造器不合適的情況,所以 Spring 採用 Objenesis 實例化對象,不通過構造器創建實例對象
4.4 ObjenesisCglibAopProxy
org.springframework.aop.framework.ObjenesisCglibAopProxy
,繼承 CglibAopProxy 類,重寫 createProxyClassAndInstance(..)
方法
class ObjenesisCglibAopProxy extends CglibAopProxy {
/**
* 創建一個 Objenesis 對象
* [**Objenesis**](//objenesis.org/) 是一個小型 Java 庫,目的是為一些特殊的 Class 對象實例化一個對象
* 應用場景:
* 1. 序列化,遠程調用和持久化 - 對象需要實例化並存儲為到一個特殊的狀態,而沒有調用代碼
* 2. 代理,AOP 庫和 Mock 對象 - 類可以被子類繼承而子類不用擔心父類的構造器
* 3. 容器框架 - 對象可以以非標準的方式被動態實例化
*/
private static final SpringObjenesis objenesis = new SpringObjenesis();
public ObjenesisCglibAopProxy(AdvisedSupport config) {
super(config);
}
@Override
protected Object createProxyClassAndInstance(Enhancer enhancer, Callback[] callbacks) {
// <1> 先創建代理對象的 Class 對象(目標類的子類)
Class<?> proxyClass = enhancer.createClass();
Object proxyInstance = null;
// <2> 是否使用 Objenesis 來實例化代理對象,默認會
// 可通過 在 `spring.properties` 文件中添加 `spring.objenesis.ignore=false` 來禁止
if (objenesis.isWorthTrying()) {
try {
// <2.1> 通過 Objenesis 實例化代理對象(非標準方式,不使用構造方法進行實例化)
proxyInstance = objenesis.newInstance(proxyClass, enhancer.getUseCache());
}
catch (Throwable ex) {
logger.debug("Unable to instantiate proxy using Objenesis, " +
"falling back to regular proxy construction", ex);
}
}
// <3> 如果藉助 Objenesis 實例化代理對象失敗
if (proxyInstance == null) {
// Regular instantiation via default constructor...
try {
// <3.1> 選擇構造器,指定了參數則使用對應的構造器,否則使用默認構造器
Constructor<?> ctor = (this.constructorArgs != null ?
proxyClass.getDeclaredConstructor(this.constructorArgTypes) :
proxyClass.getDeclaredConstructor());
ReflectionUtils.makeAccessible(ctor);
// <3.2> 通過構造器實例化代理對象(反射)
proxyInstance = (this.constructorArgs != null ?
ctor.newInstance(this.constructorArgs) : ctor.newInstance());
}
catch (Throwable ex) {
throw new AopConfigException("Unable to instantiate proxy using Objenesis, " +
"and regular proxy instantiation via default constructor fails as well", ex);
}
}
// <4> 設置 Callback 數組
((Factory) proxyInstance).setCallbacks(callbacks);
// <5> 返回代理對象
return proxyInstance;
}
}
首先我們來看到 SpringObjenesis 這個對象,它實現了 Objenesis 接口,Objenesis 是一個小型 Java 庫,目的是為一些特殊的 Class 對象實例化一個對象,應用場景:
- 序列化,遠程調用和持久化 – 對象需要實例化並存儲為到一個特殊的狀態,而沒有調用代碼
- 代理,AOP 庫和 Mock 對象 – 類可以被子類繼承而子類不用擔心父類的構造器
- 容器框架 – 對象可以以非標準的方式被動態實例化
創建代理對象的過程如下:
- 先通過 Enhancer 創建代理對象的 Class 對象(目標類的子類)
- 是否使用 Objenesis 來實例化代理對象,默認會
- 通過 Objenesis 實例化代理對象(非標準方式,不使用構造方法進行實例化)
- 如果藉助 Objenesis 實例化代理對象失敗
- 選擇構造器,指定了參數則使用對應的構造器,否則使用默認構造器
- 通過構造器實例化代理對象(反射)
- 設置 Callback 數組
- 返回代理對象
總結
在前面的《Spring AOP 自動代理(一)入口》文章中,分析了 Spring AOP 自動代理的入口是 AbstractAutoProxyCreator 對象,其中自動代理的過程主要分為下面兩步:
- 篩選出能夠應用於當前 Bean 的 Advisor
- 找到了合適 Advisor 則創建一個代理對象, JDK 動態代理或者 CGLIB 動態代理
上一篇《Spring AOP 自動代理(二)篩選合適的通知器》文章分析了上面第 1
步的處理過程。本文是接着前面兩篇文章分析上面第 2
個過程,Spring 是如何創建代理對象的,大致流程如下:
-
創建一個 ProxyFactory 代理工廠對象,設置需要創建的代理類的配置信息,例如 Advisor 數組和 TargetSource 目標類來源
-
藉助 DefaultAopProxyFactory 選擇 JdkDynamicAopProxy(JDK 動態代理)還是 ObjenesisCglibAopProxy(CGLIB 動態代理)
-
當
proxy-target-class
為false
時,優先使用 JDK 動態代理,如果目標類沒有實現可代理的接口,那麼還是使用 CGLIB 動態代理 -
如果為
true
,優先使用 CGLIB 動態代理,如果目標類本身是一個接口,那麼還是使用 JDK 動態代理
-
-
通過 JdkDynamicAopProxy 或者 ObjenesisCglibAopProxy 創建一個代理對象
- JdkDynamicAopProxy 本身是一個 InvocationHandler 實現類,通過 JDK 的
Proxy.newProxyInstance(..)
創建代理對象 - ObjenesisCglibAopProxy 藉助 CGLIB 的 Enhancer 創建代理對象,會設置 Callback 數組和 CallbackFilter 篩選器(選擇合適 Callback 處理對應的方法),整個過程相比於 JDK 動態代理更複雜點,主要的實現在 DynamicAdvisedInterceptor 方法攔截器中
- JdkDynamicAopProxy 本身是一個 InvocationHandler 實現類,通過 JDK 的
其中 CGLIB 實例化代理對象的過程使用到了 Objenesis,它是一個小型 Java 庫,目的是為一些特殊的 Class 對象實例化一個對象。因為 CGLIB 創建的子類考慮到通過構造器實例化代理對象,可能會存在構造器不合適的情況,所以 Spring 採用 Objenesis 實例化對象,不通過構造器創建實例對象。
好了,本篇文章就到這裡了,Spring AOP 中整個自動代理過程到這裡也就結束了。對於 JDK 動態代理和 CGLIB 動態代理創建的代理對象,它們的具體實現(或者說是方法攔截處理)在這裡並沒有體現出來,前者的實現在 JdkDynamicAopProxy 中,因為它實現了 InvocationHandler 接口,後者的實現則在 DynamicAdvisedInterceptor 方法攔截器中,這些內容將在下篇文章進行分析。