自定义starter:
以我们web场景启动器的自动配置类WebMVCAutoConfiguration类为例:
@Configuration
@ConditionalOnWebApplication(
type = Type.SERVLET
)
@ConditionalOnClass({Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class})
@ConditionalOnMissingBean({WebMvcConfigurationSupport.class})
@AutoConfigureOrder(-2147483638)
@AutoConfigureAfter({DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class, ValidationAutoConfiguration.class})
public class WebMvcAutoConfiguration {
在自动配置类中,经常可以看到如下的注解:
@Configuration
指明这是一个配置类@ConditionalOnXXX
在指定条件成立的情况下自动配置类生效@AutoConfigureAfter
指定自动配置类的顺序@Bean
给容器中添加组件@ConfigurationPropertie
结合相关xxxProperties
类来绑定相关的配置@EnableConfigurationProperties
让xxxProperties
生效加入到容器中而且,自动配置类要能加载,需要将他们配置在类路径下的META-INF/spring.factories
.例如springBoot的
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
启动器只用来做依赖导入,他是一个空jar文件,仅提供辅助性的依赖管理,这些依赖可能用于自动装配或者其他类库。他是专门来写一个自动配置模块;启动器依赖自动配置;别人只需要引入启动器(starter)就可以了。
mybatis-spring-boot-starter;自定义启动器名-spring-boot-starter
<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.0modelVersion>
<groupId>com.zhaoyi.startergroupId>
<artifactId>hello-spring-boot-staterartifactId>
<version>1.0-SNAPSHOTversion>
<dependencies>
<dependency>
<groupId>com.zhaoyi.startergroupId>
<artifactId>hello-spring-boot-starter-autoconfigurerartifactId>
<version>0.0.1-SNAPSHOTversion>
dependency>
dependencies>
project>
其实就是引入另外一个自动配置的坐标信息即可,至此,启动器模块无需加入任何代码,我们接下来完善自动配置模块。
hello-spring-boot-stater
我这里starter少写一个r了,请假装他是有r的。
<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.0modelVersion>
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.1.1.RELEASEversion>
<relativePath/>
parent>
<groupId>com.zhaoyi.startergroupId>
<artifactId>hello-spring-boot-starter-autoconfigurerartifactId>
<version>0.0.1-SNAPSHOTversion>
<name>hello-spring-boot-starter-autoconfigurername>
<description>Demo project for Spring Bootdescription>
<properties>
<java.version>1.8java.version>
properties>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starterartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-configuration-processorartifactId>
<optional>trueoptional>
dependency>
dependencies>
project>
删除一些其他不必要的依赖,只需要springboot-starer
以及spring-boot-configuration-processor
,这是所有starer都需要的基本配置。
下方的build也记得删除,因为我们会删除主程序的启动类,插件会报错。
spring-boot-configuration-processor
是2.x必须引入的包。
在starter包路径下添加三个如下类文件
package com.zhaoyi.starter;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties(prefix = "zhaoyi.hello")
public class HelloProperties {
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;
}
}
该类配置了Properties类,并强调了与配置文件的zhaoyi.hello前缀的配置关联,支持prefix以及suffix两项配置。
package com.zhaoyi.starter;
public class HelloService {
private HelloProperties helloProperties;
public HelloProperties getHelloProperties() {
return helloProperties;
}
public void setHelloProperties(HelloProperties helloProperties) {
this.helloProperties = helloProperties;
}
public String sayHello(String name){
return helloProperties.getPrefix() + name + helloProperties.getSuffix();
}
}
该服务类用于对外提供服务,我们可以看到他提供了一个方法,用于返回前缀+传入参数+后缀这样的字符串,同时提供了一个setter接口,用于HelloServiceAutoConfiguration进行Properties设置。
package com.zhaoyi.starter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@ConditionalOnWebApplication
@EnableConfigurationProperties(HelloProperties.class)//属性文件生效
public class HelloServiceAutoConfiguration {
@Autowired
private HelloProperties helloProperties;
@Bean
public HelloService helloService(){
HelloService helloService = new HelloService();
helloService.setHelloProperties(helloProperties);
return helloService;
}
}
该自动配置类和我们之前查看的springboot的自动配置类的源码很相似,他使用HelloProperties作为注入属性对象,同时往容器中注入一个名为helloService
的bean,提供给用户消费。
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.zhaoyi.starter.HelloServiceAutoConfiguration
至此我们的工作做完了:首先,我们写了自动配置类,这个类给容器中给容器中添加HelloService组件,该组件用到的属性是和HelloProperties绑定的,而HelloProperties的值又是可以通过从配置文件中进行配置(绑定了前缀zhaoyi.hello),我们这里支持两个属性即prefix和suffix。最后,我们通过在resources即类路径下新建META-INF/spring.factories
文件保证springboot启动后配置类会加载生效。
接下来我们将整个项目发布到本地仓库中(点击maven install)。先install自动配置模块,然后在install启动器模块(因为启动器模块是依赖于自动配置模块的,因此在后面install)。
我们会发现,两个jar包已经被安装在了我们的本地仓库中,接下来,我们就写一个测试网站来试试我们自己的starter吧。
创建一个web项目,选择web模块,并在pom文件中引入我们上一节中自己创建的starter,导入坐标信息:
<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.0modelVersion>
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.1.1.RELEASEversion>
<relativePath/>
parent>
<groupId>com.examplegroupId>
<artifactId>demoartifactId>
<version>0.0.1-SNAPSHOTversion>
<name>demoname>
<description>Demo project for Spring Bootdescription>
<properties>
<java.version>1.8java.version>
properties>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>com.zhaoyi.startergroupId>
<artifactId>hello-spring-boot-staterartifactId>
<version>1.0-SNAPSHOTversion>
dependency>
dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
plugin>
plugins>
build>
project>
还记得我们的自定义starter吗?他提供了两个配置项,于是,我们到配置文件中添加此配置。
server:
port: 8085
zhaoyi:
hello:
prefix: this is prefix
suffix: this is suffix
该配置文件指明了服务启动端口8085,同时,设置了我们自定义场景的配置:prefix以及suffix。好了,万事俱备,接下来就是消费该场景启动器提供给我们的服务了。创建一个controller:
package com.example.demo.controller;
import com.zhaoyi.starter.HelloService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class IndexController {
@Autowired
private HelloService helloService;
@RequestMapping("/hello")
public String index(){
String hello = helloService.sayHello("hello");
return hello;
}
}
在我们springboot启动的时候,springboot已经将helloService这个bean注入到了容器中,我们直接注入到controller中就可以使用了,并且我们配置的值也会随之装配到HelloProperties对象上,接下来访问http://localhost:8085/hello
,就可以得到以下的输出:
this is prefixhellothis is suffix
也就在我们传入的参数前后分别添加配置的指定值。
至此,我们的自定义starter完成了,在实际开发中,我们自己编写starter的场景其实并不多见,但是你也许会发现很多有趣的事情,如果能把一些常用的模块这样提取出来,供后来者使用,未尝不是一种对自己的提升。