前言
spring 中aop是一个核心概念,spring boot 是如何实现自动化配置的?现在我们就来分析一下

解析
spring boot 中自动化配置是读取/META-INF/spring.factories 中读取org.springframework.boot.autoconfigure.EnableAutoConfiguration配置的值,其中有关aop的只有一个,即org.springframework.boot.autoconfigure.aop.AopAutoConfiguration.该类就是打开宝箱的钥匙

AopAutoConfiguration 声明了如下注解:

@Configuration
@ConditionalOnClass({ EnableAspectJAutoProxy.class, Aspect.class, Advice.class })
@ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true)
1
2
3
@Configuration –> 配置类
@ConditionalOnClass({ EnableAspectJAutoProxy.class, Aspect.class, Advice.class }) –> 在当前的类路径下存在EnableAspectJAutoProxy.class, Aspect.class, Advice.class时该配置才被解析
@ConditionalOnProperty(prefix = “spring.aop”, name = “auto”, havingValue = “true”, matchIfMissing = true) –> 当配置有spring.aop.auto= true时生效.如果没有配置,则默认生效
AopAutoConfiguration中只有2个内部类:

JdkDynamicAutoProxyConfiguration,代码如下:

@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = false)
@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false", matchIfMissing = true)
public static class JdkDynamicAutoProxyConfiguration {

}
1
2
3
4
5
6
@Configuration –> 配置类
@EnableAspectJAutoProxy(proxyTargetClass = false) –> 开启aop注解,关于该注解,后面有解析.
@ConditionalOnProperty(prefix = “spring.aop”, name = “proxy-target-class”, havingValue = “false”, matchIfMissing = true)–> 当配置有spring.aop.proxy-target-class= false时生效,如果没有配置,默认生效.
CglibAutoProxyConfiguration,代码如下:

@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = true)
@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true", matchIfMissing = false)
public static class CglibAutoProxyConfiguration {

}
1
2
3
4
5
6
@Configuration –> 配置类
@EnableAspectJAutoProxy(proxyTargetClass = false) –> 开启aop注解
@ConditionalOnProperty(prefix = “spring.aop”, name = “proxy-target-class”, havingValue = “true”, matchIfMissing = false)–> 当配置有spring.aop.proxy-target-class= true时生效,如果没有配置,默认不生效.
因此,我们可以知道,aop 默认生效的JdkDynamicAutoProxyConfiguration.这也符合我们关于spring aop的认知,默认是使用jdk,如果使用面向类的代理,则需要配置spring.aop.proxy-target-class=true,来使用cglib进行代理

@EnableAspectJAutoProxy 代码如下:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {

// 表明是否使用基于类的代理,false--> 使用面向接口的代理(java 动态代理).true--> 使用cglib
boolean proxyTargetClass() default false;

// 表明是否暴露代理(通过ThreadLocal的方式),该属性设置为true可解决目标对象内部的自我调用将无法实施切面中的增强的问题.
boolean exposeProxy() default false;
}
1
2
3
4
5
6
7
8
9
10
11
12
关于目标对象内部的自我调用将无法实施切面中的增强的问题可看Spring事务处理时自我调用的解决方案及一些实现方式的风险 这篇博客

这里通过@Import(AspectJAutoProxyRegistrar.class),导入了AspectJAutoProxyRegistrar的配置.

还是由之前的文章可知,此时会调用ConfigurationClassParser#processImports.由于AspectJAutoProxyRegistrar实现了ImportBeanDefinitionRegistrar接口,因此会加入到JdkDynamicAutoProxyConfiguration所对应的ConfigurationClass 的importBeanDefinitionRegistrars中.

最后,在ConfigurationClassBeanDefinitionReader#loadBeanDefinitionsFromRegistrars会对importBeanDefinitionRegistrars依次调用其registerBeanDefinitions 方法.

AspectJAutoProxyRegistrar#registerBeanDefinitions 代码如下:

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);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
注册id为org.springframework.aop.config.internalAutoProxyCreator,class 为 AnnotationAwareAspectJAutoProxyCreator的bean.这里经过层层调用,最终调用AopConfigUtils#registerOrEscalateApcAsRequired方法,代码如下:

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) {
// 改变bean最重要的就是改变bean所对应的ClassName
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;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
这里传入的cls 为AnnotationAwareAspectJAutoProxyCreator.class
如果已经存在了自动代理创建器且存在的自动代理创建器与现状的不一致那么需要根据优先级来判断到底需要使用哪一个–> 如果此时传入的AnnotationAwareAspectJAutoProxyCreator的优先级比已注册的优先级高,则替换为AnnotationAwareAspectJAutoProxyCreator.然后直接return
如果已经存在自动代理创建器并且与将要创建(AnnotationAwareAspectJAutoProxyCreator)的一致,那么无需再次创建
进行注册,id为org.springframework.aop.config.internalAutoProxyCreator,class 为 AnnotationAwareAspectJAutoProxyCreator,优先级为Integer.MIN_VALUE.角色为内部使用
如果配置了proxyTargetClass等于true,则对id为org.springframework.aop.config.internalAutoProxyCreator的BeanDefinition 添加proxyTargetClass 的属性,值为true.代码如下:

public static void forceAutoProxyCreatorToUseClassProxying(BeanDefinitionRegistry registry) {
if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
BeanDefinition definition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
definition.getPropertyValues().add("proxyTargetClass", Boolean.TRUE);
}
}
1
2
3
4
5
6
如果配置了exposeProxy等于true,则对id为org.springframework.aop.config.internalAutoProxyCreator的BeanDefinition 添加exposeProxy 的属性,值为true. 代码如下:

public static void forceAutoProxyCreatorToExposeProxy(BeanDefinitionRegistry registry) {
if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
BeanDefinition definition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
definition.getPropertyValues().add("exposeProxy", Boolean.TRUE);
}
}
1
2
3
4
5
6
关于aop方面的源码,笔者准备在spring深度揭秘中一一道来,关于spring boot 中的aop 自动化配置就解析到这里.
---------------------
版权声明:本文为CSDN博主「一个努力的码农」的原创文章,遵循CC 4.0 by-sa版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_26000415/article/details/79010971

Springboot Actuator之十二:actuator aop的更多相关文章

  1. FreeSql (三十二)Aop

    FreeSql AOP 已有的功能介绍,未来为会根据用户需求不断增强. 审计 CRUD 马云说过,996是修福报.对于多数程序员来说,加班是好事...起码不是闲人,不会下岗. 当如果因为某个 sql ...

  2. Springboot Actuator之十:actuator中的audit包

    前言这篇文章我们来分析一下org.springframework.boot.actuate.security,org.springframework.boot.actuate.audit中的代码,这2 ...

  3. Springboot 系列(十二)使用 Mybatis 集成 pagehelper 分页插件和 mapper 插件

    前言 在 Springboot 系列文章第十一篇里(使用 Mybatis(自动生成插件) 访问数据库),实验了 Springboot 结合 Mybatis 以及 Mybatis-generator 生 ...

  4. SpringBoot入门教程(十二)DevTools热部署

    devtools模块,是为开发者服务的一个模块.主要的功能就是代码修改后一般在5秒之内就会自动重新加载至服务器,相当于restart成功.与JRebel不同的是,JRebel是一款商业插件,devto ...

  5. SpringBoot | 第三十二章:事件的发布和监听

    前言 今天去官网查看spring boot资料时,在特性中看见了系统的事件及监听章节.想想,spring的事件应该是在3.x版本就发布的功能了,并越来越完善,其为bean和bean之间的消息通信提供了 ...

  6. SpringBoot系列(十四)集成邮件发送服务及邮件发送的几种方式

    往期推荐 SpringBoot系列(一)idea新建Springboot项目 SpringBoot系列(二)入门知识 springBoot系列(三)配置文件详解 SpringBoot系列(四)web静 ...

  7. FreeSql (十二)更新数据时指定列

    var connstr = "Data Source=127.0.0.1;Port=3306;User ID=root;Password=root;" + "Initia ...

  8. FreeSql (二十二)Dto 映射查询

    适合喜欢使用 dto 的朋友,很多时候 entity 与 dto 属性名相同,属性数据又不完全一致. 有的人先查回所有字段数据,再使用 AutoMapper 映射. 我们的功能是先映射,再只查询映射好 ...

  9. SpringBoot第十二集:度量指标监控与异步调用(2020最新最易懂)

    SpringBoot第十二集:度量指标监控与异步调用(2020最新最易懂) Spring Boot Actuator是spring boot项目一个监控模块,提供了很多原生的端点,包含了对应用系统的自 ...

随机推荐

  1. 解决Eclipe安装不上android的ADT的办法

    Eclipse,https://dl-ssl.google.com/android/eclipse/安装不上去,ADT在线安装装不了,用离线包又出问题时会不会疯掉. 显然,国内网络和谐掉了google ...

  2. JavaScript 究竟是怎样执行的?

    摘要: 理解 JS 引擎运行原理. 作者:前端小智 原文:搞懂 JavaScript 引擎运行原理 Fundebug经授权转载,版权归原作者所有. 一些名词 JS 引擎 - 一个读取代码并运行的引擎, ...

  3. 记MacOS抹盘后--使用U盘安装MacOS实录

    背景 纯属一时手贱,本想重装系统,结果直接把磁盘抹了,然后联网安装死活安不上.但这里仍然附上联网安装方法: 按键 描述 ⌘+R 重新安装您的 Mac 上装有的最新 macOS(建议操作). Optio ...

  4. Java IO全面

    转载请注明原文地址:https://www.cnblogs.com/ygj0930/p/10857412.html 一:IO流梳理——字符流.字节流.输入流.输出流 见另一篇博文:https://ww ...

  5. docker gitlab-runner的安装

    参考: Run GitLab Runner in a container 前面介绍了gitlab-ce的安装,下面是gitlab-runner的安装,同样还是安装docker版本. 1.下载 dock ...

  6. matplotlib 中的 colors 和 cmaps

    matplotlib 中的 148 种颜色 matplotlib 中的 160 种颜色映射 1.matplotlib中的 148 种颜色 import matplotlib as plm import ...

  7. 逆向破解之160个CrackMe —— 022

    CrackMe —— 022 160 CrackMe 是比较适合新手学习逆向破解的CrackMe的一个集合一共160个待逆向破解的程序 CrackMe:它们都是一些公开给别人尝试破解的小程序,制作 c ...

  8. LCD编程_画点线圆

    上篇博客中进行了lcd的简单测试,这篇博客将进行更加复杂的测试——画点.画线.画圆.画线和画圆是在画点的基础上实现的,因此本篇博客重点实现画点操作. 先抛出这样的一个问题,已知: (x,y)的坐标: ...

  9. python网页内容提取神器lxml

    一.Xpath是什么 XPath 是一门在 XML 文档中查找信息的语言.XPath 用于在 XML 文档中通过元素和属性进行导航. XPath 使用路径表达式在 XML 文档中进行导航 XPath ...

  10. 修改Discuz!X系列开启防CC攻击,不影响搜索引擎收录

    最近网站一直被攻击,特别是新上线的交流社区,所以今天写了一个开启CC攻击防护代码,而且不影响搜索引擎收录. 在config_global.php文件中有如下代码: $_config['security ...