百度
360搜索
搜狗搜索

springboot的工作原理,SpringBoot启动原理分析详细介绍

本文目录一览: spring boot原理

前端常使用模板引擎,主要有FreeMarker和Thymeleaf,它们都是用Java语言编写的,渲染模板并输出相应文本,使得界面的设计与应用的逻辑分离,同时前端开发还会使用到Bootstrap、AngularJS、JQuery等;
在浏览器的数据传输格式上采用Json,非xml,同时提供RESTfulAPI;SpringMVC框架用于数据到达服务器后处理请求;到数据访问层主要有Hibernate、MyBatis、JPA等持久层框架;数据库常用MySQL;开发工具推荐IntelliJIDEA。
扩展资料:
SpringBoot所具备的特征有:
(1)可以创建独立的Spring应用程序,并且基于其Maven或Gradle插件,可以创建可执行的JARs和WARs;
(2)内嵌Tomcat或Jetty等Servlet容器;
(3)提供自动配置的“starter”项目对象模型(POMS)以简化Maven配置;
(4)尽可能自动配置Spring容器;
(5)提供准备好的特性,如指标、健康检查和外部化配置;
(6)绝对没有代码生成,不需要XML配置。
Spring的初衷:
1、JAVA EE开发应该更加简单。
2、使用接口而不是使用类,是更好的编程习惯。Spring将使用接口的复杂度几乎降低到了零。
3、为JavaBean提供了一个更好的应用配置框架。
4、更多地强调面向对象的设计,而不是现行的技术如JAVA EE。
5、尽量减少不必要的异常捕捉。
6、使应用程序更加容易测试。
参考资料来源:百度百科-spring框架
参考资料来源:百度百科-Spring Boot

SpringBoot工作原理?

Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置。通过这种方式,Spring Boot致力于在蓬勃发展的快速应用开发领域(rapid application development)成为领导者。
详见百科:http://baike.baidu.com/subview/19434773/20954318.htm

SpringBoot启动原理分析

自动配置核心类SpringFactoriesLoader

上面在说@EnableAutoConfiguration的时候有说META-INF下的spring.factories文件,那么这个文件是怎么被spring加载到的呢,其实就是SpringFactoriesLoader类。
SpringFactoriesLoader是一个供Spring内部使用的通用工厂装载器,SpringFactoriesLoader里有两个方法,

在这个SpringBoot应用启动过程中,SpringFactoriesLoader做了以下几件事:
加载所有META-INF/spring.factories中的Initializer
加载所有META-INF/spring.factories中的Listener
加载EnvironmentPostProcessor(允许在Spring应用构建之前定制环境配置)
接下来加载Properties和YAML的PropertySourceLoader(针对SpringBoot的两种配置文件的加载器)
各种异常情况的FailureAnalyzer(异常解释器)
加载SpringBoot内部实现的各种AutoConfiguration
模板引擎TemplateAvailabilityProvider(如Freemarker、Thymeleaf、Jsp、Velocity等)
总得来说,SpringFactoriesLoader和@EnableAutoConfiguration配合起来,整体功能就是查找spring.factories文件,加载自动配置类。

整体启动流程
在我们执行入口类的main方法之后,运行SpringApplication.run,后面new了一个SpringApplication对象,然后执行它的run方法。

初始化SpringApplication类
创建一个SpringApplication对象时,会调用它自己的initialize方法

执行核心run方法
初始化initialize方法执行完之后,会调用run方法,开始启动SpringBoot。

首先遍历执行所有通过SpringFactoriesLoader,在当前classpath下的META-INF/spring.factories中查找所有可用的SpringApplicationRunListeners并实例化。调用它们的starting()方法,通知这些监听器SpringBoot应用启动。

创建并配置当前SpringBoot应用将要使用的Environment,包括当前有效的PropertySource以及Profile。

遍历调用所有的SpringApplicationRunListeners的environmentPrepared()的方法,通知这些监听器SpringBoot应用的Environment已经完成初始化。

打印SpringBoot应用的banner,SpringApplication的showBanner属性为true时,如果classpath下存在banner.txt文件,则打印其内容,否则打印默认banner。

根据启动时设置的applicationContextClass和在initialize方法设置的webEnvironment,创建对应的applicationContext。

