Spring Boot Starter为我们做了什么?

Spring Boot遵循约定大于配置的思想为我们省去了繁杂的XML配置,其为我们提供了许多诸如:spring-boot-starter-webspring-boot-starter-data-jpaspring-boot-starter-data-redis等常用的Starter组件,使得我们整合各种常用组件时显得非常简便快捷,那么这个Starter为我们做了什么工作?让我们省去了各种繁杂的整合过程。

Spring Boot Starter是什么?

我们在使用Spring Boot开发应用的时候,经常会引入这样的包:

1
2
3
4
5
6
7
8
9
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--log4j2-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>

其实它们只是整合了当前模块需要的依赖库以及封装了当前组件的常规使用配置使其自动装配,使得我们在使用相应的starter组件的时候省去了我们手动配置的繁琐工作。按道理来说应该先看官方的starter组件源码,但是呢,之前在Spring Boot整合Mybatis Plus和DruidSpring Boot 2.X基于Mybaits-Plus实现多数据源中都用到了druid-spring-boot-starter这个starter组件,所以我们可以借此机会来看看它,因为自定义开发starter组件也都是按照官方的规范来做的。

开发Spring Boot Starter要点

自己开发一个Starter一般需要以下几个步骤:

  • 新建项目,引入Starter所要用到的依赖包
  • 组件配置类,指定配置前缀以及配置默认值设置
  • 自动装配类,让组件进行自动装配;
  • spring.factories文件,指定Starter的自动装配类的路径;

初探druid-spring-boot-starter

首先去下载druid源码,导入到IDEA中,可以看到这样的目录结构,

这里我们先来看看pom.xml,会发现里面有两个包:

1
2
3
4
5
6
7
8
9
10
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
<!-- @ConfigurationProperties annotation processing (metadata for IDEs) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
  • spring-boot-configuration-processor:用于解析传统的xml或properties配置文件,Spring Boot默认使用的是yml
  • spring-boot-autoconfigure:自动装配组件,实现自动扫描装载

    完整的pom.xml大家就去github中查看。

    druid-spring-boot-starter的配置类DruidStatProperties

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    @ConfigurationProperties("spring.datasource.druid")
    public class DruidStatProperties {
    private String[] aopPatterns;
    private StatViewServlet statViewServlet = new StatViewServlet();
    private WebStatFilter webStatFilter = new WebStatFilter();


    public String[] getAopPatterns() {
    return aopPatterns;
    }

    public void setAopPatterns(String[] aopPatterns) {
    this.aopPatterns = aopPatterns;
    }

    public StatViewServlet getStatViewServlet() {
    return statViewServlet;
    }

    public void setStatViewServlet(StatViewServlet statViewServlet) {
    this.statViewServlet = statViewServlet;
    }

    public WebStatFilter getWebStatFilter() {
    return webStatFilter;
    }

    public void setWebStatFilter(WebStatFilter webStatFilter) {
    this.webStatFilter = webStatFilter;
    }

    public static class StatViewServlet {
    /**
    * Enable StatViewServlet, default false.
    */
    private boolean enabled;
    private String urlPattern;
    private String allow;
    private String deny;
    private String loginUsername;
    private String loginPassword;
    private String resetEnable;

    public boolean isEnabled() {
    return enabled;
    }

    public void setEnabled(boolean enabled) {
    this.enabled = enabled;
    }

    public String getUrlPattern() {
    return urlPattern;
    }

    public void setUrlPattern(String urlPattern) {
    this.urlPattern = urlPattern;
    }

    public String getAllow() {
    return allow;
    }

    public void setAllow(String allow) {
    this.allow = allow;
    }

    public String getDeny() {
    return deny;
    }

    public void setDeny(String deny) {
    this.deny = deny;
    }

    public String getLoginUsername() {
    return loginUsername;
    }

    public void setLoginUsername(String loginUsername) {
    this.loginUsername = loginUsername;
    }

    public String getLoginPassword() {
    return loginPassword;
    }

    public void setLoginPassword(String loginPassword) {
    this.loginPassword = loginPassword;
    }

    public String getResetEnable() {
    return resetEnable;
    }

    public void setResetEnable(String resetEnable) {
    this.resetEnable = resetEnable;
    }
    }

    public static class WebStatFilter {
    /**
    * Enable WebStatFilter, default false.
    */
    private boolean enabled;
    private String urlPattern;
    private String exclusions;
    private String sessionStatMaxCount;
    private String sessionStatEnable;
    private String principalSessionName;
    private String principalCookieName;
    private String profileEnable;

    public boolean isEnabled() {
    return enabled;
    }

    public void setEnabled(boolean enabled) {
    this.enabled = enabled;
    }

    public String getUrlPattern() {
    return urlPattern;
    }

    public void setUrlPattern(String urlPattern) {
    this.urlPattern = urlPattern;
    }

    public String getExclusions() {
    return exclusions;
    }

    public void setExclusions(String exclusions) {
    this.exclusions = exclusions;
    }

    public String getSessionStatMaxCount() {
    return sessionStatMaxCount;
    }

    public void setSessionStatMaxCount(String sessionStatMaxCount) {
    this.sessionStatMaxCount = sessionStatMaxCount;
    }

    public String getSessionStatEnable() {
    return sessionStatEnable;
    }

    public void setSessionStatEnable(String sessionStatEnable) {
    this.sessionStatEnable = sessionStatEnable;
    }

    public String getPrincipalSessionName() {
    return principalSessionName;
    }

    public void setPrincipalSessionName(String principalSessionName) {
    this.principalSessionName = principalSessionName;
    }

    public String getPrincipalCookieName() {
    return principalCookieName;
    }

    public void setPrincipalCookieName(String principalCookieName) {
    this.principalCookieName = principalCookieName;
    }

    public String getProfileEnable() {
    return profileEnable;
    }

    public void setProfileEnable(String profileEnable) {
    this.profileEnable = profileEnable;
    }
    }
    }

    这个类是Druid的配置信息类,在类上使用了ConfigurationProperties标识了配置前缀@ConfigurationProperties("spring.datasource.druid"),该类会去获取类似如下结果的配置新信息

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    spring.datasource.druid.initial-size=
    spring.datasource.druid.max-active=
    spring.datasource.druid.min-idle=
    spring.datasource.druid.max-wait=
    spring.datasource.druid.pool-prepared-statements=
    spring.datasource.druid.max-pool-prepared-statement-per-connection-size=
    spring.datasource.druid.max-open-prepared-statements= #和上面的等价
    spring.datasource.druid.validation-query=
    spring.datasource.druid.validation-query-timeout=
    spring.datasource.druid.test-on-borrow=
    spring.datasource.druid.test-on-return=
    spring.datasource.druid.test-while-idle=
    spring.datasource.druid.time-between-eviction-runs-millis=
    spring.datasource.druid.min-evictable-idle-time-millis=
    spring.datasource.druid.max-evictable-idle-time-millis=

