注解@Order或者接口Ordered的作用是定義Spring IOC容器中Bean的執行順序的優先級,而不是定義Bean的加載順序,Bean的加載順序不受@Order或Ordered接口的影響;
@Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Documented public @interface Order { /** * 默認是最低優先級,值越小優先級越高 */ int value() default Ordered.LOWEST_PRECEDENCE; }
- 注解可以作用在類(接口、枚舉)、方法、字段聲明(包括枚舉常量);
- 注解有一個int類型的參數,可以不傳,默認是最低優先級;
- 通過常量類的值我們可以推測參數值越小優先級越高
package org.springframework.core; public interface Ordered { int HIGHEST_PRECEDENCE = -2147483648; int LOWEST_PRECEDENCE = 2147483647; int getOrder(); }
3.創建BlackPersion、YellowPersion類,這兩個類都實現CommandLineRunner
實現CommandLineRunner接口的類會在Spring IOC容器加載完畢后執行,適合預加載類及其它資源;也可以使用ApplicationRunner,使用方法及效果是一樣的
package com.yaomy.common.order; import org.springframework.boot.CommandLineRunner; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; /** * @Description: Description * @ProjectName: spring-parent * @Version: 1.0 */ @Component @Order(1) public class BlackPersion implements CommandLineRunner { @Override public void run(String... args) throws Exception { System.out.println("----BlackPersion----"); } }
package com.yaomy.common.order; import org.springframework.boot.CommandLineRunner; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; /** * @Description: Description * @ProjectName: spring-parent * @Version: 1.0 */ @Component @Order(0) public class YellowPersion implements CommandLineRunner { @Override public void run(String... args) throws Exception { System.out.println("----YellowPersion----"); } }
----YellowPersion---- ----BlackPersion----
我們可以通過調整@Order的值來調整類執行順序的優先級,即執行的先后;當然也可以將@Order注解更換為Ordered接口,效果是一樣的
5.到這里可能會疑惑IOC容器是如何根據優先級值來先后執行程序的,那接下來看容器是如何加載component的
看如下的啟動main方法
@SpringBootApplication public class CommonBootStrap { public static void main(String[] args) { SpringApplication.run(CommonBootStrap.class, args); } }
這個不用過多的解釋,進入run方法…
public ConfigurableApplicationContext run(String... args) { StopWatch stopWatch = new StopWatch(); stopWatch.start(); ConfigurableApplicationContext context = null; Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList(); this.configureHeadlessProperty(); SpringApplicationRunListeners listeners = this.getRunListeners(args); listeners.starting(); Collection exceptionReporters; try { ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments); this.configureIgnoreBeanInfo(environment); Banner printedBanner = this.printBanner(environment); context = this.createApplicationContext(); exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context); this.prepareContext(context, environment, listeners, applicationArguments, printedBanner); this.refreshContext(context); this.afterRefresh(context, applicationArguments); stopWatch.stop(); if (this.logStartupInfo) { (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch); } listeners.started(context); //這里是重點,調用具體的執行方法 this.callRunners(context, applicationArguments); } catch (Throwable var10) { this.handleRunFailure(context, var10, exceptionReporters, listeners); throw new IllegalStateException(var10); } try { listeners.running(context); return context; } catch (Throwable var9) { this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null); throw new IllegalStateException(var9); } } private void callRunners(ApplicationContext context, ApplicationArguments args) { List<Object> runners = new ArrayList(); runners.addAll(context.getBeansOfType(ApplicationRunner.class).values()); runners.addAll(context.getBeansOfType(CommandLineRunner.class).values()); //重點來了,按照定義的優先級順序排序 AnnotationAwareOrderComparator.sort(runners); Iterator var4 = (new LinkedHashSet(runners)).iterator(); //循環調用具體方法 while(var4.hasNext()) { Object runner = var4.next(); if (runner instanceof ApplicationRunner) { this.callRunner((ApplicationRunner)runner, args); } if (runner instanceof CommandLineRunner) { this.callRunner((CommandLineRunner)runner, args); } } } private void callRunner(ApplicationRunner runner, ApplicationArguments args) { try { //執行方法 runner.run(args); } catch (Exception var4) { throw new IllegalStateException("Failed to execute ApplicationRunner", var4); } } private void callRunner(CommandLineRunner runner, ApplicationArguments args) { try { //執行方法 runner.run(args.getSourceArgs()); } catch (Exception var4) { throw new IllegalStateException("Failed to execute CommandLineRunner", var4); } }
到這里優先級類的示例及其執行原理都分析完畢;不過還是要強調下@Order、Ordered不影響類的加載順序而是影響Bean加載如IOC容器之后執行的順序(優先級);
個人理解是加載代碼的底層要支持優先級執行程序,否則即使配置上Ordered、@Order也是不起任何作用的。