likes
comments
collection
share

gRPC 封装了一个非常好用的Utils ~

作者站长头像
站长
· 阅读数 30

前言

最近一直在用gRPC做服务间的通讯,目前针对于java来说市面上主要的通讯方式还是http,对于gRPC的生态还不太成熟,能实现通讯方式就已经很不错了,至于说还给你封装好完整的gRPC工具类就根本没有好用的。所以为了解决这一问题,我自己搞了一个实现发送gRPC的Util。

如果你不知道如何在SpringBoot中集成gRPC的话,请参考这篇:

废话不多说,直接上代码

通道工具类:

public class ManagedChannelUtils {

    /**
     * 初始化通道 ManagedChannel 直接就把需要配置中心的地址 端口号写死在代码中。
     *
     * 为什么直接把配置写死在代码中,因为application.yml已经不存在了,所以需要将固定连接的配置写死在代码中
     * 我在想是不是还有其他方法来记载这些固定的配置,也可以实现动态加载配置的效果。
     *
     * 每句的注释:
     * forAddress() 指定 gRPC 服务端的主机和端口
     * usePlaintext() 使用明文传输,实际环境建议使用 TLS
     * enableRetry() 启用 gRPC 的重试机制
     * maxRetryAttempts() 配置最大重试次数5
     * keepAliveTime() 保持活动连接的时间 5分钟
     *
     * @return
     */
    private static ManagedChannel initClientServe(String url, String port) {
        return ManagedChannelBuilder
                .forAddress(url, Integer.parseInt(port))
                .usePlaintext()
                .enableRetry()
                .maxRetryAttempts(5)
                .keepAliveTime(5, TimeUnit.SECONDS)
                .build();
    }

    /**
     * 获取配置好的通道,并在使用完毕后自动关闭
     *
     * @return
     */
    public static void runWithManagedChannel(String url, String port, ChannelConsumer consumer) {
        try (ManagedChannelWrapper channelWrapper = new ManagedChannelWrapper(initClientServe(url, port))) {
            ManagedChannel channel = channelWrapper.getChannel();
            consumer.accept(channel);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 包装类,实现 AutoCloseable 接口
     */
    public static class ManagedChannelWrapper implements AutoCloseable {
        private final ManagedChannel channel;

        public ManagedChannelWrapper(ManagedChannel channel) {
            this.channel = channel;
        }

        @Override
        public void close() {
            if (channel != null && !channel.isShutdown()) {
                channel.shutdown();
            }
        }

        public ManagedChannel getChannel() {
            return channel;
        }
    }

    /**
     * 函数式接口,用于接收 ManagedChannel 并执行相关操作
     */
    @FunctionalInterface
    public interface ChannelConsumer {
        void accept(ManagedChannel channel) throws Exception;
    }
    
}

使用:

ManagedChannelUtils.runWithManagedChannel(regiserveUrl, regiservePort, channel -> {
        PullConfigServiceGrpc.PullConfigServiceBlockingStub pullConfigServiceBlockingStub = PullConfigServiceGrpc.newBlockingStub(channel);

        /**
         * 调用
         */
        PullConfigResponse response = pullConfigServiceBlockingStub.getConfigByTag(PullConfigRequest
                .newBuilder()
                .setStr("user")
                .build());
        });

Utils的好处

  1. 封装连接细节: 通过提供 initClientServe 方法,将 gRPC 客户端连接的初始化细节封装在单独的方法中。这样,使用者只需调用 runWithManagedChannel 方法,而不必关心连接的具体初始化过程,使代码更简洁。
  2. 自动关闭连接: 利用 ManagedChannelWrapper 类实现了 AutoCloseable 接口,确保 ManagedChannel 在使用完毕后会自动关闭,防止连接泄漏。这种自动关闭的机制通过 try-with-resources 语句在使用 runWithManagedChannel 方法时得以体现,提高了代码的健壮性。
  3. 异常处理: ChannelConsumer 函数式接口声明了可能抛出异常的 accept 方法,使得连接的使用者可以在连接操作中处理可能出现的异常。这样的设计使代码更加健壮,同时允许使用者自定义异常处理逻辑。
  4. 灵活性: 使用者可以通过实现 ChannelConsumer 接口来执行各种连接操作,从而实现更大的灵活性。这种设计允许在接口中定义不同的连接操作,根据实际需要执行相应的逻辑。
  5. 参数配置: initClientServe 方法中提供了连接参数的配置,包括 gRPC 服务端的主机和端口、明文传输与否、重试机制等,使得工具类更具通用性,可根据具体需求进行配置。

总结

一定要多思考,如果人永远待在舒适圈的话,人永远不会成长。共勉

觉得作者写的不错的,值得你们借鉴的话,就请点一个免费的赞吧!这个对我来说真的很重要。૮(˶ᵔ ᵕ ᵔ˶)ა