Q & A

  1. Q: 与传统的依赖相比,spring-boot-starter依赖有什么特别的地方?

A : spring-boot-starter会自动配置并将Bean注入到SpringContext中,使用者开箱即用。传统的依赖,需要对依赖,手动配置。

项目源码地址

  1. demo-spring-boot-starter

  2. run-spring-boot-starter

自定义Spring Boot Starter

创建maven项目,引入以下pom.xml

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
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>com.william</groupId>
<artifactId>demo-spring-boot-starter</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>

<name>spring-start-demo</name>
<description>Demo project for Spring Boot</description>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<spring.version>2.1.0.RELEASE</spring.version>
<java.version>1.8</java.version>
</properties>

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
<version>${spring.version}</version>
</dependency>
</dependencies>
</project>

这里说下artifactId的命名问题,Spring官方Starter通常命名为spring-boot-starter-{name}spring-boot-starter-web,Spring官方建议非官方命名遵循{name}-spring-boot-starter的格式。

这里讲一下我们Starter要实现的功能,提供一个Service,包含一个能够将字符串加上前后缀的方法String wrap(String content)

1
2
3
4
5
6
7
8
9
10
11
12
13
public class ExampleService {
private String prefix;
private String suffix;

public ExampleService(String prefix, String suffix) {
this.prefix = prefix;
this.suffix = suffix;
}

public String wrap(String word){
return String.format("%s%s%s",prefix,word,suffix);
}
}

前缀、后缀通过读取application.properties内的参数来获取

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@ConfigurationProperties(prefix = "example.service")
public class ExampleServiceProperties {
private String prefix;
private String suffix;

public String getPrefix() {
return prefix;
}

public void setPrefix(String prefix) {
this.prefix = prefix;
}

public String getSuffix() {
return suffix;
}

public void setSuffix(String suffix) {
this.suffix = suffix;
}
}

重点,编写AutoConfigure类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Configuration
@ConditionalOnClass(ExampleService.class)
@EnableConfigurationProperties(ExampleServiceProperties.class)
public class ExampleAutoConfigure {
@Autowired
private ExampleServiceProperties exampleServiceProperties;

@Bean
@ConditionalOnMissingClass
@ConditionalOnProperty(prefix = "example.service",value = "enabled",havingValue = "true")
public ExampleService exampleService(){
return new ExampleService(exampleServiceProperties.getPrefix(),exampleServiceProperties.getSuffix());
}
}

解释下用到的几个和Starter相关的注解:

  • @ConditionOnClass,当classpath下发现该类的情况下进行自动配置
  • @ConditionOnMissBean,当 Spring Context中不存在该Bean时
  • @ConditionalOnProperty(prefix="example.service",value="enabled",havingValue="true"),当配置文件中example.service.enabled=true时。

最后一步,在resources/META-INFO/下创建spring.factories文件,内容参考下面:

1
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.william.springstartdemo.config.ExampleAutoConfigure

OK,运行 mvn clean install,一个Spring Boot Starter便开发完了。

引入自定义Spring Boot Starter

引入 demo-spring-boot-starter 依赖

1
2
3
4
5
<dependency>
<groupId>com.william</groupId>
<artifactId>demo-spring-boot-starter</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>

创建application.properties,进行配置

1
2
3
4
example.service.enabled=true
example.service.prefix=www.
example.service.suffix=.com
server.port=9009

创建一个简单的接口,看它能否正常工作:

1
2
3
4
5
6
7
8
9
10
11
@RestController
public class IndexController {

@Autowired
private ExampleService exampleService;

@RequestMapping(value="/index",method= RequestMethod.GET)
public String index(String content){
return exampleService.wrap(content);
}
}

启动应用,在控制台执行curl localhost:9009/index?content=baidu

Starter工作原理

  1. SpringBoot在启动时扫描项目所以来的Jar包,寻找包含spring.factories文件的jar包
  2. 根据spring.factories配置加载AutoConfigure类
  3. 根据@Conditional注解的条件,进行自动配置并将Bean注入Spring Context

参考资料

  1. 快速开发一个自定义 Spring Boot Starter,并使用它。