创建异常解析器,用在启动中发生异常的时候进行异常处理(包括记录日志、释放资源等)。

设置SpringBoot的Environment,注册Spring Bean名称的序列化器BeanNameGenerator,并设置资源加载器ResourceLoader,通过SpringFactoriesLoader加载ApplicationContextInitializer初始化器,调用initialize方法,对创建的ApplicationContext进一步初始化。

调用所有的SpringApplicationRunListeners的contextPrepared方法,通知这些Listener当前ApplicationContext已经创建完毕。

最核心的一步,将之前通过@EnableAutoConfiguration获取的所有配置以及其他形式的IoC容器配置加载到已经准备完毕的ApplicationContext。

调用所有的SpringApplicationRunListener的contextLoaded方法,加载准备完毕的ApplicationContext。

调用refreshContext,注册一个关闭Spring容器的钩子ShutdownHook,当程序在停止的时候释放资源(包括:销毁Bean,关闭SpringBean的创建工厂等)
注: 钩子可以在以下几种场景中被调用:
1)程序正常退出
2)使用System.exit()
3)终端使用Ctrl+C触发的中断
4)系统关闭
5)使用Kill pid命令杀死进程

获取当前所有ApplicationRunner和CommandLineRunner接口的实现类,执行其run方法
遍历所有的SpringApplicationRunListener的finished()方法,完成SpringBoot的启动。

SpringBoot核心原理:自动配置、事件驱动、Condition

SpringBoot是Spring的包装,通过自动配置使得SpringBoot可以做到开箱即用,上手成本非常低,但是学习其实现原理的成本大大增加,需要先了解熟悉Spring原理。

如果还不清楚Spring原理的,可以先查看博主之前的文章,本篇主要分析SpringBoot的启动、自动配置、Condition、事件驱动原理。

SpringBoot启动非常简单,因其内置了Tomcat,所以只需要通过下面几种方式启动即可:

可以看到第一种是最简单的,也是最常用的方式,需要注意类上面需要标注 @SpringBootApplication 注解,这是自动配置的核心实现,稍后分析,先来看看SpringBoot启动做了些什么?

在往下之前,不妨先猜测一下,run方法中需要做什么?对比Spring源码,我们知道,Spring的启动都会创建一个 ApplicationContext 的应用上下文对象,并调用其refresh方法启动容器,SpringBoot只是Spring的一层壳,肯定也避免不了这样的操作。

另一方面,以前通过Spring搭建的项目,都需要打成War包发布到Tomcat才行,而现在SpringBoot已经内置了Tomcat,只需要打成Jar包启动即可,所以在run方法中肯定也会创建对应的Tomcat对象并启动。以上只是我们的猜想,下面就来验证,进入run方法:

SpringBoot的启动流程就是这个方法,先看 getRunListeners 方法,这个方法就是去拿到所有的 SpringApplicationRunListener 实现类,这些类是用于SpringBoot事件发布的,关于事件驱动稍后分析,这里主要看这个方法的实现原理:

一步步追踪下去可以看到最终就是通过SPI机制根据接口类型从 META-INF/spring.factories 文件中加载对应的实现类并实例化,SpringBoot的自动配置也是这样实现的。

为什么要这样做呢?通过注解扫描不可以么?当然不行,这些类都在第三方jar包中,注解扫描实现是很麻烦的,当然你也可以通过 @Import 注解导入,但是这种方式不适合扩展类特别多的情况,所以这里采用SPI的优点就显而易见了。

回到run方法中,可以看到调用了 createApplicationContext 方法,见名知意,这个就是去创建应用上下文对象:

注意这里通过反射实例化了一个新的没见过的上下文对象 AnnotationConfigServletWebServerApplicationContext ,这个是SpringBoot扩展的,看看其构造方法:

如果你有看过Spring注解驱动的实现原理,这两个对象肯定不会陌生,一个实支持注解解析的,另外一个是扫描包用的。

上下文创建好了,下一步自然就是调用refresh方法启动容器:

这里首先会调用到其父类中 ServletWebServerApplicationContext :

可以看到是直接委托给了父类:

