构建Spring Boot Starter(一)

构建Spring Boot Starter(一)

Spring Boot Starter初印象

初识Spring Boot 时,被其简化Spring应用初始搭建以及开发过程所惊艳到,基于约定优于配置的原则,我们无需从老项目中拷贝大量的xml文件来构建项目,只需利用IDEA提供的Spring Initializr 或者通过 https://start.spring.io/ 就能轻松启动一个Spring应用,极为便捷。

除此之外,以前在没有使用Spring Boot的时候,引入第三方jar包——如引入Mybatis的时候,我们需要在pom文件中引入多个依赖:

1
2
3
4
5
6
7
8
9
10
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>${mybatis.version}</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>${mybatis.spring.version}</version>
</dependency>

这无疑给我们做第三方集成的时候增加了难度,也相应增加了依赖管理的难度,如果使用Spring Boot,我们只需引入一个依赖就ok:

1
2
3
4
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>

这是因为 mybatis-spring-boot-starter 其本身可以理解为一个库的集合,帮我们管理了spring整合mybatis所需的依赖。

Spring Boot Starter帮我们处理了Spring应用中各种库之间复杂的依赖关系,但是这不是本篇博客介绍的重点。我们这里计划实现一个自动配置的 starter ,类似启用Eureka的自动注册功能,只需在工程启动类上面加上 @EnableEurekaClient 便可开启服务注册发现功能(需要引入相关依赖),极为方便。

准备工作

首先我们要了解Spring官方推荐的命名规范,其中官方starter命名: spring-boot-starter-[name] ,非官方命名: [name]-spring-boot-starter ,所以这里我们给工具starter命名为 build-spring-boot-starter

然后我们利用IDEA提供的Spring Initializr 或者通过 https://start.spring.io/ 构建一个spring boot项目,然后引入开发Spring Boot Starter核心依赖:

1
2
3
4
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>

然后我们准备两个Serivice 用于自动配置,写的简单些,一个将字符串转为大写,一个求两个int型的最大值,都是用了现成的方法,如下:

IntegerService:

1
2
3
4
5
6
7
8
9
10
public class IntegerService {

/**
* 取两个int的最大值
*/
public int max(int i1, int i2) {
return Integer.max(i1, i2);
}

}

StringService:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class StringService {

/**
* 将字符串转为大写
*/
public String toUpperCase(String str) {
if (StringUtils.isEmpty(str)) {
return null;
} else {
return str.toUpperCase();
}
}

}

然后准备两个配置类:

1
2
3
4
5
6
public class IntegerServiceConfig {
@Bean
IntegerService integerService() {
return new IntegerService();
}
}
1
2
3
4
5
6
public class StringServiceConfig {
@Bean
StringService stringService() {
return new StringService();
}
}

然后让其自动配置,这里提供两种方式:

  1. resources/META-INF/下创建spring.factories文件,配置如下:

    1
    org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.github.baifenghe.configuration.IntegerServiceConfig

因为Spring Boot在启动的时候会扫描项目所依赖的JAR包,寻找其中spring.factories文件,然后根据其配置来加载配置类。

  1. 上述方法只要工程依赖该 starter 后便自动注入所有配置过的Bean,但是我们有时候并不想这样,可能有时候我们只需要使用一个功能,但是却将 starter 里面不需要的Bean也都注入进来,所以我们想通过一个注解来自定义开启某些功能,而不是全部开启,这时候我们可以利用 @Import 注解来实现上诉功能:

首先我们创建一个注解,EnableStringService

1
2
3
4
5
6
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({StringServiceConfig.class})
public @interface EnableStringService {
}

用 @Import 来发现配置类从而注入,很类似之前将多个配置文件导入一个主配置文件中一样。

接下来我们来测试刚刚写好的starter ,首先利用 mvn install 将刚刚开发好的 starter 安装到本地,然后新建一个 spring boot 工程引入本依赖,

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

<dependency>
<groupId>com.github.baifenghe</groupId>
<artifactId>build-spring-boot-starter</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>

然后我们写一个Controller来测试我们写的starter,如下:

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
@RestController
public class DemoController {

@Autowired
private IntegerService integerService;

@Autowired
private StringService stringService;

/**
* 测试StringService
*/
@PostMapping("testStringService")
public String testStringService(String str) {

return stringService.toUpperCase(str);
}

/**
* 测试IntegerService
*/
@PostMapping("testIntegerService")
public int testIntegerService(int n1, int n2) {

return integerService.max(n1, n2);
}

}

在主类上引用 @EnableStringService 注解,开启 StringService(IntegerService 自动注入了) 。

相关代码详见:build-spring-boot

最后的最后,欢迎 watch star fork toolkit-spring-boot-project ,一个好用的,开箱即用的工具集。

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×