服务器spring 整合使用spring framework

SpringBoot2.x常用的ConditionalXX注解

2021-05-28  本文已影响0人  小胖学编程

在源码阅读经常会遇到ConditionalXX类型的注解,它们的含义是什么?我们在开发jar时需要怎么使用?

1. @ConditionalOnMissingBean

比如我们引入了一个jar,在jar中存在一个bean,上面标有@ConditionalOnMissingBean。该注解的含义便是,当项目中存在相同类型的bean时,则不会加载jar中的bean。

案例:
org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration

@Configuration
@ConditionalOnClass(RedisOperations.class)
@EnableConfigurationProperties(RedisProperties.class)
@Import({ LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class })
public class RedisAutoConfiguration {

    @Bean
    @ConditionalOnMissingBean(name = "redisTemplate")
    public RedisTemplate<Object, Object> redisTemplate(
            RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
        RedisTemplate<Object, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }

    @Bean
    @ConditionalOnMissingBean
    public StringRedisTemplate stringRedisTemplate(
            RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
        StringRedisTemplate template = new StringRedisTemplate();
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }

}

2. @ConditionalOnProperty

当配置文件中存在规则的配置时,才会加载bean。

注意点:

  1. @Bean的方法名字不能相同,否则@ConditionalOnProperty配置失效;
  2. 配置中使用枚举类型时,@ConditionalOnProperty中的值是小写;
  3. 当配置文件中没有对应配置项时,可以使用@ConditionalOnProperty的matchIfMissing = true表示,未配置时默认初始化某bean。

场景:实现了Cache,可以根据配置文件的值灵活的切换缓存。

@Getter
public enum CacheEnum {
    MEMORY, REDIS;
}

配置文件:

@Data
@ConfigurationProperties("base")
public class BaseConfigProperties {
    /**
     * 缓存类型,默认内存级别的缓存
     * 默认支持本地缓存和Redis分布式缓存
     */
    private CacheEnum cache;

}
@Slf4j
@Configuration
@EnableConfigurationProperties(value = BaseConfigProperties.class)
public class OSAutoConfiguration {


    @Configuration
    @ConditionalOnClass(org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration.class)
    @ConditionalOnProperty(name = "base.cache", havingValue = "redis")
    protected static class RedisCacheManagerConfiguration {

        @Bean
        @ConditionalOnMissingBean
        public CacheManager redisCacheManager(StringRedisTemplate stringRedisTemplate) {
            log.info("启用redis缓存...");
            return new CacheManager() {
                @Override
                public void put(String key, String value, long time) {
                    stringRedisTemplate.opsForValue().set(key, value, time, TimeUnit.MILLISECONDS);
                }

                @Override
                public String get(String key) {
                    return stringRedisTemplate.opsForValue().get(key);
                }

                @Override
                public void remove(String key) {
                    stringRedisTemplate.delete(key);
                }
            };
        }
    }

    /**
     * 内存级别的缓存
     */
    @Bean
    @ConditionalOnMissingBean
    @ConditionalOnProperty(name = "base.cache", havingValue = "memory", matchIfMissing = true)
    public CacheManager localCacheManager() {
        log.info("启用memory缓存");
        return new MemoryCacheManager();
    }

}

如上述代码:当配置文件存在base.cache: redis时,则初始化Redis缓存,若不配置,则初始化memory缓存。

3. @ConditionalOnClass

该注解的含义当class存在时,加载bean。即jar里面的依赖可以不对外暴露,当项目中引用对应依赖时,则加载bean。

注意该类注解需要用在类上,即不允许JVM加载该类。若用在方法上,且项目没有对应class,则项目启动时出现异常。

案例:如2中所示,可以构造静态内部类实现。这也是为什么源码的Config中存在大量静态内部类声明bean的原因。

image.png

项目实战:

    /**
     * 原生Redis的缓存
     */
    @Configuration
    @ConditionalOnClass(org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration.class)
    @ConditionalOnProperty(name = "seal.os.cache", havingValue = "redis")
    protected static class RedisCacheManagerConfiguration {

        @Bean
        @ConditionalOnMissingBean
        public CacheManager redisCacheManager(StringRedisTemplate stringRedisTemplate) {
            return new RedisCacheManager(stringRedisTemplate);
        }
    }

4. @ConditionalOnBean

该注解的含义是存在某个bean时,才加载这个bean。一般用来规范bean的加载顺序。

5. @EnableConfigurationProperties

将配置文件加载到Configuration中。

案例:如2中所示。

6. @Import

按照顺序导入配置类

案例:
org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration

@Configuration
@ConditionalOnClass(RedisOperations.class)
@EnableConfigurationProperties(RedisProperties.class)
@Import({ LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class })
public class RedisAutoConfiguration {

    @Bean
    @ConditionalOnMissingBean(name = "redisTemplate")
    public RedisTemplate<Object, Object> redisTemplate(
            RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
        RedisTemplate<Object, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }

    @Bean
    @ConditionalOnMissingBean
    public StringRedisTemplate stringRedisTemplate(
            RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
        StringRedisTemplate template = new StringRedisTemplate();
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }

}

上述注解:@Import({ LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class })会按照顺序导入LettuceConnectionConfiguration和JedisConnectionConfiguration配置。

LettuceConnectionConfiguration的优先级高于JedisConnectionConfiguration。
最终是由了LettuceConnectionConfiguration的RedisConnectionFactory。

上一篇下一篇

猜你喜欢

热点阅读