一. 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,使用方法及效果是一样的
a. pom依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot</artifactId>
<version>2.0.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
<version>2.0.1.RELEASE</version>
</dependency>
b. 主启动类
package com.rgh;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class ApplicationMain {
public static void main(String[] args) {
SpringApplication.run(ApplicationMain.class, args);
}
}
c. 两个实体类
@Component
@Order(1)
public class BlackPersion implements CommandLineRunner {
@Override
public void run(String... args) throws Exception {
System.out.println("----BlackPersion----");
}
}
@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容器之后执行的顺序(优先级);
二. TimeUnit 的使用
TimeUnit是java.util.concurrent包下面的一个类,表示给定单元粒度的时间段
主要作用
- 时间颗粒度转换
- 延时
常用的颗粒度
TimeUnit.DAYS //天
TimeUnit.HOURS //小时
TimeUnit.MINUTES //分钟
TimeUnit.SECONDS //秒
TimeUnit.MILLISECONDS //毫秒
1. 时间颗粒度转换
public long toMillis(long d) //转化成毫秒
public long toSeconds(long d) //转化成秒
public long toMinutes(long d) //转化成分钟
public long toHours(long d) //转化成小时
public long toDays(long d) //转化天
例子
public class Test {
public static void main(String[] args) {
//1天有24个小时 1代表1天:将1天转化为小时
System.out.println( TimeUnit.DAYS.toHours( 1 ) );
//结果: 24
//1小时有3600秒
System.out.println( TimeUnit.HOURS.toSeconds( 1 ));=
//结果3600
//把3天转化成小时
System.out.println( TimeUnit.HOURS.convert( 3 , TimeUnit.DAYS ) );
//结果是:72
}
}
2. 延时
- 一般的写法
public class Test2 {
public static void main(String[] args) {
new Thread( new Runnable() {
@Override
public void run() {
try {
Thread.sleep( 5 * 1000 );
System.out.println( "延时完成了");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start(); ;
}
}
-
TimeUnit 写法
public class Test2 { public static void main(String[] args) { new Thread( new Runnable() { @Override public void run() { try { TimeUnit.SECONDS.sleep( 5 ); System.out.println( "延时5秒,完成了"); } catch (InterruptedException e) { e.printStackTrace(); } } }).start(); ; } }
三. oracle中的decode的使用
含义解释:
decode(条件,值1,返回值1,值2,返回值2,...值n,返回值n,缺省值)
该函数的含义如下:
IF 条件=值1 THEN
RETURN(翻译值1)
ELSIF 条件=值2 THEN
RETURN(翻译值2)
......
ELSIF 条件=值n THEN
RETURN(翻译值n)
ELSE
RETURN(缺省值)
END IF
decode(字段或字段的运算,值1,值2,值3)
这个函数运行的结果是,当字段或字段的运算的值等于值1时,该函数返回值2,否则返回值3
当然值1,值2,值3也可以是表达式,这个函数使得某些sql语句简单了许多
使用方法:
1. 比较大小
select decode(sign(变量1-变量2),-1,变量1,变量2) from dual;
--取较小值
sign()
函数根据某个值是0、正数还是负数,分别返回0、1、-1
例如:
变量1=10,变量2=20
则sign(变量1-变量2)返回-1,*decode*解码结果为“变量1”,达到了取较小值的目的。
2. 此函数用在SQL语句中,功能介绍如下:
Decode函数与一系列嵌套的 IF-THEN-ELSE语句相似。base_exp与compare1,compare2等等依次进行比较。如果base_exp和 第i 个compare项匹配,就返回第i 个对应的value 。如果base_exp与任何的compare值都不匹配,则返回default。每个compare值顺次求值,如果发现一个匹配,则剩下的compare值(如果还有的话)就都不再求值。一个为NULL的base_exp被认为和NULL compare值等价。如果需要的话,每一个compare值都被转换成和第一个compare 值相同的数据类型,这个数据类型也是返回值的类型。
Decode函数在实际开发中非常的有用
a. 结合Lpad函数,如何使主键的值自动加1并在前面补0
select LPAD(decode(count(记录编号),0,1,max(to_number(记录编号)+1)),14,'0') 记录编号 from tetdmis
补充:LPAD函数的用法
lpad('tech', 7); 将返回' tech'
lpad('tech', 2); 将返回'te'
lpad('tech', 8, '0'); 将返回'0000tech'
lpad('tech on the net', 15, 'z'); 将返回'tech on the net'
lpad('tech on the net', 16, 'z'); 将返回'ztech on the net'
例:
select decode(dir,1,0,1) from a1_interval
dir 的值是1变为0,是0则变为1
3. 比如我要查询某班男生和女生的数量分别是多少?
通常我们这么写:
select count(*) from 表 where 性别 = 男;
select count(*) from 表 where 性别 = 女;
要想显示到一起还要union一下,太麻烦了
用decode呢,只需要一句话
select sum(decode(性别,男,1,0)),sum(decode(性别,女,1,0)) from 表
4. order by对字符列进行特定的排序
大家还可以在Order by中使用Decode。
例:表table_subject,有subject_name列。要求按照:语、数、外的顺序进行排序。这时,就可以非常轻松的使用Decode完成要求了。
select * from table_subject order by decode(subject_name, '语文', 1, '数学', 2, , '外语',3)
网友评论