这篇博客是对业务中的一次重构做的总结,这个项目我放在个人博客:https://github.com/cyk110/depcloud
如果有更好的思路,欢迎留言讨论
业务场景
在业务中有两种场景:
- 云地合设场景:直接走注册中心服务发现,即直接走 Feign 请求地端
- 云地分离场景:需要走 API Gateway(即 API 网关) 代理到地端
由于这段判断走合设或分离的代码写在某个服务中,实际业务有时候不得不多走一次 rest 请求,为了节省这一次 rest 请求的开销,我认为可以抽象出代理模块,增强 Feign 请求地端的能力
实现思路
Feign 的原理是帮我们生成一个请求的 bean,只要能代理这个 bean,我们就能增强它的能力,自然而然就会想到动态代理。那生成的动态代理 bean 如何给业务呢?只需要一个代理工厂,这个东西在 Spring 中就是 FactoryBean
proxy 模块
首先实现 proxy 模块,任何需要云地合设/分离能力的服务,直接引入该模块
APIGatewayProxyFactoryBean
APIGatewayProxyFactoryBean 作为生产这个动态代理 bean 的工厂,直接实现 Spring 的 FactoryBean 接口
@RequiredArgsConstructor
public class APIGatewayProxyFactoryBean<T> implements FactoryBean<T> {
private final Object target;
private final Class<?> proxyInterface;
@Override
@SuppressWarnings("unchecked")
public T getObject() throws Exception {
APIGatewayProxy apiGatewayProxy = new APIGatewayProxy(target);
return (T) Proxy.newProxyInstance(proxyInterface.getClassLoader(), new Class[] {proxyInterface},
apiGatewayProxy);
}
@Override
public Class<?> getObjectType() {
return Proxy.class;
}
}
APIGatewayProxy
APIGatewayProxy 实现 InvocationHandler 接口,作为动态代理的实现类,在这里就可以写真正的增强后的逻辑
@RequiredArgsConstructor
public class APIGatewayProxy implements InvocationHandler {
private static final Logger LOGGER = LoggerFactory.getLogger(APIGatewayProxy.class);
private final Object target;
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
LOGGER.info("before invoke");
Object result = method.invoke(target, args);
LOGGER.info("after invoke");
return result;
}
}
业务模块
业务模块通过注入 APIGatewayProxyFactoryBean,获得增强后的动态代理 bean
@Bean(name = "groundRemoteServiceProxy")
APIGatewayProxyFactoryBean<GroundRemoteService> apiGatewayProxyFactoryBean(GroundRemoteService groundRemoteService) {
return new APIGatewayProxyFactoryBean<>(groundRemoteService, GroundRemoteService.class);
}
总结
这套思路,个人感觉还是比较直观的,没有绕什么弯子。但是这里遗留了一个问题,如果我想通过 Spring Boot 自动装配直接把动态代理类注入到业务模块,应该怎么做?
我的一个想法是通过 SPI 机制,但是这样会引入模块间循环依赖的问题