美文网首页
201009复盘:@Order-TimeUnit-decod

201009复盘:@Order-TimeUnit-decod

作者: 弹钢琴的崽崽 | 来源:发表于2020-10-11 14:00 被阅读0次

    一. 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)
    

    相关文章

      网友评论

          本文标题:201009复盘:@Order-TimeUnit-decod

          本文链接:https://www.haomeiwen.com/subject/gyrepktx.html