Programmatically restart Spring Boot application - spring

I'm using Spring Boot and I've got a use case where user can upload a file which should cause a restart of application (since user's upload is used during creation of multiple beans). I know I can avoid restarting the application, but at the moment - this is what I want.
I've found RestartEndpoint in Spring-Cloud project, but it doesn't seem like ApplicationPreparedEvent is fired. Is there any other way I can programmatically restart Spring Boot application?

The simplest way to do this by calling the refresh() method on the Spring ApplicationContext. This will kill and reload all of your beans, so you should be certain that this occurs only when it is safe for your application to do so.

I have a special case in which my Spring Boot application, which runs on Linux, is required to run as root.
Since I run the application as systemd service, I can restart it like this:
Runtime.getRuntime().exec(new String[] { "/bin/systemctl", "restart", "foo" });
If your application is (hopefully) not required to run as root, a setuid wrapper-script could be used, or better, use sudo.
Check this answer on how to do that:
https://superuser.com/questions/440363/can-i-make-a-script-always-execute-as-root

In your case it might be possible to use the /refresh endpoint (see http://cloud.spring.io/spring-cloud-config/spring-cloud-config.html#_endpoints) and annotate the beans that depend on the changed configuration with #RefreshScope.

I used the below code to restart my application from the code itself. Closing context using a separate thread will not shut the JVM.
public class DemoApplication {
private static String[] args;
private static ConfigurableApplicationContext context;
public static void main(String[] args) {
DemoApplication.args = args;
context = SpringApplication.run(DemoApplication.class, args);
}
public static void restart() {
Thread thread = new Thread(() -> {
context.close();
context = SpringApplication.run(DemoApplication.class, DemoApplication.args);
});
thread.setDaemon(false);
thread.start();
}

Related

How to restart springboot application from code

I have a springboot application with embedded tomcat. And on certain cases it should be restarted from code.
I have read several articles and SO posts regarding this,but yet to find a clean solution.
I am aware that 'context.close' , 'SpringApplication.exit(context)' exist and can be wrapped into something like this:
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();
}
source: https://www.baeldung.com/java-restart-spring-boot-app
The problem is that using context.close() just doesn't work in a clean way. The context itself will be restarted though, but bunch of Threads will be left in the background (like Thread[pool-3-thread-1,5,main] Thread[Signal Dispatcher,9,system] Thread[OkHttp TaskRunner,5,main] ..etc).
And for every context restart these will be recreated, so the number of threads adds up gradually by each restart. Resulting in huge Thread mess as time passes.
Note1: A simple application exit by using 'context.close()' also wouldn't work because of these left over Threads. So the context close doesnt even close the application.
Note2: If I use System.exit(SpringApplication.exit(context)) I can kill the app gracefully, but can't restart it.
Note3: I don't want to use neither devtools nor actuator
So the question is how to perform a total restart for a springboot application?
You can use the RestartEndPoint in spring-cloud-context dependency to restart the Spring Boot application programmatically:
#Autowired
private RestartEndpoint restartEndpoint;
...
Thread restartThread = new Thread(() -> restartEndpoint.restart());
restartThread.setDaemon(false);
restartThread.start();

How to know ports are open to serve Rest requests?

I am using Quarkus to build an application that is running on the Raspberry PI. Quarkus exposes Rest interfaces to control the PI; once Quarkus is started, Chrome is launched to serve a HTML/Javascript UI packaged within the Quarkus application.
The problem I have is that as the PI is quiet slow, I notice that when I start the browser to open the UI, the HTTP port seems not to be open yet or is not accepting any Rest requests yet and thus gets back 404. A seconds later, the port is available.
I am not sure what is the best way to detect the readiness of the Webcontainer.
I tried with this but it did not work and fires too early:
#WebListener
public class BrowserMain implements ServletContextListener {
#Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
// Start Chrome
}
}
Thanks,
Daniel
Quarkus integrates with MicroProfile Health which should do exactly what you are looking for. See this guide for more details.
If what you are looking for is a way to programmatically know when the application is ready, then you simply have to listen for the StartupEvent like so:
#ApplicationScoped
public class AppLifecycleBean {
private static final Logger LOGGER = LoggerFactory.getLogger("ListenerBean");
void onStart(#Observes StartupEvent ev) {
LOGGER.info("The application is starting...");
}
void onStop(#Observes ShutdownEvent ev) {
LOGGER.info("The application is stopping...");
}
}
To see more details check out this guide.

Spring Boot: Serving aggregated data from a websocket connection

I'd like to make a RESTful web app with Spring Boot that would be constantly receiving information from a websocket connection, aggregating it, and serving those aggregated data via its REST API.
So I'll need to open and maintain a WebSocket connection, while also running SpringApplication.run() in the main() function.
The #Scheduled annotation seems to only run tasks at a specific time or interval, but doesn't seem to have a way to always run something in the background.
What is a sensible way to achieve what I've described?
Just have your application connect to a socket on application startup
#SpringBootApplication
public class SpringBootConsoleApplication
implements CommandLineRunner {
private static Logger LOG = LoggerFactory
.getLogger(SpringBootConsoleApplication.class);
public static void main(String[] args) {
LOG.info("STARTING THE APPLICATION");
SpringApplication.run(SpringBootConsoleApplication.class, args);
LOG.info("APPLICATION FINISHED");
}
#Override
public void run(String... args) {
//Connect to socket and cache the results if you want to
}}
Spring Boot will automatically call the run method of all beans implementing this interface after the application context has been loaded
for more information about command line runner you can visit https://www.baeldung.com/spring-boot-console-app
Why not use the WebSocketClient provided by Spring? After you connect you will get notified via a callback method each time a new websocket frame is received.
You can follow the example here https://www.baeldung.com/websockets-api-java-spring-client
Just put it in a class annotated with #Component or #Service that starts the websocket session through the constructor.
You won't need to do the new Scanner(System.in).nextLine() since you have a server that is always running.

How to Integration Test Spring Shell v2.x

The new Spring Shell docs don't seem to provide any examples of how to integration test CLI commands in a Spring Boot context. Any pointers or examples would be appreciated.
The method Shell#evaluate() has been made public and has its very specific responsibility (evaluate just one command) for exactly that purpose. Please create an issue with the project if you feel like we should provide more (A documentation chapter about testing definitely needs to be written)
Here is how I got this working.
You first need to override the default shell application runner to avoid getting stuck in the jline loop. You can do this by defining your own such as:
#Component
public class CliAppRunner implements ApplicationRunner {
public CliAppRunner() {
}
#Override
public void run(ApplicationArguments args) throws Exception {
//do nothing
}
}
Note that you will have to associate this custom Application runner against a "Test" profile so it overrides only during integration testing.
If you want to test a shell command "add 1 3", you then can write a test like this:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest(classes =CliConfig.class)
public class ShellCommandIntegrationTest {
#Autowired
private Shell shell;
#Test
public void runTest(){
Object result=shell.evaluate(new Input(){
#Override
public String rawText() {
return "add 1 3";
}
});
DefaultResultHandler resulthandler=new DefaultResultHandler();
resulthandler.handleResult(result);
}
}
Note that the above test does not Assert anything. You will probably have to write your own little implementation of the ResultHandler interface that deals with parsing/formatting of the result so that it can be asserted.
Hope it helps.
Spring Shell 2.0.1 depends on Spring Boot 1.5.8, which in turn depends on Spring Framework 4.3.12. This makes researching how to implement tests challenging, since the latest version of Spring Shell does not depend on the latest versions of other Spring libraries. Take a look at my example project, sualeh/spring-shell-2-tests-example which has example unit, functional and integration tests for a sample Spring Shell application.

Automatic configuration reinitialization in Spring

In Log4j, there is a feature wherein the system can be initialized to do a configure and watch with an interval. This allows for the log4j system to reload its properties whenever the property file is changed. Does the spring framework have such a Configuration Observer facility wherein the Configuration is reloaded when it changed. The Configuration that needs reloading is not the Springs's applicationContext.xml but various other configuration files that are initialized using the Spring initialization beans.
I found a utility that does something similar to Log4J here. It's basically an extension to PropertyPlaceholderConfigurer that reloads properties when they change.
AFAIK Spring does not provide such a utility. However there is a 3rd party tool, JRebel that enables you to update an entire web application (including the Spring configuration) without requiring a server restart.
A free trial is available, and the purchase price is fairly inexpensive.
I would be extra cautious with reloading spring application context.
What do you expect to happen with singleton beans? If an object has a reference to singleton bean, should it be updated?
I develop using JRebel and I would be very wary of expecting it to refresh your configuration. Works fine with Java, not with Spring though.
If you would like to add context, I have done that in the following way :
public class ApplicationContextUtil
{
static String[] configFiles = {"applicationContextParent.xml"};
private static ApplicationContext context = null;
static
{
context = new ClassPathXmlApplicationContext ( configFiles );
}
public static void addContext( String[] newConfigFiles )
{
// add the new context to the previous context
ApplicationContext newContext = new ClassPathXmlApplicationContext ( newConfigFiles, context );
context = newContext;
}
public static ApplicationContext getApplicationContext ()
{
// return the context
return context;
}
}
This is your context provider class. For details, you can look at my blog

Resources