本文解读AOP是如何增强方法功能的。
需要提前了解@Import 注解的功能:一.Spring之组件注册bean_u014203449的博客-CSDN博客_spring注册bean
BeanPostProcessor 后置处理器的功能:二.Spring之实例生命周期_u014203449的博客-CSDN博客
Aware接口:三.Spring之属性赋值和自动装配_u014203449的博客-CSDN博客
一.演示案列
1、导入aop模块;Spring AOP:(spring-aspects)
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>4.3.12.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.12.RELEASE</version>
</dependency>
2、定义一个业务逻辑类(MathCalculator);在业务逻辑运行的时候将日志进行打印(方法之前、方法运行结束、方法出现异常,xxx)
public class MathCalculator {
public int div(int i,int j){
System.out.println("MathCalculator...div...");
return i/j;
}
}
3、定义一个日志切面类(LogAspects):切面类里面的方法需要动态感知MathCalculator.div运行到哪里然后执行;
通知方法:
前置通知(@Before):logStart:在目标方法(div)运行之前运行
后置通知(@After):logEnd:在目标方法(div)运行结束之后运行(无论方法正常结束还是异常结束)
返回通知(@AfterReturning):logReturn:在目标方法(div)正常返回之后运行
异常通知(@AfterThrowing):logException:在目标方法(div)出现异常以后运行
环绕通知(@Around):动态代理,手动推进目标方法运行(joinPoint.procced())
4、给切面类的目标方法标注何时何地运行(通知注解);
5、将切面类和业务逻辑类(目标方法所在类)都加入到容器中;
6、必须告诉Spring哪个类是切面类(给切面类上加一个注解:@Aspect)
7、标明切点,切点可以是某包、某类、某方法、某注解,通知注解的value值为切点
/**
* 切面类
* @author lfy
*
* @Aspect: 告诉Spring当前类是一个切面类
*
*/
@Aspect
public class LogAspects {
//抽取公共的切入点表达式
//1、本类引用
//2、其他的切面引用
@Pointcut("execution(public int com.atguigu.aop.MathCalculator.*(..))")
public void pointCut(){};
//@Before在目标方法之前切入;切入点表达式(指定在哪个方法切入)
@Before("pointCut()")
public void logStart(JoinPoint joinPoint){
Object[] args = joinPoint.getArgs();
System.out.println(""+joinPoint.getSignature().getName()+"运行。。。@Before:参数列表是:{"+Arrays.asList(args)+"}");
}
@After("com.atguigu.aop.LogAspects.pointCut()")
public void logEnd(JoinPoint joinPoint){
System.out.println(""+joinPoint.getSignature().getName()+"结束。。。@After");
}
//JoinPoint一定要出现在参数表的第一位
@AfterReturning(value="pointCut()",returning="result")
public void logReturn(JoinPoint joinPoint,Object result){
System.out.println(""+joinPoint.getSignature().getName()+"正常返回。。。@AfterReturning:运行结果:{"+result+"}");
}
@AfterThrowing(value="pointCut()",throwing="exception")
public void logException(JoinPoint joinPoint,Exception exception){
System.out.println(""+joinPoint.getSignature().getName()+"异常。。。异常信息:{"+exception+"}");
}
}
8、给配置类中加 @EnableAspectJAutoProxy 【开启基于注解的aop模式】
在Spring中很多的 @EnableXXX;
@EnableAspectJAutoProxy
@Configuration
public class MainConfigOfAOP {
//业务逻辑类加入容器中
@Bean
public MathCalculator calculator(){
return new MathCalculator();
}
//切面类加入到容器中
@Bean
public LogAspects logAspects(){
return new LogAspects();
}
}
单元测试:
@Test
public void test01(){
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfAOP.class);
MathCalculator mathCalculator = applicationContext.getBean(MathCalculator.class);
mathCalculator.div(1, 0);
applicationContext.close();
}
二.@EnableAspectJAutoProxy
@EnableAspectJAutoProxy注解启动了AOP功能,Spring中很多注解都是EnableXXX 去启动某个功能,我们先来看这个注解。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
@EnableAspectJAutoProxy 上有@Import注解,它会向容器中注入参数类的实例,点击看参数 AspectJAutoProxyRegistrar 类。
@Import注解有三种用法,我这篇文章介绍过:一.Spring之组件注册bean_u014203449的博客-CSDN博客_spring注册bean
/**
* Registers an {@link org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator
* AnnotationAwareAspectJAutoProxyCreator} against the current {@link BeanDefinitionRegistry}
* as appropriate based on a given @{@link EnableAspectJAutoProxy} annotation.
*
* @author Chris Beams
* @author Juergen Hoeller
* @since 3.1
* @see EnableAspectJAutoProxy
*/
class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
/**
* Register, escalate, and configure the AspectJ auto proxy creator based on the value
* of the @{@link EnableAspectJAutoProxy#proxyTargetClass()} attribute on the importing
* {@code @Configuration} class.
*/
@Override
public void registerBeanDefinitions(
AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
AnnotationAttributes enableAspectJAutoProxy =
AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}
if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
}
}
}
可以看到类注释说 基于 EnableAspectJAutoProxy注解,将 AnnotationAwareAspectJAutoProxyCreator 用BeanDefinitionRegistry注册。
AspectJAutoProxyRegistrar 类实现 ImportBeanDefinitionRegistrar 接口,在registerBeanDefinitions方法可以用参数BeanDefinitionRegistry 去手动注册实例到容器中。
可以看到 AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry); 这行代码方法名 注册AspectJxxx 如果需要的话。
点进去看。
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) {
return registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry, null);
}
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, Object source) {
return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
}
注意上面这个方法的参数是AnnotationAwareAspectJAutoProxyCreator.Class. 再点进去。
public static final String AUTO_PROXY_CREATOR_BEAN_NAME =
"org.springframework.aop.config.internalAutoProxyCreator";
private static BeanDefinition registerOrEscalateApcAsRequired(Class<?> cls, BeanDefinitionRegistry registry, Object source) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
int requiredPriority = findPriorityForClass(cls);
if (currentPriority < requiredPriority) {
apcDefinition.setBeanClassName(cls.getName());
}
}
return null;
}
RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
beanDefinition.setSource(source);
beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
return beanDefinition;
}
这个方法对参数class判断registry中是否有这个BeanDefinition,如果没有就new一个并且register这个BeanDefiniton到registry,如果有则比较优先级,更换beanClassName.
AnnotationAwareAspectJAutoProxyCreator类对应的BeanDefinition名字是固定的org.springframework.aop.config.internalAutoProxyCreator,根据这个名字取判断是否存在。
打断点看看是如何判断registry 是否有这个BeanDefinition。
来到了 DefaultListableBeanFactory类,看到用一些集合存储了已注册的BeanDefinition。
打断点,容器第一次启动时还没有这个BeanDefinition,所以会新创建我们的AnnotationAwareAspectJAutoProxyCreator对应的BeanDefinition.
断点进入 registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);又来到了DefaultListableBeanFactory类。
简单看看就是把BeanDefinition用集合变量存下来。
再看看BeanDinition有哪些东西,截取一部分代码:看方法名大概明白什么意思,BeanDinition 可以设置和获取实例在Spring容器中的属性如是否单例、优先级、对应的Class、懒加载、依赖哪些其他组件(这个蛮有用,容器在创建此实例前优先创建它依赖的实例)
public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {
String getParentName();
void setBeanClassName(String beanClassName);
String getBeanClassName();
void setScope(String scope);
String getScope();
void setLazyInit(boolean lazyInit);
boolean isLazyInit();
void setDependsOn(String... dependsOn);
String[] getDependsOn();
void setAutowireCandidate(boolean autowireCandidate);
boolean isAutowireCandidate();
void setPrimary(boolean primary);
boolean isPrimary();
回到 AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry),以上逻辑说明了@EnableAspectJAutoProxy 会将 AnnotationAwareAspectJAutoProxyCreator.Class 做参数创建一个BeanDefinition并保存到DefaultListableBeanFactory。
三.AnnotationAwareAspectJAutoProxyCreator的创建、初始化
来看看AnnotationAwareAspectJAutoProxyCreator是如何发挥作用的。
后面的类层层继承,就不一一截图了,把继承的关系链写下来:
AnnotationAwareAspectJAutoProxyCreator:
AnnotationAwareAspectJAutoProxyCreator
->AspectJAwareAdvisorAutoProxyCreator
->AbstractAdvisorAutoProxyCreator
->AbstractAutoProxyCreator
implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware(关键)
SmartInstantiationAwareBeanPostProcessor接口
->InstantiationAwareBeanPostProcessor
->BeanPostProcessor
BeanPostProcessor 是后置处理器,在实例初始化前后可以对实例进行操作。
看看InstantiationAwareBeanPostProcessor : 看文档注释可以明白,下面两个方法可以在实例创建前后进行处理。postProcessBeforeInstantiation方法注释:返回的object可以是目标bean的代理对象。
public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor {
/**Apply this BeanPostProcessor <i>before the target bean gets instantiated</i>.
* The returned bean object may be a proxy to use instead of the target bean,
* effectively suppressing default instantiation of the target bean.**/
Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException;
boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException;
}
回到AbstractAutoProxyCreator类,它实现了后置处理器接口 这样它会成为一个后置处理器; 实现了BeanFactoryAware接口,会将Spring的工厂组件注入其中。
关于XXXAware接口:三.Spring之属性赋值和自动装配_u014203449的博客-CSDN博客
以上说明AnnotationAwareAspectJAutoProxyCreator 本质是个后置处理器BeanProcessor,且其注入了BeanFachory。
我们先把断点打到AnnotationAwareAspectJAutoProxyCreator 和其层层父类的 setBeanFactory 方法上,这样可以看到它是怎样把BeanFactory注入进去,即何时执行的实例初始化方法。
AbstractAdvisorAutoProxyCreator 和AbstractAutoProxyCreator 都有setBeanFactory方法,其中调用了 initBeanFactory().
断点来了:
来看看调用链:
test01是我们的单元测试方法,依次往上看方法
第一个是 AnnotationConfigApplicationContext的构造器,这是在单元测试创建容器时调用的:
再往进看,调用到了 refresh的 registerBeanPostProcessors方法,方法名称是注册后置处理器
点击进入 PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);这个方法要仔细看看。
断点到了 BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class); 从工厂中获得一个BeanPostProcessor,从工厂获得也就是创建实例,这符合我们打断点的目的:在AnnotationAwareAspectJAutoProxyCreator实例创建完成后,执行初始化方法中, 调用setBeanFactory将BeanFactory注入。
先整体看看registerBeanPostProcessors。如下图,第一步先得到所有BeanProcessor的名称。
第二步,添加一个BeanPostProcessor,看注释是这个后置处理器是为了记录日志,在其他后置处理器创建实例时。
第三步,看注释和代码,将BeanPostProcossor 的Name数组 按照实现PriorityOrdered 、Orderd 接口和没实现排序接口的划分成不同的集合,如PriorityOrderedPostProcessors、orderedPostProcessors、nonOrderedPostProcessors。
将实现了MergedBeanDefinitionPostProcessor接口的分到internalPostProcessors 内部后置处理器集合。
如果实现了PriorityOrdered接口,则直接通过BeanFactory得到实例,并保存到PriorityOrderedPostProcessors集合。
再往后看,就是将PriorityOrderedPostProcessors集合排序sort,然后调用 registerBeanPostProcessors 方法将实例注册到容器。
以及将其他实现ordered接口的 和没有实现排序接口的BeanPostProcessor创建并注册。
看看 registerBeanPostProcessors,如何注册BeanPostProcessor:往BeanFactory中添加
到了 AbstractBeanFactory.addBeanPostProcessor(),注册就是往AbstractBeanFactory类的beanPostProcessors集合中添加一个元素。
回到之前打断点的地方,AnnotationAwareAspectJAutoProxyCreator实现了Ordered接口,所以被分到了OrderedPost集合中。
接下来看看,实例是如何在工厂中创建的。顺着这个线程调用点击,都可以看看,是有关创建实例的过程。
先写下创建实例的简单过程:
1)、创建Bean的实例
2)、populateBean;给bean的各种属性赋值
3)、initializeBean:初始化bean;
1)、invokeAwareMethods():处理Aware接口的方法回调,(就是debug的注入工厂)
2)、applyBeanPostProcessorsBeforeInitialization():应用后置处理器的postProcessBeforeInitialization()
3)、invokeInitMethods();执行自定义的初始化方法
4)、applyBeanPostProcessorsAfterInitialization();执行后置处理器的postProcessAfterInitialization();
断点看到AbstractAutowireCapableBeanFactory.doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args).
看注释:生成实例
设置属性,初始化实例,断点在初始化实例这个方法上。
断点再进去,可以看到断点在 invokeAwareMethods 方法上,即调用Aware方法,看后面分别还有调用前置处理器、ini他、后置处理器等方法,说明前置、后置处理器、Aware方法都是 初始化实例过程的一部分。
进入invokeAwareMethods,根据实例实现了哪些Aware接口,注入对应的组件。
调用线程链再往上,就来到最初我们打断点的地方。
在上面的过程中,看到了AnnotationAwareAspectJAutoProxyCreator是如何创建并初始化的过程,也简单看了实例创建初始化过程。
接下来看看AnnotationAwareAspectJAutoProxyCreator 作为后置处理器BeanPostProcessor是如何发挥作用的。
四.AnnotationAwareAspectJAutoProxyCreator后置处理器功能
把AnnotationAwareAspectJAutoProxyCreator 上有业务逻辑的BeanPostProcessor 方法打上断点,没有逻辑直接返回null或bean的不打断点。来看看AnnotationAwareAspectJAutoProxyCreator 作为BeanPostProcessor是如何发挥作用的。
有两个方法有业务逻辑:
AbstractAutoProxyCreator.postProcessBeforeInstantiation()
AbstractAutoProxyCreator.postProcessAfterInitialization()
从setBeanFactory那放开断点,就来到了 AbstractAutoProxyCreator.postProcessBeforeInstantiation()
从线程调度看,发现依然是refresh方法开始调用的。
看注释,实例化所有剩余的非懒加载的实例。在之前refresh方法中调用了 registerBeanPostProcessors 去实例化并注册了BeanPostProcessor,现在要注册剩余的其他bean。
按照线程调用链,我们点到 preInstantiateSingletons方法。在里面打断点,把断点放行到此处:
可以看到,遍历beanDifinitionNames,判断是否spring工厂中有此bean,没有就getbean()创建bean。
看看目前有多少beanDefinitionNames,之前创建并注册了BeanPostProcessor,现在会实例化剩余的bean,
重点看calculator,这是被AOP增强的类。
把断点放行,让当前beanName 是calculator,看看关注的calculator是如何创建的:
判断spring工厂中没有calculator,所以会执行getBean创建:
断点一路点进去,来到了 AbstractBeanFactory.doGetBean(),这个方法在之前BeanPostProccessor创建时也调用过,方法很长,看注释基本是对bean的校验、先实例化它depends依赖的组件。最后createBean.
再点进去,也是之前BeanPostProccessor创建时见过的方法。不同的是,这次不会直接doCreateBean,
直接跳过 resolveBeforeInstantiation 方法,会发现断点进入了之前设置的 postProcessBeforeInstantiation方法。
回头看看resolveBeforeInstantiation方法,它会先调用BeanPostProcessor的 BeanPostProcessorsBeforeInstantiation方法,尝试直接返回一个Bean,如果返回成功,就执行 BeanPostProcessorsAfterInitialization方法。
这符合 InstantiationAwareBeanPostProcessor 的功能,在实例创建前后执行。
这时能看出AnnotationAwareAspectJAutoProxyCreator作为BeanPostProcessor开始发挥作用了,来看看它的postProcessBeforeInstantiation方法:
里面主要是判断,isInfrastructureClass() 判断当前bean是不是切点、增强器之类。如果是,则加入advisedBeans
判断是否应该跳过,shouldSkip(),里面判断当前bean的名字是不是和 candidateAdvisors 候选增强器的切面相同。如果是也加入
advisedBeans。
可见advisedBeans是用来保存增强器的集合。 结果也是LogAspect加入了advisedBeans,MathCalculator没有加入。
总结AnnotationAwareAspectJAutoProxyCreator【InstantiationAwareBeanPostProcessor】 的作用:
1)、每一个bean创建之前,调用postProcessBeforeInstantiation();
关心MathCalculator和LogAspect的创建
1)、判断当前bean是否在advisedBeans中(保存了所有增强器)
2)、判断当前bean是否是基础类型的Advice、Pointcut、Advisor、AopInfrastructureBean,
或者是否是切面(@Aspect)
3)、是否需要跳过shouldSkip()
1)、获取候选的增强器(切面里面的通知方法)【List<Advisor> candidateAdvisors】
每一个封装的通知方法的增强器是 InstantiationModelAwarePointcutAdvisor;
判断每一个增强器是否是 AspectJPointcutAdvisor 类型的;返回true
2)、永远返回false
再看AnnotationAwareAspectJAutoProxyCreator 的postProcessAfterInitialization方法,当前bean为calculator时,会进入wrapIfNecessary方法, 包装bean方法。
earlyProxyReferences是创建bean时会把引用加到这个集合,可以自行查看依赖关系。
这是AnnotationAwareAspectJAutoProxyCreator 作为BeanPostProcessor最核心的地方:
如果bean是增强器已经在advisedBeans中,或者符合isInfrastructureClass 和shouldSkip 方法,就直接返回bean本身。
否则就会判断增强器数量,如果数量不为空,就认为需要代理、返回一个代理对象。
看看getAdvicesAndAdvisorsForBean方法,找到符合当前bean的增强器。
1)、获取当前bean的所有增强器(增强器就是通知方法,每个通知对应一个Advisor对象、属性有切点) Object[] specificInterceptors
1、找到 候选的 所有的增强器(会遍历所有切面的所有通知,这些通知就是候选增强器) AbstractAdvisorAutoProxyCreator.getAdvicesAndAdvisorsForBean()
2、获取到能在bean使用的增强器。(遍历候选增强器,去判断增强器是否作用于当前bean,通过通知对应的切点、反射bean类去判断)
3、给增强器排序 AbstractAdvisorAutoProxyCreator.findEligibleAdvisors
然后创建代理:
1)、如果当前bean需要增强(有对应的增强器),创建当前bean的代理对象;
1)、获取所有增强器(通知方法)
2)、保存到proxyFactory
3)、创建代理对象:Spring自动决定 ,何时选用何种代理Spring源码分析-SpringAop什么时候调用jdk动态代理?什么时候调用cglib - cao_xiaobo - 博客园
JdkDynamicAopProxy(config);jdk动态代理;
ObjenesisCglibAopProxy(config);cglib的动态代理;
2)、给容器中返回当前组件使用cglib增强了的代理对象;
3)、以后容器中获取到的就是这个组件的代理对象,执行目标方法的时候,代理对象就会执行通知方法的流程;
五.通知方法执行流程
将断点打到切点。
断点进入运行方法,会发现并没有直接进入 div方法,而是进入了 CglibAopProxy的 intercept方法。这就是代理执行的方法
看看方法参数:
method是切点方法,args有参数。
proxy 有增强的信息,当前bean被哪些增强器(通知增强)
方法中会得到一个chain链,比较关键
往进走,缓存不用管,基本都是为了下次使用,第一次肯定没有缓存。进入
this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice
这个方法简单来说是把advisor遍历,转为 MethodInterceptor集合返回
目前有这些advisor增强器,就是切面中的四个通知方法,外加spring默认的ExposeInvocationInterceptor。
MethodInterceptor[] interceptors = registry.getInterceptors(advisor); 这个方法时由advisor变为MethodInterceptor的方法,看看。
判断如果是MethodInterceptor直接强转,如果不是 则通过AdvisorAdapter 适配器转换。
有三个Adapter,遍历尝试转换
转换也就是构造一个MethodInterceptor 方法拦截器
总之最后得到了一个MethodInterceptorChain,由一个默认的ExposeInvocationInterceptor 和四个 我们写的通知组成。
继续CglibAopProxy的 intercept方法。看注释,如果链是空的,则直接调用目标方法。
chain不是空的,则new 一个 CglibMethodInvocation ,并且执行其proceed()方法。
CglibMethodInvocation继承了 ReflectiveMethodInvocation,proceed是ReflectiveMethodInvocation的方法。
CglibMethodInvocation 构造方法没有什么,就是将形参赋值给它的属性。进入proceed方法。interceptorsAndDynamicMethodMatchers是MethodInterceptorChain,第一步是一个判断,如果链当前索引是-1 则跳出。为-1说明链遍历结束了。但现在大小是5。
然后从链中取出第一个拦截器,调用它的invoke方法,形参是CglibMethodInvocation本身(这个MethodInvocation参数保证了一会能继续执行它的proceed方法,然后遍历通知拦截器 执行)。
(其实chain这个名字不太对,这不像一个链,因为前后元素并没有指针关联,是通过共同的形参MethodInvocation,去遍历连接器集合)
断点放开,发现程序又执行到了proceed方法。而这次遍历的是第二个元素,
异常 通知代表的方法拦截器AspectJAfterThrowingAdvice。
断点进入AspectJAfterThrowingAdvice.invoke(), 里面还是调用CglibMethodInvocation(ReflectiveMethodInvocation
)的proceed方法,到时索引将会变为3,执行下一个方法拦截器的proceed方法。
但这里对proceed 捕捉了异常,如果发生异常则调用 增强方法,即异常通知。
到这里已经很明显了,接下来依次调用的拦截器的会是 返回通知、后置通知、被增强的方法、前置通知。
调用后还需要回到原方法,当前置通知执行完,再执行div(被增强的方法),然后后置通知、返回通知,直到第一个默认的方法拦截器执行完。
一次打断点看,接下来是返回通知:执行proceed后,最终会执行返回通知的增强方法。
然后是后置通知,这里用了try finally,保证即使异常也会执行后置通知。
最后是前置通知,先执行前置通知的方法,再执行被增强的方法,
当执行了前置通知后,控制台打印出了前置通知内容:
执行div后,因为有异常,进入了异常方法拦截器的异常捕捉,调用了异常通知,也一样要把异常抛出去。
到这里就说明了通知的执行流程。
六.总结
1)、 @EnableAspectJAutoProxy 开启AOP功能
2)、 @EnableAspectJAutoProxy 会给容器中注册一个组件 AnnotationAwareAspectJAutoProxyCreator
3)、AnnotationAwareAspectJAutoProxyCreator是一个后置处理器;
4)、容器的创建流程:
1)、registerBeanPostProcessors()注册后置处理器;创建AnnotationAwareAspectJAutoProxyCreator对象
2)、finishBeanFactoryInitialization()初始化剩下的单实例bean
1)、创建业务逻辑组件和切面组件
2)、AnnotationAwareAspectJAutoProxyCreator拦截组件的创建过程
3)、组件创建完之后,判断组件是否需要增强
怎么判断?遍历所有的增强器(增强器就是通知),增强器有切点信息,通过反射bean类型判断能否增强bean
若是:切面的通知方法,包装成增强器(Advisor);给业务逻辑组件创建一个代理对象(cglib);如果bean实现了接口,默认是jdk动态代理
5)、执行目标方法:
1)、代理对象执行目标方法
2)、CglibAopProxy.intercept();
1)、得到目标方法的拦截器链(增强器包装成拦截器MethodInterceptor)
2)、利用拦截器的链式机制,依次进入每一个拦截器进行执行;
3)、效果:
正常执行:前置通知-》目标方法-》后置通知-》返回通知
出现异常:前置通知-》目标方法-》后置通知-》异常通知