警告:閱讀此文前務(wù)必先閱讀之前寫的《spring如何解決循環(huán)引用》,本篇文章高度依賴循環(huán)引用。
在循環(huán)依賴中我們講了spring實例化bean的入口,refresh->finishBeanFactoryInitialization->preInstantiateSingletons->getBean->doGetBean,看doGetBean中的如下代碼
if (mbd.isSingleton()) {
// 實例化bean
sharedInstance = getSingleton(beanName, () -> {
try {
// 真正的完成bean的創(chuàng)建
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
destroySingleton(beanName);
throw ex;
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
createBean(beanName, mbd, args);方法真正的完成了bean的實例化,包括循環(huán)依賴、AOP、生命周期等。
AOP是在何時完成的?
所謂的AOP無非就是將bean加強,在bean的方法前后加上其他的方法而已,bean的class在虛擬機啟動的時候就加載到JVM里了,我們不會通過修改class來動態(tài)擴展bean的功能,但是可以新生成一個類(動態(tài)代理類),這個類呢,包含了bean的所有功能,同時又進行了加強,然后將這個動態(tài)代理類實例化,替換掉原有的bean,最后放到spring單例池中。不知道我這毫無文采的大白話有沒有講清楚。
所以,AOP肯定是跟bean的實例化息息相關(guān)的,注意,我說的是實例化,而不是生命周期。也就是說,我們AOP肯定是在bean實例化好了后再進行動態(tài)代理,想想JDK的動態(tài)代理,是需要一個實例化的被代理對象的,在《spring如何解決循環(huán)引用》這篇文章中我們詳細講了實例化及循環(huán)依賴。所以,AOP是在兩個地方完成代理的:
- 所有的bean實例化完成,且循環(huán)依賴也完成,緊接著開始AOP動態(tài)代理,前提是你所代理的類沒有被別的類依賴。
- 如果你的類被別的類依賴了,那么在依賴獲取的過程中進行AOP動態(tài)代理。
這是《spring如何解決循環(huán)引用》文章最后三級緩存的總結(jié)
問什么需要二級緩存?為什么需要bean的半成品需要提前暴露一個工廠? AOP就是一個原因吧!我現(xiàn)在有一個實例A,實例B要依賴我,但是A需要被代理,也就是說,A被代理后才能注入給B,那我B現(xiàn)在就要注入你,總不能等整個容器所有bean都實例化好后再來注入吧,講道理也不是不可能,只是spring覺著太麻煩沒那個必要,干脆,在注入的時候就直接AOP吧(后面會將源碼)!講清楚了沒有!
OK,下馬開始講AOP源碼!
AOP的準備工作
先把測試代碼寫出來
定義一個切面
@Component
@Aspect
public class UserAspect {
@Pointcut("execution(* com.config.aop.AopTest.*(..))")
public void pintCut(){
System.out.println("point cut");
}
@Before("com.config.aop.UserAspect.pintCut()")
public void beforeAdvice(){
System.out.println("before");
}
}
被代理的業(yè)務(wù)類
@Service
public class AopTest {
public void aop(){
System.out.println("This is my aop test");
}
}
public class SpringTest {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(Config.class);
context.refresh();
AopTest aopTest = context.getBean(AopTest.class);
System.out.println(aopTest);
aopTest.aop();
}
}
隨著項目的進行,我們的業(yè)務(wù)類會越來越多,spring首先要過濾掉哪些類需要代理,哪些不需要。其實,就是判斷類上的注解啦!
跟著上面的源碼createBean(beanName, mbd, args);繼續(xù)走。
再次聲明 !!! 這里不明白上文的源碼的,補習(xí)《spring如何解決循環(huán)引用》,不要放棄。
進入createBean源碼,找到如下代碼
// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
看英文翻譯,給Bean后置處理器一個機會,返回一個替代目標對象的代理對象。
注意,此時還沒后面的bean初始化代碼,這里只是做準備工作,做什么準備?繼續(xù)看。
原來,AOP實現(xiàn)是靠后置處理器完成的,本專題以前的博文講了BeanFactoryPostProcessor,而這里是 BeanPostProcessors ,兩者有啥區(qū)別?BeanFactoryPostProcessor后置處理器干預(yù)了BeanDefinition的生成,而BeanPostProcessors 干預(yù)了bean的實例化。
Object bean = resolveBeforeInstantiation(beanName, mbdToUse); 是AOP第一次開始調(diào)用后置處理器,進去看看吧!
直接定位到核心代碼
bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
有些讀者會懷疑,不是說逐行閱讀嗎?怎么最近都是直接定位了!講道理,如果之前的博文你都讀過,非核心的代碼你都能自行分析了,太簡單的沒必要在這列出了,畢竟大家的時間都很寶貴!
進入源碼
protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
if (result != null) {
return result;
}
}
}
return null;
}
for循環(huán),拿到所有的BeanPostProcessors。

