一直有个想法,想实现如何让spring boot服务重启,满足下面的使用场景

1.通过集群方式部署后,用户可以无感知的实现spring boot重启

2.结合定时工具,可以指定在某个时间点自动重启

3.屏蔽开源热加载工具导致的一些错误。

4.重启不适合互联网项目,但是比较适合企业级项目部署,互联网项目还是需要考虑热加载,以及完善热加载的功能

1.方法一:通过创建新上下文重新启动

我们可以通过关闭应用程序上下文并从头创建一个新上下文来重新启动应用程序。尽管这种方法非常简单,但我们必须小心处理一些微妙的细节,才能使其发挥作用。让我们看看如何在Spring Boot应用程序的主要方法中实现这一点:

@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();
    }
}

正如我们在上面的示例中所看到的,在一个单独的非守护线程中重新创建上下文是很重要的—这样我们可以防止由close方法触发的JVM关闭关闭我们的应用程序。否则,我们的应用程序将停止,因为JVM不会在终止守护进程线程之前等待它们完成。

另外,让我们添加一个REST端点,通过它可以触发重启:

@RestController
public class RestartController {
    
    @PostMapping("/restart")
    public void restart() {
        Application.restart();
    } 
}

这里,我们添加了一个带有映射方法的控制器,该映射方法调用重启方法。然后,我们可以调用新端点来重新启动应用程序:

curl -X POST localhost:port/restart

当然,如果我们在实际应用程序中添加这样的端点,我们还必须保护它,可以通过设置白名单功能来进行触发。

方法二:执行器的重启端点

重新启动应用程序的另一种方法是使用Spring Boot Actuator的内置RestartEndpoint。

首先,让我们添加所需的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>

接下来,我们必须在application.properties文件中启用内置的重启端点:

management.endpoint.restart.enabled=true

既然我们已经设置了所有内容,我们可以将RestartEndpoint注入我们的服务:

@Service
public class RestartService {
    
    @Autowired
    private RestartEndpoint restartEndpoint;
    
    public void restartApp() {
        restartEndpoint.restart();
    }
}

在上面的代码中,我们使用RestartEndpoint bean来重新启动应用程序。这是一种很好的重新启动方法,因为我们只需要调用一个完成所有工作的方法。

如我们所见,使用RestartEndpoint是重启应用程序的一种简单方法。另一方面,这种方法有一个缺点,因为它需要我们添加所提到的库。如果我们还没有使用它们,那么仅此功能可能会有太多的开销。在这种情况下,我们可以坚持上一节中的手动方法,因为它只需要多出几行代码。

方法三:刷新应用程序上下文

在某些情况下,我们可以通过调用其刷新方法来重新加载应用程序上下文。

尽管这个方法听起来很有前途,但是只有一些应用程序上下文类型支持刷新已经初始化的上下文。例如,FileSystemXmlApplicationContext、GroovyWebApplicationContext和其他一些文件都支持它。

不幸的是,如果在Spring Boot web应用程序中尝试此操作,将出现以下错误:

java.lang.IllegalStateException: GenericApplicationContext does not support multiple refresh attempts:
just call 'refresh' once

最后,尽管有些上下文类型支持多次刷新,但我们应该避免这样做。原因是refresh方法被设计为框架用来初始化应用程序上下文的内部方法。github参考https://github.com/eugenp/tutorials/tree/master/spring-boot-modules/spring-boot-runtime

本文全文都参考:https://www.baeldung.com/java-restart-spring-boot-app#refreshing-the-application-context这篇文章,具体英文,请看这篇文档。

 

 

 

 

 

 

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