这个方法不会陌生吧,之前已经分析过了,这里不再赘述,至此SpringBoot的容器就启动了,但是Tomcat启动是在哪里呢?run方法中也没有看到。

实际上Tomcat的启动也是在refresh流程中,这个方法其中一步是调用了onRefresh方法,在Spring中这是一个没有实现的模板方法,而SpringBoot就通过这个方法完成了Tomcat的启动:

这里首先拿到 TomcatServletWebServerFactory 对象,通过该对象再去创建和启动Tomcat:

上面的每一步都可以对比Tomcat的配置文件,需要注意默认只支持了http协议:

如果想要扩展的话则可以对 additionalTomcatConnectors 属性设置值,需要注意这个属性没有对应的setter方法,只有 addAdditionalTomcatConnectors 方法,也就是说我们只能通过实现 BeanFactoryPostProcessor 接口的 postProcessBeanFactory 方法,而不能通过 BeanDefinitionRegistryPostProcessor 的 postProcessBeanDefinitionRegistry 方法,因为前者可以通过传入的BeanFactory对象提前获取到 TomcatServletWebServerFactory 对象调用 addAdditionalTomcatConnectors 即可;而后者只能拿到BeanDefinition对象,该对象只能通过setter方法设置值。

这段代码会在控制台打印所有的事件名称,按照顺序如下:

以上是正常启动关闭,如果发生异常还有发布 ApplicationFailedEvent 事件。事件的发布遍布在整个容器的启动关闭周期中,事件发布对象刚刚我们也看到了是通过SPI加载的 SpringApplicationRunListener 实现类 EventPublishingRunListener ,同样事件监听器也是在 spring.factories 文件中配置的,默认实现了以下监听器:

可以看到有用于文件编码的( FileEncodingApplicationListener ),有加载日志框架的( LoggingApplicationListener ),还有加载配置的( ConfigFileApplicationListener )等等一系列监听器,SpringBoot也就是通过这系列监听器将必要的配置和组件加载到容器中来,这里不再详细分析,感兴趣的读者可以通过其实现的 onApplicationEvent 方法看到每个监听器究竟是监听的哪一个事件,当然事件发布和监听我们自己也是可以扩展的。

SpringBoot最核心的还是自动配置,为什么它能做到开箱即用,不再需要我们手动使用 @EnableXXX 等注解来开启?这一切的答案就在 @SpringBootApplication 注解中:

这里重要的注解有三个: @SpringBootConfiguration 、 @EnableAutoConfiguration 、 @ComponentScan 。 @ComponentScan 就不用再说了, @SpringBootConfiguration 等同于 @Configuration ,而 @EnableAutoConfiguration 就是开启自动配置:

@AutoConfigurationPackage 注解的作用就是将该注解所标记类所在的包作为自动配置的包,简单看看就行,主要看 AutoConfigurationImportSelector ,这个就是实现自动配置的核心类,注意这个类是实现的 DeferredImportSelector 接口。

在这个类中有一个 selectImports 方法。这个方法在我之前的文章这一次搞懂Spring事务注解的解析也有分析过,只是实现类不同,它同样会被 ConfigurationClassPostProcessor 类调用,先来看这个方法做了些什么:

追踪源码最终可以看到也是从 META-INF/spring.factories 文件中拿到所有 EnableAutoConfiguration 对应的值(在 spring-boot-autoconfigure 中)并通过反射实例化,过滤后包装成 AutoConfigurationEntry 对象返回。

看到这里你应该会觉得自动配置的实现就是通过这个 selectImports 方法,但实际上这个方法通常并不会被调用到,而是会调用该类的内部类 AutoConfigurationGroup 的process和selectImports方法,前者同样是通过 getAutoConfigurationEntry 拿到所有的自动配置类,而后者这是过滤排序并包装后返回。

下面就来分析 ConfigurationClassPostProcessor 是怎么调用到这里的,直接进入 processConfigBeanDefinitions 方法:

前面一大段主要是拿到合格的 Configuration 配置类,主要逻辑是在 ConfigurationClassParser.parse 方法中,该方法完成了对 @Component 、 @Bean 、 @Import 、 @ComponentScans 等注解的解析,这里主要看对 @Import 的解析,其它的读者可自行分析。一步步追踪,最终会进入到 processConfigurationClass 方法:

