nats java feign 风格服务调用
属于一个简单的示例玩法,方便使用类似feign 模式进行代码强类型调用
参考玩法
核心是基于接口的动态代理
- NatsInvocationHandler
public class NatsInvocationHandler implements InvocationHandler {
private final Connection nats;
private final ObjectMapper objectMapper;
private Duration timeout = Duration.ofSeconds(120);
public NatsInvocationHandler(Connection nats, ObjectMapper objectMapper,Duration timeout) {
this.nats = nats;
this.objectMapper = objectMapper;
if(timeout != null){
this.timeout = timeout;
}
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
Class<?> clazz = method.getDeclaringClass();
RpcClient service = clazz.getAnnotation(RpcClient.class);
String subject = service.serviceFullEndpoint();
// 0 代表数据,1 代表Headers
byte[] req = objectMapper.writeValueAsBytes(args[0]);
Message msg;
if(args.length >1) {
msg = nats.request(subject, (Headers) args[1],req, timeout);
} else{
msg = nats.request(subject, req, timeout);
}
Type returnType = method.getGenericReturnType();
JavaType javaType = objectMapper.getTypeFactory()
.constructType(returnType);
if (returnType == Void.TYPE) {
return null;
}
return objectMapper.readValue(msg.getData(), javaType);
}
}
- RpcClient
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface RpcClient {
String serviceFullEndpoint();
}
- proxy
public class RpcServiceProxy {
public static <T> T create(Class<T> serviceInterface, Connection nats, ObjectMapper objectMapper, Duration timeout) {
return (T) Proxy.newProxyInstance(
serviceInterface.getClassLoader(),
new Class[]{serviceInterface},
new NatsInvocationHandler(nats, objectMapper, timeout)
);
}
}
- rpcclient
@Builder
public class RpcServiceClient {
private Connection connection;
private ObjectMapper objectMapper;
private Duration timeout;
public <T> T target(Class<T> serviceInterface) {
return RpcServiceProxy.create(serviceInterface,connection, objectMapper,timeout);
}
}
使用
- 接口定义
注意有一个缺陷,就是参数顺序,第一个是数据,第二个是header,如果不传,不处理
@RpcClient(
serviceFullEndpoint = "authservice.svc.global.tenantauthservice"
)
public interface DemoApi {
List<ResponseMessage<String>> auth(Message message);
}
- 调用
ObjectMapper objectMapper = new ObjectMapper();
Connection connection = Nats.connect("nats://data_a:pass@me:4222");
DemoApi serviceClient = RpcServiceClient.builder().objectMapper(objectMapper)
.connection(connection)
.build().target(DemoApi.class);
var msg = new Message("demo");
msg.setType("tenantauthmessage");
List<ResponseMessage<String>> response = serviceClient.auth(msg);
System.out.println("Response: " + response);
参考资料
https://github.com/OpenFeign/feign/tree/master
https://docs.nats.io/nats-concepts/core-nats/reqreply/reqreply_walkthrough
浙公网安备 33010602011771号