SpringBoot中神奇的@Enable*注解?
在SpringBoot开发过程,我们经常会遇到@Enable开始的好多注解,比如@EnableEurekaServer、@EnableAsync、@EnableScheduling等,今天我们就来分析下这些注解到底是如何工作的?
本文目录
一、@Enable*实现的原理二、@Import注解的用法1. 直接导入配置类2. 依据条件选择配置类3. 动态注册Bean
一、@Enable*实现的原理
通过这些@Enable*注解的源码可以看出,所有@Enable*注解里面都有一个@Import注解,而@Import是用来导入配置类的,所以@Enable*自动开启的实现原理其实就是导入了一些自动配置的Bean。
二、@Import注解的用法
@Import注解允许导入@Configuration类,ImportSelector和ImportBeanDefinitionRegistrar的实现类,等同于正常的组件类。
有以下三种使用方式
1. 直接导入配置类
@EnableEurekaServer使用了这种方式,注解源码如下:
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({EurekaServerMarkerConfiguration.class})
public @interface EnableEurekaServer {
}
可以看到@EnableEurekaServer注解直接导入了配置类EurekaServerMarkerConfiguration,而这个配置类中向spring容器中注册了一个EurekaServerMarkerConfiguration的Bean。
EurekaServerMarkerConfiguration的源码如下:
@Configuration
public class EurekaServerMarkerConfiguration {
public EurekaServerMarkerConfiguration() {
}
@Bean
public EurekaServerMarkerConfiguration.Marker eurekaServerMarkerBean() {
return new EurekaServerMarkerConfiguration.Marker();
}
class Marker {
Marker() {
}
}
}
2. 依据条件选择配置类
@EnableAsync使用了这种方式,注解源码如下:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AsyncConfigurationSelector.class)
public @interface EnableAsync {
Class<? extends Annotation> annotation() default Annotation.class;
boolean proxyTargetClass() default false;
AdviceMode mode() default AdviceMode.PROXY;
int order() default Ordered.LOWEST_PRECEDENCE;
}
EnableAsync注解中导入了AsyncConfigurationSelector,AsyncConfigurationSelector通过条件来选择需要导入的配置类,继承AdviceModeImportSelector又实现了ImportSelector接口,接口重写selectImports方法进行事先条件判断PROXY或者ASPECTJ选择不同的配置类。
AsyncConfigurationSelector源码如下:
public class AsyncConfigurationSelector extends AdviceModeImportSelector<EnableAsync> {
private static final String ASYNC_EXECUTION_ASPECT_CONFIGURATION_CLASS_NAME =
"org.springframework.scheduling.aspectj.AspectJAsyncConfiguration";
/**
* Returns {@link ProxyAsyncConfiguration} or {@code AspectJAsyncConfiguration}
* for {@code PROXY} and {@code ASPECTJ} values of {@link EnableAsync#mode()},
* respectively.
*/
@Override
@Nullable
public String[] selectImports(AdviceMode adviceMode) {
switch (adviceMode) {
case PROXY:
return new String[] {ProxyAsyncConfiguration.class.getName()};
case ASPECTJ:
return new String[] {ASYNC_EXECUTION_ASPECT_CONFIGURATION_CLASS_NAME};
default:
return null;
}
}
}
3. 动态注册Bean
@EnableAspectJAutoProxy使用了这种方式,注解源码如下:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
boolean proxyTargetClass() default false;
boolean exposeProxy() default false;
}
EnableAspectJAutoProxy注解中导入了AspectJAutoProxyRegistrar,AspectJAutoProxyRegistrar实现了ImportBeanDefinitionRegistrar接口,在运行时把Bean注册到spring容器中。
AspectJAutoProxyRegistrar的源码如下:
class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
/**
* Register, escalate, and configure the AspectJ auto proxy creator based on the value
* of the @{@link EnableAspectJAutoProxy#proxyTargetClass()} attribute on the importing
* {@code @Configuration} class.
*/
@Override
public void registerBeanDefinitions(
AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
AnnotationAttributes enableAspectJAutoProxy =
AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
if (enableAspectJAutoProxy != null) {
if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}
if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
}
}
}
}
推荐阅读
1.Java中Integer.parseInt和Integer.valueOf,你还傻傻分不清吗?
2.SpringCloud系列-整合Hystrix的两种方式)
3.SpringCloud系列-利用Feign实现声明式服务调用)
4.手把手带你利用Ribbon实现客户端的负载均》
5.SpringCloud搭建注册中心与服务注册
Java碎碎念公众号限时领取免费Java相关资料,涵盖了Java、Redis、MongoDB、MySQL、Zookeeper、Spring Cloud、Dubbo/Kafka、Hadoop、Hbase、Flink等高并发分布式、大数据、机器学习等技术。
关注下方公众号即可免费领取:
原文地址:https://www.cnblogs.com/haha12/p/11730357.html
- 简单易学的机器学习算法——Logistic回归
- Python 用OPEN读文件报错 ,路径以及r
- Oracle 12c PDB浅析(r9笔记第10天)
- merge语句导致的CPU使用率过高的优化(二) (r7笔记第9天)
- 网页爬虫-R语言实现基本函数
- Python中的random模块用于生成随机数
- 简单易学的机器学习算法——极限学习机(ELM)
- 图片数据集太少?Keras Image Data Augmentation 各参数详解
- 备库归档删除策略失效的问题分析 (r7笔记第6天)
- 优化算法——梯度下降法
- Java基础-26(02)总结网络编程
- 记一次数据同步需求的改进(二) (r7笔记第5天)
- Python信贷数据处理与初步分析(ZIP解压)
- web前端之锋利的jQuery八:jQuery插件的使用(表单验证、表单提交)
- java教程
- Java快速入门
- Java 开发环境配置
- Java基本语法
- Java 对象和类
- Java 基本数据类型
- Java 变量类型
- Java 修饰符
- Java 运算符
- Java 循环结构
- Java 分支结构
- Java Number类
- Java Character类
- Java String类
- Java StringBuffer和StringBuilder类
- Java 数组
- Java 日期时间
- Java 正则表达式
- Java 方法
- Java 流(Stream)、文件(File)和IO
- Java 异常处理
- Java 继承
- Java 重写(Override)与重载(Overload)
- Java 多态
- Java 抽象类
- Java 封装
- Java 接口
- Java 包(package)
- Java 数据结构
- Java 集合框架
- Java 泛型
- Java 序列化
- Java 网络编程
- Java 发送邮件
- Java 多线程编程
- Java Applet基础
- Java 文档注释
- Flutter下Android Studio配置gradle的方法
- Flutter 实现整个App变为灰色的方法示例
- Android studio开发小型对话机器人app(实例代码)
- php中的钩子理解及应用实例分析
- AndroidX下使用Activity和Fragment的变化详解
- PHP Primary script unknown 解决方法总结
- PHP如何将图片文件上传到另外一台服务器上
- android实现滑动解锁
- laravel框架模板之公共模板、继承、包含实现方法分析
- Android项目实战之百度地图地点签到功能
- PHP Redis扩展无法加载的问题解决方法
- PHP 文件上传限制问题
- Flutter permission_handler 权限插件的使用详解
- Flutter使用JsBridge方式处理Webview与H5通信的方法
- flutter 怎么实现app整体灰色效果