一个Controller网关根据请求参数和版本号调用分发多个Service和方法

一个Controller网关根据请求参数和版本号分发Service

公司原有项目就是根据请求参数进行分发逻辑的,这次想着通过反射加入了版本号的分发,减轻各种版本的业务代码逻辑耦合度。

在一个项目中需要写很多的controller去调用不同的service,而写一个网关可以省去写controller层的痛苦,其实就是策略模式的体现。

下面开始介绍根据版本号version和请求参数分发不同service的逻辑。

1.获取bean

因为service在项目启动时就已全部注入到spring容器中,所以我们需要写一个工具类,可以从spring上下文(applicationContext)中获取到对应service

@Component
public class SpringUtil implements ApplicationContextAware {
    @Autowired
    private static ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        if (SpringUtil.applicationContext == null) {
            SpringUtil.applicationContext = applicationContext;
        }
    }

    //获取applicationContext
    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }

    //通过name获取 Bean.
    public static Object getBean(String name) {
        return getApplicationContext().getBean(name);
    }

    //通过class获取Bean.
    public static <T> T getBean(Class<T> clazz) {
        return getApplicationContext().getBean(clazz);
    }

    //通过name,以及Clazz返回指定的Bean
    public static <T> T getBean(String name, Class<T> clazz) {
        return getApplicationContext().getBean(name, clazz);
    }
}

2.基准Service接口

接下来的具体业务的sevice只需要实现这个接口,CommonResponse为公共响应参数。写这么多个执行方法,是为了以后的版本做准备,我暂时没想到其他的好方法,先使用这种。

public interface RootService {

    CommonResponse execute(Integer version, Map<String,Object> requestParams);


    default CommonResponse execute1(Integer version, Map<String,Object> requestParams){
        return new CommonResponse();
    }

    default CommonResponse execute2(Integer version, Map<String,Object> requestParams){
        return new CommonResponse();
    }

    default CommonResponse execute3(Integer version, Map<String,Object> requestParams){
        return new CommonResponse();
    }

    default CommonResponse execute4(Integer version, Map<String,Object> requestParams){
        return new CommonResponse();
    }

    default CommonResponse execute5(Integer version, Map<String,Object> requestParams){
        return new CommonResponse();
    }

    default CommonResponse execute6(Integer version, Map<String,Object> requestParams){
        return new CommonResponse();
    }

    default CommonResponse execute7(Integer version, Object... objects){
        return new CommonResponse();
    }

    default CommonResponse execute8(Integer version, Object... objects){
        return new CommonResponse();
    }
}

3.版本号控制的注解

这里的思路主要是通过不同的注解,调用一个service里不同的method

注解

/**
 * @author xucl
 * @version 1.0
 * @date 2020/9/6 10:08
 * @description  在什么之后
 */
@Target({ElementType.METHOD}) //声明自定义的注解使用在方法上
@Retention(RetentionPolicy.RUNTIME)//注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在
@Documented
public @interface VersionAfter {

    /**
     * 版本号
     * @return
     */
    int no() default 0;


    /**
     * 都满足大于此版本时的执行顺序  0优先级最高
     * @return
     */
    int order() default 0;


    /**
     * 大于此版本
     * @return
     */
    CompareEnum action() default CompareEnum.AFTER;
}
/**
 * @author xucl
 * @version 1.0
 * @date 2020/9/6 10:15
 * @description 在什么之前
 */
@Target({ElementType.METHOD}) //声明自定义的注解使用在方法上
@Retention(RetentionPolicy.RUNTIME)//注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在
@Documented
public @interface VersionBefore {


    /**
     * 版本号
     * @return
     */
    int no() default 0;

    /**
     * 都满足小于此版本时的执行顺序 0优先级最高
     * @return
     */
    int order() default 0;

    /**
     * 小于此版本
     * @return
     */
    CompareEnum action() default CompareEnum.BEFORE;
}
/**
 * @author xucl
 * @version 1.0
 * @date 2020/9/6 12:58
 * @description 两者之间,包含
 */
@Target({ElementType.METHOD}) //声明自定义的注解使用在方法上
@Retention(RetentionPolicy.RUNTIME)//注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在
@Documented
public @interface VersionBetween {

    /**
     * 版本号1
     * @return
     */
    int no() default 0;

    /**
     * 版本号2
     * @return
     */
    int no2() default 0;

    /**
     * 都满足小于此版本时的执行顺序 0优先级最高
     * @return
     */
    int order() default 0;

    /**
     * 小于此版本
     * @return
     */
    CompareEnum action() default CompareEnum.BETWEEN;
}
/**
 * @author xucl
 * @version 1.0
 * @date 2020/9/6 10:19
 * @description
 */
@Target({ElementType.METHOD}) //声明自定义的注解使用在方法上
@Retention(RetentionPolicy.RUNTIME)//注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在
@Documented
public @interface VersionEqual {