这里需要注意 this.conditionEvaluator.shouldSkip 方法的调用,这个方法就是进行Bean加载过滤的,即根据 @Condition 注解的匹配值判断是否加载该Bean,具体实现稍后分析,继续跟踪主流程 doProcessConfigurationClass :

这里就是完成对一系列注解的支撑,我省略掉了,主要看 processImports 方法,这个方法就是处理 @Import 注解的:

刚刚我提醒过 AutoConfigurationImportSelector 是实现 DeferredImportSelector 接口的,如果不是该接口的实现类则是直接调用 selectImports 方法,反之则是调用 DeferredImportSelectorHandler.handle 方法:

首先创建了一个 DeferredImportSelectorHolder 对象,如果是第一次执行则是添加到 deferredImportSelectors 属性中,等到 ConfigurationClassParser.parse 的最后调用process方法:

反之则是直接执行,首先通过register拿到 AutoConfigurationGroup 对象:

然后在 processGroupImports 方法中进行真正的处理:

阅读更多 >>>  dede网站模板,dedehtml

在 getImports 方法中就完成了对process和 selectImports 方法的调用,拿到自动配置类后再递归调用调用 processImports 方法完成对自动配置类的加载。至此,自动配置的加载过程就分析完了,下面是时序图:

在自动配置类中有很多Condition相关的注解,以AOP为例:

这里就能看到 @ConditionalOnProperty 、 @ConditionalOnClass 、 @ConditionalOnMissingClass ,另外还有 @ConditionalOnBean 、 @ConditionalOnMissingBean 等等很多条件匹配注解。

这些注解表示条件匹配才会加载该Bean,以 @ConditionalOnProperty 为例,表明配置文件中符合条件才会加载对应的Bean,prefix表示在配置文件中的前缀,name表示配置的名称, havingValue 表示配置为该值时才匹配, matchIfMissing 则是表示没有该配置是否默认加载对应的Bean。其它注解可类比理解记忆,下面主要来分析该注解的实现原理。

这里注解点进去看会发现每个注解上都标注了 @Conditional 注解,并且value值都对应一个类,比如 OnBeanCondition ,而这些类都实现了 Condition 接口,看看其继承体系:

上面只展示了几个实现类,但实际上Condition的实现类是非常多的,我们还可以自己实现该接口来扩展 @Condition 注解。Condition接口中有一个matches方法,这个方法返回true则表示匹配。该方法在 ConfigurationClassParser 中多处都有调用,也就是刚刚我提醒过的shouldSkip方法,具体实现是在 ConditionEvaluator 类中:

再来看看matches的实现,但 OnBeanCondition 类中没有实现该方法,而是在其父类 SpringBootCondition 中:

getMatchOutcome 方法也是一个模板方法,具体的匹配逻辑就在这个方法中实现,该方法返回的 ConditionOutcome 对象就包含了是否匹配和日志消息两个字段。进入到 OnBeanCondition 类中:

可以看到该类支持了 @ConditionalOnBean 、 @ConditionalOnSingleCandidate 、 @ConditionalOnMissingBean 注解,主要的匹配逻辑在 getMatchingBeans 方法中:

这里逻辑看起来比较复杂,但实际上就做了两件事,首先通过 getNamesOfBeansIgnoredByType 方法调用 beanFactory.getBeanNamesForType 拿到容器中对应的Bean实例,然后根据返回的结果判断哪些Bean存在,哪些Bean不存在(Condition注解中是可以配置多个值的)并返回MatchResult对象,而MatchResult中只要有一个Bean没有匹配上就返回false,也就决定了当前Bean是否需要实例化。

本篇分析了SpringBoot核心原理的实现,通过本篇相信读者也将能更加熟练地使用和扩展SpringBoot。

另外还有一些常用的组件我没有展开分析,如事务、MVC、监听器的自动配置,这些我们有了Spring源码基础的话下来看一下就明白了,这里就不赘述了。

最后读者可以思考一下我们应该如何自定义starter启动器,相信看完本篇应该难不倒你。

SpringBoot自动装配原理

