Spring @Order注解的使用小结

 更新时间:2025年01月31日 10:28:13   作者:立小言先森  
本文主要介绍了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容器之后执行的顺序(优先级);

个人理解是加载代码的底层要支持优先级执行程序,否则即使配置上Ordered、@Order也是不起任何作用的,
个人的力量总是很微小的,欢迎大家来讨论,一起努力成长!!

GitHub源码:https://github.com/mingyang66/spring-parent

到此这篇关于Spring @Order注解的使用小结的文章就介绍到这了,更多相关Spring @Order注解内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • springboot+element-ui实现多文件一次上传功能

    springboot+element-ui实现多文件一次上传功能

    这篇文章主要介绍了springboot+element-ui多文件一次上传功能,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-06-06
  • SpringBoot中9个内置过滤器用法的完整指南

    SpringBoot中9个内置过滤器用法的完整指南

    这篇文章主要为大家详细介绍了SpringBoot中9个内置过滤器用法的相关知识,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一
    2025-08-08
  • 基于java内部类作用的深入分析

    基于java内部类作用的深入分析

    本篇文章介绍了,基于java内部类作用的深入分析。需要的朋友参考下
    2013-05-05
  • springboot使用redis缓存乱码(key或者value乱码)的解决

    springboot使用redis缓存乱码(key或者value乱码)的解决

    在通过springboot缓存数据的时候,发现key是一堆很不友好的东西,本文主要介绍了springboot使用redis缓存乱码(key或者value乱码)的解决,感兴趣的可以了解一下
    2023-11-11
  • Java通俗易懂讲解泛型

    Java通俗易懂讲解泛型

    在正式进入内容之前说明一下:泛型的内容太多,也太复杂。这里因为Java中写数据结构的时候会使用到,所以加上。关于泛型我找了挺多文章,再结合自己的理解,尽可能将其讲清楚。不求会使用泛型,只要求后面数据结构出现泛型的时候能够知道是在干什么即可
    2022-05-05
  • springboot创建监听和处理事件的操作方法

    springboot创建监听和处理事件的操作方法

    这篇文章主要介绍了springboot创建监听和处理事件的操作方法,使用Spring Boot的事件机制来监听和处理事件有多种优势,本文给大家介绍的非常详细,需要的朋友参考下吧
    2024-07-07
  • springboot 启动时初始化数据库的步骤

    springboot 启动时初始化数据库的步骤

    这篇文章主要介绍了springboot 启动时初始化数据库的步骤,帮助大家更好的理解和使用springboot框架,感兴趣的朋友可以了解下
    2021-01-01
  • Java实现整合文件上传到FastDFS的方法详细

    Java实现整合文件上传到FastDFS的方法详细

    FastDFS是一个开源的轻量级分布式文件系统,对文件进行管理,功能包括:文件存储、文件同步、文件上传、文件下载等,解决了大容量存储和负载均衡的问题。本文将提供Java将文件上传至FastDFS的示例代码,需要的参考一下
    2022-02-02
  • Java使用DateTimeFormatter实现格式化时间

    Java使用DateTimeFormatter实现格式化时间

    这篇文章主要介绍了Java使用DateTimeFormatter实现格式化时间,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-01-01
  • IDEA之MyBatisX使用的图文步骤

    IDEA之MyBatisX使用的图文步骤

    本文主要介绍了IDEA之MyBatisX使用,文中通过图文示例介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2025-05-05

最新评论