一、背景

在项目中需要调用外部接口,由于需要调用不同环境(生产、测试、开发)的相同接口(例如:向生、测试、开发环境的设备下发同一个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@Slf4jpublic 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@Slf4jpublic 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。

@Componentpublic 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,但是代码基本上都是一样的。有没有什么方式不用写代码而提供默认实现?

动态代理提供默认实现

@Slf4jpublic 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(...);

参考链接:动态代理提供接口默认实现

总结

以上我们只是抛出在实际开发中面临的问题,以及找到解决问题的第一步的方法。 当然动态代理提供接口的默认实现只是演示,并没有什么实际内容。