Я создал класс в модуле библиотеки, у которого есть bean-компонент ServletWebServerFactory, чтобы при запуске моего приложения весенней загрузки вызывался этот метод bean-компонента, чтобы я мог программно установить порт для tomcat на основе некоторых свойств среды. В основном, если server.port не установлен, он использует SocketUtils для получения случайного доступного порта в пределах диапазона, определенного свойствами server.port.min и server.port.max (или их значениями по умолчанию)
public class TomcatServlet {
final Logger logger = LoggerFactory.getLogger(TomcatServlet.class);
@Autowired
private Environment environment;
@Bean
public ServletWebServerFactory servletWebServerFactory() {
String serverPort = environment.getProperty("server.port");
// Note: min port number should be greater or equal to 49152 as lower values are either registered or semi-reserved
int minPort = Integer.parseInt(environment.getProperty("server.port.min", "49152"));
int maxPort = Integer.parseInt(environment.getProperty("server.port.max", "65535"));
logger.info("server.port: {}, server.port.min: {}, server.port.max: {}", serverPort, minPort, maxPort);
// if serverPort is defined then use that value
int port;
// if serverPort is not defined then get a random available port in the defined or default range
if (serverPort == null) {
// get an available port in the range
port = getRandomPort(minPort, maxPort);
} else {
port = Integer.parseInt(serverPort);
}
logger.info("port to set tomcat on: {}", port);
Long unloadDelay = Long.valueOf(environment.getProperty("tomcat.unload.timeout", "30000"));
logger.info("Tomcat unloadDelay = {}", unloadDelay);
TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory();
Long finalUnloadDelay = unloadDelay;
tomcat.addContextCustomizers(context -> {
if(context instanceof StandardContext) {
((StandardContext) context).setUnloadDelay(finalUnloadDelay);
}
});
tomcat.setPort(port);
return tomcat;
}
private int getRandomPort(int minPort, int maxPort) {
int returnPort = 0;
try {
returnPort = SocketUtils.findAvailableTcpPort(minPort, maxPort);
logger.info("Random Server Port is {}.", returnPort);
} catch( IllegalStateException e) {
// no available port found so it will use the configured server.port value
logger.warn("No port available in range {$minPort}-{$maxPort}. Default configuration {$returnPort} will be used.");
}
return returnPort;
}
}
Это все работает нормально, tomcat запускается на ожидаемом порту, и я могу включить эту библиотеку во все наши службы, и все они будут запускаться на ожидаемых портах.
Однако , каждая служба определяется как служба клиента Eureka и как таковая регистрируется на сервере Eureka. Когда он делает это, он отправляет информацию об имени сервера и номере порта на сервер Eureka.
Номер порта берется из свойства server.port, которое не обязательно является портом, на котором был запущен tomcat. Поэтому я хотел бы сохранить рассчитанный порт в свойстве server.port в том месте, где он рассчитан. Есть ли способ получить доступ к свойствам приложений таким образом, чтобы их можно было изменить в моем классе TomcatServlet?
Я провел тестовую реализацию аналогичных функций в основном классе одного из сервисов, чтобы я мог получить доступ к SpringApplication и используйте метод setDefaultProperties для установки server.port, и в этом случае мне не пришлось бы делать это в классе библиотеки.
public static void main(String[] args) {
SpringApplication application = new SpringApplication(AddressBSMain.class);
Properties properties = new Properties();
int port = HttpUtils.getRandomPort(50000, 50100);
properties.put("server.port", port);
application.setDefaultProperties(properties);
application.run(args);
}
Опять же, это работает нормально. Единственная проблема с этим состоит в том, что мы должны были бы внедрить это изменение в каждую из наших 60 с лишним услуг. В идеале мы хотели бы сохранить код в нашей общей библиотеке, чтобы все, что нам нужно было сделать, - это изменить каждый файл maven pom служб, чтобы изменить версию зависимости
Есть предложения?