SpringBootStarter的定义方式

定义AutoConfiguration

一. 常用注解

1. Configuration

用于定义配置类,可替换xml配置文件,被注解的类内部包含有一个或多个被@Bean注解的方法,这些方法将会被AnnotationConfigApplicationContext或AnnotationConfigWebApplicationContext类进行扫描,并用于构建bean定义,初始化Spring容器。

和xml配置一样,可以配置Bean的生命周期中的各个方法。

1
@Bean(name="testBean",initMethod="start",destroyMethod="stop")

问题1:加了Configuration后,怎么将想要的Bean加载到应用的Spring容器中呢?

  • 可以想想之前xml的bean配置文件怎么加载的。
1
2
3
4
5
6
7
8
9
public interface ConfigurableApplicationContext extends ApplicationContext, Lifecycle, Closeable {
...
}

FileSystemXmlApplicationContext
ClassPathXmlApplicationContext
EmbeddedWebApplicationContext
GroovyWebApplicationContext
AnnotationConfigApplicationContext

也就是在初始化以上各个ApplicationContext的时候,会加载指定的Configuration, 不管是xml还是注解方式的。

那Configuration配置的Bean的加载方式就是可以通过AnnotationConfigApplicationContext。
ApplicationContext context = new AnnotationConfigApplicationContext(TestConfiguration.class);

问题2: Configuration的配置类在做一些组件的时候怎么定义,来实现组件的灵活性

这个问题如果了解一些初始化ApplicationContext的时候对Configuration的识别加载流程可能更容易理解。TODO.

另外,在@configuration中还可以引入其它注解配置

1
2
@ImportResource("classpath:applicationContext-configuration.xml")
@Import(TestConfiguration.class)

主要作用理解为是将相关的Bean加载到Spring容器。

2. EnableConfigurationProperties

@EnableConfigurationProperties注解的作用是:使使用 @ConfigurationProperties 注解的类生效。

如果一个配置类只配置@ConfigurationProperties注解,而没有使用@Component,那么在IOC容器中是获取不到properties 配置文件转化的bean。

@EnableConfigurationProperties 相当于把使用 @ConfigurationProperties 的类进行了一次注入。

当@EnableConfigurationProperties注解应用到@Configuration时, 任何被@ConfigurationProperties注解的beans将自动被Environment属性配置。 这种风格的配置特别适合与SpringApplication的外部YAML配置进行配合使用。

感觉和@Component的功能类似。将属性配置类注入到容器。

3. Conditional

Spring4推出了@Conditional注解,方便程序根据当前环境或者容器情况来动态注入bean.

继@Conditional注解后,又基于此注解推出了很多派生注解,比如@ConditionalOnBean、@ConditionalOnMissingBean、@ConditionalOnExpression、@ConditionalOnClass……实现动态注入bean

ConditionalOnClass 自动配置的重要支撑之一。判断当前classpath下是否存在指定类,若是则将当前的配置装载入spring容器。

但这个还不会熟练使用。只是理解了大概是这个意思。

1
2
@ConditionalOnClass(JsonRedisTemplate.class)
public class LinkWhiteListRedisOps{}

如果classpath存在JsonRedisTemplate的情况下,则将LinkWhiteListRedisOps装载到spring容器。

4. ConditionalXXXX

  • @ConditionalOnBean 当指定一个Bean存在是,才创建当前这个Bean
  • @ConditionalOnMissingBean 当指定Bean不存在是,才创建这个Bean.
  • @ConditionalOnProperty来控制Configuration是否生效

Class的存在与否作为条件。

从使用来看,和前面基本上没有太大的区别,无非就是将bean换成了class;这样就可以避免因为Class Not Found导致的编译异常了。

如提供了一个bean名为RedisOperBean,用于封装redis相关的操作;但是我这个bean需要依赖restTemplate这个bean,只有当应用引入了redis的相关依赖,并存在RestTemplate这个bean的时候,我这个bean才会生效.

1
2
3
4
5
6
7
8
@Component
@ConditionalOnBean(name="redisTemplate")
public class RedisOperBean {
private final RedisTemplate redisTemplate;
public RedisOperBean(RedisTemplate redisTemplate) {
// ...
}
}

springboot注解丰富,我们可以利用好这些注解来实现我们自定义的starter配置,减少硬编码的校验,降低组件间的耦合性!!!

二. 两种方式集成方式

主动生效和被动生效

从使用者的角度。

1. 主动生效

使用@Import注解。主动声明启用该starter才生效。比如加到我们的启动来,或者将该注解标记到你自定义的@Enable注解上。

1
2
3
4
5
6
@Target(ElementType.TYPE)
@Documented
@Import(RedisToolsAutoConfiguration.class)
public @interface EnableRedisTools{

}

2. 被动生效

在starter组件集成入SpringBoot应用时,就已经被应用捕捉到。类似java的SPI机制。

新建 META-INF/spring.factories文件。
写入AutoConfiguration全限定名。

1
2
3
# AutoConfiguration
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
ch.quiz.redis.distributed.config.RedisLimitAutoConfiguration

3. 优缺点

  1. 主动生效的方式需要在使用的项目中手动指定,enable. 也属于硬编码。而相对被动生效。我们可以通过配置来实现组件的生效。

  2. 被动生效虽然可以通过配置来控制组件生效,但AutoConfiguration中配置的一些组件对象会实例到容器。
    比如redis连接,不管是否生效,他都会在实例化的时候连接默认的redis.如果不适用,实例化就是有些浪费。

三.命名规范

Spring官方Starter通常命名为spring-boot-starter-{name}如 spring-boot-starter-web

Spring官方建议非官方Starter命名应遵循{name}-spring-boot-starter的格式, 如mybatis-spring-boot-starter。