SpringAOP實現源碼解讀

1、Spring AOP樣例

簡單介紹怎麼樣基於Spring實現AOP編程(註解方式在目標對象方法中織入通知方法)

2、AOP關鍵註解@EnableAspectJAutoProxy

分析@EnableAspectJAutoProxy註解源,瞭解實現AOP需要給容器提供的配置信息

3、AOP實現的關鍵類AnnotationAwareAspectJAutoProxyCreator

靜態分析Spring框架裏面,創建AOP代理對象的類

4、AnnotationAwareAspectJAutoProxyCreator的實例化和註冊

動態分析AnnotationAwareAspectJAutoProxyCreator在容器中的實例化和註冊過程

5、AnnotationAwareAspectJAutoProxyCreator創建目標代理對象

動態分析Spring容器使用AnnotationAwareAspectJAutoProxyCreator創建目標代理對象過程

01

Spring AOP樣例

本樣例代碼工程,是基於Maven的,使用的是Spring5.0.5版本,pom.xml如下:

4.0.0

cn.com.tuling.openclass.aop

explore-06-spring-aop

0.0.1-SNAPSHOT

<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>

<java.version>1.8</java.version>

<spring.version>5.0.5.RELEASE</spring.version>

org.springframework

spring-context

${spring.version}

org.aspectj

aspectjweaver

1.8.13

junit

junit

4.7

test

(左右滑動查看完整代碼)

當前樣例比較簡單,直接貼代碼如下:

1)IPowerService和PowerServiceImpl

目標類的接口和實現,裏面就一個login方法,將用來織入AOP的通知方法

package cn.com.tuling.openclass.service;

public interface IPowerService {

public boolean login(String userName,String password);

}

package cn.com.tuling.openclass.service.impl;

import org.springframework.stereotype.Service;

import cn.com.tuling.openclass.service.IPowerService;

@Service

public class PowerServiceImpl implements IPowerService {

@Override

public boolean login(String userName, String password) {

boolean bool = false;

System.out.println(“to execute PowerServiceImpl.login() method…”);

bool = userName != null && userName.startsWith(“zhang”);

return bool;

}

}

2)LogServiceImpl

這裏面定義了幾個日誌方法,以便封裝成通知,織入到切入點中

package cn.com.tuling.openclass.service.impl;

import org.aspectj.lang.annotation.After;

import org.aspectj.lang.annotation.AfterReturning;

import org.aspectj.lang.annotation.AfterThrowing;

import org.aspectj.lang.annotation.Aspect;

import org.aspectj.lang.annotation.Before;

import org.aspectj.lang.annotation.Pointcut;

import org.springframework.stereotype.Component;

@Component//聲明當前類爲組件類

@Aspect//切面

public class LogServiceImpl{

//定義切入點

@Pointcut(“execution(* cn.com.tuling….(…))”)

public void myPointCut(){}

//將logBefore方法封裝成Before通知,織入到myPointCut()切入點br/>@Before("myPointCut()")
public void logBefore() {
}
//將logAfter方法封裝成After通知,織入到myPointCut()切入點
@After("myPointCut()")
br/>System.out.println("....logServiceImpl.logBefore....");
}
//將logAfter方法封裝成After通知,織入到myPointCut()切入點
@After("myPointCut()")
public void logAfter() {}
//將logReturnAfter方法封裝成AfterReturning通知,織入到myPointCut()切入點
@AfterReturning("myPointCut()")
br/>System.out.println("....logServiceImpl.logAfter....");
}
//將logReturnAfter方法封裝成AfterReturning通知,織入到myPointCut()切入點
@AfterReturning("myPointCut()")
public void logReturnAfter() {}
//將logThrowing方法封裝成AfterThrowing通知,織入到myPointCut()切入點
@AfterThrowing("myPointCut()")
br/>System.out.println("....logServiceImpl.logReturnAfter....");
}
//將logThrowing方法封裝成AfterThrowing通知,織入到myPointCut()切入點
@AfterThrowing("myPointCut()")
public void logThrowing() {
System.out.println("....logServiceImpl.logThrowing....");
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
}

3)ConfigAOP

Spring註解式配置類

