SpringBoot动态代理|反射|注释| AOP优化代码(1)
优采云 发布时间: 2020-08-06 17:18I. 背景
在项目中,您需要调用一个外部接口,因为您需要在不同的环境(生产,测试,开发)中调用相同的接口(例如: 将相同的APP发送到生产,测试和测试中的设备)开发环境).
1.生产环境由SpringCloud注册中心,通过Feign调用,
2.其它环境直接通过OKHttp直接通过Url调用。
因此,有必要根据传入环境选择不同的调用方法.
优化前的代码结构
以下是添加和删除设备接口的示例(都很简单,它不代表真实的业务代码):
public interface DeviceHandler {
void remoteAddBatch(RemoteAddDeviceParam remoteAddDeviceParam, Integer envValue);
void remoteDeleteBatch(Integer envValue, List snsList);
}
好的实现方式:
@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 snsList) {
RestResult restResult = deviceFeignClient.deleteBySnList(snsList);
...
}
}
网址模式实现
@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 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 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 newMapperProxy(Class 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(...);
参考链接: 动态代理提供接口的默认实现
摘要
以上我们只是抛出了实际开发中遇到的问题,并找到了解决问题的第一种方法. 当然,动态代理提供的接口的默认实现只是一个演示,而没有实际内容.