相关推荐recommended
SpringBoot 启动后执行功能
作者:mmseoamin日期:2024-03-20

本文介绍SpringBoot项目的四种启动后执行功能的方式。

  • 方法1: ApplicationRunner 接口

    import org.springframework.boot.ApplicationArguments;
    import org.springframework.boot.ApplicationRunner;
    import org.springframework.core.annotation.Order;
    import org.springframework.stereotype.Component;
    @Component
    @Order(value = 2)
    public class ApplicationRunnerTest implements ApplicationRunner {
    	@Override
    	public void run(ApplicationArguments args) throws Exception {
    		System.out.println("========ApplicationRunner========");
    		// 失败后,服务停止
    //		throw new RuntimeException();
    	}
    }
    1. 类需要实现ApplicationRunner接口,实现public void run(ApplicationArguments args) throws Exception 方法

    2. 类增加@Component注解成为spring可管理的bean

    3. 多个ApplicationRunner实现类,可以通过@Order注解指定执行顺序,数越小就越先执行

    4. 当run方法执行异常,则服务启动失败

    • 方法2: CommandLineRunner 接口

      import org.springframework.boot.CommandLineRunner;
      import org.springframework.core.annotation.Order;
      import org.springframework.stereotype.Component;
      @Component
      @Order(value = 2)
      public class CommandLineRunnerTest implements CommandLineRunner {
      	@Override
      	public void run(String... args) throws Exception {
      		System.out.println("========CommandLineRunner========");
      		// 失败后,服务停止
      //		throw new RuntimeException();
      	}
      }
      1. 类需要实现CommandLineRunner接口,实现public void run(String... args) throws Exception 方法

      2. 类增加@Component注解成为spring可管理的bean

      3. 多个CommandLineRunner实现类,可以通过@Order注解指定执行顺序,数越小就越先执行

      4. 当run方法执行异常,则服务启动失败

      • 方法3: @PostConstruct 注解

        import javax.annotation.PostConstruct;
        import org.springframework.stereotype.Component;
        @Component
        public class PostConstructTest {
        	@PostConstruct
        	public void init() {
        		System.out.println("========PostConstruct========");
        		// 失败后,服务停止
        //		throw new RuntimeException();
        	}
        }
        1. 类增加@Component注解成为spring可管理的bean

        2. 在需要执行的方法上,增加@PostConstruct注解,方法名称不一定是init

        3. 当方法执行异常,则服务启动失败

        4. 多个方法标注@Component注解,按照顺序依次执行,即使方法上标注@Order注解。

        import javax.annotation.PostConstruct;
        import org.springframework.core.annotation.Order;
        import org.springframework.stereotype.Component;
        @Component
        public class PostConstructTest {
        	@PostConstruct
        	@Order(value = 2)
        	public void init() {
        		System.out.println("========PostConstruct========");
        	}
        	
        	@PostConstruct
        	@Order(value = 1)
        	public void init2() {
        		System.out.println("========PostConstruct2========");
        	}
        }

        虽然将两个方法上都加了@Order注解,并且init2()方法的设置顺序小于init()方法,但是仍然先执行init()方法

        • 方法4: ApplicationListener 接口

          import org.springframework.context.ApplicationListener;
          import org.springframework.context.event.ContextRefreshedEvent;
          import org.springframework.stereotype.Component;
          @Component
          public class ApplicationListenerTest implements ApplicationListener{
          	@Override
          	public void onApplicationEvent(ContextRefreshedEvent event) {
          		System.out.println("========ApplicationListener========");
          		// 失败后,服务停止
          //		throw new RuntimeException();
          	}
          }
          1. 类需要实现ApplicationListener接口,实现public void onApplicationEvent(E event) 方法

          2. 类增加@Component注解成为spring可管理的bean

          3. 多个CommandLineRunner实现类,可以通过@Order注解指定执行顺序,数越小就越先执行

          4. 当onApplicationEvent方法执行异常,则服务启动失败

          5. 当onApplicationEvent方法采用异步执行时,方法执行异常,服务启动不会失败

          • 四种方式比较

            1. @PostConstruct注解在类被加载的时候执行,而ApplicationRunner、CommandLineRunner接口是在工程启动后才执行

            2. ApplicationListener接口执行顺序晚于@PostConstruct注解,早于ApplicationRunner、CommandLineRunner接口

            3. 四种方式在执行方法时,只要失败,服务均不能启动

            4. ApplicationRunner、CommandLineRunner接口同时存在时,通过指定@Order注解可以改变总体的自行顺序,并不是哪个接口一定先执行

            5. 无@Order注解或者@Order注解的顺序一致时,ApplicationRunner、CommandLineRunner接口同时存在时,则ApplicationRunner接口优先执行

            6. 注 由于ApplicationListener接口是基于发布订阅模式的,因此可以支持异步执行,异步执行时,ApplicationListener接口早于ApplicationRunner、CommandLineRunner接口执行,但不是等到ApplicationListener接口执行完成后才执行ApplicationRunner、CommandLineRunner接口

            import org.springframework.context.ApplicationListener;
            import org.springframework.context.event.ContextRefreshedEvent;
            import org.springframework.core.annotation.Order;
            import org.springframework.scheduling.annotation.Async;
            import org.springframework.stereotype.Component;
            @Component
            public class ApplicationListenerTest implements ApplicationListener{
            	@Override
            	@Async  // 已经在SpringBoot启动类增加了@EnableAsync注解
            	public void onApplicationEvent(ContextRefreshedEvent event) {
            		System.out.println("========ApplicationListener========");
            		try {
            			Thread.sleep(10000);
            		} catch (InterruptedException e) {
            			e.printStackTrace();
            		}
            		// 由于异步执行,所以方法执行失败后,仍然不会停止服务
            //		throw new RuntimeException();
            	}
            }

            • 其他

              • 对于@Order注解,也可以采用Ordered接口来实现,需要实现public int getOrder()方法

                @Component
                //@Order(value = 2)
                public class CommandLineRunnerTest implements CommandLineRunner ,Ordered {
                	@Override
                	public int getOrder() {
                		return 1;
                	}
                	
                	@Override
                	public void run(String... args) throws Exception {
                		System.out.println("========CommandLineRunner========");
                		// 失败后,服务停止
                //		throw new RuntimeException();
                	}
                }