初看@SpringBootApplication有很多的注解组成,其实归纳就是一个"三体"结构,重要的只有三个Annotation:
(1)@Configuration注解
(2)@ComponentScan
(3)@EnableAutoConfiguration
从源码中可以知道,最关键的要属@Import(EnableAutoConfigurationImportSelector.class),借助EnableAutoConfigurationImportSelector,@EnableAutoConfiguration可以帮助SpringBoot应用将所有符合条件的@Configuration配置都加载到当前SpringBoot创建并使用的IoC容器。同时借助于Spring框架原有的一个工具类:SpringFactoriesLoader,@EnableAutoConfiguration就可以实现智能的自动配置。
总结 :@EnableAutoConfiguration作用就是从classpath中搜寻所有的META-INF/spring.factories配置文件,并将其中org.springframework.boot.autoconfigure.EnableutoConfiguration对应的配置项通过反射(Java Refletion)实例化为对应的标注了@Configuration的JavaConfig形式的IoC容器配置类,然后汇总为一个并加载到IoC容器。这些功能配置类要生效的话,会去classpath中找是否有该类的依赖类(也就是pom.xml必须有对应功能的jar包才行)并且配置类里面注入了默认属性值类,功能类可以引用并赋默认值。生成功能类的原则是自定义优先,没有自定义时才会使用自动装配类。
1、从spring-boot-autoconfigure.jar/META-INF/spring.factories中获取redis的相关配置类全限定名(有120多个的配置类)RedisAutoConfiguration,一般一个功能配置类围绕该功能,负责管理创建多个相关的功能类,比如RedisAutoConfiguration负责:JedisConnectionFactory、RedisTemplate、StringRedisTemplate这3个功能类的创建
2、RedisAutoConfiguration配置类生效的一个条件是在classpath路径下有RedisOperations类存在,因此springboot的自动装配机制会会去classpath下去查找对应的class文件。
3.如果pom.xml有对应的jar包,就能匹配到对应依赖class,
4、匹配成功,这个功能配置类才会生效,同时会注入默认的属性配置类@EnableConfigurationProperties(RedisProperties.class)
5.Redis功能配置里面会根据条件生成最终的JedisConnectionFactory、RedisTemplate,并提供了默认的配置形式@ConditionalOnMissingBean(name = "redisTemplate")
6.最终创建好的默认装配类,会通过功能配置类里面的 @Bean注解,注入到IOC当中 7.用户使用,当用户在配置文件中自定义时候就会覆盖默认的配置@ConditionalOnMissingBean(name = "redisTemplate")
1.通过各种注解实现了类与类之间的依赖关系,容器在启动的时候Application.run,会调用EnableAutoConfigurationImportSelector.class的selectImports方法(其实是其父类的方法)-- 这里需要注意,调用这个方法之前发生了什么和是在哪里调用这个方法需要进一步的探讨
2.selectImports方法最终会调用SpringFactoriesLoader.loadFactoryNames方法来获取一个全面的常用BeanConfiguration列表
3.loadFactoryNames方法会读取FACTORIES_RESOURCE_LOCATION(也就是spring-boot-autoconfigure.jar 下面的spring.factories),获取到所有的Spring相关的Bean的全限定名ClassName,大概120多个
4.selectImports方法继续调用filter(configurations, autoConfigurationMetadata);这个时候会根据这些BeanConfiguration里面的条件,来一一筛选,最关键的是 @ConditionalOnClass,这个条件注解会去classpath下查找,jar包里面是否有这个条件依赖类,所以必须有了相应的jar包,才有这些依赖类,才会生成IOC环境需要的一些默认配置Bean
5.最后把符合条件的BeanConfiguration注入默认的EnableConfigurationPropertie类里面的属性值,并且注入到IOC环境当中

springboot的自动装配原理,如何实现按需加载?

