Spring Boot 中 @EnableX 注解的驱动逻辑
作者 | 温安适
来源 |
工作中经常用到 , 如下注解:
- @EnableEurekaClient
- @EnableFeignClients
- @EnableCircuitBreaker
- @EnableHystrix
@Enable驱动逻辑找入口@Enable的模块驱动 , 依赖于@Import实现 。
@Import作用是装载导入类 , 主要包括@Configuration class,ImportSelector实现类,ImportBeanDefinitionRegistrar实现类 。
XML时代 , 经常是@Import,
根据 Spring Framework 2.0引入的可扩展的XML编程机制 , XML Schema命名空间需要与Handler建立映射关系 。
该关系配置在相对于classpath下的/META-INF/spring.handlers中 。
查看ContextNamespaceHandler 源码
public class ContextNamespaceHandler extends NamespaceHandlerSupport {@Overridepublic void init() {//省略其他代码registerBeanDefinitionParser("annotation-config",new AnnotationConfigBeanDefinitionParser());}}复制代码
** 对应AnnotationConfigBeanDefinitionParser这个就是要找的入口**找核心类从AnnotationConfigBeanDefinitionParser的parse方法开始一路向下 , 找到
AnnotationConfigUtils.registerAnnotationConfigProcessors中注册了ConfigurationClassPostProcessor 。
文章插图
img
ConfigurationClassPostProcessor类注释说明
\1. 用于的引导处理@Configuration类
\2. context:annotation-config/或 context:component-scan/时会注册
否则需要手工编程
\3. ConfigurationClassPostProcessor第一优先级 , 保证
@Configuration}类中声明@Bean , 在其他 BeanFactoryPostProcessor执行之前被注册
扩展
AnnotationConfigApplicationContext中new AnnotationBeanDefinitionreader也调用了 AnnotationConfigUtils .
registerAnnotationConfigProcessors
从类注释中 , 可以看出ConfigurationClassPostProcessor就是要找的核心类
找核心方法
查看 ConfigurationClassPostProcessor 的层级关系为
文章插图
img
Aware系列注入相应资源 , Ordered设置优先级 , 值得关注的就是
postProcessBeanDefinitionRegistry了 。
postProcessBeanDefinitionRegistry其内部有2个方法
- postProcessBeanDefinitionRegistry在BeanDefinition注册之后 , BeanFactoryPostProcessor执行之前 , 修改或重写BeanDefinition
- 继承自BeanFactoryPostProcessor的postProcessBeanFactory , BeanDefinition加载之后 , Bean实例化之前 , 重写或添加BeanDefinition , 修改BeanFactory
文章插图
img
ConfigurationClassPostProcessor#processConfigBeanDefinitions就是要找的核心方法
梳理流程
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {List configCandidates = new ArrayList<>();String[] candidateNames = registry.getBeanDefinitionNames();for (String beanName : candidateNames) {BeanDefinition beanDef = registry.getBeanDefinition(beanName);if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {if (logger.isDebugEnabled()) {logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);}}else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));}}// 没有找到 @Configuration classes 立即返回if (configCandidates.isEmpty()) {return;}//根据@Order 值进行排序configCandidates.sort((bd1, bd2) -> {int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());return Integer.compare(i1, i2);});//通过封闭的应用程序上下文 ,检测任何自定义bean名称生成策略supplied through the enclosing application contextSingletonBeanRegistry sbr = null;if (registry instanceof SingletonBeanRegistry) {sbr = (SingletonBeanRegistry) registry;if (!this.localBeanNameGeneratorSet) {BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(CONFIGURATION_BEAN_NAME_GENERATOR);if (generator != null) {this.componentScanBeanNameGenerator = generator;this.importBeanNameGenerator = generator;}}}if (this.environment == null) {this.environment = new StandardEnvironment();}// 解析@Configuration classConfigurationClassParser parser = new ConfigurationClassParser(this.metadataReaderFactory, this.problemReporter, this.environment,this.resourceLoader, this.componentScanBeanNameGenerator, registry);Set candidates = new LinkedHashSet
- 文件系统(02):基于SpringBoot管理Xml和CSV
- SpringBoot2.x入门到项目实战课程系列(第二章)
- SpringBoot集成Mybatis
- 大牛深入解析SpringBoot核心运行原理和运作原理源码
- SpringBoot写后端接口,看这一篇就够了
- SpringBoot2.x入门到项目实战课程系列(第五章)
- SpringBoot整合JWT+Shiro
- 14 个 SpringMVC顶级技巧,随时用随时爽
- 高分力推java文档!Spring MVC 中文学习文档
- 不做CRUD的我开源了Springboot API一键生成器