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

posted on 2025-12-24 17:56  荣锋亮  阅读(1)  评论(0)    收藏  举报

导航