Spring Boot starter(自定义启动器)

1. Spring Boot运行原理

Spring 4.x中提供基于条件来配置Bean的能力,Spring Boot的自动配置也基于这一原理。Spring 关于自动配置的源码在spring-boot-autoconfiguration这个jar包中。

(1)注解@SpringBootApplicaiton

@SpringBootApplicaiton注解由@SpringBootConfiguration、@EnableAutoConfiguration和@ComponentScan注解组成。它的核心功能是@EnableAutoConfiguration注解提供的。其中它的关键功能是@Import注解导入的配置功能,

 

该类内部使用SpringFactoriesLoader.loadFactoryNames方法来扫描具有META-INF/spring.factories文件的jar包。

(2)核心注解

注解

说明

@ConditionalOnBean

当容器里有指定的Bean的条件下

@ConditionalOnClass

当类路径下有指定的类的条件下

@ConditionalOnExpression

基于SpEL表达式作为判断条件

@ConditionalOnJava

基于JVM版本作为判断条件

@ConditionalOnJndi

在JNDI存在的条件下查找指定的位置

@ConditionalOnMissingBean

当容器里没有指定的Bean的情况下

@ConditionalOnMissingClass

当类路径下没有指定的类的条件下

@ConditionalOnNotWebApplication

当前项目不是Web项目的条件下

@ConditionalOnProperty

指定的属性是否有指定的值

@ConditionalOnResource

类路径是否有指定的值

@ConditionalOnSingleCandidate

当指定Bean在容器中只有一个,或者虽然有多个但是指定首选的Bean

@ConditionalOnWebApplication

当前项目是Web项目的条件下

 

以@ConditionalOnWebApplication注解为例

可以看出它有一个type属性,用于指定条件是哪种web项目,其中包含ANY(任何)、SERVLET(servlet web项目)、REACTIVE(reactive web项目)。

根据Type类型进行相应的检查,通过构造ConditionOutcome类的对象来帮助我们,通过isMatch方法返回boolean值来确定条件。

ANY类型即为既不是servlet web项目也不是reactive web项目

如servlet web项目的判断条件是:

(1)GenericWebApplicationContext是否在类路径中

(2)容器中是否有名为session的scope

(3)当前容器的Environmemt是否为ConfigurableWebEnvironment

(4)当前容器的ResourceLoader是否为WebApplicationContext(ResourceLoader是WebApplicationContext的顶级接口之一)

 

2. 自定义http编码配置启动器(starter)

(1)常规项目中的http编码配置(配置filter)

<filter>
    <filter-name>encodingFilter</filter-name>
    <filter-class>org.springFramework.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
        <param-name>encoding</param-name>
        <param-value>UTF-8</param-value>
    </init-param>
    <init-param>
        <param-name>forceEncoding</param-name>
        <param-value>true</param-value>
    </init-param>
</filter>

自动配置要满足两个条件:

a. 能配置CharacterEncodingFilter这个Bean

b. 能配置encoding和forceEncoding这两个属性

 

(2)配置参数

基于类型安全的配置,Spring Boot的自动配置也是基于这一点实现的,这里的配置类可以在application.propeties中直接配置,代码如下:

/**
 * 在application.properties配置的时候前缀是spring.http.encoding
 * 具体的key就是spring.http.encoding.charset和spring.http.encoding.force
 * 即prefix + 成员变量名称的格式
 * 当application.properties有配置时使用配置的值,否则使用默认值
 */
@ConfigurationProperties(prefix = "spring.http.encoding")
public class HttpEncodingProperties {
    public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
    
    //默认使用UTF-8编码方式,forceEncoding默认为true,设置为true则强制覆盖之前的编码格式
    private Charset charset = DEFAULT_CHARSET;
    private boolean force = true;

    public Charset getCharset() {
        return charset;
    }

    public void setCharset(Charset charset) {
        this.charset = charset;
    }

    public boolean isForce() {
        return force;
    }

    public void setForce(boolean force) {
        this.force = force;
    }
}

 

(3)配置Bean

利用上述的配置,并根据条件来配置CharacterEncodingFilter这个Bean,代码如下:

/**
 * 1. @Configuration:该类为配置类
 * 2. @EnableConfigurationProperties:开启属性注入,使用 @Autowired注入HttpEncodingProperties
 * 3. @ConditionalOnClass:在类路径下有CharacterEncodingFilter类的条件下
 * 4. @ConditionalOnProperty:当设置了spring.http.encoding.enabled=true的条件下,如果没有设置则默认true,即满足条件
 * 5. 3和4为自动配置的满足条件(与关系)
 */
@Configuration
@EnableConfigurationProperties(HttpEncodingProperties.class)
@ConditionalOnClass(CharacterEncodingFilter.class)
@ConditionalOnProperty(prefix = "spring.http.encoding", value="enabled", matchIfMissing = true)
public class HttpEncodingAutoConfiguration {

    //自动注入HttpEncodingProperties
    @Autowired
    private HttpEncodingProperties httpEncodingProperties;