package cn.com.tuling.openclass.config;

import org.springframework.context.annotation.ComponentScan;

import org.springframework.context.annotation.Configuration;

import org.springframework.context.annotation.EnableAspectJAutoProxy;

@Configuration//聲明當前類爲Spring註解配置類

@EnableAspectJAutoProxy//支持AspectJ註解

@ComponentScan(basePackages=“cn.com.tuling.openclass”)//自動掃描組件路徑

public class ConfigAOP {

}

4)TestAOP,測試類

package cn.com.tuling.openclass.service;

import org.junit.Test;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import cn.com.tuling.openclass.config.ConfigAOP;

public class TestAOP {

@Test

public void test01(){

// 初始化註解式IOC容器

AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(ConfigAOP.class);

// 從容器中獲取PowerService實例

IPowerService powerService = (IPowerService)ctx.getBean(IPowerService.class);

// 調用PowerService的login方法

boolean bool = powerService.login(“zhangsan”, “123”);

// 關閉IOC容器

ctx.close();

}

}

運行TestAOP裏面的test01方法,運行如下日誌:

我們在TestAOP的test01方法中,只是調用了IPowerService的login方法,卻在它前後輸出了每個通知的打印,說明已經基於Spring的AOP,完成了通知到目標切入點的織入。

02

AOP關鍵註解@EnableAspectJAutoProxy

通過調整我們前面的ConfigAOP類的代碼,我們能感覺到,如果註釋掉ConfigAOP類上面的@EnableAspectJAutoProxy,運行TestAOP的test01方法的時候,將看不到通知織入的效果(只會執行PowerServiceImpl中的login方法,不會執行LogServiceImpl中對應的通知方法),說明@EnableAspectJAutoProxy註解裏面,定義了SpringAOP織入通知的關鍵信息,這信息是什麼呢,我們來研究@EnableAspectJAutoProxy的源碼。

package org.springframework.context.annotation;

import java.lang.annotation.Documented;

import java.lang.annotation.ElementType;

import java.lang.annotation.Retention;

import java.lang.annotation.RetentionPolicy;

import java.lang.annotation.Target;

/**

支持AspectJ註解,使用註解的方式實現AOP織入,效果等同xml配置文件中的aop:aspectj-autoproxy/
@author Chris Beams
@author Juergen Hoeller
@since 3.1
@see org.aspectj.lang.annotation.Aspectbr/>/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
br/>@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
/
Indicate whether subclass-based (CGLIB) proxies are to be created as opposed
to standard Java interface-based proxies. The default is {@code false}.
/
boolean proxyTargetClass() default false;
/

Indicate that the proxy should be exposed by the AOP framework as a {@code ThreadLocal}
for retrieval via the {@link org.springframework.aop.framework.AopContext} class.
Off by default, i.e. no guarantees that {@code AopContext} access will work.
@since 4.3.1
*/
boolean exposeProxy() default false;
}
通過查看@EnableAspectJAutoProxy源碼,我們瞭解到@EnableAspectJAutoProxy的作用,同xml配置文件中的aop:aspectj-autoproxy一樣,告訴Spring容器,支持註解式Aspect。

@EnableAspectJAutoProxy有兩個屬性:

1)proxyTargetClass 指定是否使用CGLIB的方式創建實現接口的目標對象的代理。缺省值爲false,使用JDK方式創建接口對象的代理

exposeProxy 標記代理對象是否應該被aop框架通過AopContext以ThreadLocal的形式暴露出去。當一個代理對象需要調用它自己的另外一個代理方法時,這個屬性將非常有用。默認是是false,以避免不必要的攔截。
exposeProxy屬性的使用案例,請查看另外一個專題(《坑、坑、坑,同一個類中的切入方法無效!》),這裏就不重複了。

通觀前面的代碼,沒有哪個地方有描述怎麼樣實現AOP,不過有發現紅色代碼行,從名字上就同咱們的目標AOP(AspectJ切面)有關係,我們跟進去,看AspectJAutoProxyRegistrar類源代碼如下:

package org.springframework.context.annotation;

import org.springframework.aop.config.AopConfigUtils;

