Spring boot restarts the application after job completion [duplicate] - java

My Spring Boot application is not a web server, but it's a server using custom protocol (using Camel in this case).
But Spring Boot immediately stops (gracefully) after started. How do I prevent this?
I'd like the app to stop if Ctrl+C or programmatically.
#CompileStatic
#Configuration
class CamelConfig {
#Bean
CamelContextFactoryBean camelContext() {
final camelContextFactory = new CamelContextFactoryBean()
camelContextFactory.id = 'camelContext'
camelContextFactory
}
}

I found the solution, using org.springframework.boot.CommandLineRunner + Thread.currentThread().join(), e.g.:
(note: code below is in Groovy, not Java)
package id.ac.itb.lumen.social
import org.slf4j.LoggerFactory
import org.springframework.boot.CommandLineRunner
import org.springframework.boot.SpringApplication
import org.springframework.boot.autoconfigure.SpringBootApplication
#SpringBootApplication
class LumenSocialApplication implements CommandLineRunner {
private static final log = LoggerFactory.getLogger(LumenSocialApplication.class)
static void main(String[] args) {
SpringApplication.run LumenSocialApplication, args
}
#Override
void run(String... args) throws Exception {
log.info('Joining thread, you can press Ctrl+C to shutdown application')
Thread.currentThread().join()
}
}

As of Apache Camel 2.17 there is a cleaner answer. To quote http://camel.apache.org/spring-boot.html:
To keep the main thread blocked so that Camel stays up, either include the spring-boot-starter-web dependency, or add camel.springboot.main-run-controller=true to your application.properties or application.yml file.
You will want the following dependency too:
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-spring-boot-starter</artifactId>
<version>2.17.0</version>
</dependency>
Clearly replace <version>2.17.0</version> or use the camel BOM to import dependency-management information for consistency.

An example implementation using a CountDownLatch:
#Bean
public CountDownLatch closeLatch() {
return new CountDownLatch(1);
}
public static void main(String... args) throws InterruptedException {
ApplicationContext ctx = SpringApplication.run(MyApp.class, args);
final CountDownLatch closeLatch = ctx.getBean(CountDownLatch.class);
Runtime.getRuntime().addShutdownHook(new Thread() {
#Override
public void run() {
closeLatch.countDown();
}
});
closeLatch.await();
}
Now to stop your application, you can look up the process ID and issue a kill command from the console:
kill <PID>

Spring Boot leaves the task of running the application to the protocol around which the application is implemented. See, for example, this guide:
Also required are some housekeeping objects like a CountDownLatch to keep the main thread alive...
So the way of running a Camel service, for example, would to be to run Camel as a standalone application from your main Spring Boot application class.

This is now made even simpler.
Just add camel.springboot.main-run-controller=true to your application.properties

All threads are completed, the program will close automatically.
So, register an empty task with #Scheduled will create a loop thread to prevent shutdown.
file application.yml
spring:
main:
web-application-type: none
file DemoApplication.java
#SpringBootApplication
#EnableScheduling
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
file KeepAlive.java
#Component
public class KeepAlive {
private static final Logger log = LoggerFactory.getLogger(ScheduledTasks.class);
private static final SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
#Scheduled(fixedRate = 1 * 1000 * 60) // 1 minute
public void reportCurrentTime() {
log.info("Keepalive at time {}", dateFormat.format(new Date()));
}
}

My project is NON WEB Spirng Boot.
My elegant solution is create a daemon thread by CommandLineRunner.
Then, Application do not shutdown immediately.
#Bean
public CommandLineRunner deQueue() {
return args -> {
Thread daemonThread;
consumer.connect(3);
daemonThread = new Thread(() -> {
try {
consumer.work();
} catch (InterruptedException e) {
logger.info("daemon thread is interrupted", e);
}
});
daemonThread.setDaemon(true);
daemonThread.start();
};
}

To keep the java process alive when not deploying a web application set the webEnvironment property to false like so:
SpringApplication sa = new SpringApplication();
sa.setWebEnvironment(false); //important
ApplicationContext ctx = sa.run(ApplicationMain.class, args);

for springboot app to run continously it has to be run in a container, otherwise it is just like any java app all threads are done it finishes,
you can add
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
and it will turn it into webapp, if not you are responsible keeping it alive in your implementation

Related

Spring Boot : java.awt.HeadlessException