    /**
     * 版本号
     * @return
     */
    int no() default 0;

    /**
     * 都满足等于此版本时的执行顺序  0优先级最高
     * @return
     */
    int order() default 0;

    /**
     * 等于此版本
     * @return
     */
    CompareEnum action() default CompareEnum.EQUAL;
}

@Target({ElementType.TYPE}) //声明自定义的注解使用在类上
@Retention(RetentionPolicy.RUNTIME)//注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在
@Documented
public @interface VersionController {
}

常量

public enum CompareEnum {

    AFTER(1,">"),

    BEFORE(0,"<"),

    EQUAL(2,"="),

    BETWEEN(3,"no<=,<=no2"),
    ;

    private int id;

    private String value;

    CompareEnum(int id, String value) {
        this.id = id;
        this.value = value;
    }
}

4.网关


/**
 * @author xucl
 * @version 1.0
 * @date 2020/9/6 9:52
 * @description 网关
 */
@Slf4j
@Controller
@RequestMapping("/A")
public class GetewayController {

    @ResponseBody
    @RequestMapping(value = "/Android",produces = {"application/json;charset=UTF-8"},method = RequestMethod.POST)
    public Object rootAndroid(@RequestBody Map<String,Object> map, @RequestParam Map<String,Object> params,
                           HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse){
        String service = (String) map.get("service");
        Integer version =  (Integer)map.get("version");
        String serviceBean = service.concat("Service");

        RootService rootService = (RootService) SpringUtil.getBean(serviceBean);
        if (null != version){
            Object o = gateWay(map, rootService.getClass(), rootService,version);
            if (null != o){
                return o;
            }
        }
        return rootService.execute(version,map);
    }

   @ResponseBody
    @RequestMapping(value = "/IOS",produces = {"application/json;charset=UTF-8"},method = RequestMethod.POST)
    public Object rootIOS(@RequestBody Map<String,Object> map, @RequestParam Map<String,Object> params,
                       HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse){
        String service = (String) map.get("service");
        Integer version =  (Integer)map.get("version");
        String serviceBean = service.concat("Service");

        RootService rootService = (RootService) SpringUtil.getBean(serviceBean);
        if (null != version){
            long start = System.currentTimeMillis();
            Object o = gateWay(map, rootService.getClass(),rootService, version);
            long end = System.currentTimeMillis();
            log.error("反射执行时间{}ms",(end-start));
            if (null != o){
                return o;
            }
        }
        return rootService.execute(version,map);
    }