import org.springframework.beans.factory.support.BeanDefinitionRegistry;

import org.springframework.core.annotation.AnnotationAttributes;

import org.springframework.core.type.AnnotationMetadata;

/**

… …
*/
class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {br/>@Override
public void registerBeanDefinitions(
AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
AnnotationAttributes enableAspectJAutoProxy =
AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
if (enableAspectJAutoProxy != null) {
if (enableAspectJAutoProxy.getBoolean(“proxyTargetClass”)) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}
if (enableAspectJAutoProxy.getBoolean(“exposeProxy”)) {
AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
}
}
}
}
在AspectJAutoProxyRegistrar.java的源碼中,紅色標記部分,從名稱上可以猜出來,是在調用一個方法,完成註解式代理對象的創建器(Creator)行,繼續這樣的思路,我們進一步跟進如上紅色部分的代碼如下:

public abstract class AopConfigUtils {

… …

@Nullable

public static BeanDefinition registerAspectJAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) {

return registerAspectJAutoProxyCreatorIfNecessary(registry, null);

}

@Nullable

public static BeanDefinition registerAspectJAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry,

@Nullable Object source) {

return registerOrEscalateApcAsRequired(AspectJAwareAdvisorAutoProxyCreator.class, registry, source);

}

… …

}

跟到AopConfigUtils源代碼中,我們發現最終會調用紅色標記部分的代碼,該行代碼的作用,是在容器中註冊一個AspectJAwareAdvisorAutoProxyCreator類。

到這裏,我們就找到了SpringAOP中,創建目標對象的代理對象的源(作俑者)。這個作俑者是在@EnableAspectJAutoProxy中告知Spring IOC容器的,也就是說,通過@EnableAspectJAutoProxy註解,通知Spring容器在需要的時候,使用AspectJAwareAdvisorAutoProxyCreator對象創建目標的代理對象,實現通知的織入(實現AOP)。

03

AnnotationAwareAspectJAutoProxyCreator類靜態源碼分析

作用:

代碼層次:

AnnotationAwareAspectJAutoProxyCreator

->AspectJAwareAdvisorAutoProxyCreator

->AbstractAdvisorAutoProxyCreator

->AbstractAutoProxyCreator

->ProxyProcessorSupport

implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware(自動裝配Bean)

SmartInstantiationAwareBeanPostProcessor

->InstantiationAwareBeanPostProcessor

->BeanPostProcessor(後置處理器)

後置處理器:Spring中重要組件,在IOC容器初始化過程中,加入新的功能

自動裝配Bean(Aware):給目標對象提供一個獲取系統對象的接口

代碼功能:

bstractAutoProxyCreator.setBeanFactory(BeanFactory)//Aware,獲取Spring的BeanFactory對象

AbstractAutoProxyCreator.postProcessBeforeInstantiation()//後置處理器添加初始化前置功能
判斷advisedBeans裏面是否有包含當前beanName,是否是基礎註解類,如果包含或是基類,返回null
否則就創建目標對象的代理對象
AbstractAdvisorAutoProxyCreator.setBeanFactory()
super.setBeanFactory()
initBeanFactory()// 模板方法
AnnotationAwareAspectJAutoProxyCreator.initBeanFactory()
super.initBeanFactory()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
04

AnnotationAwareAspectJAutoProxyCreator的實例化和註冊

到現在,我們根據源代碼的摸索,基本上找到了實現AOP的關鍵類AspectJAwareAdvisorAutoProxyCreator,那這個類的對象什麼時候實例化,又在什麼時候創建的AOP代理對象的呢?能回答出這個問題,咱們的AOP原理是不是就搞定了。

接下來我們先研究AspectJAwareAdvisorAutoProxyCreator對象的創建過程。

我們在TestAOP的test01方法裏的AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(ConfigAOP.class);代碼上,添加一個debug,用debug的方式,跟進代碼,歷經如下:

AnnotationConfigApplicationContext.AnnotationConfigApplicationContext(Class … annotatedClasses)

->AbstractApplicationContext.refresh()

refresh方法的代碼如下:

// 初始化容器上下文(比如容器啓動時間等)

prepareRefresh();

