Spring根据业务选择不同的策略Bean执行

目录

一、背景

二、方式一:Map获取Bean

三、方式二:ApplicationContext获取Bean

四、总结


一、背景

在执行业务的时候,对于不同情况将有不同的算法逻辑进行运算。比如,从前端或表记录中传递了一个字段mode,当mode为1时,执行策略1,;当mode为2时,执行策略2。对于以上算法的选择,以下有两种处理方式:

1、使用if,else逻辑判断分支,当值mode值为1时,调用策略1;否则调用策略2。当策略比较少的情况下,使用if,else是合适的,但是,当后期开发中我们逐步添加更多的策略时,每次都需要往if,else分支上再新增一个elseif分支进行判断,十分麻烦,而且不利于拓展。

2、剔除if,else分支。将策略Bean存放到Map中,调用时根据mode取Bean。或者根据mode每次直接从Spring容器中获取Bean。

以上将围绕2的两个方案进行,感兴趣的小伙伴可以往下看看。

二、方式一:Map获取Bean

1、创建一个策略枚举类,主要的作用是用于索引策略

public enum StrategyModeEnum {

    ONE(1,"策略一"),
    TWO(2, "策略二");

    private final Integer index;

    private final String info;

    StrategyModeEnum(Integer index, String info){
        this.index = index;
        this.info = info;
    }

    public Integer getIndex() {
        return index;
    }

    public String getInfo() {
        return info;
    }
}

2、创建一个注解,作用主要是标注在策略类上,用于标识策略类的基础信息(index, info)

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface StrategyMode {

    StrategyModeEnum mode();

}

3、创建一个抽象类BaseStrategy,以及两个子类OneStrategy、TwoStrategy

public abstract class BaseStrategy {


    public abstract void invoke();

}
@StrategyMode(mode = StrategyModeEnum.ONE)
@Component("oneStrategy")
public class OneStrategy extends BaseStrategy {

    @Override
    public void invoke() {
        System.out.println("1、先吃早餐");

        System.out.println("2、再刷牙");

        System.out.println("3、然后上班");
    }

}
@StrategyMode(mode = StrategyModeEnum.TWO)
@Component("twoStrategy")
public class TwoStrategy extends BaseStrategy {

    @Override
    public void invoke() {
        System.out.println("1、先刷牙");

        System.out.println("2、再吃早餐");

        System.out.println("3、然后上班");
    }

}

4、创建一个StrategyConfig类,主要的作用是将步骤三的两个Bean对象存放到Map中

public class StrategyConfig {

    // 会将容器中的两个bean:oneStrategy、twoStrategy注入到List中
    @Resource
    private List<BaseStrategy> strategyList = new ArrayList<>();

    // 存放策略bean:1 -> oneStrategy, 2-> twoStrategy
    private final Map<Integer, BaseStrategy> strategyMap = new ConcurrentHashMap<>();

    @PostConstruct
    private void init(){
        // 遍历BaseStrategy类型的所有bean对象
        strategyList.forEach(strategy -> {
            // 获取到标注在BaseStrategy具体子类上的@StrategyMode注解,也就是OneStrategy和TwoStrategy类上的注解@StrategyMode注解
            StrategyMode annotation = AnnotationUtils.findAnnotation(strategy.getClass(), StrategyMode.class);
            if(null != annotation){
                // 将策略对应枚举类型中的index基础信息进行保存
                strategyMap.put(annotation.mode().getIndex(), strategy);
            }
        });
    }

    public BaseStrategy getStrategy(Integer mode){
        return strategyMap.get(mode);
    }

}

5、创建一个TestService类,继承StrategyConfig类,即可根据mode得到具体的策略

@Service
public class TestService extends StrategyConfig {

    public void doInvoke(Integer mode){
        BaseStrategy strategy = getStrategy(mode);
        if(null == strategy){
            return;
        }
        strategy.invoke();
    }


}

6、测试上述功能

@SpringBootTest
@RunWith(SpringRunner.class)
public class AutoTest {

    @Resource
    private TestService testService;

    @Test
    public void testInvoke(){
        testService.doInvoke(1);
        //testService.doInvoke(2);
    }


}

经过测试,能够选择到具体的策略进行执行

三、方式二:ApplicationContext获取Bean

1、改造策略枚举类,主要的作用是用于索引策略(此处beanName需要与OneStrategy、TwoStrategy注册时name一致)

public enum StrategyModeEnum {

    ONE(1,"oneStrategy"),
    TWO(2, "twoStrategy");

    private final Integer index;

    private final String bean;

    StrategyModeEnum(Integer index, String bean){
        this.index = index;
        this.bean = bean;
    }

    public Integer getIndex() {
        return index;
    }

    public String getInfo() {
        return bean;
    }
    
    public StrategyModeEnum find(Integer mode){
        StrategyModeEnum[] values = StrategyModeEnum.values();
        for(StrategyModeEnum strategyMode : values){
            if(strategyMode.getIndex().equals(mode)){
                return strategyMode;
            }
        }
        return null;
    }
}

2、创建一个抽象类BaseStrategy,以及两个子类OneStrategy、TwoStrategy,同上(移除@StrategyMode注解)

3、创建SpringContextUtil,从容器中获取bean;改造StrategyConfig类,根据mode模式返回策略bean

@Component
public class ApplicationContextUtil implements ApplicationContextAware {

    private static ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        ApplicationContextUtil.applicationContext = applicationContext;
    }

    public static <T> T getBean(String beanName, Class<T> clazz){
        return applicationContext.getBean(beanName, clazz);
    }
}
public class StrategyConfig {

    public BaseStrategy getStrategy(Integer mode){
        StrategyModeEnum strategyModeEnum = StrategyModeEnum.find(mode);
        BaseStrategy strategy = ApplicationContextUtil.getBean(strategyModeEnum.getBean(), BaseStrategy.class);
        return strategy;
    }

}

4、创建一个TestService类,继承StrategyConfig类,即可根据mode得到具体的策略,同上

四、总结

以上就是两个根据mode获取bean进行执行的方式,以上的方式主要就是剔除if,else分支,新增策略时减少改动地方

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值