1

When using spring-boot-starter-web, The spring-boot application won't exit after startup.

And with Jetbrain IDEA, There is an icon show spring-boot start up finished:

enter image description here

enter image description here

But if I using :

public static void main ( String[] args ){
    SpringApplication.run(Application.class, args);
    Thread.sleep(Long.MAX_VALUE);
}

Or

public class MyRunner implements ApplicationRunner{
    public void run() {
        Thread.sleep(Long.MAX_VALUE);
    }
}

Can let spring-boot keep running but the IDEA icon will loading forever, So that must be different way compare with starter-web.

Update1: And those two method will cause SpringBootTest wait forever

Question: What's the code that spring-boot-starter-web prevent spring-boot exit ?

Alceatraz
  • 432
  • 1
  • 3
  • 13
  • 2
    You are running your code in embedded tomcat so it is natural to NOT to exit. You are simply using web server. – Gurkan İlleez Jun 17 '22 at 07:30
  • @Gurkanİlleez My application don't need seb server. This question is talking about how to achive same result without starter-web – Alceatraz Jun 18 '22 at 16:09
  • It is not clear what your goal is. You want an application running until you cancel it's execution, but not in a web server? As if it were a simple Java application? – Jetto Martínez Jun 18 '22 at 17:55
  • 1
    Also see https://stackoverflow.com/questions/2213340/what-is-a-daemon-thread-in-java/2213348#2213348 – Adam Kotwasinski Jun 24 '22 at 20:02

2 Answers2

2

I don't know, what is a reason, but without webserver, you can prevent shutdown only if any other thread still active (non-daemon thread). Infinite loop in another thread will prevent program exit.

package com.example.demo;

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

@SpringBootApplication
public class DemoApplication {

    public static void main(String[] args) {
        System.out.println("main started");
        new Thread(() -> {
            System.out.println("thread started");
            ConfigurableApplicationContext context = SpringApplication.run(DemoApplication.class, args);
            while (true) {
                System.out.println(context);
                try {
                    Thread.sleep(1000L);
                } catch (InterruptedException e) {
                }
            }
        }).start();
        System.out.println("main finished");
    }



}

output example

    main started
    main finished
    thread started

    .   ____          _            __ _ _
    /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
    ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
    \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
    '  |____| .__|_| |_|_| |_\__, | / / / /
    =========|_|==============|___/=/_/_/_/
    :: Spring Boot ::                (v2.6.7)

    2022-06-24 22:34:31.648  INFO 8084 --- [       Thread-1] o.s.boot.SpringApplication               : Starting application using Java 1.8.0_312 on DESKTOP with PID 8084 (started by user in C:\Users\user\IdeaProjects\demo)
    2022-06-24 22:34:31.650  INFO 8084 --- [       Thread-1] o.s.boot.SpringApplication               : No active profile set, falling back to 1 default profile: "default"
    2022-06-24 22:34:31.985  INFO 8084 --- [       Thread-1] org.quartz.impl.StdSchedulerFactory      : Using default implementation for ThreadExecutor
    2022-06-24 22:34:31.991  INFO 8084 --- [       Thread-1] org.quartz.core.SchedulerSignalerImpl    : Initialized Scheduler Signaller of type: class org.quartz.core.SchedulerSignalerImpl
    2022-06-24 22:34:31.991  INFO 8084 --- [       Thread-1] org.quartz.core.QuartzScheduler          : Quartz Scheduler v.2.3.2 created.
    2022-06-24 22:34:31.991  INFO 8084 --- [       Thread-1] org.quartz.simpl.RAMJobStore             : RAMJobStore initialized.
    2022-06-24 22:34:31.992  INFO 8084 --- [       Thread-1] org.quartz.core.QuartzScheduler          : Scheduler meta-data: Quartz Scheduler (v2.3.2) 'quartzScheduler' with instanceId 'NON_CLUSTERED'
    Scheduler class: 'org.quartz.core.QuartzScheduler' - running locally.
    NOT STARTED.
    Currently in standby mode.
    Number of jobs executed: 0
    Using thread pool 'org.quartz.simpl.SimpleThreadPool' - with 10 threads.
    Using job-store 'org.quartz.simpl.RAMJobStore' - which does not support persistence. and is not clustered.

    2022-06-24 22:34:31.992  INFO 8084 --- [       Thread-1] org.quartz.impl.StdSchedulerFactory      : Quartz scheduler 'quartzScheduler' initialized from an externally provided properties instance.
    2022-06-24 22:34:31.992  INFO 8084 --- [       Thread-1] org.quartz.impl.StdSchedulerFactory      : Quartz scheduler version: 2.3.2
    2022-06-24 22:34:31.992  INFO 8084 --- [       Thread-1] org.quartz.core.QuartzScheduler          : JobFactory set to: org.springframework.scheduling.quartz.SpringBeanJobFactory@501627dc
    2022-06-24 22:34:32.009  INFO 8084 --- [       Thread-1] o.s.s.quartz.SchedulerFactoryBean        : Starting Quartz Scheduler now
    2022-06-24 22:34:32.010  INFO 8084 --- [       Thread-1] org.quartz.core.QuartzScheduler          : Scheduler quartzScheduler_$_NON_CLUSTERED started.
    2022-06-24 22:34:32.015  INFO 8084 --- [       Thread-1] o.s.boot.SpringApplication               : Started application in 0.601 seconds (JVM running for 1.051)
    org.springframework.context.annotation.AnnotationConfigApplicationContext@74ed4e3, started on Fri Jun 24 22:34:31 MSK 2022
    org.springframework.context.annotation.AnnotationConfigApplicationContext@74ed4e3, started on Fri Jun 24 22:34:31 MSK 2022
    org.springframework.context.annotation.AnnotationConfigApplicationContext@74ed4e3, started on Fri Jun 24 22:34:31 MSK 2022
and so on...

only 1 dependency (just random starter, not web, quartz not required here)

org.springframework.boot:spring-boot-starter-quartz

just infinite loop in non-daemon thread...

Slongtong
  • 111
  • 5
2

To answer the question

What's the code that spring-boot-starter-web prevent spring-boot exit

spring-boot-web creates web server beans, that use non-daemon listener threads (as you want them to be alive and running to waiting for incoming connections and handle them).

This makes your code reach end of your main method, however JVM does not exit, as it has non-daemon threads running.

If you want to keep your application alive, you'd need to do the same - the simplest way would be to e.g. create a Thread in a bean like @Slongtong has suggested.

Adam Kotwasinski
  • 4,377
  • 3
  • 17
  • 40
  • Thanks with that. You point the most confusion: "main exit" with some test. I figure out the mechanism: Main will exit, that will let idea know application booted. And using a undemon thread to "stuck" the jvm, And event main exit, Springboot still working. And I can do what ever in the runner – Alceatraz Jun 27 '22 at 01:00