這么多后置處理器用到哪一個呢,自己調(diào)試去,看我吹沒用。

AnnotationAwareAspectJAutoProxyCreator,就他!F5跟進代碼,代碼很難,簡單講一部分,等講生命周期(更難)的時候還會講
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
Object cacheKey = getCacheKey(beanClass, beanName);
if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
if (this.advisedBeans.containsKey(cacheKey)) {
return null;
}
if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return null;
}
}
// 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;
}
if (this.advisedBeans.containsKey(cacheKey))查看advisedBeans集合是否包含這個類的名字,如果包含就直接返回null了。
private final Map<Object, Boolean> advisedBeans = new ConcurrentHashMap<>(256);
advisedBeans 就是一個集合,用來保存不需要代理的類。比如我們上面定義的切面本身是不需要被代理的,還有加了@Configuration注解的Config配置類,也是不需要代理的,Config其實已經(jīng)被代理了,之前講過。
if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName))
這行代碼就是判斷我們這個業(yè)務(wù)類是否需要被代理,進入isInfrastructureClass代碼:
protected boolean isInfrastructureClass(Class<?> beanClass) {
return (super.isInfrastructureClass(beanClass) ||
(this.aspectJAdvisorFactory != null && this.aspectJAdvisorFactory.isAspect(beanClass)));
}
調(diào)用父類的方法
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;
}
首先會調(diào)用父類的方法
class1.isAssignableFrom(class2) 判定此 Class1 對象所表示的類或接口與指定的 Class2 參數(shù)所表示的類或接口是否相同,或是否是其超類或超接口。如果是則返回 true;否則返回 false。
Advice、Pointcut、Advisor等是跟切面相關(guān)的,不需要代理。
如果父類方法返回false,繼續(xù)判斷該類是不是一個切面,是切面的話也是不需要被代理的。
shouldSkip(beanClass, beanName)會根據(jù)你的AOP配置,找到
符合條件的放入advisedBeans 集合中,后面會根據(jù)這個集合判斷業(yè)務(wù)類是否需要被代理。
OK,趁熱打鐵,我們看AOP代理實現(xiàn),我們現(xiàn)在跳回createBean源碼,從Object bean = resolveBeforeInstantiation(beanName, mbdToUse);繼續(xù)往后看Object beanInstance = doCreateBean(beanName, mbdToUse, args);這行代碼,進入到方法內(nèi),找到下面代碼
//處理循環(huán)依賴
populateBean(beanName, mbd, instanceWrapper);
//開啟生命周期!?。。。?!
exposedObject = initializeBean(beanName, exposedObject, mbd);
populateBean完成了bean的實例化及循環(huán)依賴,繼續(xù)看initializeBean方法,這個方法就是開啟了聲明周期,AOP實現(xiàn)也是在這里面,進入看源碼倒數(shù)第二行wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);,這個方法就是完成了AOP代理的實現(xiàn),他是怎么實現(xiàn)的呢???
@Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
Object current = processor.postProcessAfterInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
擦!還是后置處理器誒!

進去

進入wrapIfNecessary方法。
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// Create proxy if we have advice.
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
尼瑪,spring源碼太難了! 我花了好久好久才研究到這里。
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey)))和if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)),這兩行判斷跟上面的一樣,不解釋。
如果這兩個判斷都不成立,下面的代碼就是代理的創(chuàng)建!創(chuàng)建!創(chuàng)建!

createProxy里面創(chuàng)建了代理,具體怎么通過CGLIB創(chuàng)建的?讀者自行查看吧!讀spring源碼一定要動手調(diào)試,光看,沒用!
返回到exposedObject = initializeBean(beanName, exposedObject, mbd);
這個時候,exposedObject 就是代理對象了

繼續(xù)返回,

然后繼續(xù)F6往下調(diào)試代碼

