在项目中需要调用外部接口,由于需要调用不同环境(生产、测试、开发)的相同接口(例如:向生、测试、开发环境的设备下发同一个APP)。
1.生产环境由SpringCloud注册中心,通过Feign调用, 2.其它环境直接通过OKHttp直接通过Url调用。
因此需要根据传入的环境调选择不同的调用方式。
下面以添加和删除设备接口为例(一切从简,不代表真正业务代码):
public interface DeviceHandler { void remoteAddBatch(RemoteAddDeviceParam remoteAddDeviceParam, Integer envValue); void remoteDeleteBatch(Integer envValue, List<String> snsList); }
Feign方式实现:
@Component @Slf4j public class DeviceHandlerFeignImpl implements DeviceHandler { @Autowired private DeviceFeignClient deviceFeignClient; @Override public void remoteAddBatch(RemoteAddDeviceParam remoteAddDeviceParam, Integer envValue) { RestResult restResult = deviceFeignClient.create(remoteAddDeviceParam); ... } @Override public void remoteDeleteBatch(Integer envValue, List<String> snsList) { RestResult restResult = deviceFeignClient.deleteBySnList(snsList); ... } }
Url方式实现
@Component @Slf4j public class DeviceHandlerUrlImpl implements DeviceHandler { @Override public void remoteAddBatch(RemoteAddDeviceParam remoteAddDeviceParam, Integer envValue) { String url = getAddUrlByEnvValue(envValue); String response = OkHttpUtils.httpPostSyn(url, JSON.toJSONString(snsList), false); RestResult restResult = JSON.parseObject(response, RestResult.class); ... } @Override public void remoteDeleteBatch(Integer envValue, List<String> snsList) { String url = getDelUrlByEnvValue(envValue); String response = OkHttpUtils.httpPostSyn(url, JSON.toJSONString(snsList), false); RestResult restResult = JSON.parseObject(response, RestResult.class); ... } }
起到路由作用的DeviceHandlerRouter(其实类似代理),选择具体调用哪种实现,对上层服务暴露的是DeviceHandlerRouter。
@Component public class DeviceHandlerRouter implements DeviceHandler { ... @Autowired private DeviceHandlerUrlImpl deviceHandlerUrlImpl; @Autowired private DeviceHandlerUrlImpl deviceHandlerUrlImpl; @Override public void remoteAddBatch(RemoteAddDeviceParam remoteAddDeviceParam, Integer envValue) { getDeviceHandler(envValue).remoteAddBatch(remoteAddDeviceParam,envValue); } @Override public void remoteDeleteBatch(Integer envValue, List<String> snsList) { getDeviceHandler(envValue).remoteDeleteBatch(envValue,snsList); } private DeviceHandler getDeviceHandler(Integer envValue) { //根据传入的环境返回DeviceHandlerUrlImpl 或 DeviceHandlerUrlImpl } }
上层服务调用 DeviceHandlerRouter 实现对设备的添加和删除操作。
如果新增一直接口调用就需要新增实现xxxRouter,但是代码基本上都是一样的。有没有什么方式不用写代码而提供默认实现?
@Slf4j public class DynamicProxyBeanFactory implements InvocationHandler { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //各位客官别急,这里只是简单打印一下,真正的代码在下一篇 log.info("DynamicProxyBeanFactory------------------>invoke") //正儿八经的随便创建一个DeviceHandlerUrlImpl return new DeviceHandlerUrlImpl(); } public static <T> T newMapperProxy(Class<T> mapperInterface) { ClassLoader classLoader = mapperInterface.getClassLoader(); Class<?>[] interfaces = new Class[]{mapperInterface}; DynamicProxyBeanFactory proxy = new DynamicProxyBeanFactory(); return (T) Proxy.newProxyInstance(classLoader, interfaces, proxy); } }
调用:
DeviceHandler deviceHandler = DynamicProxyBeanFactory.newMapperProxy(DeviceHandler.class);
deviceHandler.remoteAddBatch(...);
参考链接: 动态代理提供接口默认实现
以上我们只是抛出在实际开发中面临的问题,以及找到解决问题的第一步的方法。 当然动态代理提供接口的默认实现只是演示,并没有什么实际内容。