SpringBoot自动配置原理

embedded/2024/10/21 5:34:06/

SpringBoot自动配置原理

自动配置到底配置了些什么?

对于一个Spring项目,主要就是有两种配置:

  1. 一种是类似端口号,数据库地址,用户名密码等
  2. 一种是各种Bean,比如整合Mybatis需要配置的MapperFactoryBean,比如整合事务需要配置的DataSourceTransactionManager

关于SpringBoot的Servlet容器是如何加载

ServletWebServerApplicationContext类中有个createWebServer()方法,该方法调用时机在Spring容器完全初始化后。

java">private void createWebServer() {WebServer webServer = this.webServer;ServletContext servletContext = this.getServletContext();if (webServer == null && servletContext == null) {StartupStep createWebServer = this.getApplicationStartup().start("spring.boot.webserver.create");ServletWebServerFactory factory = this.getWebServerFactory();createWebServer.tag("factory", factory.getClass().toString());this.webServer = factory.getWebServer(new ServletContextInitializer[]{this.getSelfInitializer()});createWebServer.end();this.getBeanFactory().registerSingleton("webServerGracefulShutdown", new WebServerGracefulShutdownLifecycle(this.webServer));this.getBeanFactory().registerSingleton("webServerStartStop", new WebServerStartStopLifecycle(this, this.webServer));} else if (servletContext != null) {try {this.getSelfInitializer().onStartup(servletContext);} catch (ServletException var5) {throw new ApplicationContextException("Cannot initialize servlet context", var5);}}this.initPropertySources();}
如何通过引入的serlvet容器starter来动态获取servlet 容器
createWebServer中如何获取
java">ServletWebServerFactory factory = this.getWebServerFactory();
关于ServletWebServerFactory
java">public interface ServletWebServerFactory {WebServer getWebServer(ServletContextInitializer... initializers);
}

可以看到里面是一个函数式接口,提供工厂的形式来获取WebServer。

ServletWebServerFactory的实现类
  1. JettyServletWebServerFactory
  2. TomcatServletWebServerFactory
  3. UndertowServletWebServerFactory

SpringBoot分别提供了三个实现类分别作为Tomcat,jetty,underTow的工厂类。

getWebServerFactory
java">protected ServletWebServerFactory getWebServerFactory() {String[] beanNames = this.getBeanFactory().getBeanNamesForType(ServletWebServerFactory.class);if (beanNames.length == 0) {throw new ApplicationContextException("Unable to start ServletWebServerApplicationContext due to missing ServletWebServerFactory bean.");} else if (beanNames.length > 1) {throw new ApplicationContextException("Unable to start ServletWebServerApplicationContext due to multiple ServletWebServerFactory beans : " + StringUtils.arrayToCommaDelimitedString(beanNames));} else {return (ServletWebServerFactory)this.getBeanFactory().getBean(beanNames[0], ServletWebServerFactory.class);}}

利用BeanFactory的getBeanNamesByType(ServletWebServerFactory.class)来获取Spring容器的ServletWebServerFactory对象。

产生疑问,ServletWebServerFacotry的实现类是什么时候交给Spring管理的呢?

在ServletWebServerFactoryAutoConfiguration中

java">@Configuration(proxyBeanMethods = false
)
@AutoConfigureOrder(Integer.MIN_VALUE)
@ConditionalOnClass({ServletRequest.class})
@ConditionalOnWebApplication(type = Type.SERVLET
)
@EnableConfigurationProperties({ServerProperties.class})
@Import({BeanPostProcessorsRegistrar.class, ServletWebServerFactoryConfiguration.EmbeddedTomcat.class, ServletWebServerFactoryConfiguration.EmbeddedJetty.class, ServletWebServerFactoryConfiguration.EmbeddedUndertow.class})
public class ServletWebServerFactoryAutoConfiguration {.....
}

分别导入了EmbeddedTomcat,EmbeddedJetty,EmbeddedUnderTow等几个类,如果该应用满足上面的条件则会导入该类。

