SpringAop原始碼分析(基於註解)三:建立代理物件
阿新 • • 發佈:2019-12-31
在上篇文章SpringAop原始碼分析(基於註解)二:篩選通知器中,我們對AOP中通知的建立和篩選過程進行了分析,本章我們一起來看看,AOP是怎麼建立代理物件的。
我們先回到Bean初始化之後,呼叫BeanPostProcessor後置處理器的地方。
//AbstractAutoProxyCreator.java
//在Bean初始化之後回撥
@Override
public Object postProcessAfterInitialization(@Nullable Object bean,String beanName) throws BeansException {
if (bean != null ) {
Object cacheKey = getCacheKey(bean.getClass(),beanName);
//判斷快取中是否有
if (!this.earlyProxyReferences.contains(cacheKey)) {
// 沒有,為 bean 生成代理物件
return wrapIfNecessary(bean,beanName,cacheKey);
}
}
return bean;
}
複製程式碼
wrapIfNecessary程式碼:
//AbstractAutoProxyCreator.java
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;
}
/*
* 如果是基礎設施類(Pointcut、Advice、Advisor 等介面的實現類),或是應該跳過的類,
* 則不應該生成代理,此時直接返回 bean
*/
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(),beanName)) {
this.advisedBeans.put(cacheKey,Boolean.FALSE);
return bean;
}
// Create proxy if we have advice.
<1> // 返回匹配當前 bean 的所有的通知器 advisor、advice、interceptor
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(),null);
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey,Boolean.TRUE);
// 核心!建立代理物件
<2> Object proxy = createProxy(
bean.getClass(),specificInterceptors,new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey,proxy.getClass());
return proxy;
}
this.advisedBeans.put(cacheKey,Boolean.FALSE);
return bean;
}
複製程式碼
上篇文章我們主要分析的是<1>處程式碼,現在有了合適的通知器,我們要為當前Bean建立代理物件,把通知器(Advisor)所持有的通知(Advice)織入到 bean 的某些方法前後。
看程式碼:
//AbstractAutoProxyCreator.java
protected Object createProxy(Class<?> beanClass,@Nullable String beanName,@Nullable Object[] specificInterceptors,TargetSource targetSource) {
if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory,beanClass);
}
//建立代理工廠
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this);
//proxyTargetClass是 @EnableAspectJAutoProxy 的屬性之一
//true -> 強制使用CGLIB代理
if (!proxyFactory.isProxyTargetClass()) {
//false
if (shouldProxyTargetClass(beanClass,beanName)) {
proxyFactory.setProxyTargetClass(true);
}
else {
//檢測 beanClass 是否實現了介面,若未實現,則將
//proxyFactory 的成員變數 proxyTargetClass 設為 true
evaluateProxyInterfaces(beanClass,proxyFactory);
}
}
//封裝proxyFactory
Advisor[] advisors = buildAdvisors(beanName,specificInterceptors);
proxyFactory.addAdvisors(advisors);
proxyFactory.setTargetSource(targetSource);
customizeProxyFactory(proxyFactory);
proxyFactory.setFrozen(this.freezeProxy);
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}
// 建立並獲取代理物件
return proxyFactory.getProxy(getProxyClassLoader());
}
複製程式碼
這裡我們主要看下核心邏輯:
- 建立代理工廠 ProxyFactory
- 判斷使用JDK還是CGLIB
- 封裝ProxyFactory
- 建立並獲取代理物件
這裡的 isProxyTargetClass() 其實就是我們前面用的註解@EnableAspectJAutoProxy
的屬性之一,當其為true時,強制使用CGLIB代理。
下面我們接著看建立代理的程式碼:
//ProxyFactory.java
public Object getProxy(@Nullable ClassLoader classLoader) {
return createAopProxy().getProxy(classLoader);
}
複製程式碼
這段方法有兩個方法呼叫:
- createAopProxy()
建立 AopProxy 實現類物件 - getProxy(classLoader)
建立代理物件
我們先來看下createAopProxy():
//DefaultAopProxyFactory.java
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
//if中的3個條件
//1、 config.isOptimize() - 是否需要優化
//2、 config.isProxyTargetClass() - 檢測 proxyTargetClass 的值
//3、 hasNoUserSuppliedProxyInterfaces(config) - 目標 bean 是否實現了介面
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)) {
//建立JdkDynamicAopProxy
return new JdkDynamicAopProxy(config);
}
//建立CglibAopProxy
return new ObjenesisCglibAopProxy(config);
}
else {
//建立JdkDynamicAopProxy
return new JdkDynamicAopProxy(config);
}
}
複製程式碼
最終呼叫的是DefaultAopProxyFactory#createAopProxy(...)
方法,通過這個方法建立AopProxy 的實現類,如: JdkDynamicAopProxy,然後根據這個實現類再建立代理物件。
我們以JdkDynamicAopProxy為例,看下getProxy(classLoader)
:
//JdkDynamicAopProxy.java
public Object getProxy() {
return getProxy(ClassUtils.getDefaultClassLoader());
}
public Object getProxy(ClassLoader classLoader) {
if (logger.isDebugEnabled()) {
logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());
}
Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised,true);
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
// 呼叫 newProxyInstance 建立代理物件
return Proxy.newProxyInstance(classLoader,proxiedInterfaces,this);
}
複製程式碼
直接看程式碼最後一行,最終呼叫 Proxy.newProxyInstance 方法建立代理物件。