// 創建beanFactory容器對象,以前有銷燬再創建,以前沒有,創一個新對象

ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

// 初始化beanFactory.(類加載器、Application…Processor、Aware、環境對象等)

prepareBeanFactory(beanFactory);

try {

// 模板方法,在Bean定義加載完後,爲子類提供一個可以修改BeanFactory的入口

postProcessBeanFactory(beanFactory);

// 調用註冊在容器中的BeanFactory處理器

invokeBeanFactoryPostProcessors(beanFactory);

// 註冊Bean後置處理器,這些處理器會在創建Bean對象的時候被調用

registerBeanPostProcessors(beanFactory);

// 初始化資源

initMessageSource();

// 初始化容器的事件廣播器

initApplicationEventMulticaster();

// 模板方法,給子類提供一個在容器中實例化其他特殊bean的機會

onRefresh();

// 檢測並註冊監聽器

registerListeners();

// 實例化其他的非延時加載的單例對象.

finishBeanFactoryInitialization(beanFactory);

// 發佈容器事件

finishRefresh();

}

… …

通過查看AspectJAwareAdvisorAutoProxyCreator的父類和實現類,我們可以發現AspectJAwareAdvisorAutoProxyCreator實際上是一個BeanPostProcessor子類,所以在Spring中,是在refresh方法中標紅語句(registerBeanPostProcessors)的方法中完成的。我們debug到registerBeanPostProcessors方法中去,路徑如下:

AnnotationConfigApplicationContext(AbstractApplicationContext).refresh() line: 535

->AnnotationConfigApplicationContext(AbstractApplicationContext).registerBeanPostProcessors(ConfigurableListableBeanFactory) line: 710
->PostProcessorRegistrationDelegate.registerBeanPostProcessors(ConfigurableListableBeanFactory, AbstractApplicationContext) line: 189
1
2
3
PostProcessorRegistrationDelegate.registerBeanPostProcessors(ConfigurableListableBeanFactory,

AbstractApplicationContext)方法的代碼如下:

String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);

// Register BeanPostProcessorChecker that logs an info message when

// a bean is created during BeanPostProcessor instantiation, i.e. when

// a bean is not eligible for getting processed by all BeanPostProcessors.

int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;

beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));

// Separate between BeanPostProcessors that implement PriorityOrdered,

// Ordered, and the rest.

List priorityOrderedPostProcessors = new ArrayList<>();

List internalPostProcessors = new ArrayList<>();

List orderedPostProcessorNames = new ArrayList<>();

List nonOrderedPostProcessorNames = new ArrayList<>();

for (String ppName : postProcessorNames) {

if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {

BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);

priorityOrderedPostProcessors.add(pp);

if (pp instanceof MergedBeanDefinitionPostProcessor) {

internalPostProcessors.add(pp);

}

}

else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {

orderedPostProcessorNames.add(ppName);

}

else {

nonOrderedPostProcessorNames.add(ppName);

}

}

// First, register the BeanPostProcessors that implement PriorityOrdered.

sortPostProcessors(priorityOrderedPostProcessors, beanFactory);

registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);

// Next, register the BeanPostProcessors that implement Ordered.

List orderedPostProcessors = new ArrayList<>();

for (String ppName : orderedPostProcessorNames) {

BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);①

orderedPostProcessors.add(pp);

if (pp instanceof MergedBeanDefinitionPostProcessor) {

internalPostProcessors.add(pp);

}

}

sortPostProcessors(orderedPostProcessors, beanFactory);

registerBeanPostProcessors(beanFactory, orderedPostProcessors);②

// Now, register all regular BeanPostProcessors.

List nonOrderedPostProcessors = new ArrayList<>();

for (String ppName : nonOrderedPostProcessorNames) {

BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);

nonOrderedPostProcessors.add(pp);

if (pp instanceof MergedBeanDefinitionPostProcessor) {

internalPostProcessors.add(pp);

}

}

registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);

// Finally, re-register all internal BeanPostProcessors.

sortPostProcessors(internalPostProcessors, beanFactory);

registerBeanPostProcessors(beanFactory, internalPostProcessors);

