Spring 自定义集合实现策略
日常开发中,如果遇到复杂业务通常会用一个接口实现多个实现类。需要根据对应参数判断获取不同实现类。例如支付场景,根据选择支付方式,选择相应路由。如果实现类不多,通常会这样。如果实现类多了,每次新增一个实现,还需要修改路由,写的就恶心了。有没有什么好的方式可以解决呢?
if(rule1){
return a 的实例;
}
if(rule12){
retuen 实现类b的实例;
}
方法一
利用Spring applicationContext
Map<String, xx> beans = applicationContext.getBeansOfType(xx.class);
然后封装工具类,根据key从map 获取对应实现类
伪代码如下
private static Map<String,xxService> serviceMap = new HashMap<>();
Map<String, xxService> beans = applicationContext.getBeansOfType(xxService.class);
for (xxService s : beans.values()) {
if(serviceMap.putIfAbsent(s.type(), s) != null){
throw new RuntimeException(s.class.getSimpleName() + " 已经存在[" + s.type() + "]类型");
}
}
或者直接注入
@Autowired
List<xxService> xxList;
通常也是使用这种方式比较多,但是感觉还是不够通用。新增了一种多态实现,还是需要改代码,存入map
方法二Spring Bean选择器模式
利用spring的注入功能,使用注解来实现依赖注入,这里自定义了列表,。其中用到了CustomCollectionEditor类。直接上代码
/**
* @author: one
* @date: 2024/7/27 17:29
**/
public interface MatchBean<K> {
boolean match(K factor);
}
/**
* @author: one
* @date: 2024/7/27 17:29
**/
public interface MultiServiceFactory<E extends MatchBean<K>, K> extends List<E> {
E getBean(K factor);
List<E> getBeanList(K factor);
}
/**
* @author: one
* @date: 2024/7/27 17:29
**/
public class MultiServiceFactoryImpl<E extends MatchBean<K>, K> extends ArrayList<E> implements MultiServiceFactory<E, K>, Serializable {
@Override
public E getBean(K factor) {
Iterator<E> itr = iterator();
while (itr.hasNext()) {
E beanMatch = itr.next();
if (beanMatch.match(factor)) {
return beanMatch;
}
}
return null;
}
@Override
public List<E> getBeanList(K factor) {
Iterator<E> itr = iterator();
while (itr.hasNext()) {
E beanMatch = itr.next();
if (!beanMatch.match(factor)) {
itr.remove();
}
}
return this;
}
}
MultiServiceFactoryEditor类的命名,必须是接口类MultiServiceFactory的类名+Editor组成。
super(MultiServiceFactoryImpl.class),通过CustomCollectionEditor注册了转换器。
spring-beans这个jar的BeanUtils类的findEditorByConvention方法里面,可以看到editor类名的拼接过程。targetTypeName 为工厂类的类名,editorName 为工厂类所对应的editor类名
public class MultiServiceFactoryEditor extends CustomCollectionEditor {
public MultiServiceFactoryEditor() {
super(MultiServiceFactoryImpl.class);
}
}
然后在你的多态实现MatchBean接口即可,上demo
public interface Animals extends MatchBean<String> {
String name();
String run();
@Override
default boolean match(String factor) {
return this.name().equals(factor);
}
}
@Service
public class Dog implements Animals {
@Override
public String name() {
return "dog";
}
@Override
public String run() {
return "狗跑";
}
}
@Service
public class Cat implements Animals {
@Override
public String name() {
return "cat";
}
@Override
public String run() {
return "猫跑";
}
}
测试
@Autowired
private MultiServiceFactory<Animals, String> multiServiceFactory;
@PostConstruct
public void init() {
System.out.println(multiServiceFactory.getBean("dog").run());
System.out.println(multiServiceFactory.getBean("cat").run());
}