1. @EnableAspectJAutoProxy 註解做了什麼?
在springboot中,@EnableAspectJAutoProxy 註解開啓AOP , 在這個註解裏面,通過@Import 給容器中導入AspectJAutoProxyRegistrar 對象.
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {...}
AspectJAutoProxyRegistrar 實現了ImportBeanDefinitionRegistrar接口,通過這個接口可以向容器中增加Bean的定義。
class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
@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);
}
}
}
}
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry); 這一句往裏走,最後創建了一個AnnotationAwareAspectJAutoProxyCreator 對象的Bean定義,加到註冊器中,key爲org.springframework.aop.config.internalAutoProxyCreator.
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, @Nullable Object source) {
return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
}
private static BeanDefinition registerOrEscalateApcAsRequired(Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
if (registry.containsBeanDefinition("org.springframework.aop.config.internalAutoProxyCreator")) {
...
} else {
RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
beanDefinition.setSource(source);
beanDefinition.getPropertyValues().add("order", -2147483648);
beanDefinition.setRole(2);
registry.registerBeanDefinition("org.springframework.aop.config.internalAutoProxyCreator", beanDefinition);
return beanDefinition;
}
}
2. 什麼時候註冊1中的AnnotationAwareAspectJAutoProxyCreator對象的定義?
在AspectJAutoProxyRegistrar.registerBeanDefinitions() 方法打斷點調試,查看調用鏈路
大致流程是
spring容器啓動階段的 AbstractApplicationContext.refresh()
invokeBeanFactoryPostProcessors(beanFactory) // 調用工廠的後置處理器, 增加即將加入容器中Bean的定義
this**.**reader.loadBeanDefinitions(configClasses); // 加載所有配置類, 有@Configration註解的類
loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars()); // 把配置類中import引入的註冊器類加載進來
AspectJAutoProxyRegistrar.registerBeanDefinitions() // 進入到aop的註冊bean定義的方法。
3. 什麼時候創建1中的AnnotationAwareAspectJAutoProxyCreator對象?
通過AnnotationAwareAspectJAutoProxyCreator 類的繼承關係,可以看到它實現了BeanPostProcessor. 在spring容器的啓動過程中 AbstractApplicationContext.refresh() 有專門負責加載所有實現BeanPostProcessor接口的方法
registerBeanPostProcessors(beanFactory); // 加載所有實現BeanPostProcessor接口的方法
它裏面的內容包括如下:
// 獲取所有實現了BeanPostProcessor接口的bean的名稱
String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);
...
// 逐個創建Bean
for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
// BeanFatory.getBean方法獲取到的就是已經創建好的Bean了
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);
}
}
...
// 把創建好的bean加到容器中
registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);
4. 加到容器中的AnnotationAwareAspectJAutoProxyCreator 怎麼生效呢?
AOP的本質是代理,那麼就會有創建Bean的時候,不會使用原本類型指定的對象,而是創建一個增強的對象。那麼我們就從創建bean的過程中尋找。我們知道spring 容器啓動的過程中,會先加載 BeanPostProcessor 等類型的bean,像我們代碼中自己定義的切面等其他業務相關bean,都是之後加載的,從spring容器啓動過程的refresh()方法的代碼順序也可以看出來,這一點在這裏也不重要,我只是提一下。
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
...
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
既然創建的對象是代理對象,那麼直接在AbstractAutowireCapableBeanFactory 類的createBean 方法裏面打斷點,並且給斷電加上Condition, 只在創建我們定義的需要被切的對象的時候斷住,比如我寫了一個Say這個類,那麼我加的條件就是beanName.equals(“say”). 一步步的調試,發現走到applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName) -> wrapIfNecessary(bean, beanName, cacheKey) 方法中的時候,有這麼一段代碼
// 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;
}
這個方法是在 AbstractAutoProxyCreator 的 註釋也說的很清楚了,如果有通知就創建代理。通過切點表達式和類的關係,就能找到我們定義的通知方法,被封裝爲Advisor對象。代理創建完成後,可以看到通知方法作爲攔截器鏈添加到了道理對象中。其中的攔截器鏈已經根據Before, After等註解信息排好了順序,排序是使用 ReflectiveAspectJAdvisorFactory 類的METHOD_COMPARATOR 方法實現了,裏面已經定義好了各個註解的順序。
至此,需要增強的對象創建完成,調用的時候,進入CglibAopProxy 的 intercept 方法,因爲我這裏是對類進行的增強,所以spring自動的選則了使用cglib 代理。
先獲取所有的增強方法組成的攔截器鏈
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
把代理對象(Cglib增強後的對象),目標對象(Say),方法,參數,連接器鏈等信息封裝爲一個CglibMethodInvocation 對象,並執行該對象的.proceed() 方法。
public Object proceed() throws Throwable {
// We start with an index of -1 and increment early.
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
// Evaluate dynamic method matcher here: static part will already have
// been evaluated and found to match.
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
}
else {
// Dynamic matching failed.
// Skip this interceptor and invoke the next in the chain.
return proceed();
}
}
else {
// It's an interceptor, so we just invoke it: The pointcut will have
// been evaluated statically before this object was constructed.
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
調試可以看到鏈式的調用,逐個攔截器不斷的調用 mi.proceed(); 逐漸深入到最後一個攔截器MethodBeforeAdviceInterceptor 的時候,可以看到執行了前置通知的方法
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
return mi.proceed();
}
前置通知執行完以後,mo.proceed()方法中滿足了執行方法本體的條件,被增強的方法本體執行。
// We start with an index of -1 and increment early.
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
執行完後線程棧退回到上一層的攔截器,是AspectJAfterAdvice, 因爲是在finally 塊中的,所以必然執行。
public Object invoke(MethodInvocation mi) throws Throwable {
try {
return mi.proceed();
}
finally {
invokeAdviceMethod(getJoinPointMatch(), null, null);
}
}
結束後線程退回到AfterReturningAdviceInterceptor 攔截器,到這裏爲止所有的攔截器中都沒有捕獲異常,所以如果前面有異常的時候,後置攔截器的內容就不執行了。
public Object invoke(MethodInvocation mi) throws Throwable {
Object retVal = mi.proceed();
this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
return retVal;
}
之後回到AspectJAfterThrowingAdvice 攔截器,這裏是在catch 塊中,沒有異常就不執行。
public Object invoke(MethodInvocation mi) throws Throwable {
try {
return mi.proceed();
}
catch (Throwable ex) {
if (shouldInvokeOnThrowing(ex)) {
invokeAdviceMethod(getJoinPointMatch(), null, ex);
}
throw ex;
}
}
5. 看的時候一定要寫個demo,一遍調試一遍看,光讀文字看不懂的。我的demo如下
/**
* Author: susq
* Date: 2019-08-04 12:06
*/
public class Say {
public void sayHello() {
log.info("Say -- sayHello : hello !");
}
}
@Aspect
public class SayAspect {
@Pointcut("execution(public * com.su.demo.aop.Say.sayHello(..))")
public void sayPointCut() {}
@After("sayPointCut()")
public void afterSay() {
System.out.println("=====afterSay=====");
}
@AfterThrowing("sayPointCut()")
public void afterThrow() {
System.out.println("=====afterThrow=====");
}
@Before("sayPointCut()")
public void beforeSay() {
System.out.println("=====beforeSay=====");
}
@AfterReturning("sayPointCut()")
public void afterReturn() {
System.out.println("=====afterReturn=====");
}
}
@EnableAspectJAutoProxy
@Configuration
public class SayConfig {
@Bean
public Say say() {
return new Say();
}
@Bean
public SayAspect sayAspect() {
return new SayAspect();
}
}
public class AppTest {
public static void main(String[] args) {
AnnotationConfigApplicationContext configApplicationContext = new AnnotationConfigApplicationContext(SayConfig.class);
Say say = configApplicationContext.getBean(Say.class);
say.sayHello();
}
}