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项目一个监控模块,提供了很多原生的端点,包含了对应用系统的自 ...
随机推荐
- Linux C 后台服务程序单进程控制
介绍 通常后台服务器程序都必须有且只有一个进程,那么如何单进程呢? 本例子是通过flock函数对/var/run/myserver.pid记录pid文件的进行加锁 若加锁不正常,说明后台服务进程已经在 ...
- linq to js 用法
/** * 排序汇总 * */ var result = Enumerable.From(vm.productList).GroupBy("$.goods_id", null, f ...
- linux 下按照文件名模糊查找文件
fnmatch int fnmatch(const char *pattern, const char *string, int flags); 参数说明 FNM_NOESCAPE 如果这个标志设置了 ...
- Alipay支付宝支付 报错 invalid [default store dir]: /tmp/
1.如果使用支付宝sdk,首先lotusphp_runtime 文件也要一起使用 支付宝现在的php sdk中有lotus框架可以和aop文件. 2.保证AopSdk.php文件中的方法可以走到这个 ...
- React源码 ReactDOM.render
在 react 当中,主要创建更新的有三种方式 1.ReactDOM.render || hydrate 这两个api都是要把这个应用第一次渲染到我们页面上面,展现出来整个应用的样子的过程,这就是初 ...
- 模型选择---KFold,StratifiedKFold k折交叉切分
StratifiedKFold用法类似Kfold,但是他是分层采样,确保训练集,测试集中各类别样本的比例与原始数据集中相同. 例子: import numpy as np from sklearn.m ...
- 201671030113 李星宇 实验十四 团队项目评审&课程学习总结
项目 内容 所属课程 [所属课程(https://www.cnblogs.com/nwnu-daizh/) 作业要求 作业要求 课程学习目标 (1)掌握软件项目评审会流程:(2)反思总结课程学习内容 ...
- Python学习笔记7 头文件的添加规则(转载)
转载自:https://www.cnblogs.com/taurusfy/p/7605787.html ************************************************ ...
- 【mybatis】JdbcType 与Oracle、MySql数据类型对应关系
- 【oracle】定时任务
--创建定时任务-------------------------------------------------------------------------------------------- ...