// Re-register post-processor for detecting inner beans as ApplicationListeners,

// moving it to the end of the processor chain (for picking up proxies etc).

beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));

上面的代碼,大概思路是這樣的:

1)獲取容器中的所有BeanPostProcessor的beanName,也就是咱們在Spring容器中註冊bean時的id或name

2)根據BeanPostProcessor是否實現了PriorityOrdered、Ordered、普通BeanPostProcessor對Processor進行分類

3)按PriorityOrdered、Ordered、普通種類的順序,初始化並註冊對應的BeanPostProcessor

我們可以查看一下AnnotationAwareAspectJAutoProxyCreator的父類,會發現它是實現了Ordered接口的(實際上ProiorityOrdered也是Ordered的子類),所以AnnotationAwareAspectJAutoProxyCreator對象是在上面紅色標記的①代碼實例化的,在②代碼註冊到beanFactory中的。其中beanFactory.getBean(…)方法,是Spring獲取對象的統一方式,詳細過程,我們在後面進行代碼跟蹤,這裏咱們暫時記住getBean方法裏面,完成了AnnotationAwareAspectJAutoProxyCreator對象的創建,並通過②代碼完成了AnnotationAwareAspectJAutoProxyCreator的註冊(在容器中創建了對象,並且保存下來,beanName是org.springframework.aop.config.internalAutoProxyCreator)

05

AnnotationAwareAspectJAutoProxyCreator創建目標代理對象

前面我們瞭解了Spring創建和註冊AnnotationAwareAspectJAutoProxyCreator對象的過程,在這小節,我們將研究Spring是怎樣使用註冊好的AnnotationAwareAspectJAutoProxyCreator對象創建AOP代理對象的。

在我們的案例中,PowerServiceImpl對象是要織入通知的目標對象,接下來我們跟蹤PowerServiceImpl對象的實例化和創建AOP代理對象的過程。

跟蹤第4小節,AbstractApplicationContext.refresh()方法中的finishBeanFactoryInitialization(beanFactory);代碼(PowerServiceImpl屬於非延時加載的代理對象,所以在這行代碼裏面完成實例化)

因爲AOP的代理創建,是在SpringIOC容器初始化的時候實現的,爲了方便找到PowerServiceImpl的AOP代理對象的創建代碼,我們在TestAOP的test01方法裏的AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(ConfigAOP.class);代碼上,添加一個debug,用debug的方式,跟進代碼,歷經如下:

AnnotationConfigApplicationContext.<init>(Class<?>...) line: 88
->AbstractApplicationContext.refresh() line: 550
->AbstractApplicationContext.finishBeanFactoryInitialization(ConfigurableListableBeanFactory) line: 869
->DefaultListableBeanFactory.preInstantiateSingletons() line: 728
1
2
3
4
5
6
7
DefaultListableBeanFactory.

preInstantiateSingletons()方法的代碼塊如下:

if (this.logger.isDebugEnabled()) {

this.logger.debug("Pre-instantiating singletons in " + this);

}

// Iterate over a copy to allow for init methods which in turn register new bean definitions.

// While this may not be part of the regular factory bootstrap, it does otherwise work fine.

List beanNames = new ArrayList<>(this.beanDefinitionNames);

// 觸發所有非延時加載的單例對象的實例化

for (String beanName : beanNames) {

RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);

if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {

if (isFactoryBean(beanName)) {

Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);

if (bean instanceof FactoryBean) {

final FactoryBean<?> factory = (FactoryBean<?>) bean;

boolean isEagerInit;

if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {

isEagerInit = AccessController.doPrivileged((PrivilegedAction)

((SmartFactoryBean<?>) factory)::isEagerInit,

getAccessControlContext());

}

else {

isEagerInit = (factory instanceof SmartFactoryBean &&

((SmartFactoryBean<?>) factory).isEagerInit());

}

if (isEagerInit) {

getBean(beanName);①

}

}

}

else {

getBean(beanName);

}

}

}

// 觸發所有對應bean初始化後的回調方法

