问题的提出
在实际工作中,我们经常会遇到一个接口及多个实现类的情况,并且在不同的条件下会使用不同的实现类。从使用方式上看,有些类似SPI的用法,但是由于SPI的
使用并不是太方便,那么怎么办呢?我们可以借助ApplicationContext的getBeansOfType来实现我们需要的结果。
首先我们看一下这个方法的签名
1
| <T> Map<String, T> getBeansOfType(Class<T> type) throws BeansException;
|
从上面的代码上我们可以看出来这个方法能返回一个接口的全部实现类(前提是所有实现类都必须由Spring IoC容器管理)。
org.springframework.beans及org.springframework.context这两个包是Spring IoC容器的基础,
其中重要的类有BeanFactory,BeanFactory是IoC容器的核心接口,其职责包括:实例化、定位、配置应用程序中的对象及建立这些对象间的依赖关系。
ApplicationContext作为BeanFactory的子类,在Bean管理的功能上得到了很大的增强,也更易于与Spring AOP集成使用。
ApplicationContext的一种实际应用方式,如果Bean实现了ApplicationContextAware接口的话,Spring将调用Bean的setApplicationContext()方
法,将bean所在应用上下文引用传入进来。
工作实例
我们有N多个报表,每个报表需要实现不同的查询功能,同时,我们可以用一个枚举类型类标识不同的报表,以下是具体实现
枚举类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| public enum ReportEnum {
R004_FISP("R004_FISP"),
R004_PBOC("R004_PBOC"),
R004_AMAC("R004_AMAC"),
R004_CUS("R004_CUS"),
R004_SAC("R004_SAC");
private final String type;
ReportEnum(String type) { this.type = type; }
public static ReportEnum fromType(String type) { if (type == null) { return null; } return EnumSet.allOf(ReportEnum.class).stream() .filter(s -> s.toString().equals(type)) .findAny() .orElseThrow(() -> new IllegalArgumentException("Invalid type: " + type)); }
}
|
接口类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| public interface AssociatedProcessService {
ReportEnum getCode();
List<AssociatedProcessDetailVo> getDetail(Map<String, Object> request) throws Exception;
}
|
实现类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| @Service public class AssProFispServiceImpl implements AssociatedProcessService {
@Override public ReportEnum getCode() { return ReportEnum.R004_FISP; }
@Override public List<AssociatedProcessDetailVo> getDetail(Map<String, Object> request) throws Exception { ... }
}
|
工厂类/工具类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| @Component public class SpringContextUtil implements ApplicationContextAware {
private static Map<ReportEnum, AssociatedProcessService> associatedProcessBeanMap;
@Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { Map<String, AssociatedProcessService> map = applicationContext.getBeansOfType(AssociatedProcessService.class); associatedProcessBeanMap = new EnumMap<>(ReportEnum.class); map.forEach((key, value) -> associatedProcessBeanMap.put(value.getCode(), value)); }
public static <T extends AssociatedProcessService> T getAssociatedProcessService(ReportEnum code) { return (T) associatedProcessBeanMap.get(code); }
}
|
控制器调用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
|
@ResourceDeclare(sysId = BaseConst.SYS_ID, note = "", type = BaseConst.PUBLIC_URL) @PostMapping("/queryAssociatedProcessesDetail") @ApiOperation(value = "查询关联流程详情", notes = "查询关联流程详情") public ObjectRestResponse<List<AssociatedProcessDetailVo>> queryAssociatedProcessesDetail(@RequestBody Map<String, Object> request) { try { log.info("开始处理-查询关联流程详情接口逻辑, request:{}", request); String reportType = (String) request.get("reportType"); return new ObjectRestResponse<List<AssociatedProcessDetailVo>>() .data(SpringContextUtil.getAssociatedProcessService(ReportEnum.fromType(reportType)).getDetail(request)) .rel(true); } catch (Exception e) { throw new BaseException(e.getMessage(), e); } }
|