1. @ConditionalOnMissingBean
案例:
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的方法名字不能相同,否则@ConditionalOnProperty配置失效;
- 配置中使用枚举类型时,@ConditionalOnProperty中的值是小写;
- 当配置文件中没有对应配置项时,可以使用@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
注意该类注解需要用在类上,即不允许JVM加载该类。若用在方法上,且项目没有对应class,则项目启动时出现异常。
案例:如2中所示,可以构造静态内部类实现。这也是为什么源码的Config中存在大量静态内部类声明bean的原因。
项目实战:
/**
* 原生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
5. @EnableConfigurationProperties
案例:如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。