for (String beanName : beanNames) {

Object singletonInstance = getSingleton(beanName);

if (singletonInstance instanceof SmartInitializingSingleton) {

final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;

if (System.getSecurityManager() != null) {

AccessController.doPrivileged((PrivilegedAction) () -> {

smartSingleton.afterSingletonsInstantiated();

return null;

}, getAccessControlContext());

}

else {

smartSingleton.afterSingletonsInstantiated();

}

}

}

上面代碼主要做兩個事情:一個是實例化所有非延時加載的單例對象;一個是調用實例化對象後的回調方法。所有對象的實例化過程,都是在如上代碼,紅色標記語句①getBean(beanName)完成的。

爲了瞭解AOP代理對象的創建過程,我們需要在getBean(beanName)①;上加上一個debug斷點。同時考慮到每個對象都會進入這個斷點,進行對象的創建,而我們只關心PowerServiceImpl對象和對應AOP代理對象的創建過程,所以我們可以在getBean()方法的斷點上面,加上條件。這樣只有符合條件的時候,纔會在該斷點停下來,方便我們debug進去。

添加條件斷點的方式如下:

1)在getBean()行代碼前面,雙擊添加一個斷點(位置很重要,注意如下圖所示)

2)在斷點上點擊鼠標右鍵,選擇菜單中的 Breakpoint Properties… 選項

3)點擊Breakpoint Properties…選項,進入屬性設置頁面,選擇conditional選項,同事在條件輸入框中輸入條件語句。如下圖:

4)點擊OK按鈕,清除其他斷點()只留當前加上的條件斷點),重新debug運行TestAOP的test01方法

從前面加上的條件斷點開始,逐步debug進去,debug的線路如下(第一次debug不妨按如下的參考進行,先確定AOP對象創建的位置,回過來再瞭解每個過程中涉及方法的邏輯流程):

DefaultListableBeanFactory.preInstantiateSingletons() line: 760

->AbstractBeanFactory.getBean(String) line: 199
->AbstractBeanFactory.doGetBean(String, Class<T>, Object[], boolean) line: 315
->DefaultSingletonBeanRegistry.getSingleton(String, ObjectFactory<?>) line: 228
->AbstractBeanFactory.lambda$doGetBean$0(String, RootBeanDefinition, Object[]) line: 317
->AbstractAutowireCapableBeanFactory.createBean(String, RootBeanDefinition, Object[]) line: 501
->AbstractAutowireCapableBeanFactory.doCreateBean(...) line: 579
->AbstractAutowireCapableBeanFactory.initializeBean(...) line: 1706
->AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsAfterInitialization(.) line: 436
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
到這一步,就進入了Spring容器中,給PowerServiceImpl創建AOP代理對象的過程,前面分析@EnableAspectJAutoProxy源碼的時候,咱們知道在AspectJAutoProxyRegistrar類中,有註冊了一個AnnotationAwareAspectJAutoProxyCreator類,並且也初步告訴大家,Spring在初始化容器的時候,會根據需要,使用該類的對象,創建AOP代理對象,完成通知到目標切入點方法的織入。該動作就在AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsAfterInitialization(.)方法中完成的。

我們查看AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsAfterInitialization(.)方法裏面的源代碼如下:

public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)

throws BeansException {

Object result = existingBean;

for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) { ①

Object current = beanProcessor.postProcessAfterInitialization(result, beanName);②

if (current == null) {

return result;

}

result = current;

}

return result;

}

通過閱讀上面的源代碼,我們可以瞭解到,該代碼是獲取容器中所有有註冊的BeanPostProcessor(Bean後置處理器),循環的調用每個BeanPostProcessor(Bean後置處理器)的postProcessAfterInitialization方法,對當前的目標對象進行處理(beanName對應的對象)。選擇上面代碼①行的getBeanPostProcessors()部分代碼,點擊鼠標右鍵,選擇Wath選項,如圖:

點擊Watch選項,進入Debug窗口的Expression視圖,可以看到getBeanPostProcessors()方法能獲取到的,將要遍歷調用的所有Bean後置處理器,其中第四個,就是AnnotationAwareAspectJAutoProxyCreator,如下圖:

我們循環到第四個後置處理器,繼續debug進去,如:

AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsAfterInitialization(Object, String) line: 437

