Spring cloud war package deployment causes the service not registered to Nacos normally

Recently, a spring boot project has been connected to microservice, using spring boot 2.1.9.release and spring cloud greenwich.sr3. Local tests are normal, but after going online, there is a situation like this:

There is no statement like Nacos registry in the log, and there is no exception information, just like there is no microservice configured at all.

Profile checked, OK

Local test, normal registration

Later, I asked the team leader for help and found that it was the problem of war package deployment:

Spring cloud project uses external Tomcat to deploy its war package. Its startup command and port are configured by external container Tomcat. Nacos or other service registration methods need the port number of the current project to register the microservice.

Take Nacos for example. The class for automatically registering microservices is NacosAutoServiceRegistration. Let's see its source code:

public class NacosAutoServiceRegistration extends AbstractAutoServiceRegistration<Registration> {

    private NacosRegistration registration;

    @Deprecated
    public void setPort(int port) {
        this.getPort().set(port);
    }

    protected NacosRegistration getRegistration() {
        if (this.registration.getPort() < 0 && this.getPort().get() > 0) {
            this.registration.setPort(this.getPort().get());
        }

        Assert.isTrue(this.registration.getPort() > 0, "service.port has not been set");
        return this.registration;
    }

We see that NacosAutoServiceRegistration uses this.registration.setPort(this.getPort().get()); to set the port number.

The port number is obtained from the method in its parent class AbstractAutoServiceRegistration:

public abstract class AbstractAutoServiceRegistration<R extends Registration>
		implements AutoServiceRegistration, ApplicationContextAware,
		ApplicationListener<WebServerInitializedEvent> {

	private AtomicInteger port = new AtomicInteger(0);


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

This code listens for the start completion event of the built-in container. After obtaining the container port, it registers the service with the registry.

Therefore, when an external container is used, the Tomcat at this location deploys the project, abstractautoservice registration cannot listen to the container start event, and it will not attempt to register the current microservice with the service registry, so the registration fails, and there is no exception information.

The solution is to customize the method of getting the port of the external container, and then listen for the application startup event. When the application is started, get the port number of the external container startup, and then set the port to nacoasautoserviceregistration.

Here is the complete solution:

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.cloud.alibaba.nacos.registry.NacosAutoServiceRegistration;
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;

@Component
public class NacosConfig implements ApplicationRunner {

    @Autowired(required = false)
    private NacosAutoServiceRegistration registration;

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

    @Override
    public void run(ApplicationArguments args) {
        if (registration != null && port != null) {
            Integer tomcatPort = port;
            try {
                tomcatPort = new Integer(getTomcatPort());
            } catch (Exception e) {
                e.printStackTrace();
            }

            registration.setPort(tomcatPort);
            registration.start();
        }
    }

    /**
     * Get external tomcat port
     */
    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;
    }
}

Communication learning

Personal wechat: guanlanju6688

Personal website: http://www.eknown.cn

GitHub: https://github.com/laolunsi

Public number: apes story, "sharing technology, and understanding life", welcome attention!

Keywords: Programming Spring Tomcat Java github

Added by csteff24 on Mon, 30 Dec 2019 14:49:19 +0200