浅尝Spring注解开发_AOP原理及完整过程分析(源码)
浅尝Spring注解开发_AOP原理及完整过程分析(源码)
浅尝Spring注解开发,基于Spring 4.3.12
分析AOP执行过程及源码,包含AOP注解使用、AOP原理、分析AnnotationAwareAspectJAutoProxyCreator、AOP代理、拦截器、链式调用
以初学者的角度跟着雷丰阳的视频走完AOP整个过程,设计很巧妙。补充了自己的理解,为了流程连续性,所以全放在放在一篇里,如有错误请多多指教。
浅尝Spring注解开发_自定义注册组件、属性赋值、自动装配
浅尝Spring注解开发_Bean生命周期及执行过程
浅尝Spring注解开发_AOP原理及完整过程分析(源码)
AOP注解使用
AOP动态代理:指在程序运行期间动态的将某段代码切入到指定方法指定位置进行运行的编程方式
1)、将业务逻辑组件和切面类都加入到容器中,告诉Spring哪个是切面类(@Aspect)
2)、在切面类上的每一个通知方法上标注通知注解,告诉Spring何时何地运行(切入点表达式)
3)、开启基于注解的aop模式:@EnableAspectJAutoProxy
1、导入aop模块;Spring AOP:(spring-aspects)
2、定义一个业务逻辑类(MathCalculator);在业务逻辑运行的时候将日志进行打印(方法之前、方法运行结束、方法出现异常,xxx)
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]、给配置类中加 @EnableAspectJAutoProxy 【开启基于注解的aop模式】
在Spring中很多的 @EnableXXX;
导入aop模块:org.springframework.spring-aspects
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>4.3.12.RELEASE</version>
</dependency>
定义一个业务逻辑类(MathCalculator)。在业务逻辑运行的时候将日志进行打印(方法之前、方法运行结束、方法出现异常,xxx)。
//业务类
public class MathCalculator { public int div(int i,int j){
System.out.println("MathCalculator...div...");
return i/j;
} }
定义一个日志切面类(LogAspects):切面类里面的方法需要动态感知MathCalculator.div运行到哪里然后执行。通知方法:
- 前置通知(@Before):logStart:在目标方法(div)运行之前运行
- 最终通知(@After):logEnd:在目标方法(div)运行结束之后运行(无论方法正常结束还是异常结束)
- 后置通知/返回通知(@AfterReturning):logReturn:在目标方法(div)正常返回之后运行
- 异常通知(@AfterThrowing):logException:在目标方法(div)出现异常以后运行
- 环绕通知(@Around):动态代理,手动推进目标方法运行(joinPoint.proceed())
给切面类的目标方法标注何时何地运行(通知注解)。
//@Aspect: 告诉Spring当前类是一个切面类
@Aspect
public class LogAspects { //抽取公共的切入点表达式,空方法,只使用注解
//1、本类引用使用:pointCut()
//2、其他的切面引用使用:com.xxx.aop.LogAspects.pointCut()
@Pointcut("execution(public int com.atguigu.aop.MathCalculator.*(..))")
public void pointCut(){}; //前置通知,JoinPoint可以获取切入点信息
//@Before在目标方法之前切入,切入点表达式(指定在哪个方法切入),JoinPoint封装了切面方法信息
@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+"}");
} }
将切面类和业务逻辑类(目标方法所在类)都加入到容器中。
必须告诉Spring哪个类是切面类(给切面类上加一个注解:@Aspect)。
给配置类中加 @EnableAspectJAutoProxy (开启基于注解的aop模式)
- 在Spring中很多的 @EnableXXX
//开启基于注解的aop模式
@EnableAspectJAutoProxy
@Configuration
public class MainConfigOfAOP { //业务逻辑类加入容器中
@Bean
public MathCalculator calculator(){
return new MathCalculator();
} //切面类加入到容器中
@Bean
public LogAspects logAspects(){
return new LogAspects();
}
}
测试
必须使用Spring容器调用
public class IOCTest_AOP { @Test
public void test01(){
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfAOP.class); //1、不要自己创建对象
// MathCalculator mathCalculator = new MathCalculator();
// mathCalculator.div(1, 1);
MathCalculator mathCalculator = applicationContext.getBean(MathCalculator.class); mathCalculator.div(1, 0); applicationContext.close();
} }
输出
div运行...@Before:参数列表是{[1,0]}
//业务方法运行
MathCalculator...div...
div结束...@After
div异常...异常信息:{java.lang.ArithmeticException: / by zero}
AOP原理
看给容器中注册了什么组件,这个组件什么时候工作,这个组件的功能是什么?
- 先将AnnotationAwareAspectJAutoProxyCreator(注释感知AspectJ自动代理创建器)注入容器
0. AnnotationAwareAspectJAutoProxyCreator[BeanPostProcessor]本身也是Bean,Bean注入的过程如下:- InstantiationAwareBeanPostProcessor实例化后置处理器
- 创建Bean实例
- InstantiationAwareBeanPostProcessor实例化后置处理器
- Bean属性赋值
- 初始化Bean
0. 每一个[自定义等]初始化都要执行,过程如下:- 处理Aware接口的方法回调
- BeanPostProcessor初始化后置处理器前置方法
- [自定义]初始化
- BeanPostProcessor初始化后置处理器后置方法
开始时干了啥?@EnableAspectJAutoProxy注解
@EnableAspectJAutoProxy最终给容器中注册一个AnnotationAwareAspectJAutoProxyCreator(注解装配模式的AspectJ切面自动代理创建器)
- 进入@EnableAspectJAutoProxy
- 发现注解@Import(AspectJAutoProxyRegistrar.class)给容器中导入AspectJAutoProxyRegistrar组件
- 它实现了ImportBeanDefinitionRegistart,这是一个接口,可以实现自定义注册组件(在之前的注入组件文章中讲过)
- 它给容器自定义注册bean定义信息(BeanDefinetion) ,就是org.springframework.aop.config.internalAutoProxyCreator,类型是AnnotationAwareAspectJAutoProxyCreator(注解装配模式的AspectJ切面自动代理创建器)
- 并且判断@EnableAspectJAutoProxy注解并处理信息
AnnotationAwareAspectJAutoProxyCreator继承关系
AnnotationAwareAspectJAutoProxyCreator
-> extends AspectJAwareAdvisorAutoProxyCreator
-> extends AbstractAdvisorAutoProxyCreator
-> extends AbstractAutoProxyCreator
implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware(关注后置处理器(在bean初始化完成前后做事情)、自动装配BeanFactory)
大有来头?分析AnnotationAwareAspectJAutoProxyCreator
查看AnnotationAwareAspectJAutoProxyCreator继承关系中这些类的方法,找出与后置处理器和Bean工厂有关的方法,打断点观察,包括上面注入的ioc入口、业务和AOP。从父类开始:
注意区别两个不同的后置处理器
postProcessBeforeInstantiation 实例化前的后处理(这个是[Smart]InstantiationAwareBeanPostProcessor的)
postProcessBeforeInitialization 初始化前的后处理(这个是BeanPostProcessor的)
- AbstractAutoProxyCreator(抽象自动代理创建者)
- AbstractAutoProxyCreator.setBeanFactory()
- AbstractAutoProxyCreator.有后置处理器的逻辑(postProcessBeforeInstantiation(实例化前的后置处理器))
- AbstractAdvisorAutoProxyCreator.[重写]setBeanFactory()-->{ initBeanFactory() }
- 给AbstractAdvisorAutoProxyCreator.setBeanFactory()打上断点
- AnnotationAwareAspectJAutoProxyCreator.[重写]initBeanFactory()
我注册我?注册AnnotationAwareAspectJAutoProxyCreator
“我”(指BeanPostProcessor)注册“我”(指AnnotationAwareAspectJAutoProxyCreator),这里是说AnnotationAwareAspectJAutoProxyCreator本质是BeanPostProcessor,它自己要按照BeanPostProcessor的方式注册
通过后置处理器注入了一个后置处理器
执行过程
启动程序,首先创建容器
AnnotationConfigApplicationContext
传入配置类,创建ioc容器注册配置类
register()
,调用refresh()
刷新容器refresh()
中有registerBeanPostProcessors(beanFactory)
注册bean的后置处理器(注释:注册拦截 Bean 创建的 Bean 处理器),用来拦截bean的创建后置处理器的注册逻辑:
beanFactory.getBeanNamesForType()
先获取ioc容器已经定义了的需要创建对象的所有BeanPostProcessor
(为什么更启动就有已定义的BeanPostProcessor
?是因为在启动时有一个注解@EnableAspectJAutoProxy
已经注册了一个AnnotationAwareAspectJAutoProxyCreator
和容器中其他一些默认的,只是定义还没创建对象,在上面讲过)- 根据获取的
postProcessorNames
,发现里面有一个org.springframework.aop.config.internalAutoProxyCreator
,就是通过@EnableAspectJAutoProxy
注册的AnnotationAwareAspectJAutoProxyCreator
类型的属性的名字 - 接下来按照
postProcessorNames
来创建对象 beanFactory.addBeanPostProcessor()
给容器中加入别的BeanPostProcessor
- 通过
postProcessorNames
判断是否有实现Ordered
优先级接口的,分别放在一起分步处理- 优先注册实现了
PriorityOrdered
接口的BeanPostProcessor
- 再给容器中注册实现了
Ordered
接口的BeanPostProcessor
- 注册没实现优先级接口的
BeanPostProcessor
- 执行每个优先级中的
beanFactory.getBean(ppName, BeanPostProcessor.class)
,跳转到下一调用创建Bean
- 优先注册实现了
- 注册
BeanPostProcessor
,实际上就是创建BeanPostProcessor
对象,保存在容器中(重要,每次创建Bean都要执行,BeanPostProcessor
本质也是Bean)
0. 下面创建internalAutoProxyCreator
的BeanPostProcessor
类型是AnnotationAwareAspectJAutoProxyCreator
- 创建Bean的实例(先从
beanFactory.getBean()
获取名字,由getBean()
->doGetBean()
,在doGetBean()
中调getSingleton()
获取单实例的bean,第一次没有,所以用singletonFactory.getObject()
->createBean()
->doCreateBean()
->createBeanInstance()
创建bean实例,下面进行初始化。如同之前讲过的BeanPostProcessor
原理) populateBean(beanName,mbd,instanceWrapper)
:给bean的各种属性赋值initializeBean(beanName,exposedObject,mbd)
:初始化beaninvokeAwareMethods(beanName,bean)
:处理Aware接口的方法回调- 先判断是否是
BeanFactoryAware
类型,然后到达AbstractAutoProxyCreator.setBeanFactory(beanFactory)
方法,就是上面分析AnnotationAwareAspectJAutoProxyCreator
的父类AbstractAutoProxyCreator
。 - 然后执行
initBeanFactory(beanFactory)
初始化BeanFacotry
- 先判断是否是
applyBeanPostProcessorsBeforeInitialization()
:应用后置处理器的postProcessBeforeInitialization()
invokeInitMethods(beanName,wrappedBean,mbd)
:执行自定义的初始化方法applyBeanPostProcessorsAfterInitialization()
:执行后置处理器的postProcessAfterInitialization()
BeanPostProcessor(AnnotationAwareAspectJAutoProxyCreator)
创建成功
- 创建Bean的实例(先从
- 把
BeanPostProcessor(AnnotationAwareAspectJAutoProxyCreator)
注册到BeanFactory
中,beanFactory.addBeanPostProcessor(postProcessor)
给BeanFactory
添加新的BeanPostProcessor
。
以上是创建和注册AnnotationAwareAspectJAutoProxyCreator
的过程
- 根据获取的
部分源码
注册后置处理器
public static void registerBeanPostProcessors(
ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) { String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false); // 注册记录信息消息的BeanPostProcessorChecker
// bean是在BeanPostProcessor实例化期间创建的
// bean不适合被所有BeanPostProcessors处理。
int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount)); // 在实现prioritordered、Ordered和其他功能的BeanPostProcessors之间分离。
List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<BeanPostProcessor>();
List<BeanPostProcessor> internalPostProcessors = new ArrayList<BeanPostProcessor>();
List<String> orderedPostProcessorNames = new ArrayList<String>();
List<String> nonOrderedPostProcessorNames = new ArrayList<String>();
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);
}
} // 首先,注册实现prioritordered的BeanPostProcessors。
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors); // 接下来,注册实现Ordered的BeanPostProcessors。
List<BeanPostProcessor> orderedPostProcessors = new ArrayList<BeanPostProcessor>();
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); // 现在,注册所有常规的BeanPostProcessors。
List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<BeanPostProcessor>();
for (String ppName : nonOrderedPostProcessorNames) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
nonOrderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors); // 最后,重新注册所有内部BeanPostProcessors。
sortPostProcessors(internalPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, internalPostProcessors); // 将用于检测内部bean的后处理器重新注册为applicationlistener,
// 将它移动到处理器链的末端(用于获取代理等)。
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
}
属性赋值与初始化
// 初始化bean实例
Object exposedObject = bean;
try {
// 属性赋值
populateBean(beanName, mbd, instanceWrapper);
if (exposedObject != null) {
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
}
初始化BeanFacotry
public void setBeanFactory(BeanFactory beanFactory) {
super.setBeanFactory(beanFactory);
if (!(beanFactory instanceof ConfigurableListableBeanFactory)) {
throw new IllegalArgumentException("AdvisorAutoProxyCreator requires a ConfigurableListableBeanFactory: " + beanFactory);
} else {
//初始化BeanFacotry
this.initBeanFactory((ConfigurableListableBeanFactory)beanFactory);
}
}
运行时栈信息
beanFactory.getBeanNamesForType()
先获取ioc容器已经定义了的需要创建对象的所有BeanPostProcessor
创建bean
把
BeanPostProcessor
注册到BeanFactory
中,给BeanFactory
添加BeanPostProcessor
你比我快?AnnotationAwareAspectJAutoProxyCreator执行时机
“你”(指AnnotationAwareAspectJAutoProxyCreator)比“我”(指BeanPostProcessor)快,这里是说AnnotationAwareAspectJAutoProxyCreator早于某些BeanPostProcessor执行,可以提前实例化一些组件
上面代码执行后,注册了AnnotationAwareAspectJAutoProxyCreator,它是一个后置处理器,当其他组件在创建对象时,都要经过创建Bean实例、给Bean属性赋值、初始化及前后处理器,所以它可以拦截到这些组件的创建过程,接下来要看它作为后置处理器都做了什么?
执行流程
接着上面的AbstractAutoProxyCreator.setBeanFactory(beanFactory)执行,然后调用AbstractAutoProxyCreator.postProcessBeforeInstantiation(),注意区分[Smart]InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation()和BeanPostProcessor.postProcessBeforeInitialization(),这一点上面分析AnnotationAwareAspectJAutoProxyCreator时也有提到,为什么会调用这个方法?在整个程序开始时,AnnotationConfigApplicationContext创建ioc容器注册配置,register()调用refresh()刷新容器,上面第(3)步执行的是registerBeanPostProcessors(beanFactory)注册bean的后置处理器方法,在它下面有一个finishBeanFactoryInitialization(beanFactory)方法
finishBeanFactoryInitialization(beanFactory)
:完成BeanFactory初始化工作,创建剩下的单实例bean遍历获取容器中所有的Bean,依次创建对象(这一步还没创建,只是获取,下一步才创建)
DefaultListableBeanFactory.getBean(beanName)
->AbstractBeanFactory.getBean()->doGetBean()->getSingleton(beanName, new ObjectFactory<Object>())
=>创建Bean实例,返回一个sharedInstance
属性,注释是"Create bean instance"(创建bean实例)
- 观察之前的代码,发现sharedInstance已经创建
Object sharedInstance = getSingleton(beanName)
注释是"Eagerly check singleton cache for manually registered singletons(急切地检查单例缓存中是否有手动注册的单例)"
- 可以发现Bean不是直接创建出来的
创建bean
先从缓存中获取当前bean,如果能获取到,说明bean是之前被创建过的,直接使用,否则再创建。只要创建好的Bean都会被缓存起来
执行
getSingleton(beanName, new ObjectFactory<Object>())
参数中的匿名内部类方法createBean()
:创建beancreateBean()
创建bean包括RootBeanDefinition mbd
是bean的定义信息等,继续执行resolveBeforeInstantiation(beanName, mbdToUse)
注释是"Give BeanPostProcessors a chance to return a proxy instead of the target bean instance"(让BeanPostProcessors有机会返回一个代理而不是目标bean实例)
解析
BeforeInstantiation
,希望后置处理器在此能返回一个代理对象如果能返回代理对象就使用,如果不能就继续,后置处理器先尝试返回对象:
- 分析:
AnnotationAwareAspectJAutoProxyCreator
会在任何bean创建之前先尝试返回bean的实例InstantiationAwareBeanPostProcessor
是在创建Bean实例之前先尝试用后置处理器返回对象的BeanPostProcessor
是在Bean对象创建完成[自定义]初始化前后调用的- 【
InstantiationAwareBeanPostProcessor
是在构造方法前后执行(就在这一步),BeanPostProcessor
是在Bean属性赋值[初始化之后],自定义初始化前后执行(就在下一步)】
//拿到所有后置处理器,如果是InstantiationAwareBeanPostProcessor就执行postProcessBeforeInstantiation
bean = applyBeanPostProcessorsBeforeInstantiation():
if (bean != null) {
bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
}
//------------
if (bp instanceof InstantiationAwareBeanPostProcessor) {
ibp.postProcessBeforeInstantiation(beanClass, beanName);
}
doCreateBean(beanName, mbdToUse, args)
:真正的去创建一个bean实例,包括createBeanInstance()
创建Bean实例、populateBean()
属性赋值、initializeBean()
初始化Bean、Aware接口、前置后置等,和上一节的(3.4)一样
部分源码
创建一个 Bean 实例
/**
* 此类的中心方法:创建一个 Bean 实例,
* 填充 Bean 实例、应用后处理器等。
* @see #doCreateBean
*/
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException {
if (logger.isDebugEnabled()) {
logger.debug("Creating instance of bean '" + beanName + "'");
}
RootBeanDefinition mbdToUse = mbd; // 确保此时实际解析了 Bean 类,并且
// 在动态解析类的情况下克隆 Bean 定义
// 不能存储在共享的合并 Bean 定义中。
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
mbdToUse = new RootBeanDefinition(mbd);
mbdToUse.setBeanClass(resolvedClass);
} // 准备方法覆盖。
try {
mbdToUse.prepareMethodOverrides();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
beanName, "Validation of method overrides failed", ex);
} try {
// 给 BeanPostProcessors 一个返回代理而不是目标 Bean 实例的机会。
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
}
catch (Throwable ex) {
throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
"BeanPostProcessor before instantiation of bean failed", ex);
}
// 实际创建指定的bean
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
if (logger.isDebugEnabled()) {
logger.debug("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
}
尝试返回一个代理
protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
Object bean = null;
if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
// 确保此时实际解析了 Bean 类。
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
Class<?> targetType = determineTargetType(beanName, mbd);
if (targetType != null) {
bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
if (bean != null) {
bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
}
}
}
mbd.beforeInstantiationResolved = (bean != null);
}
return bean;
}
运行时栈信息
准备实例化
你先我后?创建AOP代理
“你”(指AnnotationAwareAspectJAutoProxyCreator[类型是InstantiationAwareBeanPostProcessor])先“我”(指其他某些BeanPostProcessor)后
经过上面的流程,已经知道创建Bean需要调用AnnotationAwareAspectJAutoProxyCreator[类型是InstantiationAwareBeanPostProcessor]的后置处理器,然后才是初始化前后的BeanPostProcessor后置处理器,下面关心在AnnotationAwareAspectJAutoProxyCreator.postProcessBeforeInstantiation()中都做了什么操作
执行过程
- 继续上节倒数第二步,进入应用后置处理器中,每一个bean创建之前,调用
InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation()
0. 关心MathCalculator[业务类]
和LogAspect[切面类]
的创建this.advisedBeans.contaionsKey(cacheKey)
判断当前bean是否在advisedBeans
中(保存了所有需要增强bean)?现在没有isInfrastructureClass(beanClass)
判断当前bean是否是基础类型的Advice、Pointcut、Advisor、AopInfrastructureBean
,this.aspectJAdvisorFactory.isAspect(beanClass)
或者是否是切面(通过有没有@Aspect
注解判断)shouldSkip(beanClass,beanName)
是否需要跳过List<Advisor> candidateAdvisors = findCandidateAdvisors()
找到候选的增强器(增强器就是自定义的LogAspect
切面中通知方法),每一个封装的通知方法的增强器是InstantiationModelAwarePointcutAdvisor: expression [pointCut()]; advice method [public void com.atguigu.aop.LogAspects.logStart(org.aspectj.lang.JoinPoint)]
,判断每一个增强器是否是AspectJPointcutAdvisor
类型的,是就返回true,现在都不是
- 然后创建bean对象后,(在初始化后)执行
[AbstractAutoProxyCreator]BeanPostProcessor.postProcessAfterInitialization()
0. 进入return wrapIfNecessary(bean, beanName, cacheKey)
如有必要,就包装,只有被代理类才会创建代理对象Object[] specificInterceptors=getAdvicesAndAdvisorsForBean(bean.getClass(),beanName,null)
注释是Create proxy if we have advice(如果我们有通知方法,请创建代理)
获取当前bean的所有增强器(通知方法),进入findEligibleAdvisors(beanClass,beanName)
找到候选的所有的增强器(找哪些通知方法是需要切入当前bean方法的)- 获取到能在bean使用的增强器,如切入点表达式
- 给增强器排序
- 已经获取到可用增强器,保存当前bean在已增强集合中
this.advisedBeans.put()
- 如果当前bean需要增强,创建当前bean的代理对象
Object proxy = createProxy()
- 获取所有增强器(通知方法)
- 保存到
proxyFactory
- 创建代理对象
proxyFactory.getProxy(getProxyClassLoader())
:Spring自动决定两种方式JdkDynamicAopProxy(config)
:jdk动态代理(需要接口);ObjenesisCglibAopProxy(config)
:cglib的动态代理;
- 创建完成后得到的bean的增强代理对象
- 给容器中返回当前组件使用cglib增强了的代理对象
- 以后容器中获取到的就是这个组件的代理对象
MathCalculator(业务类)$EnhancerBySpringCGLIB
,执行目标方法的时候,代理对象就会执行通知方法的流程
部分源码
如果必要包装
//必要时包装给定的bean,即,如果它符合被代理的条件。
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
//...
// 如果我们有建议,请创建代理。
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;
}创建代理
// 创建一个CGLIB代理或JDK动态代理。
@Override
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)) {
// 创建JDK动态代理
return new JdkDynamicAopProxy(config);
}
// 创建CGLIB代理
return new ObjenesisCglibAopProxy(config);
}
else {
return new JdkDynamicAopProxy(config);
}
}
如此包装?获取拦截器链MethodInterceptor
如此“包装”(将切入点增强器包装为方法拦截器)
接着上面代码执行,在上面已经获取到被代理后的对象,现在需要把所有的增强方法转为MethodInterceptor类型。
执行过程
(被代理后的)目标方法执行:容器中保存了组件的代理对象(cglib增强后的对象),这个对象里面保存了详细信息(比如增强器,目标对象,xxx)
debug 从ioc容器中的目标方法执行开始进入下一步(或者:入-出-出-入-出-入-出-入)
CglibAopProxy.intercept()
:拦截目标方法的执行根据
ProxyFactory
对象获取将要执行的目标方法拦截器链:List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass)
List<Object> interceptorList = new ArrayList<Object>(config.getAdvisors().length)
保存所有拦截器,拦截器列表长度就是config.getAdvisors()
长度,等于5。包括一个默认的ExposeInvocationInterceptor
和 4个(自定义)增强器- 遍历所有的增强器,如果是切入点的增强器,将其转为拦截器
MethodInterceptor
,MethodInterceptor[] interceptor = registry.getInterceptors(advisor)
3. 将增强器转为List<MethodInterceptor>
拦截器- 如果是
MethodInterceptor
,直接加入到集合中 - 如果不是,使用
AdvisorAdapter
将增强器转为MethodInterceptor
3. 转换完成返回MethodInterceptor
数组
- 如果是
或者本身是
Interceptor
,或者由其他类型转为MethodInterceptor
,最终返回拦截器列表(此次是5个)
如果没有拦截器链
chain.isEmpty()
,直接执行目标方法methodProxy.invoke()
- 如果有拦截器链,把需要执行的目标对象,目标方法,拦截器链等信息传入创建一个
CglibMethodInvocation
对象,并调用Object retVal = new CglibMethodInvocation(proxy,traget,method,args,targetClass,chain,methodProxy).proceed()
继续执行
- 如果有拦截器链,把需要执行的目标对象,目标方法,拦截器链等信息传入创建一个
部分源码
代理对象刚执行时的拦截方法
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
Class<?> targetClass = null;
Object target = null;
try {
if (this.advised.exposeProxy) {
// 在必要时使调用可用。
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// 可能为空。尽可能晚地减少我们“拥有”目标的时间,以防它来自池...
target = getTarget();
if (target != null) {
targetClass = target.getClass();
}
// 获取拦截器链
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
Object retVal;
// 检查是否有拦截器链
if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
// 我们可以跳过创建方法调用:只需直接调用目标即可。请注意,最终的调用程序必须是 InvokerInterceptor,因此我们知道它只对目标执行反射操作,并且没有热插拔或花哨的代理。
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = methodProxy.invoke(target, argsToUse);
}
else {
// 我们需要创建一个方法调用(执行目标方法)...
retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
}
retVal = processReturnType(proxy, target, method, retVal);
return retVal;
}
//...
}
包装拦截器
@Override
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
Advised config, Method method, Class<?> targetClass) { // 这有点棘手...我们必须首先处理介绍,但我们需要保持最终列表中的秩序。
List<Object> interceptorList = new ArrayList<Object>(config.getAdvisors().length);
Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
boolean hasIntroductions = hasMatchingIntroductions(config, actualClass);
AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance(); for (Advisor advisor : config.getAdvisors()) {
if (advisor instanceof PointcutAdvisor) {
// 有条件地添加它。
PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
// 转为拦截器
MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
if (MethodMatchers.matches(mm, method, actualClass, hasIntroductions)) {
if (mm.isRuntime()) {
// 在 getInterceptors()方法中创建新的对象实例不是问题,因为我们通常缓存创建的链。
for (MethodInterceptor interceptor : interceptors) {
interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
}
}
else {
interceptorList.addAll(Arrays.asList(interceptors));
}
}
}
}
else if (advisor instanceof IntroductionAdvisor) {
// ...将其余类型都转为拦截器
}
return interceptorList;
}
喵啊?链式调用通知方法
妙啊,执行过程设计的很有趣
所有准备都做好了(创建代理,增强器排序(倒序),增强器包装获取拦截器链),现在开始调用通知方法
执行过程
- 拦截器链的触发过程:
- 如果没有拦截器执行执行目标方法,或者拦截器的索引和拦截器数组-1大小一样(执行到了最后一个拦截器)执行目标方法
- 链式获取每一个拦截器,拦截器执行invoke方法,每一个拦截器等待下一个拦截器执行完成返回以后再来执行。拦截器链的机制,保证通知方法与目标方法的执行顺序
5个拦截器(1个默认+4个自定义)的执行顺序
执行上一节最后一步,获取到拦截器链后执行new CglibMethodInvocation(proxy,traget,method,args,targetClass,chain,methodProxy).proceed()
的proceed()
方法
- 进入
proceed()
方法,先判断currentInterceptorIndex
索引的值,默认是-1。this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1 -->{return invokeJoinpoint()}
- 判断是否有拦截器,如果没有
0 - 1 = -1
,正好等于默认值,没有拦截器,就直接执行目标方法(业务)method.invoke(target,args)
- 判断是否是否要执行目标方法。程序多次执行,每加载一个拦截器,就+1,直到最后一个拦截器时,
this.currentInterceptorIndex=4
(从-1到4),判断4 == 5 - 1
,拦截器加载完了,开始执行目标方法(业务)。 - 开始执行
-1 == 5 - 1
不通过,表示有拦截器,执行this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex)
,从-1到0,获取第0号拦截器。- 第 [0] 号拦截器是默认拦截器
ExposenvocationInterceptor
调用invoke(this)
,参数this
就是被代理目标类(业务类)CgliMethodInvocation
,进入invoke(this)
,里面调用mi[MethodInvocation].proceed()
,这个proceed()
就是本节第(1)步的proceed()
,每个拦截器都会执行 - 获取索引为 [1] 的拦截器
AspectJAfterThrowingAdvice
前置拦截器->判断->自增->invoke(this)
->mi.proceed()
- 获取索引为 [2] 的拦截器
AfterReturingAdviceInterceptor
返回通知拦截器->判断->自增->invoke(this)
->mi.proceed()
- 获取索引为 [3] 的拦截器
AspectJAfterAdvice
->判断->自增->invoke(this)
->mi.proceed()
- 获取索引为 [4] 的拦截器
MethodBeforeAdviceInterceptor
前置拦截器->判断->自增->invoke(this)
{ 这里与之前不同,因为是前置通知,所以要在目标方法执行前先执行增强方法,this.advice.before(mi.getMethod(),mi.getArguments(),mi.getThis())
此时执行自定义的前置通知 }->mi.proceed()
- 执行完最后一个拦截器,满足条件
4 = 5 - 1
,所以进入判断执行invokeJoinpoint()
利用反射执行目标方法(业务),到达底部同时准备返回
- 开始返回
- 执行完目标方法,返回到第 [3] 个拦截器
AspectJAfterAdvice
执行最终通知,不管是否有异常finally{ invokeAdviceMethod(getJoinPointMatch(),null,null) }
- 继续返回,到第 [2] 个拦截器,
AfterReturingAdviceInterceptor
执行返回通知,但是目标方法抛了异常,此处代码将异常继续上抛throws Throwable
,所以此处不做任何执行,如果没有异常,就正常调用返回通知this.advice.afterReturning()
- 继续返回,到第 [1] 个拦截器,
AfterReturingAdviceInterceptor
执行异常通知,它可以处理异常catch(Throwable ex){ if(){invokeAdviceMethod(getJoinPointMatch(),null,ex)} throw ex }
- 继续返回,自定义增强方法执行完了,执行第 [0] 个默认拦截器
- 增强方法执行过程:逆向执行拦截器,到达底部执行目标方法,返回时正向执行增强方法
部分源码
获取拦截器后继续方法调用
@Override
public Object proceed() throws Throwable {
// 我们从 -1 的索引开始,并提前递增。
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
} // 每次将索引自增
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
// 在此处评估动态方法匹配器:静态部分将已经过评估并发现匹配。
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
}
else {
// 动态匹配失败。
// 跳过此侦听器并调用链中的下一个侦听器。
return proceed();
}
}
else {
// 调用这个
// 它是一个拦截器,所以我们只需调用它:在构造此对象之前,切入点将进行静态计算。
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
依次调用拦截器的
mi.proceed()
异常通知:AspectJAfterThrowingAdvice
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
try {
return mi.proceed();
}
catch (Throwable ex) {
if (shouldInvokeOnThrowing(ex)) {
invokeAdviceMethod(getJoinPointMatch(), null, ex);
}
throw ex;
}
}
返回通知:AspectJAfterReturningAdvice
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
Object retVal = mi.proceed();
this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
return retVal;
}
后置通知:AspectJAfterAdvice
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
try {
return mi.proceed();
}
finally {
invokeAdviceMethod(getJoinPointMatch(), null, null);
}
}
前置通知:AspectJMethodBeforeAdvice
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() );
return mi.proceed();
}
调完拦截器之后执行目标方法
满足条件执行目标方法
// 我们从-1的索引和早期的增量开始。
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
然后一层层向上返回拦截器,并处理通知(除了前置通知,因为它已经在目标方法前执行了)
如下:它返回到异常通知拦截器,并处理异常
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
try {
return mi.proceed();
}
catch (Throwable ex) {
if (shouldInvokeOnThrowing(ex)) {
//处理异常
invokeAdviceMethod(getJoinPointMatch(), null, ex);
}
throw ex;
}
}
总结
@EnableAspectJAutoProxy
开启AOP功能@EnableAspectJAutoProxy
会给容器中注册一个组件AnnotationAwareAspectJAutoProxyCreator
AnnotationAwareAspectJAutoProxyCreator
是一个后置处理器- 容器的创建流程:
registerBeanPostProcessors()
注册后置处理器,创建AnnotationAwareAspectJAutoProxyCreator
对象finishBeanFactoryInitialization()
初始化剩下的单实例bean- 创建业务逻辑组件和切面组件
AnnotationAwareAspectJAutoProxyCreator
拦截组件的创建过程- 组件创建完之后,判断组件是否需要增强
如果是:切面的通知方法,包装成增强器(Advisor);给业务逻辑组件创建一个代理对象(cglib);
- 执行目标方法:
- 代理对象执行目标方法
CglibAopProxy.intercept()
- 得到目标方法的拦截器链(增强器包装成拦截器
MethodInterceptor
) - 利用拦截器的链式机制,依次进入每一个拦截器进行执行;
- 效果:
正常执行:前置通知-》目标方法-》后置通知-》返回通知
出现异常:前置通知-》目标方法-》后置通知-》异常通知
- 得到目标方法的拦截器链(增强器包装成拦截器
浅尝Spring注解开发_AOP原理及完整过程分析(源码)的更多相关文章
- 浅尝Spring注解开发_Servlet3.0与SpringMVC
浅尝Spring注解开发_Servlet 3.0 与 SpringMVC 浅尝Spring注解开发,基于Spring 4.3.12 Servlet3.0新增了注解支持.异步处理,可以省去web.xml ...
- 浅尝Spring注解开发_Bean生命周期及执行过程
Spring注解开发 浅尝Spring注解开发,基于Spring 4.3.12 包含Bean生命周期.自定义初始化方法.Debug BeanPostProcessor执行过程及在Spring底层中的应 ...
- 浅尝Spring注解开发_自定义注册组件、属性赋值、自动装配
Spring注解开发 浅尝Spring注解开发,基于Spring 4.3.12 包含自定义扫描组件.自定义导入组件.手动注册组件.自动注入方法和参数.使用Spring容器底层组件等 配置 @Confi ...
- spring注解开发-扩展原理(源码)
1.BeanFactoryPostProcessor BeanPostProcessor:bean后置处理器,bean创建对象初始化前后进行拦截工作的; BeanFactoryPostProcesso ...
- Spring注解开发_Spring容器创建概述
浅尝Spring注解开发_Spring容器创建概述 浅尝Spring注解开发,基于Spring 4.3.12 概述Spring容器创建的过程,包括12个方法的执行 浅尝Spring注解开发_自定义注册 ...
- Spring注解开发-全面解析常用注解使用方法之生命周期
本文github位置:https://github.com/WillVi/Spring-Annotation/ 往期文章:Spring注解开发-全面解析常用注解使用方法之组件注册 bean生命周期 ...
- Annotation(三)——Spring注解开发
Spring框架的核心功能IoC(Inversion of Control),也就是通过Spring容器进行对象的管理,以及对象之间组合关系的映射.通常情况下我们会在xml配置文件中进行action, ...
- spring注解开发中常用注解以及简单配置
一.spring注解开发中常用注解以及简单配置 1.为什么要用注解开发:spring的核心是Ioc容器和Aop,对于传统的Ioc编程来说我们需要在spring的配置文件中邪大量的bean来向sprin ...
- JAVAEE——SSH项目实战06:统计信息管理、Spring注解开发和EasyUI
作者: kent鹏 转载请注明出处: http://www.cnblogs.com/xieyupeng/p/7190925.html 一.统计信息管理 二.Spring注解开发 1.service ...
随机推荐
- 使用 RabbitMQ 有什么好处?
(1)服务间高度解耦 (2)异步通信性能高 (3)流量削峰
- Kafka 的高可靠性是怎么实现的?
可以参见我这篇文章:Kafka 是如何保证数据可靠性和一致性
- Spring配置文件?
Spring配置文件是个XML 文件,这个文件包含了类信息,描述了如何配置它们,以及如何相互调用.
- OGNL(Object-Graph Navigation Language)使用
OGNL表达式:https://www.jianshu.com/p/6bc6752d11f4 Apache OGNL:http://commons.apache.org/proper/commons- ...
- SpringAOP+RabbitMQ+WebSocket实战
背景 最近公司的客户要求,分配给员工的任务除了有微信通知外,还希望PC端的网页也能实时收到通知.管理员分配任务是在我们的系统A,而员工接受任务是在系统B.两个系统都是现在已投入使用的系统. 技术选型 ...
- java后端使用token处理表单重复提交
保证接口幂等性,表单重复提交 前台解决方案:提交后按钮禁用.置灰.页面出现遮罩后台解决方案: 使用token,每个token只能使用一次1.在调用接口之前生成对应的Token,存放至redis 2 ...
- Samba通过Openldap统一认证
1.环境准备1.1.实验环境[root@moban ~]# cat /etc/redhat-releaseCentOS release 6.8 (Final)[root@moban ~]# uname ...
- ACM - 最短路 - CodeForces 295B Greg and Graph
CodeForces 295B Greg and Graph 题解 \(Floyd\) 算法是一种基于动态规划的算法,以此题为例介绍最短路算法中的 \(Floyd\) 算法. 我们考虑给定一个图,要找 ...
- C语言常用字符串函数
string.h头文件中常用的函数 C 库函数 - strcat() char *strcat(char *dest, const char *src) 把 src 所指向的字符串追加到 dest 所 ...
- PC端免费高效的同声翻译
疫情期间上网课,对于英语听力较差或者需要观看英文视频,但实际上并没有双语字幕的这种情况下需要找一个实时的翻译工具.虽然说手机上此类软件比较多,但电脑上没有特别合适的应用可以做为一个免费实时翻译.哪怕是 ...