Spring AOP源码
2019-08-16 12:12:02来源:博客园 阅读 ()
Spring AOP源码
结合 Spring 后置处理器源码 和 Spring Aware源码 ,再来看下 Spring AOP 的源码。
启动 AOP
使用 @EnableAspectJAutoProxy 这个注解来启用 AOP 的能力了。它使用 @Import 导入类 AspectJAutoProxyRegistrar,这个类实现了 ImportBeanDefinitionRegistrar,所以它会被 ConfigurationClassParser 扫描,并加入缓存中。然后 ConfigurationClassBeanDefinitionReader 从缓存中会拿到这个类,再执行其实现的方法 registerBeanDefinitions()。
AspectJAutoProxyRegistrar.registerBeanDefinitions() 源码
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
}
上述方法又使用 AOP 配置工具类 AopConfigUtils 将 AnnotationAwareAspectJAutoProxyCreator 也注册到 BeanFactory,其 name 为 org.springframework.aop.config.internalAutoProxyCreator。
下图,展示了 AnnotationAwareAspectJAutoProxyCreator 的类继承关系
可以看出来 AnnotationAwareAspectJAutoProxyCreator 就是 BeanPostProcessor 和 Aware,其顶层抽象类 AbstractAutoProxyCreator 实现它们的接口。
创建代理对象
Spring Aware源码 中可知,BeanFactoryAware 实现类会在 invokeAwareMethods() 被回调 setBeanFactory() 方法,将 DefaultListableBeanFactory 注入给 AnnotationAwareAspectJAutoProxyCreator。
InstantiationAwareBeanPostProcessor 新增了后置处理器方法 postProcessBeforeInstantiation() 和 postProcessAfterInstantiation(),这两个方法会在 Bean 初始化之前,也就是在 BeanPostProcessor 定义的方法之前先调用。
- postProcessBeforeInstantiation() 会在反射调用 Bean 的构造器之前调用。
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
// 会返回一个代理对象,会执行 postProcessBeforeInstantiation()
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
return doCreateBean(beanName, mbdToUse, args);
}
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
// 从缓存获取
Object cacheKey = getCacheKey(beanClass, beanName);
if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
// 判断是否已经在 advisedBeans 缓存
if (this.advisedBeans.containsKey(cacheKey)) {
return null;
}
// 判断 Bean 是否是 Advice/Pointcut/Advisor/AopInfrastructureBean 这些不需要代理的基础类型;或者是否 @Aspect 注解类
// 找到切面类中的所有通知方法,判断是否 AspectJPointcutAdvisor 类型,否则返回 false
if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return null;
}
}
return null;
}
- postProcessAfterInstantiation() 会在给属性赋值的方法 populateBean() 中执行。
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args) {
// 属性赋值,会执行 postProcessAfterInstantiation()
populateBean(beanName, mbd, instanceWrapper);
// 执行 BeanPostProcessor 的方法
return initializeBean(beanName, exposedObject, mbd);
}
- BeanPostProcessor 的方法是在 initializeBean() 中才执行的。其中 postProcessAfterInitialization() 方法会获取切面类的所有通知方法,利用动态代理技术,创建增强的代理对象(比如:
com.xxx.Service$$EnhancerBySpringCGLIB$$e86c6525@57eda880
),同时会设置回调方法,完成后返回。
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
// 包装
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
// 包装类
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
// 找到所有的候选通知方法
List<Advisor> candidateAdvisors = findCandidateAdvisors();
// 从候选通知方法找到可用于当前 Bean 的通知
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
// 获取所有的通知拦截器对象
Object[] specificInterceptors = eligibleAdvisors.toArray();
// 利用 AopProxy 来创建代理对象
// AopProxy 包含 JDK 和 CGLib 两种实现
Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
return proxy;
}
至此,动态代理对象以及创建完成了,容器中就会有这个增强后的代理对象,方法执行时,也就会利用这个代理对象来执行通知方法了。
执行代理对象
执行被代理的方法时,会被 CglibAopProxy 拦截器拦截,获取这个方法的拦截器链。如果有拦截器链,则创建 CglibMethodInvocation 对象,执行 proceed(),即执行通知方法,最后返回 retVal,即方法的返回值;如果没有拦截器链,则直接执行方法;
拦截器链实际上就是把方法拦截器放在 ArrayList 队列中,第一个默认是 ExposeInvocationInterceptor,剩下的默认顺序为 AspectJAfterThrowingAdvice、AspectJAfterReturningAdvice、AspectJAfterAdvice、AspectJAroundAdvice、AspectJMethodBeforeAdvice。
proceed() 按照上面 ArrayList 中的顺序递归调用,当遇到 AspectJAroundAdvice、AspectJMethodBeforeAdvice 类型的通知时,会利用反射直接执行它们的通知方法,其他类型通知不会立即执行,会等待递归返回之后再行调用 invoke() 方法。这样,就能保证通知和方法的执行顺序:
环绕通知执行 proceed() 前->前置通知->执行方法->环绕通知执行 proceed() 后->后置通知->返回通知->方法返回
总结
- @EnableAspectJAutoProxy 使用 @Import(AspectJAutoProxyRegistrar.class) 导入 (AspectJAutoProxyRegistrar)ImportBeanDefinitionRegistrar。
- 容器刷新时,invokeBeanFactoryPostProcessors() 执行 (AspectJAutoProxyRegistrar)ImportBeanDefinitionRegistrar.registerBeanDefinitions() 注册 AnnotationAwareAspectJAutoProxyCreator 到 BeanFactory。
- AnnotationAwareAspectJAutoProxyCreator 实现了 InstantiationAwareBeanPostProcessor 和 BeanFactoryAware,在 registerBeanPostProcessors() 将其注册到 BeanFactory,并且执行 invokeAwareMethods() 回调 (AbstractAdvisorAutoProxyCreator)BeanFactoryAware.setBeanFactory() 方法。
- finishBeanFactoryInitialization() 执行 (AnnotationAwareAspectJAutoProxyCreator)BeanPostProcessor.postProcessAfterInitialization(),找到切面类及其切面通知方法,使用动态代理技术(ObjenesisCglibAopProxy/JdkDynamicAopProxy),对切面类进行增强,创建增强后的代理对象
com.xxx.Service$$EnhancerBySpringCGLIB$$e86c6525@57eda880
。 - 执行被代理的方法时,会被 CglibAopProxy 的拦截器拦截,拿到方法的拦截器链,按顺序递归调用,利用反射技术执行通知方法,以此实现不同通知的调用顺序。
原文链接:https://www.cnblogs.com/bigshark/p/11324595.html
如有疑问请与原作者联系
标签:
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有
- Spring系列.ApplicationContext接口 2020-06-11
- springboot2配置JavaMelody与springMVC配置JavaMelody 2020-06-11
- 给你一份超详细 Spring Boot 知识清单 2020-06-11
- SpringBoot 2.3 整合最新版 ShardingJdbc + Druid + MyBatis 2020-06-11
- 掌握SpringBoot-2.3的容器探针:实战篇 2020-06-11
IDC资讯: 主机资讯 注册资讯 托管资讯 vps资讯 网站建设
网站运营: 建站经验 策划盈利 搜索优化 网站推广 免费资源
网络编程: Asp.Net编程 Asp编程 Php编程 Xml编程 Access Mssql Mysql 其它
服务器技术: Web服务器 Ftp服务器 Mail服务器 Dns服务器 安全防护
软件技巧: 其它软件 Word Excel Powerpoint Ghost Vista QQ空间 QQ FlashGet 迅雷
网页制作: FrontPages Dreamweaver Javascript css photoshop fireworks Flash