一、SpringBoot的starter简介
1.1 什么是starter(场景启动器)
在SpringBoot呈现之前,如果咱们想应用SpringMVC来构建咱们的web我的项目,必须要做的几件事件如下:
- 首先我的项目中须要引入SpringMVC的依赖
- 在web.xml中注册SpringMVC的
DispatcherServlet
,并配置url映射 - 编写
springmcv-servlet.xml
,在其中配置SpringMVC中几个重要的组件,解决映射器(HandlerMapping)、解决适配器(HandlerAdapter)、视图解析器(ViewResolver) - 在
applicationcontext.xml
文件中引入springmvc-servlet.xml
文件 - …
以上这几步只是配置好了SpringMVC,如果咱们还须要与数据库进行交互,就要在application.xml中配置数据库连接池DataSource,如果须要数据库事务,还须要配置TransactionManager…
这就是应用Spring框架开发我的项目带来的一些的问题:
- 依赖导入问题: 每个我的项目都须要来独自保护本人所依赖的jar包,在我的项目中应用到什么性能就须要引入什么样的依赖。手动导入依赖容易出错,且无奈对立集中管理
- 配置繁琐: 在引入依赖之后须要做繁冗的配置,并且这些配置是每个我的项目来说都是必要的,例如web.xml配置(Listener配置、Filter配置、Servlet配置)、log4j配置、数据库连接池配置等等。这些配置反复且繁冗,在不同的我的项目中须要进行多次重复开发,这在很大水平上升高了咱们的开发效率
而在SpringBoot呈现之后,它为咱们提供了一个弱小的性能来解决上述的两个痛点,这就是SpringBoot的starters(场景启动器)。
Spring Boot通过将咱们罕用的性能场景抽取进去,做成的一系列场景启动器,这些启动器帮咱们导入了实现各个性能所须要依赖的全副组件,咱们只须要在我的项目中引入这些starters,相干场景的所有依赖就会全副被导入进来,并且咱们能够摈弃繁冗的配置,仅须要通过配置文件来进行大量的配置就能够应用相应的性能。
二、SpringBoot场景启动器的原理
在导入的starter之后,SpringBoot次要帮咱们实现了两件事件:
- 相干组件的主动导入
- 相干组件的主动配置
这两件事件对立称为SpringBoot的主动配置
2.1 主动配置原理
2.1.1 主动配置类的获取与注入
咱们从主程序入口来摸索一下整个过程的原理:
@SpringBootApplication //标注这个类是一个springboot的利用public class CommunityApplication { public static void main(String[] args) { //将springboot利用启动 SpringApplication.run(CommunityApplication.class, args); }}
Spring Boot 根底就不介绍了,举荐下这个实战教程:
https://github.com/javastacks...
@SpringBootApplication
注解内部结构如下图所示:
AutoConfigurationImportSelector
:重点看该类中重写的selectImports办法,看下它返回的字符串数组是如何得来的:
咱们能够去到上边提到的spring.factories
文件中去看一下,找到spring官网提供的spring-boot-autoconfigure
包,在其上来找一下该文件:
能够看到这个就是SpringBoot官网为咱们提供的所有主动配置类的候选列表。咱们能够在其中找到一个咱们比拟相熟的主动配置类去看一下它外部的实现:
能够看到这些一个个的都是JavaConfig配置类,而且都通过@Bean
注解向容器中注入了一些Bean
论断:
- SpringBoot在启动的时候从类门路下的
META-INF/spring.factories
中获取EnableAutoConfiguration指定的所有主动配置类的全限定类名 - 将这些主动配置类导入容器,主动配置类就失效,帮咱们进行主动配置工作;
- 整个J2EE的整体解决方案和主动配置都在
spring-boot-autoconfigure
的jar包中; - 它会给容器中导入十分多的主动配置类 (xxxAutoConfiguration), 就是给容器中导入这个场景须要的所有组件,并配置好这些组件 ;
- 有了主动配置类,免去了咱们手动编写配置注入性能组件等的工作;
2.1.2 主动配置的过程
主动配置类被注入到容器当中后,会帮咱们进行组件的主动配置和主动注入的工作,咱们以HttpEncodingAutoConfiguration(Http编码主动配置)为例解释这个过程:
首先咱们先看下SpringBoot中配置文件与POJO类之间映射的办法,这是进行主动配置的根底。
配置集中化治理:SpringBoot中所有可配置项都集中在一个文件中(application.yml),这个文件中的配置通过@ConfigurationProperties
注解来与咱们程序外部定义的POJO类来产生关联,这些POJO类对立命名为xxxProperties
,并且这些xxxProperties
类中各个属性字段都有本人的默认值,这也是SpringBoot约定大于配置理念的体现,尽可能减少用户做抉择的次数,但同时又不失灵活性。只有咱们想,配置文件中的配置随时能够笼罩默认值。
之后,通过配合@EnableConfigurationProperties
注解,就能够主动将与配置文件绑定好的这个类注入到容器中供咱们应用。
主动配置类的工作流程:
- 依据限定的条件向容器中注入组件
- 应用xxxProperties对注入的组件的相干属性进行配置
//示意这是一个配置类,和以前编写的配置文件一样,也能够给容器中增加组件;@Configuration//将与配置文件绑定好的某个类注入到容器中,使其失效//进入这个HttpProperties查看,将配置文件中对应的值和HttpProperties绑定起来;//并把HttpProperties退出到ioc容器中@EnableConfigurationProperties(HttpProperties.class)//Spring底层@Conditional注解//依据不同的条件判断,如果满足指定的条件,整个配置类外面的配置就会失效;//这里的意思就是判断以后利用是否是web利用,如果是,以后配置类失效@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)//判断零碎中有没有CharacterEncodingFilter这个类,如果有配置类才失效@ConditionalOnClass(CharacterEncodingFilter.class)//判断配置文件中是否存在某个配置:spring.http.encoding.enabled;//matchIfMissing = true表明即便咱们配置文件中不配置pring.http.encoding.enabled=true,该配置类也是默认失效的;@ConditionalOnProperty(prefix = "spring.http.encoding", value = "enabled", matchIfMissing = true)public class HttpEncodingAutoConfiguration { //该类曾经与配置文件绑定了 private final HttpProperties.Encoding properties; //构建该主动配置类时将与配置文件绑定的配置类作为入参传递进去 public HttpEncodingAutoConfiguration(HttpProperties properties) { this.properties = properties.getEncoding(); } @Bean @ConditionalOnMissingBean public CharacterEncodingFilter characterEncodingFilter() { CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter(); filter.setEncoding(this.properties.getCharset().name()); //注入bean时应用配置类中属性的值进行初始化,相当于将配置文件中的值映射到了组件的某些属性上 filter.setForceRequestEncoding(this.properties.shouldForce(Type.REQUEST)); filter.setForceResponseEncoding(this.properties.shouldForce(Type.RESPONSE)); return filter; //注入配置好的bean }}
一句话总结下主动配置类的工作过程 :
- 首先容器会依据以后不同的条件判断,决定这个配置类是否失效!
- 一但这个配置类失效;这个配置类就会给容器中增加相应组件;
- 这些组件的属性是从对应的properties类中获取的,这些类外面的每一个属性又是和配置文件绑定的;
- 所有在配置文件中能配置的属性都是在xxxxProperties类中封装着,配置文件能够配置什么内容,能够参照该前缀对应的属性类中的属性字段
//从配置文件中获取指定的值和bean的属性进行绑定@ConfigurationProperties(prefix = "spring.http")public class HttpProperties { // .....}
2.2 SpringBoot主动配置应用总结
- SpringBoot启动会加载大量的主动配置类
- 咱们首先能够看咱们须要的性能有没有在SpringBoot默认写好的主动配置类当中;
- 咱们再来看这个主动配置类中到底配置了哪些组件;(只有咱们要用的组件存在在其中,咱们就不须要再手动配置了)
- 给容器中主动配置类增加组件的时候,会从properties类中获取某些属性。咱们只须要在配置文件中指定这些属性的值即可;
xxxxAutoConfigurartion
:主动配置类;给容器中增加组件xxxxProperties
:封装配置文件中相干属性;
理解完主动拆卸的原理后,咱们来关注一个细节问题,主动配置类必须在肯定的条件下能力失效;@Conditional
派生注解(Spring注解版原生的@Conditional
作用)
作用:必须是@Conditional
指定的条件成立,才给容器中增加组件,配置外面的所有内容才失效;
那么多的主动配置类,必须在肯定的条件下能力失效;也就是说,咱们加载了这么多的配置类,但不是所有的都失效了。
咱们怎么晓得哪些主动配置类失效?
咱们能够通过启用 debug=true
属性;来让控制台打印主动配置报告,这样咱们就能够很不便的晓得哪些主动配置类失效;
#在配置文件中开启springboot的调试类debug=true
Positive matches
:(主动配置类启用的:正匹配)
Positive matches:----------------- AopAutoConfiguration matched: - @ConditionalOnClass found required classes 'org.springframework.context.annotation.EnableAspectJAutoProxy', 'org.aspectj.lang.annotation.Aspect', 'org.aspectj.lang.reflect.Advice', 'org.aspectj.weaver.AnnotatedElement' (OnClassCondition) - @ConditionalOnProperty (spring.aop.auto=true) matched (OnPropertyCondition) AopAutoConfiguration.CglibAutoProxyConfiguration matched: - @ConditionalOnProperty (spring.aop.proxy-target-class=true) matched (OnPropertyCondition) AuditAutoConfiguration#auditListener matched: - @ConditionalOnMissingBean (types: org.springframework.boot.actuate.audit.listener.AbstractAuditListener; SearchStrategy: all) did not find any beans (OnBeanCondition) AuditAutoConfiguration#authenticationAuditListener matched: - @ConditionalOnClass found required class 'org.springframework.security.authentication.event.AbstractAuthenticationEvent' (OnClassCondition) - @ConditionalOnMissingBean (types: org.springframework.boot.actuate.security.AbstractAuthenticationAuditListener; SearchStrategy: all) did not find any beans (OnBeanCondition)
Negative matches
:(没有启动,没有匹配胜利的主动配置类:负匹配)
Negative matches:----------------- ActiveMQAutoConfiguration: Did not match: - @ConditionalOnClass did not find required class 'javax.jms.ConnectionFactory' (OnClassCondition) AopAutoConfiguration.JdkDynamicAutoProxyConfiguration: Did not match: - @ConditionalOnProperty (spring.aop.proxy-target-class=false) did not find property 'proxy-target-class' (OnPropertyCondition) AppOpticsMetricsExportAutoConfiguration: Did not match: - @ConditionalOnClass did not find required class 'io.micrometer.appoptics.AppOpticsMeterRegistry' (OnClassCondition) ArtemisAutoConfiguration: Did not match: - @ConditionalOnClass did not find required class 'javax.jms.ConnectionFactory' (OnClassCondition)
Exclusions、Unconditional classes(排除的、没有限定条件的主动配置类):
Exclusions:----------- org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfigurationUnconditional classes:---------------------- org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration org.springframework.boot.actuate.autoconfigure.endpoint.jmx.JmxEndpointAutoConfiguration org.springframework.boot.actuate.autoconfigure.health.HealthIndicatorAutoConfiguration org.springframework.boot.actuate.autoconfigure.info.InfoContributorAutoConfiguration
三、自定义场景启动器
当初咱们曾经理解了场景启动器的概念以及其暗藏在背地的主动配置的原理,咱们就能够本人来对SpringBoot进行性能拓展,定义咱们本人的场景启动器。
3.1 starter的命名标准
官网命名空间
- 前缀:spring-boot-starter-
- 模式:spring-boot-starter-模块名
- 举例:spring-boot-starter-web、spring-boot-starter-jdbc
自定义命名空间
- 后缀:-spring-boot-starter
- 模式:模块-spring-boot-starter
- 举例:mybatis-spring-boot-starter
举荐一个 Spring Boot 基础教程及实战示例:
https://github.com/javastacks...
3.2 starter模块整体构造
通过上边的介绍,能够总结starter的整体实现逻辑次要由两个根本局部组成:
xxxAutoConfiguration
:主动配置类,对某个场景下须要应用到的一些组件进行主动注入,并利用xxxProperties类来进行组件相干配置
xxxProperties
:某个场景下所有可配置属性的集成,在配置文件中配置能够进行属性值的笼罩 依照SpringBoot官网的定义,Starer的作用就是依赖聚合,因而间接在starter外部去进行代码实现是不符合规定的,starter应该只起到依赖导入的作用,而具体的代码实现应该去交给其余模块来实现,而后在starter中去援用该模块即可,因而整体的starter的形成应该如下图所示:
可见starter模块依赖了两局部,一部分是一些罕用依赖,另一部分就是对主动配置模块的依赖,而xxxAutoConfiguration
与xxxProperties
的具体实现,都封装在主动配置模块中,starter理论是通过该模块来对外提供相应的性能。
3.3 autoconfigure模块开发
3.3.1 依赖引入
首先所有的主动配置模块都要引入两个jar包依赖:
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-autoconfigure</artifactId> <!-- 蕴含很多与主动配置相干的注解的定义,必须要引入 --> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <!-- 非必须的,引入后能够在配置文件中输出咱们自定义配置的时候有相应的提醒,也能够通过其余.properties文件为相干类进行属性映射(SpringBoot默认应用application.yml)--> <optional>true</optional> </dependency> <dependencies>
其余依赖的抉择依据我的项目须要进行增加即可
3.3.2 xxxAutoConfiguration的实现
autoconfigure模块中最重要的就是主动配置类的编写,它为咱们实现组件的主动配置与主动注入。
在编写主动配置类的时候,咱们应该要思考向容器中注入什么组件,如何去配置它。
@Configuration@ConditionalOnxxx@ConditionalOnxxx//限定主动配置类失效的一些条件@EnableConfigurationProperties(xxxProperties.class)public class xxxAutoConfiguration { @Autowired private xxxProperties properties; @Bean public static BeanYouNeed beanYouNeed() { BeanYouNeed bean = new BeanYouNeed() bean.setField(properties.get(field)); bean.setField(properties.get(field)); bean.setField(properties.get(field)); ...... }}
3.3.3 xxxProperties的实现
这是跟配置文件相绑定的类,里边的属性就是咱们能够在配置文件中配置的内容,而后通过@ConfigurationProperties
将其与配置文件绑定:
@ConfigurationProperties(prefix = "your properties") //应用@ConfigurationProperties注解绑定配置文件public class xxxProperties { private boolean enabled = true; private String clientId; private String beanName; private String scanBasePackage; private String path; private String token;}
3.3.4 配置spring.factories文件
在resource目录下新建META-INF文件夹,在文件夹下新建spring.factories
文件,并增加写好的xxxAutoConfiguration
类:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\com.meituan.xframe.boot.mcc.autoconfigure.xxxAutoConfiguration
3.4 Starter模块开发
starter模块中只进行依赖导入,在pom文件中增加对autoconfigure模块的依赖,并增加一些其余必要的依赖项:
<dependencies> ================================================================ <!--增加了对autoconfigure模块的援用--> <dependency> <groupId>com.test.starter</groupId> <artifactId>xxx-spring-boot-autoconfigure</artifactId> </dependency> =============================================================== <!--其余的一些必要依赖项--> <dependency> <groupId>commons-collections</groupId> <artifactId>commons-collections</artifactId> </dependency> </dependencies>
这两个模块都开发实现之后,通过mvn install命令或者deploy命令将包公布到本地或者地方仓库,即可间接在其余我的项目中援用咱们自定义的starter模块了
起源:blog.csdn.net/qq_21310939/article/details/107401400
近期热文举荐:
1.1,000+ 道 Java面试题及答案整顿(2021最新版)
2.别在再满屏的 if/ else 了,试试策略模式,真香!!
3.卧槽!Java 中的 xx ≠ null 是什么新语法?
4.Spring Boot 2.6 正式公布,一大波新个性。。
5.《Java开发手册(嵩山版)》最新公布,速速下载!
感觉不错,别忘了顺手点赞+转发哦!