    //当容器中没有CharacterEncodingFilter这个Bean时创建这个Bean
    //使用httpEncodingProperties参数的值
    @Bean
    @ConditionalOnMissingBean(CharacterEncodingFilter.class)
    public CharacterEncodingFilter getHttpEncodingProperties() {
        CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();
        characterEncodingFilter.setEncoding(HttpEncodingProperties.DEFAULT_CHARSET.name());
        characterEncodingFilter.setForceEncoding(httpEncodingProperties.isForce());
        return characterEncodingFilter;
    }
}

 

3. 自定义启动器实战

(1)业务说明

自定义启动器提供Service层服务,返回相应的"hello " + msg字符串(msg值可在application.xml中配置)。在使用该启动器的项目中,调用服务取得字符串返回到前端,在浏览器中现实。

 

(2)新建starter的Maven项目

自定义的starter项目artifact Id采用 *-spring-boot-starter的方式(Spring Boot官方的启动器使用spring-boot-starter-*的方式)

在pom.xml中引入autoconfiguration依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-autoconfigure</artifactId>
    <version>2.2.5.RELEASE</version>
</dependency>

(3)配置参数

基于类型安全的配置,代码如下

/**
 * 1. 引入配置,配置项为hello.msg
 * 2. msg默认值为world
 */
@ConfigurationProperties(prefix = "hello")
public class HelloServiceProperties {
    private static final String DEFAULT_MSG = "world";

    public String msg = DEFAULT_MSG;

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }
}

(4) 判断依据类(第三方项目使用的类)

/**
 * 1. sayHello()方法提供返回字符串的服务
 */
public class HelloService {
    private String msg;

    public String sayHello() {
        return "hello " + msg;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }
}

 

(5)自动配置类

/**
 * 1. @Configuration:该类为配置类
 * 2. @EnableConfigurationProperties:开启属性注入,使用 @Autowired注入HelloServiceProperties
 * 3. @ConditionalOnClass:在类路径下有HelloService类的条件下
 * 4. @ConditionalOnProperty:但设置了hello.enabled=true的条件下,如果没有设置则默认true,即满足条件
 * 5. matchIfMissing默认值为false,此时就需要在配置文件中设置hello.enabled=true才能进行自动配置
 * 6. 3和4为自动配置的满足条件(与关系)
 */
@Configuration
@EnableConfigurationProperties(HelloServiceProperties.class)
@ConditionalOnClass(HelloService.class)
@ConditionalOnProperty(prefix = "hello", value = "enabled", matchIfMissing = true)
public class HelloServiceAutoConfiguration {

    @Autowired
    private HelloServiceProperties helloServiceProperties;

    @Bean
    @ConditionalOnMissingBean(HelloService.class)
    public HelloService getHelloService() {
        HelloService helloService = new HelloService();
        helloService.setMsg(helloServiceProperties.getMsg());
        return helloService;
    }
}

 

(6)注册配置

如果想要自动配置生效,就需要注册自动配置类,在src/main/resources下新建META-INF/spring.factories,并填写如下内容:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  com.test.wjb.hello.configuration.HelloServiceAutoConfiguration

如果有多个配置,用","隔开,此处"/"是为了换行后仍能读到属性

 

(7)部署到本地仓库

开发完成后,使用mvn install命令将该启动器打包部署到本地仓库(或私服等),idea编辑器可以直接运行install

(8)其它项目引入依赖

在需要使用的项目中引入该依赖包,如下:

<dependency>
    <groupId>com.test.wjb</groupId>
    <artifactId>hello-spring-boot-starter</artifactId>
    <version>1.0.0</version>
</dependency>

 

(9)配置使用服务

在apllication.properties中加入所需的配置

# 当自动配置类的@ConditionalOnProperty的matchIfMissing=false时,
# 需要使用如下配置开启自动配置
# hello.enabled=true

# 配置msg的值
hello.msg=my first starter

编写业务代码,返回内容

/**
 * 1. 定义Controller
 * 2. @Autowired自动注入服务
 * 3. helloService.sayHello()获取内容
 */
@RestController
@RequestMapping("/test")
public class TestController {

    @Autowired
    private HelloService helloService;

    @RequestMapping("/sayHello")
    public String index() {
        return helloService.sayHello();
    }
}

 

(10)测试

浏览器中输入:http://localhost:8080/test/sayHello进行测试,结果如下:

 

4. 总结

(1)基于类型安全的配置,使用@ConfigurationProperties引入配置,prefix属性指定配置key前缀,成员变量名称指定配置key名称,因此配置项key为:prefix.成员变量名称

 

(2)自动配置类条件注解@ConditionalOnProperty,prefix指定配置key前缀,value指定配置key名称,配置文件中配置内容为:prefix.value=ture/false(如hello.enabled=true)。matchIfMissing为当没有改配置时的默认值。配置值为true时才能开启自动配置(没有其它条件的情况下)。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值