springboot之bean别名
事件起因
近期在工作中,遇到了相同的bean映射到多个名称的需求;经过了一番资料查找和研究,最后找到了解决方法,遂做一下记录。
程序原先的逻辑是这样的:程序中会有多种资源,每种资源都会有创建和销毁操作,但各个资源的具体操作是不相同的,为了避免使用过多的if…else…判断,增加系统的扩展性,采用了模版方法和简单工厂模式,创建了抽象的处理类,每种资源都有对应的实现类来实现对应的创建和销毁逻辑,代码示例如下:
public interface Operation {
/**
* 执行方法
* @param param 参数
*/
void op(Param param) throws Exception;
}
@Component("XXX_CREATE")
public class XXXCreateOperation implements Operation {
@Override
public void op(Param param) throws Exception {
System.out.println("xxx");
}
}
创建一个工厂类,用来根据名称获取对应的具体bean实例。类中使用了springboot的map注入,会根据@Component的名称,建立名称和实例一一对应的映射关系。
public class OperationFactory {
@Resource
Map<String, Operation> operationMap = new ConcurrentHashMap<>();
public Operation getOperation(RequestOpEnum requestOpType) {
if(requestOpType == null){
return operationMap.get("default");
}
Operation operation = operationMap.get(requestOpType.name());
if (operation == null) {
return operationMap.get("default");
}
return operation;
}
}
但现在遇到一个问题,有一种操作多个资源都会涉及,并且处理逻辑也是同样的,就需要有一个Operation实例bean对应多个名称,这种情况该怎么处理呢?
解决方式
通过查找资料了解到,springboot中的bean是有别名这个概念的,但@Component注解只能配置一个名称,但@Bean注解是可以配置别名的,当只写一个值的时候,只有名称没有别名。但是当你写多个值的时候,除了第一个是名称,后面的全都是别名。
@Bean(value = {"aaa", "bbb", "ccc"})
public Object object() {
return new Object();
}
名称的问题解决了,那spingboot能不能帮我们把别名也注入到map中呢,通过代码实验,很遗憾并不能,接下来就要解决这个问题。
经过一下午的努力,搜了很多文章,也看了springboot的有关注入源码,都没有找到解决方法,很郁闷,到了晚上的时候,无意间搜到了一篇英文论坛在讨论这个问题,思路瞬间打开了,我为什么一定要用map注入呢?springboot不是提供了通用的获取bean的方法么,可不可以用这个方法替换掉工厂中的map注入方法,来获取bean实例呢?带着激动的心情立马写段代码验证了一下,果然是可以的,最终修改工厂类代码如下:
public class OperationFactory {
@Resource
ApplicationContext applicationContext;
public Operation getOperation(RequestOpEnum requestOpType) {
if(requestOpType == null){
return applicationContext.getBean(requestOpType.name,Operation.class);
}
Operation operation = applicationContext.getBean(taskType,Operation.class);
if (requestOpType == null) {
return applicationContext.getBean("default",Operation.class);
}
return operation;
}
}
总结
以上,该问题得到解决。以后解决问题时,应该把思路多发散一些,可以各个方向都思考一下,也许会有意想不到的收获。