When we are trying to get the Clipboard instance.
Clipboard cb = Toolkit.getDefaultToolkit().getSystemClipboard();
Also i have tried to run the Spring boot application by setting the head.
SpringApplicationBuilder builder = new SpringApplicationBuilder(SpringBootApplication.class,args);
builder.headless(false).run(args);
we are getting below exception.
java.awt.HeadlessException
at sun.awt.HeadlessToolkit.getSystemClipboard(HeadlessToolkit.java:309)
at com.kpit.ecueditor.core.utils.ClipboardUtility.copyToClipboard(ClipboardUtility.java:57)
Can someone suggest me what i am missing here.
If i run the same clipboard code in simple java application , it is working but not in the spring boot application.
instead of this line
SpringApplication.run(Application.class, args);
use
SpringApplicationBuilder builder = new SpringApplicationBuilder(Application.class);
builder.headless(false);
ConfigurableApplicationContext context = builder.run(args);
It will work
I had the same Exception, using Spring Boot 2 in a swing application.
Here is a sample of what worked for me:
In the main class:
//Main.java
#SpringBootApplication
public class Main implements CommandLineRunner {
public static void main(String[] args) {
ApplicationContext contexto = new SpringApplicationBuilder(Main.class)
.web(WebApplicationType.NONE)
.headless(false)
.bannerMode(Banner.Mode.OFF)
.run(args);
}
#Override
public void run(String... args) throws Exception {
SwingUtilities.invokeLater(() -> {
JFrame frame = new JFrame();
frame.setVisible(true);
});
}
}
In the test class, you'll need to set java.awt.headless propety, so that you won't get a java.awt.HeadlessException when testing the code:
//MainTest.java
#RunWith(SpringRunner.class)
#SpringBootTest
public class MainTest {
#BeforeClass
public static void setupHeadlessMode() {
System.setProperty("java.awt.headless", "false");
}
#Test
public void someTest() { }
}
For those who are having this exception using JavaFX this answer might help.
You can also just pass the a JVM parameter when running your application, no code change required:
-Djava.awt.headless=false
Tested on springboot 2.2.5.RELEASE
I was facing same issue, all of the solutions shown here didn't work out.
Finally noticed DB server user id was disabled hence this was happening no code change was really required. This error was hella misleading.
Suggestion for whoever is facing similar to validate stacktrace and if db connection class is getting this error test out database through simple java class/IDE instead of Spring boot.

Spring Boot - Use Application Listener

After starting my spring boot application I want to start an customer process like creating required folders, files, etc. For that I'm using ApplicationListener<ApplicationReadyEvent>. This works like expected. But I'm building my spring application context with SpringApplicationBuilder. Every child notifies that the application is started correctly. So my customer post-process startes even more than one time.
#SpringBootApplication
#EnableConfigurationProperties(value = {StorageProperties.class})
#EnableAsync
public class Application {
public static void main(String[] args) {
SpringApplicationBuilder parentBuilder
= new SpringApplicationBuilder(Application.class);
parentBuilder.child(Config1.class)
.properties("server.port:1443")
...
.run(args);
parentBuilder.child(Config2.class)
.properties("server.port:2443")
...
.run(args);
}
}
My first idea was, that I can create manuelly a new Bean with #Bean in Config1 for my Event-Listener. But I was not able to overhand the configuration file StorageProperties.class, which is necessary for this class.
Because the Listener has an constructor based dependency injection:
private final Path mPathTo;
public AfterStart(StorageProperties prop) {
this.mPathTo = Paths.get(prob.getPath());
}
How can I be able to start the listener just once per start?
For everyone who is interested in this question. This solution worked for me:
public void onApplicationEvent(ApplicationReadyEvent e) {
if (e.getApplicationContext().getParent == null) {
System.out.println("******************************");
System.out.println("Post-process begins.");
System.out.println("******************************");
}
}

Apache camel copy file between directories

I am new to apache camel and spring boot. I am writing an application where i need to transfer a file from a folder to jms queue. But before that i am trying to transfer the file from one folder to another, which is not happening. On running the application as spring boot application the input folder gets created. If a paste the file in this folder, the destination folder is not formed and the log statements are also not appearing. This is how I added the route:
#SpringBootApplication
public class CamelApplication extends FatJarRouter {
public static void main(String ... args) {
SpringApplication.run(CamelApplication.class, args);
}
#Override
public void configure() throws Exception {
from("file:input?noop=true")
.log("Read from the input file")
.to("file:destination")
.log("Written to output file");
}
}
It should work, and it does work for me, perhaps you haven't refreshed your workspace in your IDE, if that's how you're tracking the progress.
EDIT
I see now what's wrong with your configuration - you probably don't have spring-boot-starter-web on your classpath so your main method does not get blocked and exits instantly.
You should remove the main method from CamelApplication and add this entry to application.properties:
spring.main.sources = com.example.CamelApplication
Or, you can change your main method to run CamelSpringBootApplicationController:
#SpringBootApplication
public class CamelApplication extends FatJarRouter {
public static void main(String... args) {
ApplicationContext applicationContext = SpringApplication.run(DemoApplication.class, args);
CamelSpringBootApplicationController applicationController =
applicationContext.getBean(CamelSpringBootApplicationController.class);
applicationController.run();
}
#Override
public void configure() throws Exception {
from("file:input?noop=true")
.log("Read from the input file")
.to("file:destination")
.log("Written to output file");
}
}
Alternatively, you can add this to your pom.xml to force an embedded Tomcat to start and block your main method:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
add to application.properties to keep the JVM running
camel.springboot.main-run-controller = true

