Spring Boot 的便利性体现在,它简化了很多繁缛的配置,这对于开发人员来说是一个福音,通过引入各种 Spring Boot Starter 包能够疾速搭建出一个我的项目的脚手架举荐分布式架构源码。
目前提供的 Spring Boot Starter 包有:
spring-boot-starter-web:疾速构建基于 Spring MVC 的 Web 我的项目,应用 Tomcat 做默认嵌入式容器。
spring-boot-starter-data-redis:操作 Redis。
spring-boot-starter-data-mongodb:操作 Mongodb。
spring-boot-starter-data-jpa:操作 Mysql。
spring-boot-starter-activemq:操作 Activemq。
……
主动配置十分不便,当咱们要操作 Mongodb 的时候,只须要引入 spring-boot-starter-data-mongodb 的依赖,而后配置 Mongodb 的链接信息 spring.data.mongodb.uri=mongodb://localhost/test 就能够应用 MongoTemplate 来操作数据,MongoTemplate 的初始化工作全副交给 Starter 来实现。
主动配置麻烦的是当呈现谬误时,排查问题的难度回升了。主动配置的逻辑都在 Spring Boot Starter 中,要想疾速定位问题,就必须得理解 Spring Boot Starter 的外部原理。接下来咱们本人入手来实现一个 Spring Boot Starter。
Spring Boot Starter 我的项目创立
创立一个我的项目 spring-boot-starter-demo,pom.xml 配置代码如下所示。
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
创立一个配置类,用于在属性文件中配置值,相当于 spring.data.mongo 这种模式,代码如下所示。
import org.springframework.boot.context.properties.ConfigurationProperties;
import lombok.Data;
@Data
@ConfigurationProperties("spring.user")
public class UserPorperties {private String name;}
再定义一个 Client,相当于 MongoTemplate,外面定一个办法,用于获取配置中的值,代码如下所示。
public class UserClient {
private UserPorperties userPorperties;
public UserClient() {}
public UserClient(UserPorperties p) {this.userPorperties = p;}
public String getName() {return userPorperties.getName();
}
}
主动创立客户端
一个最根本的 Starter 包定义好了,但目前必定是不能应用 UserClient,因为咱们没有主动构建 UserClient 的实例。接下来开始构建 UserClient,代码如下所示。
@Configuration
@EnableConfigurationProperties(UserPorperties.class)
public class UserAutoConfigure {
@Bean
@ConditionalOnProperty(prefix = "spring.user", value = "enabled", havingValue = "true")
public UserClient userClient(UserPorperties userPorperties) {return new UserClient(userPorperties);
}
}
Spring Boot 会默认扫描跟启动类平级的包,如果咱们的 Starter 跟启动类不在同一个主包下,如何能让 UserAutoConfigure 失效?
在 resources 下创立一个 META-INF 文件夹,而后在 META-INF 文件夹中创立一个 spring.factories 文件,文件中指定主动配置的类:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.cxytiandi.demo.UserAutoConfigure
Spring Boot 启动时会去读取 spring.factories 文件,而后依据配置激活对应的配置类,至此一个简略的 Starter 包就实现了。
应用 Starter
当初能够在其余的我的项目中引入这个 Starter 包,代码如下所示。
<dependency>
<groupId>com.cxytiandi</groupId>
<artifactId>spring-boot-starter-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
引入之后就间接能够应用 UserClient,UserClient 在我的项目启动的时候曾经主动初始化好,代码如下所示。
@RestController
public class UserController {
@Autowired
private UserClient userClient;
@GetMapping("/user/name")
public String getUserName() {return userClient.getName();
}
}
属性文件中配置 name 的值和开启 UserClient:
spring.user.name=zhangsan
spring.user.enabled=true
拜访 /user/name 就能够返回咱们配置的 zhangsan。
应用注解开启 Starter 主动构建
很多时候咱们不想在引入 Starter 包时就执行初始化的逻辑,而是想要由用户来指定是否要开启 Starter 包的主动配置性能,比方罕用的 @EnableAsync 这个注解就是用于开启调用办法异步执行的性能。
同样地,咱们也能够通过注解的形式来开启是否主动配置,如果用注解的形式,那么 spring.factories 就不须要编写了,上面就来看一下怎么定义启用主动配置的注解,代码如下所示。
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import({UserAutoConfigure.class})
public @interface EnableUserClient {}
这段代码的外围是 @Import({UserAutoConfigure.class}),通过导入的形式实现把 UserAutoConfigure 实例退出 SpringIOC 容器中,这样就能开启主动配置了。
应用形式就是在启动类上加上该注解,代码如下所示。
@SpringBootApplication
public class SpringBootDemoApplication {public static void main(String[] args) {SpringApplication.run(SpringBootDemoApplication.class, args);
}
}
应用配置开启 Starter 主动构建
在某些场景下,UserAutoConfigure 中会配置多个对象,对于这些对象,如果不想全副配置,或是想让用户指定须要开启配置的时候再去构建对象,这个时候咱们能够通过 @ConditionalOnProperty 来指定是否开启配置的性能,代码如下所示。
@Bean
@ConditionalOnProperty(prefix = "spring.user",value = "enabled",havingValue = "true")
public UserClient userClient(UserPorperties userPorperties) {return new UserClient(userPorperties);
}
通过下面的配置,只有当启动类加了 @EnableUserClient 并且配置文件中 spring.user.enabled=true 的时候才会主动配置 UserClient。
配置 Starter 内容提醒
在自定义 Starter 包的过程中,还有一点比拟重要,就是对配置的内容项进行提醒,须要留神的是,Eclipse 中是不反对提醒的,Spring Tools 4 for Eclipse 中能够提醒。
定义提醒内容须要在 META-INF 中创立一个 spring-configuration-metadata.json 文件,代码如下所示。
{"properties": [ { "name": "spring.user.name", "defaultValue": "cxytinadi"}, {"name": "spring.user.enabled", "type": "java.lang.Boolean", "defaultValue": false} ] }
name:配置名
type:配置的数据类型
defaultValue:默认值
举荐分布式架构码源