近期做一個專案投標演示(POC)環境支持,需要整合Nacos服務端。考慮到現有專案中已經有了Nacos相關依賴,那還不簡單?新建個服務端,配置幾下重啟不就搞定了嗎?然而事情遠遠沒有想得這麼簡單。同樣的程式碼在我本地IDE裡運作就能註冊成功,在示範環境 Tomcat War 部署就不行了。
經過遠端Debug程式碼,發現Nacos客戶端的執行緒都有啟動,卻沒有註冊成功。
想到可能與Tomcat部署模式有關係,就去查了官方issue和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
大致是說只有當Spring Boot 啟動內嵌Tomcat 成功後,才會發布WebServerInitializedEvent
事件。而Nacos客戶端在等這個事件出現才會向服務端註冊自己。又因為部署在外部Tomcat中就不會初始化內嵌Tomcat,也就沒觸發這個事件。
所以解決方法就是將Nacos等事件的部分程式碼呼叫下,讓他們啟動註冊。
Nacos的自動註冊類別是NacosAutoServiceRegistration
,它繼承Spring Cloud的AbstractAutoServiceRegistration
#,在AbstractAutoServiceRegistration
#等的bind(WebSerEventInitialized)
方法監聽事件,設定連接埠號碼並啟動註冊。這裡邊 this.port
是從事件中取得的,需要我們自行取得。
設定port的位置可見,是從org.springframework.cloud.client.serviceregistry.Registration
中取到的,給它設定一下就可以了。
我寫了一個完整的設定類別放到了這個ISSUE下邊,這裡直接貼在下邊。
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); } }
以上是SpringBoot部署到外部Tomcat無法註冊到Nacos服務端如何解決的詳細內容。更多資訊請關注PHP中文網其他相關文章!