共计 10109 个字符,预计需要花费 26 分钟才能阅读完成。
一、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.DataSourceAutoConfiguration
Unconditional 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 开发手册(嵩山版)》最新公布,速速下载!
感觉不错,别忘了顺手点赞 + 转发哦!