【java-nacos】注册grpc端口至nacos

背景

公司使用nacos-discovery作为服务注册和服务发现,使用nacos-conf作为配置中心,通信的方式使用的是grpc,所以希望关闭http端口,使用grpc端口

技术方案

application.properties文件中关闭web配置,即spring.main.web-application-type设置为 none,并且添加配置spring.cloud.nacos.discovery.port=XXX

一. 出现问题

启动服务时一切正常,但是发现服务不往nacos上注册,也没有出现任何异常提示,直接调用grpc端口可以正常通信。

二. nacos注册原理和时机

nacos-client主要是通过com.alibaba.cloud.nacos.registry.NacosAutoServiceRegistration管理注册行为,实际上就是向nacos-server上发送一个POST请求

该类继承自org.springframework.cloud.client.serviceregistry.AbstractAutoServiceRegistration,这个类是spirng-cloud对于服务注册的一个通用抽象,其中一个关键的接口是ApplicationListener<WebServerInitializedEvent>

换句话说,服务注册到nacos上的时机是收到spirng中web组件成功实例化后发布的事件后。

那么这就合理了,将web端口关闭后,spring不会去初始化web相关实例,也就不会发布web实例初始化成功的事件,所以nacos不会执行注册的东西,而其他操作毫无影响

三. 解决方案
NacosServiceRegistry是nacos注册到spring当中的bean,其中的register()方法也是底层最终实现注册动作的类,所以我们可以通过将该bean注入到我们自己的服务中,并通过手动调用的方式注册到nacos-server上

四. 其他
另有同学说,有没有可能grpc server正在实例化,端口就已经注册到nacos上了,会不会造成短暂的不可用?
spring启动的核心逻辑在org.springframework.context.support.AbstractApplicationContext#refresh方法中,如下

...
            // Prepare this context for refreshing.
            prepareRefresh();

            // Tell the subclass to refresh the internal bean factory.
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

            // Prepare the bean factory for use in this context.
            prepareBeanFactory(beanFactory);

            
            // Allows post-processing of the bean factory in context subclasses.
            postProcessBeanFactory(beanFactory);

            StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
            // Invoke factory processors registered as beans in the context.
            invokeBeanFactoryPostProcessors(beanFactory);

            // Register bean processors that intercept bean creation.
            registerBeanPostProcessors(beanFactory);
            beanPostProcess.end();

            // Initialize message source for this context.
            initMessageSource();

            // Initialize event multicaster for this context.
            initApplicationEventMulticaster();

            // Initialize other special beans in specific context subclasses.
            onRefresh();

            // Check for listener beans and register them.
            registerListeners();

            // Instantiate all remaining (non-lazy-init) singletons.
            finishBeanFactoryInitialization(beanFactory);

            // Last step: publish corresponding event.
            finishRefresh();
···     

finishRefresh方法如下

protected void finishRefresh() {
        // Clear context-level resource caches (such as ASM metadata from scanning).
        clearResourceCaches();

        // Initialize lifecycle processor for this context.
        initLifecycleProcessor();

        // Propagate refresh to lifecycle processor first.
        getLifecycleProcessor().onRefresh();

        // Publish the final event.
        publishEvent(new ContextRefreshedEvent(this));

        // Participate in LiveBeansView MBean, if active.
        if (!IN_NATIVE_IMAGE) {
            LiveBeansView.registerApplicationContext(this);
        }
    }

可以很清楚的看到,只有当所有的bean都实例化完成之后才会轮到finishRefresh,而发布web事件是在getLifecycleProcessor().onRefresh();,所以只要grpc-server是一个spring的bean,那注册到nacos上的端口就一定可用

结论

spring-cloud环境下,nacos的服务注册是依赖于spring的事件发布的,我们自己的服务也可以利用事件发布在spring初始化后做一些相应的操作

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容