实现同一个serveice拥有多个beanName+策略模式

背景

  • 最近有个特别紧急的需求,今天开发明天就要演示,而且还是16点开的需求会,听说涉及过亿的金额(mmp,分我嘛),抱怨归抱怨,工作还是要保质保量完成的.

需求内容

  • 之前已经开发了一套新版的基础信息,包含了学校信息,年级信息,班级信息,学生信息等13个分类,现在想在教育局做一个统计页面,统计汇总教育局下面学校相关的信息,涉及web端和平台端,一句话就是今天晚上要通宵,明天上午要演示(听完心态都崩了,f**k!).

需求分解

  • 考虑到紧急性,什么好不好扩展好不好维护基本上都不用想的了,将13个分类按功能相近分成4个模块,也就是4张表,大大减少了建表的时间.

  • 因为请求和传参的基本上一致,对外就提供一个接口,使用策略模式和统一接口实现

  • 表里的数据,不可能去写相关的逻辑实现,要写相关的逻辑,没有半个月搞不定,还能怎么办,手动填充,到时候页面上展示对不上就要看产品的应急能力或者让他绕开.

接口实现

public interface IBaseStatisticalService {

    StatisticalRespDTO query(StatisticalReqDTO dto);
}
复制代码
  • controller
@PostMapping("/query")
@Description("查找对应的统计")
public ResultRespDto query(@RequestBody StatisticalReqDTO dto) {
    return Rets.success(this.handler.query(dto));
}
复制代码
  • 策略模式调用(核心)
```
@Autowired
private Map<String, IBaseStatisticalService> baseStatisticalServiceMap ;

public StatisticalRespDTO query(StatisticalReqDTO dto) {
    logger.info("BaseStatisticalHandler.query,dto:{}",dto);
    if (Objects.isNull(dto)){
        ExceptionEnum.throwException(ExceptionEnum.FAILED,"参数为空");
    }
    String key = BaseStatisticalConstance.BASE_STATISTICAL + dto.getType();
    IBaseStatisticalService baseStatisticalService = baseStatisticalServiceMap.get(key);
    if (Objects.isNull(baseStatisticalService)){
        ExceptionEnum.throwException(ExceptionEnum.FAILED,"对应类型不存在");
    }
    return baseStatisticalService.query(dto);
}
复制代码
  • 相关的分类只要实现接口去实现自己的业务,这样既能统一管理又能更好的扩展.就当我为自己洋洋得意的时候,其他同事说有问题,我们现在是按4张表来开发的,也就是4个service类要包含13中类型,而我设计的这个,是根据beanName来进行策略的,而spring默认只有一个beanName,就是相当要有13个类才行,这样的开发很恶心(难搞啊!),没有后退可言!
  • 现在就是要扩展spring原有的beanName让其支持一个bean多个name,查了一会发现spring提供自带的是不支持的,只能自己写,停下笔,想了好一会,突然灵光一现.
  • 定义注解
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface BaseTypeMapping {
    
    String[] types() default {};
}
复制代码
  • 实现类使用
@Service
@BaseTypeMapping(types = {BaseStatisticalConstance.CLASS,BaseStatisticalConstance.GRADE,BaseStatisticalConstance.DEPARTMENT})
public class BaseStatisticalGroupServiceImpl extends ServiceImpl<BaseStatisticalGroupMapper, BaseStatisticalGroup> 
        implements BaseStatisticalGroupService , IBaseStatisticalService {

    @Autowired
    private BaseStatisticalGroupMapper baseStatisticalGroupMapper;

    @Override
    public StatisticalRespDTO query(StatisticalReqDTO dto) {
        //业务代码
    }
}
复制代码
  • 实现ApplicationContextAware,完整代码如下
@Component
public class BaseStatisticalHandler implements ApplicationContextAware {

    private final static Logger logger = LoggerFactory.getLogger(BaseStatisticalHandler.class);
    
    private Map<String, IBaseStatisticalService> baseStatisticalServiceMap = new ConcurrentHashMap<>();
    
    public StatisticalRespDTO query(StatisticalReqDTO dto) {
        logger.info("BaseStatisticalHandler.query,dto:{}",dto);
        if (Objects.isNull(dto)){
            ExceptionEnum.throwException(ExceptionEnum.FAILED,"参数为空");
        }
        String key = BaseStatisticalConstance.BASE_STATISTICAL + dto.getType();
        IBaseStatisticalService baseStatisticalService = baseStatisticalServiceMap.get(key);
        if (Objects.isNull(baseStatisticalService)){
            ExceptionEnum.throwException(ExceptionEnum.FAILED,"对应类型不存在");
        }
        return baseStatisticalService.query(dto);
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        Map<String, IBaseStatisticalService> map = applicationContext.getBeansOfType(IBaseStatisticalService.class);
        for (Map.Entry<String, IBaseStatisticalService> entry : map.entrySet()) {
            IBaseStatisticalService value = entry.getValue();
            String key = entry.getKey();
            logger.info("{}:{}:{}", key, value.getClass(), value.getClass().isAnnotationPresent(BaseTypeMapping.class));
            BaseTypeMapping annotation = value.getClass().getAnnotation(BaseTypeMapping.class);
            if (annotation == null) {
                continue;
            }
            String[] types = annotation.types();
            for (String type : types) {
                logger.info("types:{},beanName:{},class:{}", types, key, value);
                String basetKey = BaseStatisticalConstance.BASE_STATISTICAL+ type;
                if (baseStatisticalServiceMap.containsKey(key)) {
                    //类已经存在
                    IBaseStatisticalService baseStatisticalService = baseStatisticalServiceMap.get(key);
                    logger.error("IBaseStatisticalService,type:{},beanName:{},class:{} 已经被定义", type, key, baseStatisticalService);
                    throw new BeanCurrentlyInCreationException(key);
                }
                baseStatisticalServiceMap.put(basetKey, value);
            }
        }
    }

}
复制代码

自己本地试了一下,木有问题,开心!推广给同事,按这一套标准来实现,在联调的过程中也没发现问题,敲开心!

总结

以上是本人在这一次紧急需求中的相关处理,可能很多不到位,也有存在不合理的地方,希望大家一起指出,互相学习互相成就!