为什么可以自定义starter?
当然是spring官方提供了相应的接口,让第三方自己去集成springboot,因为spring官方的人员不可能提供所有的starter,但是不知道为什么Druid不是spring官方集成的?
我为什么去探究springboot starter呢?
我考虑的是springboot提到的是默认包扫描路径是启动类的子包,那么加入的这些starter显然不是在这个路径下,为什么可以被spring管理呢,这些starter做了什么操作。在研究完了springboot starter后,就有了这个自定义的car-spring-boot-starter。
实现自己的car-spring-boot-starter
项目概要描述
这里会涉及到两个maven工程,springboot-starter-car和springboot-starter-test-car,第一个是我们要构建的starter,第二个是springboot工程用于测试我们的starter是否能正常使用。
工程目录截图
springboot-starter-car工程目录 springboot的测试工程目录
构建springboot-starter-car工程
1.创建maven工程,引入maven依赖
<?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.lzy.springboot.starter.car</groupId>
<artifactId>car-springboot-starter</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
<version>1.5.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<version>1.5.2.RELEASE</version>
<optional>true</optional>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
2.创建CarProperties类,该类就是一个接受配置的pojo,使用@ConfigurationProperties(prefix = "car")指定了接受配置文件参数的前缀
package com.lzy.springboot.starter.car;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* 接受配置文件的pojo
*
* @author admin
*
*/
// 定义application.properties配置文件中的配置前缀
@ConfigurationProperties(prefix = "car")
public class CarProperties {
// 价格
private int price;
// 重量
private int weight;
get/set方法省略
}
3.创建CarService类,该类是这个starter对外所提供的服务,这里仅提供获取价格和重量的服务
package com.lzy.springboot.starter.car.service;
import com.lzy.springboot.starter.car.CarProperties;
/**
* 引入该starter后,通过配置文件的信息可以提供什么功能
*
* @author admin
*
*/
public class CarService {
private CarProperties properties;
public CarService(CarProperties properties){
this.properties = properties;
}
public CarService(){
}
public int getCarPrice(){
return properties.getPrice();
}
public int getCarWeight(){
return properties.getWeight();
}
}
4.创建自动配置类CarAutoConfiguration,主要是将配置文件的信息读取到CarProperties中,并将CarService服务实例化。代码中已经给了详细解释,就不再赘述。
package com.lzy.springboot.starter.car.conf;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.lzy.springboot.starter.car.CarProperties;
import com.lzy.springboot.starter.car.service.CarService;
// 配置注解 ,标记该类是个配文类
@Configuration
// 开启指定类的配置,既是接受配置文件中的参数的类, 多个时我们可以这么写value={Properties1.class,Properteis2.class....}
@EnableConfigurationProperties(CarProperties.class)
// 当这个类(CarService)在classPath下,并且容器 中没有相同的,就自动配置
@ConditionalOnClass(CarService.class)
// 表示只有我们的配置文件是否配置了以car为前缀的资源项值,并且在该资源项值为enabled,如果没有配置我们默认设置为enabled
@ConditionalOnProperty(prefix="car", value="enabled", matchIfMissing=true)
public class CarAutoConfiguration {
@Autowired
private CarProperties properties;
@Bean
@ConditionalOnMissingBean(CarService.class)// 当容器中没有指定Bean的情况下,自动配置carService类
public CarService carService(){
CarService personService = new CarService(properties);
return personService;
}
}
这里再提一点就是这个类可能用到的注解
@ConditionalOnBean:当容器中有指定的Bean的条件下
@ConditionalOnClass:当类路径下有指定的类的条件下
@ConditionalOnExpression:基于SpEL表达式作为判断条件
@ConditionalOnJava:基于JVM版本作为判断条件
@ConditionalOnJndi:在JNDI存在的条件下查找指定的位置
@ConditionalOnMissingBean:当容器中没有指定Bean的情况下
@ConditionalOnMissingClass:当类路径下没有指定的类的条件下
@ConditionalOnNotWebApplication:当前项目不是Web项目的条件下
@ConditionalOnProperty:指定的属性是否有指定的值
@ConditionalOnResource:类路径下是否有指定的资源
@ConditionalOnSingleCandidate:当指定的Bean在容器中只有一个,或者在有多个Bean的情况下,用来指定首选的Bean
@ConditionalOnWebApplication:当前项目是Web项目的条件下
摘抄地址:https://blog.csdn.net/liuchuanhong1/article/details/55057135
5.在src/main/resources新建META-INF文件夹,在META-INF文件夹下新建spring.factories文件,写入
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.lzy.springboot.starter.car.conf.CarAutoConfiguration
spring.factories的内容是给springboot启动时读取的。当然也可以使用注解方式代替该文件,在启动类上添加@ImportAutoConfiguration({CarAutoConfiguration.class}) 。
6.使用maven命令打包,eclipse可以直接使用如下方式打包并安装到本地maven库
7.测试,新建一个springboot项目springboot-starter-test-car,引入pom依赖
<?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.lzy.springboot.starter.car.test</groupId>
<artifactId>springboot-starter-car</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.1.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<!-- 引入car-springboot-starter -->
<groupId>com.lzy.springboot.starter.car</groupId>
<artifactId>car-springboot-starter</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
8.创建测试接口 PersonServiceController
package com.lzy.springboot.starter.car.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import com.lzy.springboot.starter.car.service.CarService;
@RestController
public class PersonServiceController {
// 自动注入starter中的carService
@Autowired
private CarService carService;
@GetMapping("/get/price")
public int getCarPrice(){
// 调用PersonService服务的方法
return carService.getCarPrice();
}
@GetMapping("/get/weight")
public int getCarWeight(){
return carService.getCarWeight();
}
}
9.启动项目,访问http://localhost:8080/get/price ,能得到配置文件中的值,就说明starter创建成功。