引言
在项目中可能我们会调用其他的rest接口,我们会写一个HttpClientSender
工具类,返回后然后一大堆的条件判断,既繁琐又不直观。我们可以运用所学的FactoryBean
手写一个rest代理,使用时可以像Mybatis那样注入接口就可以,方便又简洁。
此工具类是依据HttpClient
编写的。灵活性比较高,代码量也是比较多,还是有一些局限性,比如请求方法只支持GET、POST、PUT、DELETE等。
FactoryBean
使用FactoryBean
来动态获取代理对象,这里我们定义一个RestServiceProxyFactoryBean<T>
实现FactoryBean
接口。
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
|
@Data public class RestServiceProxyFactoryBean<T> implements FactoryBean<T> {
private RestServiceProxyFactory factory;
private Class<T> type;
@Override public T getObject() throws Exception { return factory.newRestServiceProxy(type); }
@Override public Class<?> getObjectType() { return type; }
@Override public boolean isSingleton() { return true; } }
|
RestServiceProxyFactoryBean
有两个参数:
- RestServiceProxyFactory:创建代理对象的factory,下面会说到。
- type:接口所在路径。
代理工厂RestServiceProxyFactory
当程序调用rest接口时,会由代理工厂根据各种配置生成代理对象并填充返回结果。
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 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
|
@Slf4j @Data public class RestServiceProxyFactory {
private final static RestClient restClient = new RestClient();
private ServiceConfigManager configManager;
private String location;
public RestServiceProxyFactory() {
}
public void init() { configManager = ServiceConfigManager.build(location); }
public <T> T newRestServiceProxy(Class<T> clazz) { return Reflection.newProxy(clazz, new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getDeclaringClass() == Object.class) { return method.invoke(this, args); }
if (method.isDefault()) { MethodHandle methodHandler = RestServiceProxyFactory.this.getMethodHandler(method); return methodHandler.bindTo(proxy).invokeWithArguments(args); }
InvokeParams invokeParams = InvokeParams.getInstance(configManager, method, args);
Object ret = null; try { ret = restClient.invoke(invokeParams); } catch (Throwable e) { e.printStackTrace(); } return ret; } }); }
private MethodHandle getMethodHandler(Method method) throws NoSuchMethodException, IllegalAccessException, InstantiationException, java.lang.reflect.InvocationTargetException {
Constructor<MethodHandles.Lookup> constructor = MethodHandles.Lookup.class .getDeclaredConstructor(Class.class, int.class); constructor.setAccessible(true);
Class<?> declaringClass = method.getDeclaringClass(); int allModes = (MethodHandles.Lookup.PUBLIC | MethodHandles.Lookup.PRIVATE | MethodHandles.Lookup.PROTECTED | MethodHandles.Lookup.PACKAGE); return constructor.newInstance(declaringClass, allModes) .unreflectSpecial(method, declaringClass); } }
|
开源地址
由代理对象根据配置可以调用HTTP请求反序列化并封装返回结果,这样就不需要自己做其他的工作。项目已经更新到我的GitHub:https://github.com/mx-go/rest-proxy,READM中有使用方法。打成jar放到自己的项目中即可使用。