http-client-plus是一个类似于Feign一样的申明式ESB请求代理组件,使用ESB请求代理组件,面向SpringCloud微服务的,老的项目spring3.x也支持.
背景
习惯于玩rpc的同学都知道,透明化调用对客户端来说很高效及方便,同时组件升级和客户端升级(更新下jar版本)本来都是很轻松的事情。而http-client-plus是对XX公司mule-esb-api的简单封装,用于发送http请求到esb,减少代码冗余简化操作,应用代码只需要写个interface的声明即可。
支持特性
1:通过@BeforeRequest注解,支持请求前置处理
2:通过@AfterResponse注解,支持响应后置处理
3:默认实现了响应状态的判断,和返回结果的转换
4:支持void,基本数据类型及其包装类,Object,自定义对象,
List,List<T>,Map,Future,Future<T>,Future<List>,Future<List<T>>类型的返回
5:支持各式的请求参数
6:提供@HttpParam这种简单的生成Map类型的请求参数的方法
7:支持两种方式的异步请求
7.1:通过将返回类型设置为Future或ListenableFuture
7.2:返回类型设置为void,并添加@CallBack回调方法(回调方法的[P param]默认为第一个参数,当然也可以指定其他的)
8:支持ESB(post)和HTTP(get/post)两种请求方式
9:支持自定义请求执行Bean
10:支持防重复提交
11:支持Optional(再也不需要像以前一样写一大堆代码去判断空指针)
基本用法
第一步配置xml
<bean id="httpAdapterPostProcessor" class="com.kxtx.httpadapter.spring.HttpAdapterPostProcessor">
<property name="annotationClz" value="com.kxtx.httpadapter.core.annotation.KxRequestAgent"></property>
<property name="basePackages">
<list>
<value>com.kxtx</value>
</list>
</property>
<property name="executorDelegatesClzs">
<list>
<value>com.gillion.esb.api.client.ESBClient</value>
<value>com.kxtx.httpadapter.httpClient.KxHttpClient</value>
</list>
</property>
</bean>
<!-- 设置异步执行的线程池 -->
<bean name="threadPoolInstance"
class="com.kxtx.httpadapter.core.util.ThreadManager"
factory-method="getThreadPoolInstance">
</bean>
<!-- 设置一些属性的配置 -->
<bean id="requestConfiguration" class="com.kxtx.httpadapter.spring.RequestConfigurationBean">
<property name="httpUrlPrefix" value="dev-"></property>
<property name="executorService" ref="threadPoolInstance"></property>
</bean>
第二部配置contract
如何书写申明式请求接口(这里列出最核心的几个使用方法,更多扩展方法,自己探索吧)?
@KxRequestAgent:必须:标记一个class,如果该接口在扫描类下,在项目启动时,会被扫描到,并被动态代理
@AfterResponse:必须:标记一个class或method(你们应该很难用到method级别),被标记的class下的所有方法,在执行完ESB请求后,会执行afterMethods,去进行状态校验和反序列化。其中状态校验的默认实现,建议你们用自己的系统的方法覆盖掉,可以参考Market系统的覆盖类,在文章最后给出
@Request:必须:标记一个method,url填上你想要访问的接口编号即可
@KxRequestParam:可选:如果你要访问的接口参数是key-value格式的,可以使用这个注解,注解内的内容就是key,后面的传递参数会转换成JSON格式的value
~当然,如果你不想使用上面的@KxRequestParam,或者说你很容易就封装一个Map出来,可以直接把Map当成参数即可
~如果你还不满意,想直接使用对象,那也可以,直接传递一个对象,我们会给你封装成JSON格式,放入EBS的请求参数中
~如果你不要返回结果,那简单啊,void就行了
~如果你想要异步请求,也可以,返回结果使用Future即可
~其实还有很多其他的玩法,不过感觉上面的足够你们使用了
@KxRequestAgent
@BeforeRequest(beforeMethods = TestBeforeRequest.class)
@AfterResponse(afterMethods = {DefaultStatusCheckResponseHandle.class, DefaultGenericTypeResponseHandler.class})
public interface TestRequestExecutor {
@Request(url = "OMS_S_00076_ZL")//esb
@AfterResponse(afterMethods = TestKosProductAfterResponse.class)
KosProduct kxRequestParamTest(@KxRequestParam("productUniqueKeyStr") String productUniqueKeyStr);
@Request(url = "OMS_S_00076_ZL")
@AfterResponse(overrideMethods = {DefaultStatusCheckResponseHandle.class, DefaultGenericTypeResponseHandler.class, TestAfterResponse.class})
KosProduct requestBodyTest(QueryParam queryParam);
@Request(url = "OMS_S_00076_ZL")
KosProduct mapTest(Map<String, String> param);
@Request(url = "OMS_S_00076_ZL")
String stringTest(@KxRequestParam("productUniqueKeyStr") String productUniqueKeyStr);
@Request(url = "OMS_S_00076_ZL")
void voidTest(@KxRequestParam("productUniqueKeyStr") String productUniqueKeyStr);
@Request(url = "MSHIP_S_00135")
List<OrgInfo> listTest(@KxRequestParam("memberIds") List<String> companyIds);
@Request(url = "MSHIP_S_00135")
List listWithoutTTest(@KxRequestParam("memberIds") List<String> companyIds);
@Request(url = "OMS_S_00076_ZL")
Future<KosProduct> asyncFutureTest(@KxRequestParam("productUniqueKeyStr") String productUniqueKeyStr);
@Request(url = "OMS_S_00076_ZL")
Future asyncFutureWithoutTTest(@KxRequestParam("productUniqueKeyStr") String productUniqueKeyStr);
@Request(url = "MSHIP_S_00135")
Future<List<OrgInfo>> asyncFutureListTest(@KxRequestParam("memberIds") List<String> companyIds);
@Request(url = "MSHIP_S_00135")
Future<List> asyncFutureListWithoutTTest(@KxRequestParam("memberIds") List<String> companyIds);
@Request(url = "OMS_S_00076_ZL")
@Callback(TestCallBack.class)
void callBackTest(@KxRequestParam("productUniqueKeyStr") String productUniqueKeyStr);
@Request(url = "oms.kxtx.cn/kxtx-oms/omsConfig/setConfig", requestExecutor = "defaultHttpAsyncPoolClient")//http
Object httpGetTest(@KxRequestParam(value = "key")String key, @KxRequestParam(value = "value")Integer value);
@Request(url = "oms.kxtx.cn/kxtx-oms/kosProduct/calculatePriceByProIds", requestExecutor = "defaultHttpAsyncPoolClient", httpMethod = HttpMethod.POST)//http
KosProduct httpPostTest(QueryParam queryParam);
@Request(url = "OMS_S_00076_ZL")
@UnRepeatable(0)//防止重复提交
KosProduct lockTest(@KxRequestParam("productUniqueKeyStr") String productUniqueKeyStr);
}
第三步使用
/**
** spring环境下
**/
@Autowired
private TestRequestExecutor testRequestExecutor;
@Test
public void memTest() {
Test2RequestExecutor test2RequestExecutor = this.getTestRequestExecutor(Test2RequestExecutor.class);
String productKey = "2|4*NoPick*NoRoute*2cb666ea-5342-4634-8cf7-5cfc99097498*NoInten|NoSmal|00000000-0000-0000-0000-000000000002|NoHub";
KosProduct r1 = testRequestExecutor.kxRequestParamTest(productKey);
Assert.isTrue(productKey.equals(r1.getProductUniqueKeyStr()), "R1 WRONG WRONG WRONG");
List companyIds = new ArrayList<String>() {{
add("000189d7-456e-e511-9d72-40a8f0257e10");
add("003d12ef-34d5-4256-ba61-458aaa5e7728");
}};
Future<List> f4 = testRequestExecutor.asyncFutureListWithoutTTest(companyIds);
List r11 = f4.get();
Assert.isTrue(r11.size() == 2, "R10 WRONG WRONG WRONG");
}
实现源码