EmbeddedTomcat
java">	@Configuration(proxyBeanMethods = false)@ConditionalOnClass({Servlet.class, Tomcat.class, UpgradeProtocol.class})@ConditionalOnMissingBean(value = {ServletWebServerFactory.class},search = SearchStrategy.CURRENT)static class EmbeddedTomcat {EmbeddedTomcat() {}@BeanTomcatServletWebServerFactory tomcatServletWebServerFactory(ObjectProvider<TomcatConnectorCustomizer> connectorCustomizers, ObjectProvider<TomcatContextCustomizer> contextCustomizers, ObjectProvider<TomcatProtocolHandlerCustomizer<?>> protocolHandlerCustomizers) {TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();factory.getTomcatConnectorCustomizers().addAll((Collection)connectorCustomizers.orderedStream().collect(Collectors.toList()));factory.getTomcatContextCustomizers().addAll((Collection)contextCustomizers.orderedStream().collect(Collectors.toList()));factory.getTomcatProtocolHandlerCustomizers().addAll((Collection)protocolHandlerCustomizers.orderedStream().collect(Collectors.toList()));return factory;}}

该类的职责主要还是在满足一定的条件下往Spring容器中注入TomcatServletWebServerFactory,这就可以让上一步中获取到ServletWebServerFactory。从而实现开启tomcat 容器。

自动配置

SpringBoot提供了一种机制,会自动配置某些必须的类,不需要程序员再自己配置。如原生Spring项目中需要手动配置aop并开启。SpringBoot中只需要引入spring-boot-starter-aop,便自动开启了aop功能。

EnableAutoConfiguration

java">@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";Class<?>[] exclude() default {};String[] excludeName() default {};
}

EnableAutoConfiguration表示开启SpringBoot的自动配置,并可以配置排除不需要哪些Configuration类配置。

EnableAutoConfiguration导入了AutoConfigurationImportSelector,则Spring容器会直接将该类放进容器中。

关于ImportSelector机制

ImportSelector 是 Spring 框架中的一个接口,用于动态地定义和注册 Bean 到 Spring 容器中。它允许开发者根据一定的条件或逻辑,选择性地导入(import)特定的配置类或 Bean 定义。

主要作用和用途:
  1. 动态注册 BeanImportSelector 主要用于在 Spring 的配置类(Configuration)中动态地注册 Bean 或者导入其他配置类。通过实现 selectImports() 方法,可以根据一些条件或逻辑返回一个字符串数组,这些字符串数组表示要导入的 Bean 定义类的全限定名。
  2. 条件化配置: 可以结合条件注解(如 @Conditional 注解)和 ImportSelector 实现类,根据运行时环境的条件来决定是否导入某些 Bean 定义或配置类,从而实现更灵活和动态的配置管理。
  3. 自定义扩展: 开发者可以根据具体需求自定义实现 ImportSelector 接口,实现特定的逻辑来选择性地导入 Bean 或配置类。这种方式适合于需要根据不同情况动态调整 Spring 容器配置的场景。

通过ImportSelector机制,SpringBoot通过AutoConfigurationImportSelector实现ImortSelector来动态的将其他jar包的bean放入Spring容器中

AutoConfigurationImportSelector

AutoConfigurationImportSelector实现了ImportSelector。核心查找配置的方法如下

通过一系列解析,将@Configuration注解的类全限定名称返回

