Recently, I have done a project bidding demonstration (POC) environment support, which needs to be integrated with the Nacos server. Considering that existing projects already have Nacos-related dependencies, isn't that simple? Create a new server, configure it and restart it a few times, right? However, things are far from being as simple as thought. The same code can be successfully registered when run in my local IDE, but cannot be deployed in the demo environment Tomcat War.
After the remote Debug code, it was found that the threads of the Nacos client were started, but the registration was not successful.
I thought it might be related to the Tomcat deployment mode, so I checked the official issue and StackOverFlow
The event is published as part of Spring Boot starting the embedded Tomcat instance . If you're deploying to an external container, there's no embedded container to start and, therefore, no event is published. – Andy Wilkinson
Roughly speaking, only when Spring Boot starts the embedded Tomcat successfully, The WebServerInitializedEvent
event will be released. The Nacos client will wait for this event to occur before registering itself with the server. And because it is deployed in external Tomcat, the embedded Tomcat will not be initialized, so this event will not be triggered.
So the solution is to call part of the code for events such as Nacos and let them start registration.
Nacos's automatic registration class is NacosAutoServiceRegistration
, which inherits Spring Cloud's AbstractAutoServiceRegistration
, bind(WebServerInitializedEvent) in
AbstractAutoServiceRegistration, etc.
Method listens for events, sets the port number and starts registration. Here this.port
is obtained from the event and needs to be obtained by ourselves.
The location where the port is set is visible. It is taken from org.springframework.cloud.client.serviceregistry.Registration
. Just set it. That's it.
I wrote a complete configuration class and placed it under the ISSUE, which is posted directly below.
import java.lang.management.ManagementFactory; import java.util.Set; import javax.annotation.PostConstruct; import javax.management.MBeanServer; import javax.management.MalformedObjectNameException; import javax.management.ObjectName; import javax.management.Query; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.core.env.Environment; import com.alibaba.cloud.nacos.registry.NacosAutoServiceRegistration; import com.alibaba.cloud.nacos.registry.NacosRegistration; @Configuration public class NacosWarDeployConfig { private static final Logger logger = LoggerFactory.getLogger(NacosWarDeployConfig.class); @Autowired private Environment env; @Autowired private NacosRegistration registration; @Autowired private NacosAutoServiceRegistration nacosAutoServiceRegistration; @PostConstruct public void nacosServerRegister() { if (registration != null) { registration.setPort(getTomcatPort()); nacosAutoServiceRegistration.start(); } } public int getTomcatPort() { try { return getProvideTomcatPort(); } catch (Exception e) { logger.warn("obtain provide tomcat port failed, fallback to embeded tomcat port."); } return getEmbeddedTomcatPort(); } private int getProvideTomcatPort() throws MalformedObjectNameException, NullPointerException { 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 Integer.valueOf(port); } private int getEmbeddedTomcatPort() { return env.getProperty("server.port", Integer.class, 8080); } }
The above is the detailed content of How to solve the problem when SpringBoot is deployed to external Tomcat and cannot be registered to the Nacos server. For more information, please follow other related articles on the PHP Chinese website!