    /**
     * 反射使用版本注解
     *
     * @param map
     * @param clazz
     * @param service
     * @param version
     * @return
     */
    public Object gateWay(Map<String,Object> map,Class clazz,RootService service,Integer version) {
        //包名且不可忘记,不然扫描全部项目包,包括引用的jar
        //Reflections reflections = new Reflections("com.xu.test.service");

        // 判断服务方法上是否有version注解
        boolean annotationPresent = clazz.isAnnotationPresent(VersionController.class);
        if (annotationPresent) {
            // 获取这个类的所有方法
            List<MethodVersionVO> methodVersionVOS = new ArrayList<>();

            Method[] methods = clazz.getDeclaredMethods();
            for (Method method : methods) {
                // 在什么之前 旧
                if (method.isAnnotationPresent(VersionBefore.class)) {
                    VersionBefore versionBefore = method.getAnnotation(VersionBefore.class);
                    MethodVersionVO vo = new MethodVersionVO(method, versionBefore.order(), versionBefore.action(), versionBefore.no());
                    methodVersionVOS.add(vo);
                }
                // 在什么之后 新
                if (method.isAnnotationPresent(VersionAfter.class)) {
                    VersionAfter versionAfter = method.getAnnotation(VersionAfter.class);
                    MethodVersionVO vo = new MethodVersionVO(method, versionAfter.order(), versionAfter.action(), versionAfter.no());
                    methodVersionVOS.add(vo);
                }
                // 相等
                if (method.isAnnotationPresent(VersionEqual.class)) {
                    VersionEqual versionEqual = method.getAnnotation(VersionEqual.class);
                    MethodVersionVO vo = new MethodVersionVO(method, versionEqual.order(), versionEqual.action(), versionEqual.no());
                    methodVersionVOS.add(vo);
                }
                // 两者间,包含
                if (method.isAnnotationPresent(VersionBetween.class)) {
                    VersionBetween versionBetween = method.getAnnotation(VersionBetween.class);
                    MethodVersionVO vo = new MethodVersionVO(method,versionBetween.order(),versionBetween.action(),versionBetween.no(),
                            versionBetween.no2());
                    methodVersionVOS.add(vo);
                }
            }

            if (CollectionUtils.isNotEmpty(methodVersionVOS)) {

                // 优先匹配两者间,包含
                MethodVersionVO vo0 = methodVersionVOS.stream().sorted(Comparator.comparingInt(MethodVersionVO::getOrder))
                        .filter(vo -> version <= vo.getVersion2() && version >= vo.getVersion() &&
                                CompareEnum.BETWEEN.equals(vo.getCompare()))
                        .findFirst().orElse(null);

                if (null != vo0) {
                    try {
                        return (CommonResponse) vo0.getMethod().invoke(service, version, map);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }

                // 匹配相等此version
                MethodVersionVO vo2 = methodVersionVOS.stream().sorted(Comparator.comparingInt(MethodVersionVO::getOrder))
                        .filter(vo -> vo.getVersion() == version && CompareEnum.EQUAL.equals(vo.getCompare()))
                        .findFirst().orElse(null);

                if (null != vo2) {
                    try {
                        return (CommonResponse) vo2.getMethod().invoke(service, version, map);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }

                // 匹配大于此version
                MethodVersionVO vo1 = methodVersionVOS.stream().sorted(Comparator.comparingInt(MethodVersionVO::getOrder))
                        .filter(vo -> vo.getVersion() > version && CompareEnum.AFTER.equals(vo.getCompare()))
                        .findFirst().orElse(null);

                if (null != vo1) {
                    try {
                        return (CommonResponse) vo1.getMethod().invoke(service, version, map);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }


                // 最后兼容旧版本
                MethodVersionVO vo3 = methodVersionVOS.stream().sorted(Comparator.comparingInt(MethodVersionVO::getOrder))
                        .filter(vo -> vo.getVersion() < version && CompareEnum.BEFORE.equals(vo.getCompare()))
                        .findFirst().orElse(null);

                if (null != vo3) {
                    try {
                        return (CommonResponse) vo3.getMethod().invoke(service, version, map);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }


            }
            return null;

        }
        return null;
    }


}

@Getter
@Setter
public class MethodVersionVO {

    private Method method;

    private int order;

    private CompareEnum compare;

    private int version;

    private int version2;

    public MethodVersionVO(Method method, int order, CompareEnum compare, int version) {
        this.method = method;
        this.order = order;
        this.compare = compare;
        this.version = version;
    }

    public MethodVersionVO(Method method, int order, CompareEnum compare, int version, int version2) {
        this.method = method;
        this.order = order;
        this.compare = compare;
        this.version = version;
        this.version2 = version2;
    }
}

5.服务实现

@VersionController
@Service("A110Service")
public class A110Service implements RootService {

    @VersionEqual(no = 700,order = 0)
    @Override
    public CommonResponse execute(Integer version, Map<String, Object> requestParams) {
        Map<String,Object> map = new LinkedHashMap<>();
        map.put("name","小王");
        map.put("age",17);
        map.put("action","equal 0");
        return CommonResponse.successResponse(map);
    }

    @VersionEqual(no = 700,order = 1)
    @Override
    public CommonResponse execute1(Integer version, Map<String, Object> requestParams) {
        Map<String,Object> map = new LinkedHashMap<>();
        map.put("name","小王");
        map.put("age",88);
        map.put("action","equal 1");
        return CommonResponse.successResponse(map);
    }



    @VersionAfter(no = 710,order = 1)
    @Override
    public CommonResponse execute2(Integer version, Map<String, Object> requestParams) {
        Map<String,Object> map = new LinkedHashMap<>();
        map.put("name","小王");
        map.put("age",770);
        map.put("action","在什么之后 > 1");
        return CommonResponse.successResponse(map);
    }

    @VersionBefore(no = 710,order = 1)
    @Override
    public CommonResponse execute3(Integer version, Map<String, Object> requestParams) {
        Map<String,Object> map = new LinkedHashMap<>();
        map.put("name","小王");
        map.put("age",38);
        map.put("action","在什么之前 < 1");
        return CommonResponse.successResponse(map);
    }

    @VersionEqual(no = 710,order = 0)
    @Override
    public CommonResponse execute4(Integer version, Map<String, Object> requestParams) {
        Map<String,Object> map = new LinkedHashMap<>();
        map.put("name","小王");
        map.put("age",48);
        map.put("action","equal 0");
        return CommonResponse.successResponse(map);
    }

    @VersionBetween(no = 100,no2 = 690,order = 0)
    @Override
    public CommonResponse execute5(Integer version, Map<String, Object> requestParams) {
        Map<String,Object> map = new LinkedHashMap<>();
        map.put("name","小55王");
        map.put("age",69);
        map.put("action","between 0");
        return CommonResponse.successResponse(map);
    }


}

6.调用结果

posted @ 2020-09-06 14:09  樱阙诗汀  阅读(985)  评论(1编辑  收藏  举报