1. Overview
1.概述
In this tutorial, we’ll show how to programmatically restart a Spring Boot application.
在本教程中,我们将展示如何以编程方式重新启动Spring Boot应用程序。
Restarting our application can be very handy in some cases:
在某些情况下,重启我们的应用程序是非常方便的。
- Reloading config files upon changing some parameter
- Changing the currently active profile at runtime
- Re-initializing the application context for any reason
While this article covers the functionality of restarting a Spring Boot application, note that we also have a great tutorial about shutting down Spring Boot applications.
虽然本文涵盖了重启Spring Boot应用程序的功能,但请注意,我们也有一篇关于关闭Spring Boot应用程序的精彩教程。
Now, let’s explore different ways we can implement the restart of a Spring Boot application.
现在,让我们来探讨一下实现Spring Boot应用重启的不同方法。
2. Restart by Creating a New Context
2.通过创建一个新的上下文重新启动
We can restart our application by closing the application context and creating a new context from scratch. Although this approach is quite simple, there are some delicate details we have to be careful with to make it work.
我们可以通过关闭应用程序上下文并从头创建一个新的上下文来重新启动我们的应用程序。虽然这种方法很简单,但有一些微妙的细节,我们必须小心翼翼地使其发挥作用。
Let’s see how to implement this in the main method of our Spring Boot app:
让我们看看如何在Spring Boot应用程序的main方法中实现这一点。
@SpringBootApplication
public class Application {
private static ConfigurableApplicationContext context;
public static void main(String[] args) {
context = SpringApplication.run(Application.class, args);
}
public static void restart() {
ApplicationArguments args = context.getBean(ApplicationArguments.class);
Thread thread = new Thread(() -> {
context.close();
context = SpringApplication.run(Application.class, args.getSourceArgs());
});
thread.setDaemon(false);
thread.start();
}
}
As we can see in the above example, it’s important to recreate the context in a separate non-daemon thread — this way we prevent the JVM shutdown, triggered by the close method, from closing our application. Otherwise, our application would stop since the JVM doesn’t wait for daemon threads to finish before terminating them.
正如我们在上面的例子中所看到的,在一个单独的非守护线程中重新创建上下文是很重要的–这样我们就可以防止由close方法触发的JVM关闭,从而关闭我们的应用程序。否则,我们的应用程序就会停止,因为JVM在终止守护线程之前不会等待它们完成。
Additionally, let’s add a REST endpoint through which we can trigger the restart:
此外,让我们添加一个REST端点,通过它我们可以触发重启。
@RestController
public class RestartController {
@PostMapping("/restart")
public void restart() {
Application.restart();
}
}
Here, we’ve added a controller with a mapping method that invokes our restart method.
在这里,我们添加了一个控制器,它的映射方法调用了我们的restart方法。
We can then call our new endpoint to restart the application:
然后我们可以调用我们的新端点来重新启动应用程序。
curl -X POST localhost:port/restart
Of course, if we add an endpoint like this in a real-life application, we’ll have to secure it as well.
当然,如果我们在现实生活中的应用中添加这样一个端点,我们也必须确保其安全性。
3. Actuator’s Restart Endpoint
3.执行器的重启端点
Another way to restart our application is to use the built-in RestartEndpoint from Spring Boot Actuator.
另一种重启我们的应用程序的方法是使用来自RestartEndpoint的内置RestartEndpoint>。Spring Boot Actuator。
First, let’s add the required Maven dependencies:
首先,让我们添加所需的Maven依赖项。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-cloud-starter</artifactId>
</dependency>
Next, we have to enable the built-in restart endpoint in our application.properties file:
接下来,我们必须在application.properties文件中启用内置重启端点。
management.endpoint.restart.enabled=true
Now that we have set up everything, we can inject the RestartEndpoint into our service:
现在我们已经设置好了一切,我们可以将RestartEndpoint注入到我们的服务。
@Service
public class RestartService {
@Autowired
private RestartEndpoint restartEndpoint;
public void restartApp() {
restartEndpoint.restart();
}
}
In the above code, we are using the RestartEndpoint bean to restart our application. This is a nice way of restarting because we only have to call one method that does all the work.
在上面的代码中,我们使用RestartEndpointbean来重新启动我们的应用程序。这是一种很好的重启方式,因为我们只需要调用一个方法就可以完成所有的工作。
As we can see, using the RestartEndpoint is a simple way to restart our application. On the other side, there is a drawback with this approach because it requires us to add the mentioned libraries. If we aren’t using them already, this might be too much overhead for only this functionality. In that case, we can stick to the manual approach from the previous section since it requires only a few more lines of code.
正如我们所看到的,使用RestartEndpoint是一个简单的方法来重新启动我们的应用程序。另一方面,这种方法也有一个缺点,因为它要求我们添加上述的库。如果我们还没有使用它们,这可能会对这个功能造成太大的开销。在这种情况下,我们可以坚持上一节中的手动方法,因为它只需要多写几行代码。
4. Refreshing the Application Context
4.刷新应用程序上下文
In some cases, we can reload the application context by calling its refresh method.
在某些情况下,我们可以通过调用其refresh方法重新加载应用程序上下文。
Although this method might sound promising, only some application context types support refreshing an already initialized context. For example, FileSystemXmlApplicationContext, GroovyWebApplicationContext, and a few others support it.
虽然这种方法听起来很有前途,但只有一些应用程序上下文类型支持刷新已经初始化的上下文。例如,FileSystemXmlApplicationContext、GroovyWebApplicationContext和其他一些类型支持该方法。
Unfortunately, if we try this in a Spring Boot web application, we will get the following error:
不幸的是,如果我们在Spring Boot网络应用中尝试这样做,我们会得到以下错误。
java.lang.IllegalStateException: GenericApplicationContext does not support multiple refresh attempts:
just call 'refresh' once
Finally, although there are some context types that support multiple refreshes, we should avoid doing this. The reason is that the refresh method is designed as an internal method used by the framework to initialize the application context.
最后,虽然有一些上下文类型支持多次刷新,但我们应该避免这样做。原因是refresh方法被设计为框架用来初始化应用程序上下文的内部方法。
5. Conclusion
5.结论
In this article, we explored a number of different ways how to restart a Spring Boot application programmatically.
在这篇文章中,我们探讨了如何以编程方式重启Spring Boot应用程序的若干不同方法。
As always, we can find the source code for the examples over on GitHub.
一如既往,我们可以在GitHub上找到这些例子的源代码。