Spring Boot 2 -Spring Boot 如何解决项目启动时初始化资源

Spring Boot 2 -Spring Boot 如何解决项目启动时初始化资源

我们在开发中可能会有这样的情景。需要在容器启动的时候执行一些内容。比如读取配置文件,数据库连接之类的。SpringBoot给我们提供了两个接口来帮助我们实现这种需求。这两个接口分别为CommandLineRunnerApplicationRunner,这两个接口的Component会在所有Spring Beans 都初始化之后,SpringApplication.run() 之前执行,非常适合在应用程序启动之初进行一些数据初始化的工作。

这两个接口中有一个run方法,我们只需要实现这个方法即可。这两个接口的不同之处在于:ApplicationRunner中run方法的参数为ApplicationArguments,而CommandLineRunner接口中run方法的参数为String数组。下面我写两个简单的例子,来看一下这两个接口的实现。

CommandLineRunner和ApplicationRunner的例子

接下来我们就运用案例测试它如何使用,在测试之前在启动类加两行打印提示,方便我们识别CommandLineRunner的执行时机。

@SpringBootApplication
public class CommandLineRunnerApplication {
	public static void main(String[] args) {
		System.out.println("The service to start.");
		SpringApplication.run(CommandLineRunnerApplication.class, args);
		System.out.println("The service has started.");
	}
}

接下来我们直接创建一个类继承CommandLineRunner,并实现它的run()方法。

@Component
public class Runner implements CommandLineRunner {
    @Override
    public void run(String... args) throws Exception {
        System.out.println("The Runner start to initialize ...");
    }
}

我们在run()方法中打印了一些参数来抛光它的执行时机。完成之后启动项目进行测试:

The service to start.

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.0.0.RELEASE)
...
2018-04-21 22:21:34.706  INFO 27016 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2018-04-21 22:21:34.710  INFO 27016 --- [           main] com.neo.CommandLineRunnerApplication     : Started CommandLineRunnerApplication in 3.796 seconds (JVM running for 5.128)
The Runner start to initialize ...
The service has started.

根据控制台的打印信息我们可以抛光CommandLineRunner中的方法会在Spring Boot容器加载之后执行,执行完成后项目启动完成。

同理ApplicationRunner一样。

ApplicationRunner与CommandLineRunner谁先执行

我们在一个应用中分别实现两个接口

 @Component
    public class CommandLineRunnerTest implements CommandLineRunner {

	@Override
	public void run(String... arg0) throws Exception {
		System.out.println("CommandLineRunner=====执行开始");
		    for (int i = 0; i < arg0.length; i++) {
			    System.out.println(arg0[i]);
		    }
		System.out.println("CommandLineRunner=====执行完毕");

	    }

    }
 @Component
    public class ApplicationRunnerTest implements ApplicationRunner {
    
    	@Override
    	public void run(ApplicationArguments arg0) throws Exception {
    		System.out.println("ApplicationRunner=====执行开始");
    		System.out.println(arg0.getNonOptionArgs());
    		System.out.println(arg0.getOptionNames());
    		System.out.println("ApplicationRunner=====执行完成");
    
    	}
    
    }

从执行结果来看,ApplicationRunner默认先于CommandLineRunner执行

 ApplicationRunner=====执行开始
    []
    [name, age]
    [lisi]
    ApplicationRunner=====执行完成
    CommandLineRunner=====执行开始
    --name=lisi
    --age=12
    CommandLineRunner=====执行完毕
两者的区别,以及与main方法的联系

两个接口中都有run方法,负责接收来自应用外部的参数,ApplicationRunner的run方法会将外部参数封装成一个ApplicationArguments对象,而CommandLineRunner接口中run方法的参数则为String数组。

我们再回头看看main方法

    @SpringBootApplication
    public class AliyunmqApplication {
    
    	public static void main(String[] args) {
    		System.out.println("main方法==========执行开始");
    		for (int i = 0; i < args.length; i++) {			
    			System.out.println(args[i]);			
    		}
    		System.out.println("main方法==========执行完毕");
    		SpringApplication.run(AliyunmqApplication.class, args);
    	}
    }

我们看到main方法也是接收一个args 数组参数。

执行发现:

    main方法==========执行开始
    --name=lisi
    --age=12
    main方法==========执行完毕
    ..............
    ..............
    ApplicationRunner=====执行开始
    []
    [name, age]
    [lisi]
    ApplicationRunner=====执行完成
    CommandLineRunner=====执行开始
    --name=lisi
    --age=12
    CommandLineRunner=====执行完毕

main方法的arg参数 和 CommandLineRunner方法的arg数组的值是一样的。

总的来看: ApplicationRunner run方法中的ApplicationArguments 对象,对输入参数做了封装,让我们可以使用 get**()的形式获取参数。CommandLineRunner run方法的arg数组则是原装。

多个实现类的执行顺序

我们创造两个CommandLineRunner的实现类来进行测试:

第一个实现类:

@Component
@Order(1)
public class OrderRunner1 implements CommandLineRunner {
    @Override
    public void run(String... args) throws Exception {
        System.out.println("The OrderRunner1 start to initialize ...");
    }
}

第二个实现类:

@Component
@Order(2)
public class OrderRunner2 implements CommandLineRunner {
    @Override
    public void run(String... args) throws Exception {
        System.out.println("The OrderRunner2 start to initialize ...");
    }
}

添加完成之后重新启动,观察执行顺序:

...
The service to start.

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.0.0.RELEASE)
...
2018-04-21 22:21:34.706  INFO 27016 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2018-04-21 22:21:34.710  INFO 27016 --- [           main] com.neo.CommandLineRunnerApplication     : Started CommandLineRunnerApplication in 3.796 seconds (JVM running for 5.128)
The OrderRunner1 start to initialize ...
The OrderRunner2 start to initialize ...
The Runner start to initialize ...
The service has started.

通过控制台的输出我们发现,添加@Order注解的实现类最先执行,并且@Order()里面的值越小启动越早。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值