->AnnotationAwareAspectJAutoProxyCreator(AbstractAutoProxyCreator).postProcessAfterInitialization(…) line: 304

->AnnotationAwareAspectJAutoProxyCreator(AbstractAutoProxyCreator).wrapIfNecessary(... ...) line: 340
1
在wrapIfNecessary(…)方法中,有如下關鍵代碼:

// 獲取要織入到beanName目標對象的切入點的所有通知

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;

}

其中①代碼是獲取要織入到目標切入點中的所有通知(攔截器對象),我們用Debug中查看變量值的方式,查看specificInterceptors中的所有攔截器對象,如圖:

一共有5個通知對象,除了第一個默認通知對象外,剩下4個,都是我們再LogServiceImpl類中,有用通知註解標記後的通知對象,分別是@Before,@After,@AfterReturning和@AfterThrowing,在上圖中,標記了@AfterThrowing的關鍵信息。

真正創建AOP代理對象,完成通知織入動作,是在②行代碼,接下來我們繼續從②開始Debug進去,過程如:

AbstractAutoProxyCreator.wrapIfNecessary(Object, String, Object) line: 356

->AbstractAutoProxyCreator.createProxy(Class<?>, String, Object[], TargetSource) line: 473

->ProxyFactory.getProxy(ClassLoader) line: 110
->ProxyFactory(ProxyCreatorSupport).createAopProxy() line: 105
1
2
3
在ProxyCreatorSupport.createAopProxy()方法中,有對ProxyFactory中對AOP創建條件進行了判斷(比如在@EnableAspectJAutoProxy註解中,是否有設置proxyTargetClass屬性爲true等),決定使用CGLIB還是JDK創建AOP代理對象。具體流程,請查看createAopProxy()方法中的源代碼和中午註釋,如:

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)) { ①

// 返回基於JDK產生的動態代理對象

return new JdkDynamicAopProxy(config); ②

}

// 返回基於CGLIB產生的動態代理對象

return new ObjenesisCglibAopProxy(config); ③

}

else {

// 返回基於JDK產生的動態代理對象

return new JdkDynamicAopProxy(config); ④

}

我們當前的PowerServiceImpl對象,是面向接口編程的,而且也沒有在@EnableAspectJAutoProxy註解中聲明屬性,當前代碼會執行④行代碼,我們繼續Debug進去,路線如:

DefaultAopProxyFactory.createAopProxy(AdvisedSupport) line: 63

->ProxyFactory(ProxyCreatorSupport).createAopProxy() line: 105

->ProxyFactory.getProxy(ClassLoader) line: 110
->JdkDynamicAopProxy.getProxy(ClassLoader) line: 123
1
2
3
這時候就進入了JDK裏面的java.lang.reflect.Proxy類,進行SpringAOP的動態對象的創建(AOP代理對象),我們就找到了Spring中使用AnnotationAwareAspectJAutoProxyCreator組件,完成AOP代理對象的創建過程。

06

總結

通過前面的源代碼的風險和跟蹤,可以得出如下結論

1)通過在配置類上面添加@EnableAspectJAutoProxy註解,通知Spring容器支持註解AspectJ,實現面向AOP編程。

2)使用@Aspect、@Pointcut、@Before、@After、@AfterReturning、@AfterThrowing和@Arount註解,完成切面的聲明,切入點的聲明和各種通知的聲明。

3)Spring容器中,是通過AnnotationAwareAspectJAutoProxyCreator對象,在目標對象初始化完後,利用BeanPostProcessor後置通知的機制,完成對目標對象的AOP對象創建。

4)AnnotationAwareAspectJAutoProxyCreator對象內部,是封裝JDK和CGlib兩個技術,實現動態代理對象創建的。

5)Spring裏面,使用JDK還是CGLIB,可以在@EnableAspectJAutoProxy中設置proxyTargetClass屬性指定,也可以通過Spring自己判斷,目標對象類是否實現了接口,有實現接口,就使用JDK,否則就使用CGLIB。

喜歡這篇文章的可以給筆者點個贊,關注一下,每天都會分享Java相關文章!還有不定時的福利贈送,包括整理的學習資料,面試題,源碼等~~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章