什么是Starter
SpringBoot中的starter是一种非常重要的机制,能够抛弃以前繁杂的配置,将其统一集成进starter,应用者只需要在maven中引入starter依赖,SpringBoot就能自动扫描到要加载的信息并启动相应的默认配置。starter让我们摆脱了各种依赖库的处理,需要配置各种信息的困扰。SpringBoot会自动通过classpath路径下的类发现需要的Bean,并注册进IOC容器。SpringBoot提供了针对日常企业应用研发各种场景的spring-boot-starter依赖模块。所有这些依赖模块都遵循着约定成俗的默认配置,并允许我们调整这些配置,即遵循“约定大于配置”的理念。
比如我们在springboot里面要引入redis,那么我们需要在pom中引入以下内容:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
这其实就是一个starter。简而言之,starter就是一个外部的项目,我们需要使用它的时候就可以在当前springboot项目中引入它。
在我们的日常开发工作中,经常会有一些独立于业务之外的配置模块,我们经常将其放到一个特定的包下,然后如果另一个工程需要复用这块功能的时候,需要将代码硬拷贝到另一个工程,重新集成一遍,麻烦至极。如果我们将这些可独立于业务代码之外的功配置模块封装成一个个starter,复用的时候只需要将其在pom中引用依赖即可,再由SpringBoot为我们完成自动装配,就非常轻松了。
自定义Starter
自定义Starter的命名规范
SpringBoot提供的starter以 spring-boot-starter-xxx 的方式命名的。官方建议自定义的starter使用 xxx-spring-boot-starter 的命名规则以区分SpringBoot生态提供的starter。
自定义starter代码实现
首先,先完成自定义starter:
新建maven jar工程,工程名为rubin-spring-boot-starter,导入依赖:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
<version>2.2.9.RELEASE</version>
</dependency>
</dependencies>
然后编写配置类:
@EnableConfigurationProperties(SimpleBean.class)
@ConfigurationProperties(prefix = "simplebean")
public class SimpleBean {
private int id;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "SimpleBean{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
@Configuration
public class MyAutoConfiguration {
static {
System.out.println("MyAutoConfiguration init....");
}
@Bean
public SimpleBean simpleBean(){
return new SimpleBean();
}
}
在resources下创建/META-INF/spring.factories文件,内容如下:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.rubin.config.MyAutoConfiguration
至此我们的自定义Starter就完成了。使用的话我们打包然后再需要使用的项目中引入该依赖并在配置文件中配置好相对应的属性即可。
但是,我们上述的实现方案是有问题的。就是我们不能动态的修改自定义Starter的生效失效。也就是说,我们只能通过删除项目的依赖的方式来移除自定义Starter,而更优雅的一种方式是我们定义一个启动注解,我们加上了该注解则会使我们的Starter生效,注释掉就会失效(其实就是我们常见的@Enablexxx注解)。那么这种方式怎么实现呢?我们下面来讲解一下。
热插拔技术
我们来改造一下上面的自定义Starter来实现热插拔。首先定义一个标记类:
public class ConfigMarker {
}
新增一个开关注解@EnableRegisterServer
:
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Import({ConfigMarker.class})
public @interface EnableRegisterServer {
}
改造 MyAutoConfiguration
新增条件注解 @ConditionalOnBean(ConfigMarker.class)
,@ConditionalOnBean
这个是条件注解,前面的意思代表只有当期上下文中含有 ConfigMarker
对象,被标注的类才会被实例化。
@Configuration
@ConditionalOnBean(ConfigMarker.class)
public class MyAutoConfiguration {
static {
System.out.println("MyAutoConfiguration init....");
}
@Bean
public SimpleBean simpleBean(){
return new SimpleBean();
}
}
改造完之后,我们在应用工程的启动类上加入或者注释掉该注解就可以达到热插拔的效果。
补充:关于条件注解的讲解
- @ConditionalOnBean:仅仅在当前上下文中存在某个对象时,才会实例化一个Bean。
- @ConditionalOnClass:某个class位于类路径上,才会实例化一个Bean。
- @ConditionalOnExpression:当表达式为true的时候,才会实例化一个Bean。基于SpEL表达式的条件判断。
- @ConditionalOnMissingBean:仅仅在当前上下文中不存在某个对象时,才会实例化一个Bean。
- @ConditionalOnMissingClass:某个class类路径上不存在的时候,才会实例化一个Bean。
- @ConditionalOnNotWebApplication:不是web应用,才会实例化一个Bean。
- @ConditionalOnWebApplication:当项目是一个Web项目时进行实例化。
- @ConditionalOnProperty:当指定的属性有指定的值时进行实例化。
- @ConditionalOnJava:当JVM版本为指定的版本范围时触发实例化。
- @ConditionalOnResource:当类路径下有指定的资源时触发实例化。
- @ConditionalOnJndi:在JNDI存在的条件下触发实例化。
- @ConditionalOnSingleCandidate:当指定的Bean在容器中只有一个,或者有多个但是指定了首选的Bean时触发实例化。
文章评论