准备
我们通过AOP实现日志记录来剖析AOP
/**
* 日志切面
*
* 实现日志记录
*/
@Aspect
@Component
public class LogAspect {
public LogAspect(){
System.out.println("LogAspect 构造方法");
}
/**
* 将指定注解作为切入点
*/
@Pointcut("@annotation(com.xiaoxu.annotation.Log)")
public void log(){}
/** 下面定义joinPoint 切入时机+ 增强代码 **/
@Before("log()")
public void before(JoinPoint joinPoint){
System.out.println("Signature: "+joinPoint.getSignature());
System.out.println("Args: "+joinPoint.getArgs());
System.out.println("this: "+joinPoint.getThis());
System.out.println("before method ");
}
@AfterThrowing(pointcut = "log()",throwing = "exception")
public void AfterThrowing(JoinPoint joinPoint, Exception exception){
System.out.println("exception: "+ exception);
System.out.println("AfterThrowing method ");
}
@AfterReturning(pointcut = "log()",returning = "result")
public void AfterReturning(JoinPoint joinPoint,Object result){
System.out.println("result: "+result);
System.out.println("AfterReturning method");
}
@After("log()")
public void after(){
System.out.println("after method");
}
}
/**
* 核心配置类
*/
@Configuration
@ComponentScan({"com.xiaoxu"})
@EnableAspectJAutoProxy // 开启Spring对注解AOP的支持
public class ApplicationContextConfiguration {
}
测试类
@EnableAspectjAutoProxy分析
我们在配置类上标识了@EnableAspectJAutoProxy,表示开启AOP注解模式
@Import注册组件默认有三种方式
1、直接注册XXXX.class
2、通过ImportSelector注册组件
3、通过ImportBeanDefinitionRegistrar注册组件
@EnableAspectAutoProxy,通过@Import 的第三种方式,实现的AspectJAutoProxyRegistrar.class。向容器中注入组件
可以看到AspectJAutoProxyRegistrar 向容器中注入AnnotationAwareAspectJAutoProxyCreator 组件
好了我们现在知道 @EnableAspectjAutoProxy 通过@Import向容器中注入AnnotationAwareAspectJAutoProxyCreator 组件,而这个自动代理创建器,本质上,就是一个BeanPostProcessor。
refresh方法
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 刷新前预处理
prepareRefresh();
// 获取之前创建的BeanFactory,默认实现DefaultListableBeanFactory
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// BeanFactory的预准备⼯作(BeanFactory进⾏⼀些设置,设置类加载器,环境等等。
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// 实例化并调用默认配置,和自定义的BeanFactoryPostProcessor,实现核心配置类解析,包组件扫描封装BeanDefinition.
invokeBeanFactoryPostProcessors(beanFactory);
// 注册默认配置的和自定义的BeanPostProcessor , 实现bean创建赋值之后 init 方法前后调用
registerBeanPostProcessors(beanFactory);
// 初始化MessageSource组件,实现 国际化功能,消息绑定,消息解析
initMessageSource();
// 初始化应用事件派发器
initApplicationEventMulticaster();
// 子类重写
onRefresh();
// 注册实现了ApplicationListener接⼝的监听器
registerListeners();
// 实例化剩下的所有单例bean
finishBeanFactoryInitialization(beanFactory);
// 发布事件,交由其它组件触发对应响应,例如springMVC初始化
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}
AOP实现分析
1、注意InvokeBeanFactoryPostProcessor,Spring注册并调用了ConfigurationClassBeanPostProcessor
我们之前知道Spring通过ConfigurationClassBeanPostProcessor实现对我们自定义@Configuration核心配置类解析,而配置类上存在@EnbaleAspectjAutoProxy,那么此时也会解析这个注解,这个注解通过@Import,向容器中注册了AnnotationAwareAspectJAutoProxyCreator (简称AspectAutoProxyCreator)
可以看到目前容器中目前并没有注册AspectjAutoProxyCreator(切面自动代理创建器)
此时可以看到容器中注册了组件 ApsectjAutoProxyCreator
2、向Spring一级缓存池中注册默认的,自定义的BeanPostProcessor,包含之前的AspectjAutoProxyCreator后置处理器
3、实例化所有单例Bean,我们只关注AopTestController
将AopTestController放入三级缓存
对AopTestController进行属性赋值,依赖注入
对AopTestController进行初始化
调用XXXAware接口的set方法
4、遍历所有后置处理器的before方法,可以看到AspectjAutoProxyCreator的Before方法什么都没做
调用AopTestController init 方法
5、遍历所有后置处理器的after方法,可以看到AspectjAutoProxyCreator的after方法,主要判断当前Bean 对象需不需要代理,如果能够找到当前Bean对应的Advice增强方法,那么当前Bean就是需要代理的。通过cglib enhance或者jdk proxy实现代理对象创建
如果有必要则,创建代理。如果找到了当前Bean的增强方法,那么当前的Bean就是需要代理的。
寻找可用的增强方法为当前bean,可以看到找到了我们在Aspect类配置的增强方法,既然找到了增强方法,那么为当前Bean创建代理对象
可以看到代理对象创建成功
6、将代理对象放入一级缓存池,移除二三级缓存的当前对象
代理对象内部封装了该对象的增强方法
总结:
Spring Aop 代理对象创建流程
1、@EnableAspectAutoproxy注解,通过@Import,和register向IOC容器的BeanDefinintonMap中注册了一个组件AnnotationAwareAspectJAutoProxyCreator ,切面自动配置创建器,本质上是一个BeanPostProcessor
2、Spring通过调用ConfigurationClassPostProcessor解析核心配置类,扫描类路径下的组件进入BeanDefinitionMap中,解析@EnableAspectAutoproxy,向容器中注入AnnotationAwareAspectJAutoProxyCreator。
3、实例化默认和自定义的BeanPostProcessor,包含这个AspectjAutoProxyCreator
4、实例化所有单例Bean --》 对Bean进行依赖注入 --》 调用 XXXAware set方法
–》遍历所有BeanPostProcessor 的Before方法
–》调用当前Bean init 方法
–》遍历所有BeanPostProcessor的After方法 ,其中AspectjAutoProxyCreator 获取当前Bean 所有的advice增强方法,如果存在增强方法,通过cglib enhance和 jdk proxy 进行代理,生成代理对象,将对应的增强方法全部放入代理对象中
5、将代理对象,放入一级缓存
注意:循环依赖的化,代理对象存放是有区别的