浅谈Spring @Order注解的使用(转)
注解@Order或者接口Ordered的作用是定义Spring IOC容器中Bean的执行顺序的优先级,而不是定义Bean的加载顺序,Bean的加载顺序不受@Order或Ordered接口的影响;
1.@Order的注解源码解读
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD})
@Documented
public @interface Order { /**
* 默认是最低优先级,值越小优先级越高
*/
int value() default Ordered.LOWEST_PRECEDENCE; }
- 注解可以作用在类(接口、枚举)、方法、字段声明(包括枚举常量);
- 注解有一个int类型的参数,可以不传,默认是最低优先级;
- 通过常量类的值我们可以推测参数值越小优先级越高;
2.Ordered接口类
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----");
}
}
4.启动应用程序打印出结果
----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容器之后执行的顺序(优先级);
- 原文地址:https://blog.csdn.net/yaomingyang/article/details/86649072
浅谈Spring @Order注解的使用(转)的更多相关文章
- 浅谈Spring框架注解的用法分析
原文出处: locality 1.@Component是Spring定义的一个通用注解,可以注解任何bean. 2.@Scope定义bean的作用域,其默认作用域是”singleton”,除此之外还有 ...
- 浅谈Spring中的Quartz配置
浅谈Spring中的Quartz配置 2009-06-26 14:04 樊凯 博客园 字号:T | T Quartz是一个强大的企业级任务调度框架,Spring中继承并简化了Quartz,下面就看看在 ...
- 浅谈Spring的两种配置容器
浅谈Spring的两种配置容器 原文:https://www.jb51.net/article/126295.htm 更新时间:2017年10月20日 08:44:41 作者:黄小鱼ZZZ ...
- 1.1浅谈Spring(一个叫春的框架)
如今各种Spring框架甚嚣尘上,但是终归还是属于spring的东西.所以在这里,个人谈一谈对spring的认识,笔者觉得掌握spring原理以及spring所涉及到的设计模式对我们具有极大的帮助.我 ...
- 浅谈SpringBoot核心注解原理
SpringBoot核心注解原理 今天跟大家来探讨下SpringBoot的核心注解@SpringBootApplication以及run方法,理解下springBoot为什么不需要XML,达到零配置 ...
- 浅谈Spring MVC知识
关于MVC框架,我相信大家都不陌生,都会说也就是模型-视图-控制器这三层的框架结构,如果你参加面试的时候考官会问:“MVC框架是什么?你说一说.”其实我们都知道这个问题还需要问的,只要你是一个开发人员 ...
- 浅谈spring——注解配置(九)
spring定义一个切面是件麻烦的事情,需要实现专门的接口,还要进行一些较为复杂的配置,有没有较为简单的方法??? @AspectJ注解可以很容易定义一个切面,且不需要实现任何的接口.缺点是对JDK的 ...
- 浅谈spring中AOP以及spring中AOP的注解方式
AOP(Aspect Oriented Programming):AOP的专业术语是"面向切面编程" 什么是面向切面编程,我的理解就是:在不修改源代码的情况下增强功能.好了,下面在 ...
- [SSH 3]以网上商城项目浅谈spring配置
导读:在做ITOO项目的时候,就用到了容器+反射,从而运用了依赖注入和依赖查找.如果看过WCF端的配置文件,那么对于这个spring的配置就很容易理解.本篇博客,是对于自己做的一个小项目中所运用到的s ...
随机推荐
- ubuntu 设置静态ip,但显示scope global secondary ens33
设置静态ip 修改 /etc/network/interfaces 文件 # The loopback network interface auto lo iface lo inet loopback ...
- jQuery添加/删除Select的Option项
使用语法1. $("#select_id").append("<option value='Value'>Text</option>") ...
- centerOS7安装lnmp环境
视频地址: https://www.bilibili.com/video/av55251610?p=65 安装nginx http://nginx.org 点击 download vim /etc/y ...
- php 数组相关方法的一些实际妙用
一.php数组合并两个数组(一个数组做键名,另一个做值) 有两个方法 1.循环 $arry_a = array(0, 1, 2); $arry_b = array('dongsir','董先生','董 ...
- Python 字符串,元祖,列表之间的转换
1.字符串是 Python 中最常用的数据类型.我们可以使用引号('或")来创建字符串. 创建字符串很简单,只要为变量分配一个值即可.例如: var1 = 'Hello World!' 2. ...
- DRF cbv源码分析 restful规范10条 drf:APIView的源码 Request的源码 postman的安装和使用
CBV 执行流程 路由配置:url(r'^test/',views.Test.as_view()), --> 根据路由匹配,一旦成功,会执行后面函数(request) --> 本质就是执 ...
- 查询集 QuerySet
1 概念 Django的ORM中存在查询集的概念. 查询集,也称查询结果集.QuerySet,表示从数据库中获取的对象集合. 当调用如下过滤器方法时,Django会返回查询集(而不是简单的列表): a ...
- C++字符转换等常用方法
下面是C++中字符编码格式转换(包括ANSI转换为UTF8,UTF8转换为ANSI,ANSI转换为unicode,unicode转换为ANSI,UTF8转换为unicode,unicode转换为UTF ...
- java lesson20homework
package com.xt.lesson20; /** * 简易自动提款机 1. 创建用户类User(包含卡号.姓名.密码.余额等属性),用户开卡时录入的姓名和密码(自动分配一个卡号.初始金额设置为 ...
- Unity鼠标移动到物体上显示信息
相信大家玩游戏的时候,鼠标移动到游戏装备上,都会显示装备的的具体信息,那么接下来就写代码把,废话不多说. 下面是 效果图 鼠标移动到装备位置显示的信息,鼠标移动不在装备区域后不现实信息,下面是代码 : ...