自动装配类DruidDataSourceAutoConfigure

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Configuration
@ConditionalOnClass(DruidDataSource.class)
@AutoConfigureBefore(DataSourceAutoConfiguration.class)
@EnableConfigurationProperties({DruidStatProperties.class, DataSourceProperties.class})
@Import({DruidSpringAopConfiguration.class,
DruidStatViewServletConfiguration.class,
DruidWebStatFilterConfiguration.class,
DruidFilterConfiguration.class})
public class DruidDataSourceAutoConfigure {

private static final Logger LOGGER = LoggerFactory.getLogger(DruidDataSourceAutoConfigure.class);

@Bean(initMethod = "init")
@ConditionalOnMissingBean
public DataSource dataSource() {
LOGGER.info("Init DruidDataSource");
return new DruidDataSourceWrapper();
}
}
  • @Configuration,该注解用于标识该类为一个配置类,并注入到IOC容器中
  • @ConditionalOnClass在这里是需要DruidDataSource类才能被实例化
  • @AutoConfigureBefore,在DataSourceAutoConfiguration之前加载该类
  • @EnableConfigurationProperties注解的作用是使用@ConfigurationProperties注解的类生效。
  • @Import,把未加标识注入到IOC容器的相应类注入到当前容器中
  • @Bean(initMethod = “init”),在初始化bean时执行init方法
    在装配DruidDataSourceAutoConfigure类的时候,会执行DruidDataSource类的initDruid进行初始化。

spring.factories配置自动装配类

1
2
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure

spring boot知道我们的starter组件的装配类路径,在启动时进行加载初始化。

这里并没有说到Spring Boot Starter的启动原理,只是找了一个组件来简单了解一下它为什么做了一些什么工作,后面我们再来深入一点了解一下spring boot的启动原理。

Spring Boot Starter为我们做了什么?

https://blogs.52fx.biz/posts/1829574622.html

作者

eyiadmin

发布于

2020-02-03

更新于

2024-05-31

许可协议

评论