Springboot Actuator之十二:actuator aop
前言
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的更多相关文章
- FreeSql (三十二)Aop
FreeSql AOP 已有的功能介绍,未来为会根据用户需求不断增强. 审计 CRUD 马云说过,996是修福报.对于多数程序员来说,加班是好事...起码不是闲人,不会下岗. 当如果因为某个 sql ...
- Springboot Actuator之十:actuator中的audit包
前言这篇文章我们来分析一下org.springframework.boot.actuate.security,org.springframework.boot.actuate.audit中的代码,这2 ...
- Springboot 系列(十二)使用 Mybatis 集成 pagehelper 分页插件和 mapper 插件
前言 在 Springboot 系列文章第十一篇里(使用 Mybatis(自动生成插件) 访问数据库),实验了 Springboot 结合 Mybatis 以及 Mybatis-generator 生 ...
- SpringBoot入门教程(十二)DevTools热部署
devtools模块,是为开发者服务的一个模块.主要的功能就是代码修改后一般在5秒之内就会自动重新加载至服务器,相当于restart成功.与JRebel不同的是,JRebel是一款商业插件,devto ...
- SpringBoot | 第三十二章:事件的发布和监听
前言 今天去官网查看spring boot资料时,在特性中看见了系统的事件及监听章节.想想,spring的事件应该是在3.x版本就发布的功能了,并越来越完善,其为bean和bean之间的消息通信提供了 ...
- SpringBoot系列(十四)集成邮件发送服务及邮件发送的几种方式
往期推荐 SpringBoot系列(一)idea新建Springboot项目 SpringBoot系列(二)入门知识 springBoot系列(三)配置文件详解 SpringBoot系列(四)web静 ...
- FreeSql (十二)更新数据时指定列
var connstr = "Data Source=127.0.0.1;Port=3306;User ID=root;Password=root;" + "Initia ...
- FreeSql (二十二)Dto 映射查询
适合喜欢使用 dto 的朋友,很多时候 entity 与 dto 属性名相同,属性数据又不完全一致. 有的人先查回所有字段数据,再使用 AutoMapper 映射. 我们的功能是先映射,再只查询映射好 ...
- SpringBoot第十二集:度量指标监控与异步调用(2020最新最易懂)
SpringBoot第十二集:度量指标监控与异步调用(2020最新最易懂) Spring Boot Actuator是spring boot项目一个监控模块,提供了很多原生的端点,包含了对应用系统的自 ...
随机推荐
- 设计模式之(十一)代理模式(Proxy)
软件开发行业有一个观点:任务问题都可以添加一个中间层来解决.代理模式也是这个思想下的产物. 首先看下代理模式的定义:为其他对象提供一种代理以控制对这个对象的访问.就是把类委托给另外一个类,用这个类来控 ...
- webpack详细介绍以及配置文件属性!
1.webpack简单介绍 (1)webpack是一个用于实现前端模块化开发工具,可帮助我们自动打包编译成浏览器能够识别的代码 :同时支持commonjs规范 以及es6的import规范: 同时具备 ...
- nginx root与alias
root和alias都可以定义在location模块中,都是用来指定请求资源的真实路径,但又有区别: 采用如下设置 location /static/ { root /data/w3; } 实际访问h ...
- qtp安装和使用
QTP许可证密钥的破解步骤: 以前使用QTP9.2 使用此方法成功破解,现在本人使用的HP QuickTest Professional 11 英文版,也成功适用. 一.准备工作: 1. 由于注册码文 ...
- Linux的网络参数设置
前面讲解了lLinux 的IP组成,下面就讲一下Linux的网络设置和数据传递. 其实这地方对运维的人员来说,不会要精通,但还是要了解.必要时刻还会用到的 电脑之间数据的传递: 数据的传递要分为下面几 ...
- QElapsedTimer定时器记录程序执行时间
QElapedTimer类提供了一种快速计算运行时间的方法,从Qt4.7引入. QElapsedTimer类通常用于快速计算两个事件之间经过了多少时间.它的API与QTime相似,因此可以将正在使用的 ...
- Huawei S系列交换机 Easydeploy 特性
参考 HW S2750, S5700, S6720 V200R008C00 配置指南-基础配置-EasyDeploy配置 原理,DHCP&TFTP部署等 四. HW EasyDeploy HW ...
- [PAT] 目录
题号 PAT Basic PAT Advaced PAT Top 1001 害死人不偿命的(3n+1)猜想 1002 写出这个数 1003 我要通过! 1004 成绩排名 ...
- USB驱动程序涉及的概念及框架
引入:当我们把一个USB设备接入PC机时,会出现什么样的现象? 现象:把USB设备接到PC1.右下角弹出“发现android phone”2.跳出一个对话框,提示你安装驱动程序 首先来看一下,USB驱 ...
- 【java】oracle好用,但java运行缺失右括号
可能原因SQL拼接有空格被省略导致sql粘连. 解决办法,扩大拼接或者缩小拼接范围.