此時,就注冊到spring單例池中的,這個addSingleton方法是在getSingleton函數(shù)里完成的,為啥在這個函數(shù)里咧?在這篇文章里,我一言難盡,看《spring如何解決循環(huán)引用》。
AOP,就是這么實現(xiàn)的,調(diào)用過程很復(fù)雜,其實就是靠后置處理器。
還沒完,如果你的要代理的業(yè)務(wù)類被其他類循環(huán)依賴了,那么AOP的生成時機就不同了。
先加上兩個循環(huán)依賴的測試代碼
@Service
public class AopTest {
@Autowired
AopTest2 aopTest2;
public void aop(){
System.out.println("This is my aop test");
}
}
@Service
public class AopTest2 {
@Autowired
AopTest aopTest;
public void aop(){
System.out.println("This is my aop test");
}
}
refresh->finishBeanFactoryInitialization->preInstantiateSingletons->getBean->doGetBean,在該方法里的第三行:
Object sharedInstance = getSingleton(beanName); ,我們講過,你的業(yè)務(wù)類實例化后會提前暴露一個工廠類,依賴你的類執(zhí)行到這里時,會先調(diào)用這行代碼,我們分析過這行代碼,這里再分析,完全兩個味道
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// 這個singletonObjects就是微觀層面的IOC容器,循環(huán)創(chuàng)建剛開始時,IOC確實是空的,
// 但是我前面一開始的getBean()方法是存在遞歸調(diào)用現(xiàn)象的
/**
* 直接舉2個例子:
* 第一:假如現(xiàn)在在實例化A,結(jié)果有發(fā)現(xiàn)需要給A注入B,
* 那Spring是不是得獲得B,怎么獲得呢? 遞歸使用getBean(BName)完成,
* 第二個例子: A被添加上了@Lazy注解,是懶加載的,但是終究有一個會通過getBean(AName)獲取A,
* 這是發(fā)現(xiàn)A是實例化需要B,B肯定已經(jīng)實例化完事了,同樣是通過遞歸getBean(BName)實現(xiàn)注入,
* 在這兩個過程中就是getSingleton()保證不會重復(fù)創(chuàng)建已經(jīng)存在的實例
*/
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
看這行
singletonObject = singletonFactory.getObject();
F5跟進源碼,進入到下面代碼

對吧,就是提前暴露的工廠,F(xiàn)5跟進
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
}
}
}
return exposedObject;
}
尼瑪,又是后置處理器

跟進去

如果,有人,能看到這里,應(yīng)該不需要我解釋了。這就是AOP生成的第二個時機,在循環(huán)依賴過程中實現(xiàn)AOP,也是半成品的bean實例化完后為什么要暴露一個工廠的原因,而不是一個簡單的bean對象,因為工行能夠提供方法呀,在方法里我們就能處理這個對象啊,這里的處理單指AOP代理,不知道我講沒有講清楚。

上面講過了,一模一樣的,代碼復(fù)用啦
這里注意
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);方法就是找到切面的,怎么找到的,讀者可以跟進代碼讀一下,就是拿到所有的beanDefinition,然后找所有帶有@Aspect注解的類,因為我們可以定義多個切面,所以繼續(xù)找到我們業(yè)務(wù)類所在的那個切面,也就時遍歷所有的切面,然后根據(jù)@Pointcut("execution(* com.config.aop.AopTest.*(..))")進行匹配。

好吧,不賣關(guān)子了,我們看看
getProxy方法吧,跟進去
public Object getProxy(@Nullable ClassLoader classLoader) {
return createAopProxy().getProxy(classLoader);
}
繼續(xù)跟進createAopProxy方法
protected final synchronized AopProxy createAopProxy() {
if (!this.active) {
activate();
}
return getAopProxyFactory().createAopProxy(this);
}
跟進createAopProxy
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);
}
}
關(guān)于AOP的配置信息全部在config參數(shù)中,看一下我們最關(guān)心的兩個值,切面和目標對象。

對吧,都有了,那就代理吧!
判斷是否實現(xiàn)了接口,實現(xiàn)接口了就用JDK自帶的動態(tài)代理技術(shù),不然就用CGLIB動態(tài)代理技術(shù)。我們這里顯然用了CGLIB動態(tài)代理技術(shù),然后一直返回到下圖所示

進入
getProxy創(chuàng)建代理對象
至此,代理對象就創(chuàng)建完成了,我講的大概的過程,沒有細講每行代碼,感興趣的自行讀吧,我實在寫不下去了,肩膀疼!
我們知道aopTest2,是在populateBean(beanName, mbd, instanceWrapper);完成了屬性注入對吧,注入完成后我們看一下情況

看見沒,aopTest2依賴了aopTest,此時注入的就是代理的aopTest了。
面試中,AOP會經(jīng)常被問到,筆者給別人面試也會問。其實面試官不是想問你AOP的概念和如何使用,他會考察你對spring的了解程度,或者看你是否閱讀過源碼。面試造火箭,工作擰螺絲。確實,工作中很少去看spring源碼,但是現(xiàn)在java程序員泛濫了,你如何脫穎而出,面試官也很為難啊,我知道A和B都會用,但是A讀過源碼,說明他對技術(shù)感興趣,而且肯鉆研,工作會游刃有余!
你面試如果給面試官分析上面的動態(tài)代理過程,差不多能秒殺大部分面試官了!面試官也不見得所有的技術(shù)都去讀源碼的!
文章的最后,給大家留個懸念! Spring中的事務(wù)是怎么回事?原理呢?源碼如何實現(xiàn)?其實也是用到了AOP,你讀懂了這篇文章就很容易解決。 加油