Spring Boot 是一种基于 Spring 框架的快速应用开发框架,其自动装配的原理主要是通过自动配置机制来实现的。Spring Boot 的自动配置机制使得开发者不需要编写太多的配置文件,就能够快速搭建一个项目。
Spring Boot 的自动装配实现按需加载的主要思路是根据项目的实际需要自动启用或禁用某些组件,也就是所谓的“条件化注解”。
具体来说,Spring Boot 在启动时会读取项目的配置信息,主要包括两个部分:
1.配置文件(application.properties 或 application.yml):可以在这里配置一些参数,例如数据库连接信息等。
2.自动配置文件(META-INF/spring.factories):这里记录了所有的自动配置类,每个自动配置类都对应一个自动配置的接口(Enable...),并且这些接口都定义在 org.springframework.boot.autoconfigure.EnableAutoConfiguration 命名空间下。
当 Spring Boot 启动时,会扫描项目中的各种信息,通过这些信息来生成一个自动配置的 Bean 列表。对于每个 Bean,Spring Boot 会检查其所在的包是否在条件化注解中进行了配置。如果包在条件化注解中进行了配置,那么只有在使用到该包中的相关组件时,对应的 Bean 才会被加载。
举个例子,假设我们开发了一个使用 Spring Data JPA 的项目,而项目中并没有使用 Hibernate,那么在启动时,Spring Boot 就会根据条件化注解,只加载 Spring Data JPA 相关的组件,而不会加载 Hibernate。这样可以大大减少项目的启动时间和资源占用。
总的来说,Spring Boot 的自动装配实现按需加载的核心思想就是通过条件化注解来实现组件的按需加载,从而提高了应用的性能和启动速度。
Spring Boot 的自动装配原理主要依赖于 Spring 框架提供的 @Configuration、@ComponentScan 和 @Conditional 等注解,配合 Spring Boot 提供的 @EnableAutoConfiguration 和 spring.factories 配置文件,来实现自动装配的功能。
在 Spring Boot 应用启动时,会扫描 classpath 下的 META-INF/spring.factories 文件,该文件中配置了所有自动装配的类名称,Spring Boot 就会查找这些类并将它们实例化、注册到 Spring 容器中。这些自动装配的类通常都添加了 @Conditional 注解,用于判断特定条件是否满足,从而决定是否需要自动装配。
为了实现按需加载,Spring Boot 提供了 @ConditionalOnClass、@ConditionalOnMissingClass、@ConditionalOnBean、@ConditionalOnMissingBean、@ConditionalOnProperty 等注解,开发者可以根据具体情况使用这些注解进行条件判断,从而决定是否需要自动装配。
以 @ConditionalOnClass 注解为例,该注解会检查 classpath 下是否存在指定的类,如果存在,则启用自动装配,否则不启用。在 Spring Boot 应用启动时,会根据类路径加载的顺序,先判断项目本身的依赖是否包含了指定的类,如果项目本身的依赖中不包含,则会判断所有的依赖中是否包含指定的类,直到找到为止。
通过这种方式,可以实现按需加载,避免了不必要的装配操作,同时提高了应用程序的性能和可维护性。

springboot starter 原理解析及实践

