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;
/**
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相關文章!還有不定時的福利贈送,包括整理的學習資料,面試題,源碼等~~