说道自定义注解,可能大家都不太陌生,实际开发过程中可能多多少少也会用到,今天这边就通过自定义注解结合反射,分享一些实际开发经验。
好吧,关于什么是自定义注解,以及元注解什么什么的我这边就不一一介绍了,大家自行百度,内容也都比较简单固定,随便一篇博客都可以讲的很清楚,我这边分享更主要的是关于一些实际开发过程中,关于自定义注解的使用。
下面来看一些这样一个业务场景:
这是一个简单得业务模型,相信很多同学在实际业务开发中也都是随处可见的,核心服务通过网关调用第三方服务,这个模型很简单。下面来看下加上一些实际业务在里面:
看上面业务场景,如果有很多个业务在里面需要经过网关(A,B,C。。。),我们以最简单啊httpclient来说,是不是需要有很多的组件去接受我们的请求然后处理,这样可以是可以,然后就是没新接入一个业务,就需要新增一个组件或service去做入参转换,调用,解析参数等等来处理,这样对于实际开发,是不是很不方便,后期的开发维护成本也很高。那么是不是可以做如下业务模型转换;
如上图,我们的网关服务就就渐渐演变成了如上模型,核心为doDispatcher,为公共组件,作为真正的业务开发人员,只需要关系三个问题就好了:核心配置(就是业务对应的具体调用地址,不是我们关注点,不做赘述),调用入参的构造器,出参的解析器,这样就可以大大简化后续开发维护流程。
那么问题来了:我们怎么做到对应的业务能找到对应的参数构造器和参数解析器呢?
那么我告诉你,使用自定义注解就可以很容易做到:下面我根据上述模型做了一个简单的demo,给大家演示下如何使用自定义注解做代码的调用路由(可以少写一万个if-else了)。
demo如下:
模拟上述业务模型,定义相关组件如下:
DispatcherService: 核心组件,做业务调用
ResultParse:返回参数解析组件
ParamContruct:入参构造组件
Request:同意调用入参
HandleConfig:自定义注解
(1)HandleConfig 设置为运行时作用及作用域为类上,定义两个参数,为我们的参数构造的Class以及出参解析Class,并做一个类型约束
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface HandleConfig {
Class<? extends ParamContruct> contruct();
Class<? extends ResultParse> parse();
}
(2)Request 这里我们看一下A的实现,就是在入参处加上我们的自定义注解,告诉DispatcherService组件,我们这次请求需要的参数构造类和出参解析类是什么
@EqualsAndHashCode(callSuper = true)
@Data
@HandleConfig(contruct = AParamContruct.class,parse = AResultParse.class)
public class ARequest extends Request {
private static final long serialVersionUID = -5166944731599374964L;
private String a;
}
(3)ParamContruct 和 ResultParse 不做解释,分别打印一句话,做标记
public class AParamContruct implements ParamContruct{
public void contruct() {
System.out.println("执行了====A===的构造...");
}
}
public class AResultParse implements ResultParse{
public void parse() {
System.out.println("执行了====A===的解析...");
}
}
(4)DispatcherService 核心组件,这里一个入参的泛型约束,在这里我们就可以拿到我们的自定义注解,以及注解上的参数,再通过java的反射构建相应的参数对象做路由调用。
public class DispatcherService<T extends Request> {
public void dispatcher(T request) throws IllegalAccessException, InstantiationException {
HandleConfig handleConfig = request.getClass().getAnnotation(HandleConfig.class);
ParamContruct paramContruct = handleConfig.contruct().newInstance();
ResultParse resultParse = handleConfig.parse().newInstance();
paramContruct.contruct();
resultParse.parse();
}
}
如上,我传不同的参数,分别执行道路对应的参数构造类和参数解析类里面去了,说明以及实现了我们上述的模型调用。
补充:对于DispatcherService 我们使用了反射来获取入参的注解信息,几个常见的反射方法如下:
//获取类的指定注解信息
HandleConfig handleConfig = request.getClass().getAnnotation(HandleConfig.class);
request.getClass().getDeclaredAnnotation(HandleConfig.class);
//获取类的所有注解信息
Annotation[] annotations =request.getClass().getAnnotations();
request.getClass().getDeclaredAnnotations();
好了以上便是我日常工作中的一个实际组件开发案例,希望可以对大家有所帮助,有不足之处可以评论指正!