原创

Spring boot项目打包war部署外部tomcat无法注册到Nacos

现象

Spring boot 或者 Spring cloud 项目,如果用默认的打包jar, 使用内嵌的tomcat 启动,可以正常注册到Nacos 注册中心。
如果打包为war,部署到外部tomcat, 调用正常,消费者可以调用到 生产者服务,但是Nacos 后台的服务列表里没有显示。很诡异。。。

分析

查看源码,需从nacos的注册类找起,查找后发现,nacos注册类NacosAutoServiceRegistration继承了Spring Cloud中AbstractAutoServiceRegistration, 而在AbstractAutoServiceRegistration中绑定了一个监听事件,监听内置容器启动完成事件,监听到获取容器端口后向注册中心注册。


@EventListener({WebServerInitializedEvent.class})
public void bind(WebServerInitializedEvent event) {
    ApplicationContext context = event.getApplicationContext();
    if (!(context instanceof ConfigurableWebServerApplicationContext) || !"management".equals(((ConfigurableWebServerApplicationContext)context).getServerNamespace())) {
        this.port.compareAndSet(0, event.getWebServer().getPort());
        this.start();
    }
}

而使用外部容器时,不能监听到事件,所以自动注册失败。

解决方法

使用ApplicationRunner在服务启动完成后,加载注册。

import com.alibaba.cloud.nacos.registry.NacosAutoServiceRegistration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;

import javax.management.MBeanServer;
import javax.management.ObjectName;
import javax.management.Query;
import java.lang.management.ManagementFactory;
import java.util.Set;

/**
 * @author liushengbing
 * @version 1.0.0
 * @ClassName NacosRegisterOnWar.java
 * @Description 项目打包war情况下部署外部tomcat,需要该方式注册nacos
 * @createTime 2021年07月08日 16:36
 */
@Component
public class NacosRegisterOnWar implements ApplicationRunner {

    @Autowired(required = false)
    private NacosAutoServiceRegistration registration;

    @Value("${server.port}")
    Integer port;


    /**
     * Callback used to run the bean.
     *
     * @param args incoming application arguments
     * @throws Exception on error
     */
    @Override
    public void run(ApplicationArguments args) throws Exception {
        if(registration != null && port != null){
            Integer tomcatPort = port;
            try{
                tomcatPort = new Integer(getTomcatPort());
                registration.setPort(tomcatPort);
                registration.start();
            }catch(Exception e){
                System.out.println("使用内置tomcat启动,不需要单独注册nacos服务");
            }
        }
    }

    /**
     * @Author liushengbing
     * @Description 获取外部tomcat端口
     * @Date 2021/7/8 16:43
     * @Param
     * @return
     */
    public String getTomcatPort() throws Exception {
        MBeanServer beanServer = ManagementFactory.getPlatformMBeanServer();
        Set<ObjectName> objectNames = beanServer.queryNames(new ObjectName("*:type=Connector,*"), Query.match(Query.attr("protocol"), Query.value("HTTP/1.1")));
        String port = objectNames.iterator().next().getKeyProperty("port");
        return port;
    }

}
正文到此结束