Spring Boot - shutdown and restart application programmatically

Today we will be discussing how to shutdown and restart a Spring application programmatically.

1) New Project

First let's create a simple spring boot app with web dependency so that we can setup an endpoint to trigger the shutdown and restart. Let's head over to  https://start.spring.io/ and choose web and other dependencies that you need

2) Few words about ApplicationContext and ConfigurableApplicationContext

ApplicationContext is the central interface that represents the Spring IoC container and is responsible for instantiating, configuring, and assembling the beans.  ConfigurableApplicationContext is another interface that extends  ApplicationContext and provides facilities to configure refresh, startup & shutdown of the application and allows registration of custom listeners to respond to those events.

3) Let's code!

3.1) Simple App

Run the application and store ConfigurableApplicationContext in a static variable appCtx so that we can use it later

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

@SpringBootApplication
public class App {

static ConfigurableApplicationContext appCtx;

public static void main(String[] args) {
appCtx = SpringApplication.run(App.class, args);
}

3.2) Shutdown - call ConfigurableApplicationContext.close() 

This closes the application context, releasing all resources and locks that the implementation might hold. This includes destroying all cached singleton beans.

static void shutdown() {
appCtx.close();
}

3.3) Restart

We know how to stop and start the application. To stop, we can simply do:

appCtx.close();

And to start, we can simply call the SpringApplication.run(..)

appCtx = SpringApplication.run(App.class, args);

But the catch here is, appCtx.close() would exit the application and the SpringApplication.run(..) won't be able to run

So, a solution would be to use Daemon Thread to shutdown and start the application. Daemon thread is a type of thread that can run independently in the background(independent of the main thread). 

Thread t = new Thread(() -> {
appCtx.close();
appCtx = SpringApplication.run(...);
});

t.setDaemon(false);
t.start();


3.4) Passing the original program arguments

We may want to use the original arguments that were passed to run method when we restart the application.

 SpringApplication.run(App.class, args);

We can do that by either storing String[] args in a static variable or use ApplicationArguments bean that Spring Boot creates to store the arguments.

var args = appCtx.getBean(ApplicationArguments.class);      //retrieve
appCtx = SpringApplication.run(App.class, args.getSourceArgs()); //pass


3.5) Web endpoints to trigger the shutdown and restart

@RestController
class Ctrl {

@GetMapping("/shutdown")
void shutdown() {
App.shutdown();
}

@GetMapping("/restart")
void restart() {
App.restart();
}
}


4) Complete Example:

package gt.restart;

import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@SpringBootApplication
public class App {

static ConfigurableApplicationContext appCtx;

public static void main(String[] args) {
appCtx = SpringApplication.run(App.class, args);
}

static void shutdown() {
if (appCtx.isActive()) {
appCtx.close();
}
}

static void restart() {
var args = appCtx.getBean(ApplicationArguments.class);

Thread thread = new Thread(() -> {
appCtx.close();
appCtx = SpringApplication.run(App.class, args.getSourceArgs());
});

thread.setDaemon(false);
thread.start();
}

}

@RestController
class Ctrl {

@GetMapping("/shutdown")
void shutdown() {
App.shutdown();
}

@GetMapping("/restart")
void restart() {
App.restart();
}
}


5) Test

Call the endpoints

GET http://localhost:8080/restart

GET http://localhost:8080/shutdown

Read Request parameter String from URL in Spring/HttpServlet

Read entire query string(request parameter) in Spring Boot/HttpServlet

In Spring Boot and other Java web frameworks, we capture the request parameters (aka query parameters) and map them to individual variable or a Map<String,String>. 

But, if you want to read the entire query parameter in its raw form ( eg: to read name=Ganesh&country=Nepal&ageLt=30&page=1 from request: http://localhost:8080/search?name=Ganesh&country=Nepal&ageLt=30&page=1), you can utilize HttpServletRequest.getQueryString()

Example:

@GetMapping("/test1")
void endpoint1(HttpServletRequest req) {
var qs = req.getQueryString() //returns the entire string
qs.split("&") //split to get the individual parameters
}

Note: Spring Boot automatically resolves the HttpServletRequest object ( its the real holder of request object in Http Servlet environment)

GIT delete merged branches

How to delete merged branches from local copy:

When you work on a project for a while, there is a good chance that you will have a list of old/already merged branches showing on your local git. 

When you run $git branch it will show all the branches since you started working on the project including the ones that are not currently active.

$git branch
    PROJX-1024-add-new-button
    PROJX-1026-add-another-button
    PROJX-1027-titleupdates
    build-fix
    develop
    release
    master 

Here's how you can find the merged branches: It will only list a branch if it exists in local but not in remote(deleted from remote after merging).

$git branch --merged
    PROJX-1024-add-new-button
    build-fix
    develop
    release


Here's how you delete the merged branches except develop and release

$git branch --merged | egrep -v "(^\*|develop|release)" | xargs git branch -d


You can add any number of branches to the skip list separated by pipe |

$git branch --merged | egrep -v "(^\*|develop|release|another_branch|yet_another_branch)" | xargs git branch -d