starter是springBoot的一个重要部分。通过starter,我们能够快速的引入一个功能,而无需额外的配置。同时starter一般还会给我提供预留的自定配置选项,我们只需要在application.properties中设置相关参数,就可以实现配置的个性化。
那么这些方便的操作是怎么实现的呢?通过了解其原理,我们也可以做一个自己的starter,来让别人快速使用我们的功能。
按个人理解,我认为springBoot Starter就是一个 智能化的配置类 @Configuration 。
接下来介绍内容包括:
1、【创建module】,首先我们自定义一个starter的module,根据你的starter实现复杂度,引入相关spring组件。最基本的,我们只需引入 spring-boot-autoconfigure 模块。
2、【业务bean实现】实现我们的业务bean,案例中我们实现最简单的sayHello服务,输入msg,返回“hello,{msg}”。
3、然后就是Configuration类的创建,这个类是starter自动初始化的核心类,负责把业务相关的bean智能的加载进来。
4、配置 spring.factories ,通过该配置,才能让springboot来自动加载我们的Configuration类。具体原理我们稍后深入了解。
具体的,是在模块的 resources/META-INF 目录下,新建 spring.factories 文件。内容如下:
最后我们把上述模块单独执行以下install或者deploy,一个starter就做好了。
其他项目使用我们的starter就非常简单了:(1)引入starter依赖;(2)注入需要的service。
done!
回头再看上边的开发流程,有两个地方需要我们了解一下:
(1)如何让starter被自动识别加载:spring.factories里的EnableAutoConfiguration原理。
(2)如何实现自动加载的智能化、可配置化:@Configuration配置类里注解。
这里我们只简单的说一下大致的原理和流程,执行细节大家可以按照文章给出的思路自己去研读。
在SpringBoot的启动类,我们都会加上 @SpringBootApplication 注解。这个注解默认会引入 @EnableAutoConfiguration 注解。然后 @EnableAutoConfiguration 会 @Import(AutoConfigurationImportSelector.class) 。
AutoConfigurationImportSelector.class 的selectImports方法最终会通过 SpringFactoriesLoader.loadFactoryNames ,加载 META-INF/spring.factories 里的 EnableAutoConfiguration 配置值,也就是我们上文中设置的资源文件。
实际使用中,我们并不总是希望使用默认配置。比如有时候我想自己配置相关功能,有时候我想更改一下默认的服务参数。这些常见的场景Starter都想到了,并提供了如下的解决方案:
springboot starter提供了一系列的 @Conditional* 注解,代表什么时候启用对应的配置,具体的可以去查看一下springboot的官方文档。
比如我们案例中的 「@ConditionalOnClass(DemoHelloService.class)」,代表如果存在DemoHelloService类时,配置类才会生效;又比如「@ConditionalOnMissingBean(DemoHelloService.class)」,代表着如果项目中没有DemoHelloService类型的bean,那么该配置类会自动创建出starter默认的DemoHelloService类型bean。
这个注解主要是为了解决如下场景:我想要使用starter的默认配置类,但是又想对配置中的某些参数进行自定义配置。 @ConfigurationProperties 类就是做这个工作的。例如上述例子中,我想对默认的defaultMsg做些个性化的设置。就可以按如下方式来实现:
starter新增ConfigurationProperties类bean
启用property
在实际项目中自定义默认msg

spring boot自动装配原理

阅读更多 >>>  网页模板网站

首先打开一个基本的springboot项目,点进去@SpringBootApplication注解。
可以根据名字知道实现自动装配应该是上面的@EnableAutoConfiguration注解,继续点进去
这时候对spring注解比较了解的同学应该能感觉到实现原理就在@Import(AutoConfigurationImportSelector.class)这个注解中,@Import注解的参数可以是静态类(用作直接导入)也可以是实现了ImportSelector接口的类,当是实现了ImportSelector会根据实现的selectImports方法来对类进行导入。让我们看看AutoConfigurationImportSelector的实现
图中loadmetadata的方法是加载项目的基本配置数据信息,而getAutoConfigurationEntry方法则是自动装配的逻辑,继续点进去
还是在加载配置,继续点进去
其实到这一步基本清楚了,做的这些事情都是在加载类,那么自动装配到底加载的是什么类呢,这里从外部传入的factoryname是Enableautoconfiguration.class
点进去加载逻辑可以看到是在加载FACTORIES_RESOURCE_LOCATION路径下的类。
会自动扫描所有项目下FACTORIES_RESOURCE_LOCATION这个路径下的类,那么这个路径是啥?
总结:到这里基本清楚了,springboot的自动装配就是通过自定义实现ImportSelector接口,从而导致项目启动时会自动将所有项目META-INF/spring.factories路径下的配置类注入到spring容器中,从而实现了自动装配。
相关的starter和自定义starter都是根据这个实现的。后续有空的话还会写一下如何实现自定义starter的随笔。
以上就是springboot 自动装配的原理,还有不懂的地方欢迎关注私聊我,很高兴为你解答

Springboot 读取配置文件原理

