使用SpringBoot实现策略模式之@ConditionalOnXxx
说明
示例代码片段来源为
短链系统demo项目
参考demo项目:项目地址
代码展示
核心代码展示
使用
yaml
配置的bloom-filter.type
动态选择实现类
/**
* 可以直接 @Autowired @ConditionalOnMissingBean保证了该 Bean 在 Spring 容器中只会存在一个
*/
@Autowired
private MyBloomFilter bloomFilter;
@Configuration
@Getter
public class BloomFilterConfig {
@Bean
@ConditionalOnMissingBean
@ConditionalOnExpression("${bloom-filter.enabled:false} && '${bloom-filter.type:}'.equalsIgnoreCase('memory')")
public MyBloomFilter memoryBloomFilter() {
return new MemoryBloomFilter();
}
@Bean
@ConditionalOnMissingBean
@ConditionalOnExpression("${bloom-filter.enabled:false} && '${bloom-filter.type:}'.equalsIgnoreCase('redis')")
public MyBloomFilter redisBloomFilter() {
return new RedisBloomFilter();
}
@Bean
@ConditionalOnMissingBean
public MyBloomFilter emptyBloomFilter() {
return new EmptyBloomFilter();
}
}
bloom-filter:
enabled: false
type: redis # redis | memory
expected-insertions: 1000000 # 期望插入的元素数量
fpp: 0.1 # 误判率
redis-key: short-url:bloom-filter
额外代码展示
public interface MyBloomFilter {
default boolean enabled() {
return false;
}
boolean check(String sign);
boolean put(String sign);
}
public class EmptyBloomFilter implements MyBloomFilter {
@Override
public boolean check(String sign) {
return false;
}
@Override
public boolean put(String sign) {
return true;
}
}
import com.google.common.base.Charsets;
import com.google.common.hash.BloomFilter;
import com.google.common.hash.Funnels;
import lombok.Getter;
import org.springframework.beans.factory.annotation.Value;
import javax.annotation.PostConstruct;
/**
* @author jh.wang
* @since 2024/4/28
*/
public class MemoryBloomFilter implements MyBloomFilter {
@Value("${bloom-filter.expected-insertions}")
private int expectedInsertions;
@Value("${bloom-filter.fpp}")
private double fpp;
@Getter
private BloomFilter<String> bloomFilter;
@PostConstruct
public void init() {
bloomFilter = BloomFilter.create(Funnels.stringFunnel(Charsets.UTF_8), expectedInsertions, fpp);
}
@Override
public boolean enabled() {
return true;
}
@Override
public boolean check(String sign) {
return bloomFilter.mightContain(sign);
}
@Override
public boolean put(String sign) {
return bloomFilter.put(sign);
}
}
import lombok.Getter;
import org.redisson.api.RBloomFilter;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import javax.annotation.PostConstruct;
/**
* @author jh.wang
* @since 2024/4/28
*/
public class RedisBloomFilter implements MyBloomFilter {
private static final String DEFAULT_KEY_NAME = "short-url:bloom-filter";
@Value("${bloom-filter.expected-insertions}")
private int expectedInsertions;
@Value("${bloom-filter.fpp}")
private double fpp;
@Value("${bloom-filter.redis-key:}")
private String redisKey;
@Autowired
private RedissonClient redissonClient;
@Getter
private RBloomFilter<String> bloomFilter;
@PostConstruct
public void init() {
final String key = redisKey == null || redisKey.isBlank() ? DEFAULT_KEY_NAME : redisKey;
bloomFilter = redissonClient.getBloomFilter(key);
bloomFilter.tryInit(expectedInsertions, fpp);
}
@Override
public boolean enabled() {
return true;
}
@Override
public boolean check(String sign) {
return bloomFilter.contains(sign);
}
@Override
public boolean put(String sign) {
return bloomFilter.add(sign);
}
}