springboot项目初始化和项目结束调用自定义方法

1、在项目启动类中实现CommandLineRunner,实现run方法。run方法会在项目启动后调用。

@SpringBootApplication
@MapperScan(basePackages = "com.yin.freemakeradd.mapper")
public class FreemakeraddApplication implements CommandLineRunner {
    @Autowired
    private List inits;
public static void main(String[] args) {
        SpringApplication.run(FreemakeraddApplication.class, args);
    }

    @Override
    public void run(String... args) throws Exception {
       if(Objects.isNull(inits)){
           return;
       }
        for (Init init : inits) {
            init.init();
        }
    }
    }

2、定义一个Init接口

public interface Init {
    void init();

    void exeact();
}

3、实现Init接口

public abstract class InitWork implements Init{
    @Override
    public void init() {
        exeact();
    }
}
@Component
public class JobWorker extends InitWork {
    @Override
    public void exeact() {
        System.out.println("-----------------start job");
        close();
    }

    void close(){
        Runtime.getRuntime().addShutdownHook(new Thread(){
            @Override
            public void run() {
                System.out.println("-----------------end job");
            }
        });
    }
}

启动项目(结束代码执行—end job)

2019-10-08 19:19:55.081  INFO 9776 --- [           main] c.y.databaseweb.DatabaseWebApplication   : No active profile set, falling back to default profiles: default
2019-10-08 19:19:57.261  INFO 9776 --- [           main] c.y.databaseweb.DatabaseWebApplication   : Started DatabaseWebApplication in 3.687 seconds (JVM running for 6.341)
-----------------start job
Disconnected from the target VM, address: '127.0.0.1:63629', transport: 'socket'
-----------------end job

Runtime.getRuntime().addShutdownHook(new Thread(){})生效的条件:

Java 虚拟机会为了响应以下两类事件而关闭:

程序正常退出:这发生在最后的非守护线程退出时,或者在调用 exit(等同于System.exit)方法时。

为响应用户中断而终止虚拟机:如键入 ^C(注:也就是我们再dos窗口下常用的Ctrl+C退出命令);或发生系统事件,比如用户注销或系统关闭。

shutdown hook只是一个已初始化但尚未启动的线程。虚拟机开始启用其关闭序列时,它会以某种未指定的顺序启动所有已注册的关闭挂钩,并让它们同时运行。运行完所有的挂钩后,如果已启用退出终结,那么虚拟机接着会运行所有未调用的终结方法。最后,虚拟机会暂停。注意,关闭序列期间会继续运行守护线程,如果通过调用 exit 方法来发起关闭序列,那么也会继续运行非守护线程。

一旦开始了关闭序列,则只能通过调用 halt 方法来停止这个序列,此方法可强行终止虚拟机。

一旦开始了关闭序列,则不可能注册新的关闭挂钩或取消注册先前已注册的挂钩。尝试执行这些操作会导致抛出 IllegalStateException。

关闭挂钩可在虚拟机生命周期中的特定时间运行,因此应保护性地对其进行编码。特别是应将关闭挂钩编写为线程安全的,并尽可能地避免死锁。关闭挂钩还应该不盲目地依靠某些服务,这些服务可能已注册了自己的关闭挂钩,所以其本身可能正处于关闭进程中。

关闭挂钩应该快速地完成其工作。当程序调用 exit 时,虚拟机应该迅速地关闭并退出。由于用户注销或系统关闭而终止虚拟机时,底层的操作系统可能只允许在固定的时间内关闭并退出。因此在关闭挂钩中尝试进行任何用户交互或执行长时间的计算都是不明智的。

与其他所有线程一样,通过调用线程 ThreadGroup 对象的 uncaughtException 方法,可在关闭挂钩中处理未捕获的异常。此方法的默认实现是将该异常的堆栈跟踪 (stack trace) 打印至 System.err 并终止线程;它不会导致虚拟机退出或暂停。

仅在很少的情况下,虚拟机可能会中止,也就是没有完全关闭就停止运行。虚拟机被外部终止时会出现这种现象,比如在 Unix 上使用 SIGKILL 信号或者在 Microsoft Windows 上调用 TerminateProcess。如果由于内部数据结构损坏或试图访问不存在的内存而导致本机方法执行错误,那么可能也会中止虚拟机。如果虚拟机中止,则无法保证是否将运行关闭挂钩。

注:

在eclipse环境下,程序运行时的那个红色小方形按钮是强制终止程序,也就是相当于kill进程。因此这时候,如果你的程序中有一个hook,那么它就不会执行。因为按照上文的说法,只有在两种情况下运行hook中的程序。这一点和tomcat的程序关闭有点类似,tomcat中的listener中的contextDestroyed()方法也是在jvm关闭的时候才执行这个函数里面的程序。而我们如果直接关掉tomcat的运行窗口,就相当于直接kill掉进程了,因此并不会执行这个函数,但是如果使用的是tomcat里面的shutdown.bat命令,那么这个函数就会执行。
所以对于意外关闭JVM或者强制杀死进程的情况,想要清理垃圾或者一些资源回收的问题,本文的addShutdownHook的方法也不管用。

假如你在程序中还开启了一个端口,那么意外的程序终止,这个端口还被占用,并没有被释放,那么下一次程序重启或者别的程序要使用这个端口的时候,就会出现端口被占用的情况。

对于addShutdownHook()中的Hook,这个线程里面更不能出现死循环的情况,因为这样的话,那么当程序正常终止的时候,就会出现程序关闭不了的情况。

你可能感兴趣的:(springboot,springboot,java,初始化调用自定义方法)