事件起因

近期在工作中,遇到了相同的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;
	}
}

总结

以上,该问题得到解决。以后解决问题时,应该把思路多发散一些,可以各个方向都思考一下,也许会有意想不到的收获。