Springboot 读取配置文件(application.yaml, application.properties)的过程发生在SpringApplication#prepareEnvironment() 阶段,而prepareEnvironment又属于整个Springboot 应用启动的非常前置阶段,因为Environment的准备是后续bean创建的基础。让我们来一探启动是的详细code。除去StopWatch这些code,可以发现prepareEnvironment 发生在SpringApplication#run 这在整个应用启动的多步实质性操作中几乎是第一步。
而prepareEnvironment中最重要的是通过触发listener(EventPublishingRunListener)来通过SimpleApplicationEventMulticaster#multicastEvent发出ApplicationEnvironmentPreparedEvent。
而SimpleApplicationEventMulticaster#multicastEvent的实现其实也很简单,找到相关的监听ApplicationEnvironmentPreparedEvent的listener,然后一个个的调用他们的Listener#onApplicationEvent(event)方法,而这其中就包括了处理configuration文件的listener。 在Springboot 2.4.0 之前这个处理configuration 文件的lister是ConfigFileApplicationListener,在2.4.0之后,处理configuration 文件的lister是EnvironmentPostProcessorApplicationListener,并且对configuration文件的加载做了较大的改变,导致一些行为可能出现了变化,这也就是下面要详细讲的内容。
Springboot 2.4.0之后,configuration 文件的load顺序按照优先级是如下顺序(序号大的会被小的覆盖):
和之前版本比较,整体的属性加载顺序并无调整,只有Application properties(14,15)这里有顺序的调整,具体调整为:
如果存在多个active的profiles,例如[Test, Dev], 那么对于同时存在两个profile 配置文件中的配置,后面的profile里的配置(Dev)会覆盖前面profile(Test)里配置的值。
前面讲了这么多,终于要引出Springboot 2.4之后配置文件加载的行为变化了。
考虑这样的情况,如果我想在跑Springboot test的时候指定特定的profile,那么可以在Test class中加入@ActiveProfile("Test")。 如果我的应用中存在ApplicationEnvironmentPreparedEvent的某个自定义listener中,会根据当前environment 设置profile,如env.addActiveProfile("Dev")。 当前就会有两个active profile,由于springboot-test会在调用application#run 前利用DefaultActiveProfilesResolver把@ActiveProfile注解定义的profile(Test)先加入了active的profile,等test run的时候 env.addActiveProfile("Dev") 又会把"Dev"也作为active profile 加入,这时候当前的active profile便为["Test", "Dev"]。
据上面介绍,后面的profile(Dev)对应的configuration 会覆盖前面的(Test)。可Springboot 2.4.0之前的版本为我们做了调整,让Test class中@ActiveProfile内定义的profile所对应的配置文件成为最高优先级。
刚才提到在Springboot 2.4.0 之前这个处理configuration 文件的lister是ConfigFileApplicationListener,我们 来看看ConfigFileApplicationListener的相关code。
查看initializeProfiles(),发现此时对profile的顺序做了调整,将activatedViaProperty (Test) 放在最后add,于是profile的顺序就变成了[Dev, Test]。
在profiles.poll()时原本profile的顺序已经倒了过来,已经变为[Dev, Test], 在load()方法中由于后置的Test profile,application-Test.yaml中的值最终生效了。
可是到了Springboot2.4.0之后,ConfigFileApplicationListener被deprecated了,取而代之的是EnvironmentPostProcessorApplicationListener,EnvironmentPostProcessorApplicationListener通过调用ConfigDataEnvironmentPostProcessor来完成configuration加载。 EnvironmentPostProcessorApplicationListener.java
ConfigDataEnvironmentPostProcessor.java
ConfigDataEnvironmentPostProcessor只是老老实实的set了active profile,并没有调换profile的顺序。最后调用定义在spring.factories中的resource loader class来load 配置文件。
YamlPropertySourceLoader.java
插一句,Springboot为我们提供了很好的yaml文件parse的code,当你需要解析yaml文件时不妨直接参考Springboot的YamlPropertySourceLoader
这样一旦应用升级到Springboot 2.4.0之后相同的test code会使用application-Dev.yaml中配置的值,造成了test结果的改变。 如果要解决这个问题,根据上面介绍的配置文件优先级顺序,可以在@SpringbootTest中设置properties 来作为最终的配置覆盖当前profile对应的配置。
了解一个框架很不容易,一个小小的变化都有可能造成应用的行为变化,唯有刨根问底,不断总结才是framework人解决一切问题的不变的方法论。

网站数据信息

"springboot的工作原理,SpringBoot启动原理分析"浏览人数已经达到17次,如你需要查询该站的相关权重信息,可以点击进入"Chinaz数据" 查询。更多网站价值评估因素如:springboot的工作原理,SpringBoot启动原理分析的访问速度、搜索引擎收录以及索引量、用户体验等。 要评估一个站的价值,最主要还是需要根据您自身的需求,如网站IP、PV、跳出率等!