Spring Boot shutdown hook

How can I register/add a custom shutdown routine that shall fire when my Spring Boot application shuts down?
Scenario: I deploy my Spring Boot application to a Jetty servlet container (i.e., no embedded Jetty). My application uses Logback for logging, and I want to change logging levels during runtime using Logback's MBean JMX configurator. Its documentation states that to avoid memory leaks, on shutdown a specific LoggerContext shutdown method has to be called.
What are good ways to listen on Spring Boot shutdown events?
I have tried:
public static void main(String[] args) throws Exception {
ConfigurableApplicationContext cac = SpringApplication.run(Example.class, args);
cac.addApplicationListener(new ApplicationListener<ContextClosedEvent>() {
#Override
public void onApplicationEvent(ContextClosedEvent event) {
logger.info("Do something");
}
});
}
but this registered listener does not get called when the application shuts down.
https://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/#features.spring-application.application-exit
Each SpringApplication will register a shutdown hook with the JVM to ensure that the ApplicationContext is closed gracefully on exit. All the standard Spring lifecycle callbacks (such as the DisposableBean interface, or the #PreDestroy annotation) can be used.
In addition, beans may implement the org.springframework.boot.ExitCodeGenerator interface if they wish to return a specific exit code when the application ends.
have you tried this as mentioned by #cfrick ?
#SpringBootApplication
#Slf4j
public class SpringBootShutdownHookApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootShutdownHookApplication.class, args);
}
#PreDestroy
public void onExit() {
log.info("###STOPing###");
try {
Thread.sleep(5 * 1000);
} catch (InterruptedException e) {
log.error("", e);;
}
log.info("###STOP FROM THE LIFECYCLE###");
}
}
Your listener is registered too late (that line will never be reached until the context has already closed). It should suffice to make it a #Bean.
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;
import org.springframework.boot.web.support.SpringBootServletInitializer;
import org.springframework.context.annotation.Bean;
#SpringBootApplication
#EnableAutoConfiguration
public class Application extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#NotNull
#Bean
ServletListenerRegistrationBean<ServletContextListener> myServletListener() {
ServletListenerRegistrationBean<ServletContextListener> srb =
new ServletListenerRegistrationBean<>();
srb.setListener(new ExampleServletContextListener());
return srb;
}
}
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
public class ExampleServletContextListener implements ServletContextListener {
#Override
public void contextInitialized(
ServletContextEvent sce) {
// Context Initialised
}
#Override
public void contextDestroyed(
ServletContextEvent sce) {
// Here - what you want to do that context shutdown
}
}
I have a similar use case, where I have to hold the server's shutdown process for some minutes, I have used the same approach mentioned in the question, the only change is instead of adding the listener after booting the service, I have added the listener (ContextClosedEvent) before running the application
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication application = new SpringApplication(Application.class);
application.addListeners((ApplicationListener<ContextClosedEvent>) event -> {
log.info("Shutdown process initiated...");
try {
Thread.sleep(TimeUnit.MINUTES.toMillis(5));
} catch (InterruptedException e) {
log.error("Exception is thrown during the ContextClosedEvent", e);
}
log.info("Graceful Shutdown is processed successfully");
});
application.run(args);
}
}

Command-line application using Spring context never ends

I created mini framework to executing some spring beans from main() method rather than deploying and running full-fledged webapp just to launch those beans. It looks like this:
public abstract class BaseLauncher {
private static final String APP_CONTEXT_PATH = "com/project/dev/launchers/launchersApplicationContext.xml";
static ApplicationContext context = new ClassPathXmlApplicationContext(APP_CONTEXT_PATH);
protected void launch() {
context.getBean(getClass()).perform();
//The process never ends so we want to know when we can kill it
System.out.println("launcher finished");
}
#Transactional
abstract protected void perform();
}
And example launcher looks like this:
#Component
public class ParamLoaderLauncher extends BaseLauncher {
#Inject
ParamLoader paramLoader;
public static void main(String[] args) {
new ParamLoaderLauncher().launch();
}
#Override
protected void perform() {
paramLoader.loadParams();
}
}
It all works great except that when the invoked bean method is finished, application just keep running and we need to kill it manually. I guess it has something to do with using spring app context. Maybe some special spring-related non-deamon thread is launched? If so, is there any way to kill it? Or what other cause of this may be in such simple code?
For standalone applications (not running in any container), shutdownhook needs to be registered for clean shutdown of the spring container when application exits.

Categories