使用SpringBoot实现策略模式之@ConditionalOnXxx

文章介绍了如何在SpringBoot项目中使用@ConditionalOnXxx注解,根据yaml配置动态选择内存或Redis实现的BloomFilter,确保Bean的单例并控制其启用状态。
摘要由CSDN通过智能技术生成

使用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);
    }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值