public String[] selectImports(AnnotationMetadata annotationMetadata) {if (!this.isEnabled(annotationMetadata)) {return NO_IMPORTS;} else {//annotationMetadata代表SpringBootApplica传入的那个类元信息,通过一系列解析,将@Configuration注解的类全限定名称返回AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(annotationMetadata);return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());}}
getAutoConfigurationEntry
java">protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {if (!this.isEnabled(annotationMetadata)) {return EMPTY_ENTRY;} else {AnnotationAttributes attributes = this.getAttributes(annotationMetadata);List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);configurations = this.removeDuplicates(configurations);Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);this.checkExcludedClasses(configurations, exclusions);configurations.removeAll(exclusions);configurations = this.getConfigurationClassFilter().filter(configurations);this.fireAutoConfigurationImportEvents(configurations, exclusions);return new AutoConfigurationEntry(configurations, exclusions);}}
  • getCandidateConfigurations()将META-INF/spring.factories配置下EnableAutoConfiguration节点下的全限定名称解析出来,并返回

在这里插入图片描述

  • removeDuplicates()对返回的configurations进行去重,因为这里有可能某个配置的名称完全相同
  • getExclusions对EnableAutoConfiguration配置的exclude进行统计
  • checkExcludedClasses 对排除的内容进行校验
  • removeAll 对EnableAutoConfiguration配置的exclude进行排除
  • getConfigurationClassFilter 获取初步的排除配置类不符合条件注解的那些。

注意,这里只会对以下条件进行初步排除

org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=\
org.springframework.boot.autoconfigure.condition.OnBeanCondition,\
org.springframework.boot.autoconfigure.condition.OnClassCondition,\
org.springframework.boot.autoconfigure.condition.OnWebApplicationCondition
  • fireAutoConfigurationImportEvents这一步只是记录哪些合格,哪些是被排除掉的。

在这里插入图片描述

可以看到,最后排除掉,从133个配置类变成21个符合要求的。

  • AutoConfigurationEntry 封装Entry类并返回

http://www.ppmy.cn/embedded/54033.html

相关文章

「C系列」C 经典练习实例

文章目录 1. 基本输入输出2. 字符串操作3. 数组与循环4. 函数与递归5. 逻辑与条件6. 数学问题7. 数字与数学8. 数组与字符串9. 逻辑与条件10. 结构体和联合体11. 指针12. 文件操作13. 动态内存分配相关链接 C语言经典练习实例及详细代码可以涵盖多个方面&#xff0c;从基础输入…

初识 GPT-4 和 ChatGPT

文章目录 LLM 概述理解 Transformer 架构及其在 LLM 中的作用解密 GPT 模型的标记化和预测步骤 想象这样⼀个世界&#xff1a;在这个世界里&#xff0c;你可以像和朋友聊天⼀样快速地与计算机交互。那会是怎样的体验&#xff1f;你可以创造出什么样的应用程序&#xff1f;这正是…

SQL面试题练习 —— 求连续段的起始位置和结束位置

目录 1 题目2 建表语句3 题解 题目来源&#xff1a;拼多多。 1 题目 有一张表t_id记录了id&#xff0c;id不重复&#xff0c;但是会存在间断&#xff0c;求出连续段的起始位置和结束位置。 样例数据 ----- | id | ----- | 1 | | 2 | | 3 | | 5 | | 6 | | 8 | | …

IPSEC VPN

IPSEC VPN IPSEC是为IP网络提供安全性的协议和服务的集合,是一种协议簇&#xff0c;一个基于网络层&#xff0c;应用密码学的安全信息协议组。一开始TCP/IP 没有考虑到信息的安全传输。IPSEC协议簇诞生的意义就是保证TCP/IP的安全传输。 伪头部校验&#xff1a;TCP再校验的时…

React 18

React Redux Router路由 TS 1 React 组件化开发方式、性能优秀&#xff08;vnode、fiber&#xff09;、丰富生态、跨平台支持&#xff08;React native支持ios、安卓&#xff09; 1.1 下载React项目 利用npx create-react-app react-basic下载项目&#xff0c;下载好项目…

深度学习之生成对抗网络StyleGAN3

StyleGAN3 是由 NVIDIA 团队提出的第三代生成对抗网络(GAN),在前代 StyleGAN 和 StyleGAN2 的基础上进行了改进,以实现更高质量的图像生成。StyleGAN3 的主要改进在于解决了 StyleGAN2 中存在的伪影(artifacts)问题,并且提升了生成图像的一致性和稳定性。 StyleGAN3 的…

GPT-5对普通人有何影响

这篇文章对ChatGPT的使用方法和提问技巧进行了讨论&#xff0c;重点强调了背景信息和具体提问的重要性。文章清晰地传达了如何提高ChatGPT回答的质量&#xff0c;以及个人在使用ChatGPT时的体会和建议。然而&#xff0c;文章在逻辑组织和表达方面还有一些可以改进的地方&#x…

举例说明计算机视觉(CV)技术的优势和挑战

计算机视觉&#xff08;CV&#xff09;技术是指让计算机系统能够理解和解释图像和视频数据的能力。它具有许多优势&#xff0c;但也面临一些挑战。 优势&#xff1a; 1. 高效性&#xff1a;CV技术可以快速地处理大量的图像和视频数据&#xff0c;使计算机能够在短时间内分析和…