之前熟悉了SpringBoot的自动配置原理,相关链接:SpringBoot学习之自动配置原理,今天来玩一下自定义起步依赖starter。
以jdbc下DataSource自动配置参考为例:
@Configuration
@ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class })
@EnableConfigurationProperties(DataSourceProperties.class)
@Import({ Registrar.class, DataSourcePoolMetadataProvidersConfiguration.class })
public class DataSourceAutoConfiguration {
...
@ConfigurationProperties(prefix = "spring.datasource")
public class DataSourceProperties
implements BeanClassLoaderAware, EnvironmentAware, InitializingBean {
private ClassLoader classLoader;
private Environment environment;
...
接下来分两步走:
以自定义HttpClient自动配置为例:
<dependency>
<groupId>org.apache.httpcomponentsgroupId>
<artifactId>httpclientartifactId>
dependency>
/**
* @description: httpclient 属性配置类
* 在application.properties中进行配置,可以覆盖各属性的默认值
* @author: zrk
* @create: 2019-03-08
*/
@ConfigurationProperties(prefix = "zrk.httpclient")
public class HttpClientProperties {
private Integer connectTimeOut = 1000;
private Integer socketTimeOut = 10000;
private String agent = "agent";
private Integer maxConnPreRoute = 10;
private Integer maxConnTotal = 50;
public Integer getConnectTimeOut() {
return connectTimeOut;
}
public void setConnectTimeOut(Integer connectTimeOut) {
this.connectTimeOut = connectTimeOut;
}
public Integer getSocketTimeOut() {
return socketTimeOut;
}
public void setSocketTimeOut(Integer socketTimeOut) {
this.socketTimeOut = socketTimeOut;
}
public String getAgent() {
return agent;
}
public void setAgent(String agent) {
this.agent = agent;
}
public Integer getMaxConnPreRoute() {
return maxConnPreRoute;
}
public void setMaxConnPreRoute(Integer maxConnPreRoute) {
this.maxConnPreRoute = maxConnPreRoute;
}
public Integer getMaxConnTotal() {
return maxConnTotal;
}
public void setMaxConnTotal(Integer maxConnTotal) {
this.maxConnTotal = maxConnTotal;
}
}
/**
* @description: httpclient自动配置类
* @author: zrk
* @create: 2019-03-08
*/
@Configuration //配置类
@ConditionalOnClass({HttpClient.class}) //生效条件是HttpClient存在
@EnableConfigurationProperties(HttpClientProperties.class) //让配置文件生效并加入到容器
public class HttpClientAutoConfiguration {
private final HttpClientProperties httpClientProperties;
public HttpClientAutoConfiguration(HttpClientProperties httpClientProperties) {
this.httpClientProperties = httpClientProperties;
}
@Bean
@ConditionalOnMissingBean(HttpClient.class) //当容器中不存在HttpClient实力时此bean才加入容器
public HttpClient httpClient(){
RequestConfig requestConfig = RequestConfig.custom()
.setConnectTimeout(httpClientProperties.getConnectTimeOut())
.setSocketTimeout(httpClientProperties.getSocketTimeOut())
.build();
return HttpClientBuilder.create()
.setDefaultRequestConfig(requestConfig)
.setMaxConnPerRoute(httpClientProperties.getMaxConnPreRoute())
.setMaxConnTotal(httpClientProperties.getMaxConnTotal())
.setUserAgent(httpClientProperties.getAgent())
.build();
}
}
@RunWith(SpringRunner.class)
@SpringBootTest
public class HttpclientApplicationTests {
@Resource
HttpClient httpClient;
@Test
public void httpclientTest() throws IOException {
System.out.println(EntityUtils.toString(httpClient.execute(new HttpGet("http://www.baidu.com")).getEntity()));
}
}
运行测试方法,控制台如下:
如图,可以正常访问并打印,证明自动配置已经生效。
但是现在暂未在META-INF中进行配置,自动配置生效是因为根据SpringBoot包扫描原理会扫描主启动类所在目录及以下目录的包(可以参考SpringBoot学习之包扫描),配置类在此子包中因此可以扫描到容器。
但作为起步依赖包让其他项目用是不再包扫描范围内的,接下来就用两种方式演示在扫描包之外路径如何使自动配置生效:
移动包使其不在自动包扫描范围内
运行测试方法,报错,就是因为没有在容器中找到HttpClient的bean实例
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.zrk.httpclient1.autoconfigure.HttpClientAutoConfiguration
参考@EnableAsync方式:
先将META-INF/spring.properties删除或改名使其不生效,再创建EnableHttpClient annotation
在主启动类上添加@EnableHttpClient注解
运行测试方法,成功:
参考MyBatis起步依赖模式:
添加自动配置类、添加属性配置类、添加META-INF/spring.factories文件,可以参考上面,这里不再赘述
因为是作为第三方依赖,所以测试依赖跟相关插件等依赖可以删除
导入自定义starter:
<dependency>
<groupId>com.zrk.autoconfiguregroupId>
<artifactId>httpclient-spring-boot-starterartifactId>
<version>1.0-SNAPSHOTversion>
dependency>
@RestController
public class HttpClientController {
@Resource
private HttpClient httpClient;
@RequestMapping("goto")
public String request(){
try {
return EntityUtils.toString(httpClient.execute(new HttpGet("http://www.baidu.com")).getEntity());
} catch (IOException e) {
e.printStackTrace();
}
return "";
}
}
启动项目,访问http://localhost:8080/goto,虽有中文乱码,但是自动配置是生效了~
打断点,调试如下
修改application.properties
zrk.httpclient.connectTimeOut=2000
zrk.httpclient.socketTimeOut=20000
总之,参考源代码,理解框架的设计思路,并按照总结的方式一步步跟着玩,就可以学会自定义starter。