如果你脱口而出说添加 @Order 注解或者是实现 Ordered 接口,那么恭喜,你掉坑了。
一 @Order 注解和 Ordered 接口
在 Spring 框架中,@Order
是一个非常实用的元注解,它位于 spring-core
包下,主要用于控制某些特定上下文中组件的执行顺序或排序,但它并不直接控制 Bean 的初始化顺序。
1.1 用途
@Order 注解或者是 Ordered 接口,常见的用途主要是两种:
定义执行顺序:当多个组件(如拦截器、过滤器、监听器等)需要按照特定的顺序执行时,@Order
注解可以用来指定这些组件的执行优先级。数值越小,优先级越高,相应的组件会更早被执行或被放置在集合的前面(@Order
注解接受一个整数值,这个值可以是负数、零或正数。Spring 框架提供了 Ordered.HIGHEST_PRECEDENCE
(默认最低优先级)和 Ordered.LOWEST_PRECEDENCE
(默认最高优先级)常量,分别对应于 Integer.MIN_VALUE和 Integer.MAX_VALUE,可以方便地设定优先级。)。
集合排序:当相同类型的组件被自动装配到一个集合中时,@Order
注解会影响它们在这个集合中的排列顺序。
1.2 使用场景
经典使用场景。
拦截器排序
在 Spring MVC 中,可以使用 @Order
来控制拦截器的执行顺序。
Spring Security Filters(过滤器)
在 Spring Security 中,过滤器链的顺序通过 @Order
来定义,确保正确的安全处理流程。这个在松哥最近的教程中和大家详细介绍过了。
Event Listeners(事件监听器)
当有多个监听同一事件的监听器时,可以通过 @Order
来控制它们的触发顺序。
Bean 的集合注入
当一个 Bean 依赖于一个特定类型的 Bean 集合时,带有 @Order
注解的 Bean 将按照指定顺序被注入。
可以看到,@Order 注解的使用场景中,主要是相同类型的 Bean 存在多个时,这多个 Bean 的执行顺序可以通过 @Order 注解或者实现 Ordered 接口来确定。
但是!!!
@Order 注解不控制初始化和加载:@Order
注解不直接影响 Bean 的创建和初始化过程,这些由 Spring IoC 容器基于依赖关系和配置来决定。Spring IoC 容器根据依赖关系图来决定 Bean 的初始化顺序,而不是依据 @Order
注解。依赖关系决定了哪些 Bean 需要在其他 Bean 初始化之前被创建。
二 如何设置 Bean 的加载顺序?
有两种方式来设置 Bean 的加载顺序。
2.1 @DependsOn
@DependsOn
是 Spring 框架提供的一个注解,用于指示 Spring 容器在初始化一个 Bean 之前,必须先初始化其依赖的其他 Bean。这个注解可以帮助解决 Bean 间的依赖关系,确保依赖的 Bean 已经准备就绪。
@DependsOn
可以放在任何一个 Spring 管理的 Bean 定义上,包括但不限于配置类、服务类、数据访问对象等。其语法如下:
1 2 3 4
| @DependsOn({"beanName1", "beanName2", ...}) public class MyBean { }
|
在这个例子中,MyBean
类声明了它依赖于名为 beanName1
和 beanName2
的 Bean。这意味着,当 Spring 容器创建 MyBean
的实例时,它会首先确保 beanName1
和 beanName2
已经被正确初始化。
相关的源码在 AbstractBeanFactory#doGetBean 方法中:
在创建的 Bean 的时候,先检查该 Bean 是否依赖了其他 Bean,如果依赖了,则先把其他 Bean 创建出来,然后再继续创建当前 Bean,这样就确保了 Bean 的加载顺序。
如果小伙伴们对这块的完整流程感兴趣,可以看松哥录制的 Spring源码分析。
2.2 BeanFactoryPostProcessor
第二种方式就是利用 BeanFactoryPostProcessor,BeanFactoryPostProcessor 的执行时机比较早,从下面这张流程图中可以看到,BeanFactoryPostProcessor 在正常的 Bean 初始化之前就执行了。
那么对于想要提前初始化的 Bean,我们可以在 BeanFactoryPostProcessor 中手动调用,类似下面这样:
1 2 3 4 5 6 7 8
| @Component public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor { @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { beanFactory.getBean("serviceB"); } }
|
三 小结
多个相同类型的 Bean 该如何确保其执行顺序?这个靠 @Order 注解或者 Ordered 接口来解决。但是这两者并不能解决 Bean 的加载顺序。Bean 的加载顺序有两种方式可以调整:
- 通过 @DependsOn 注解加载。
- 手动在 BeanFactoryPostProcessor#postProcessBeanFactory 方法中提前调用 getBean 方法去初始化 Bean。
如果小伙伴们想要彻底掌握 Spring 源码,那么不妨看看松哥录制的 Spring 源码视频教程。
这套视频教程基于目前最新的 Spring6 录制,一共有 204 集约 40 个小时,从 Spring 基本用法讲起,一直讲到源码分析。
以下是完整视频目录:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210
| ├── 01.基础用法 │ ├── 01.IoC基础 │ │ ├── 01.Spring框架介绍-核心容器.mp4 │ │ ├── 02.Spring框架介绍-数据访问和通信.mp4 │ │ ├── 03.Spring框架介绍-Web模块.mp4 │ │ ├── 04.Spring框架介绍-AOP和测试.mp4 │ │ ├── 05.什么是IoC.mp4 │ │ ├── 06.自定义一个简单的IoC.mp4 │ │ ├── 07.向Spring容器注册Bean.mp4 │ │ ├── 08.从Spring容器获取Bean.mp4 │ │ ├── 09.id属性和name属性.mp4 │ │ ├── 10.基本属性注入.mp4 │ │ ├── 11.复杂属性注入.mp4 │ │ ├── 12.构造器注入.mp4 │ │ ├── 13.p名称空间注入.mp4 │ │ ├── 14.属性自动注入.mp4 │ │ ├── 15.配置文件加载.mp4 │ │ ├── 16.Java代码配置IoC.mp4 │ │ ├── 17.BeanName自动生成原理.mp4 │ │ ├── 18.id和name属性处理原理.mp4 │ │ ├── 19.Bean 的作用域.mp4 │ │ ├── 20.singleton 和 prototype 的区别.mp4 │ │ ├── 21.条件注解详解.mp4 │ │ ├── 22.多环境切换.mp4 │ │ ├── 23.Profile原理分析.mp4 │ │ ├── 24.自定义Profile.mp4 │ │ ├── 25.Bean的依赖关系.mp4 │ │ ├── 26.FactoryBean用法.mp4 │ │ ├── 27.抽取Bean的公共属性.mp4 │ │ ├── 28.父子容器问题.mp4 │ │ ├── 29.@Configuration注解的作用.mp4 │ │ ├── 30.Bean自动扫描.mp4 │ │ └── 31.属性值注入.mp4 │ ├── 02.AOP基础 │ │ ├── 01.静态代理.mp4 │ │ ├── 02.编译时增强和运行时增强.mp4 │ │ ├── 03.编译时增强.mp4 │ │ ├── 04.运行时增强-JDK.mp4 │ │ ├── 05.运行时增强-CGLIB.mp4 │ │ ├── 06.什么是Spring AOP.mp4 │ │ ├── 07.SpringAOP和AspectJAOP.mp4 │ │ ├── 08.Spring AOP核心概念.mp4 │ │ ├── 09.Spring AOP入门用法.mp4 │ │ ├── 10.五种通知.mp4 │ │ ├── 11.Java代码配置AOP.mp4 │ │ ├── 12.SpringAOP底层代理.mp4 │ │ └── 13.通过注解定义AOP拦截规则.mp4 │ ├── 03.JdbcTemplate │ │ ├── 01.JdbcTemplate基本操作.mp4 │ │ ├── 02.增删改查.mp4 │ │ └── 03.通过变量名传递参数.mp4 │ └── 04.事务 │ ├── 01.事务简介.mp4 │ ├── 02.编程式事务.mp4 │ ├── 03.XML配置声明式事务.mp4 │ ├── 04.Java配置声明式事务.mp4 │ ├── 05.Java+XML配置声明式事务.mp4 │ ├── 06.自定义事务注解.mp4 │ ├── 07.事务属性-隔离级别.mp4 │ ├── 08.事务属性-传播性.mp4 │ ├── 09.事务属性-传播性2.mp4 │ ├── 10.事务属性-回滚规则.mp4 │ ├── 11.事务属性-只读事务.mp4 │ ├── 12.事务属性-超时时间.mp4 │ └── 13.事务失效的场景.mp4 └── 02.进阶用法 ├── 001.通过name属性定义别名.mp4 ├── 002.通过alias标签定义别名.mp4 ├── 003.别名处理接口AliasRegistry.mp4 ├── 004.aliasMap变量.mp4 ├── 005.allowAliasOverriding.mp4 ├── 006.hasAlias.mp4 ├── 007.removeAlias和isAlias.mp4 ├── 008.getAliases.mp4 ├── 009.checkForAliasCircle.mp4 ├── 010.canonicalName.mp4 ├── 011.registerAlias.mp4 ├── 012.resolveAliases.mp4 ├── 013.name属性解析原理.mp4 ├── 014.alias标签解析.mp4 ├── 015.DefaultListableBeanFactory.mp4 ├── 016.StaticListableBeanFactory.mp4 ├── 017.SimpleJndiBeanFactory.mp4 ├── 018.ApplicationContext.mp4 ├── 019.FactoryBean&SmartFactoryBean.mp4 ├── 020.FactoryBean处理思路.mp4 ├── 021.Bean提前加载流程分析.mp4 ├── 022.isFactoryBean方法分析.mp4 ├── 023.getBean中&的处理逻辑.mp4 ├── 024.BeanDefinition简介.mp4 ├── 025.RootBeanDefinition.mp4 ├── 026.ChildBeanDefinition.mp4 ├── 027.GenericBeanDefinition.mp4 ├── 028.AnnotatedGenericBeanDefinition.mp4 ├── 029.ScannedGenericBeanDefinition.mp4 ├── 030.ConfigurationClassBeanDefinition.mp4 ├── 031.CreateFromClassBeanDefinition.mp4 ├── 032.ClassDerivedBeanDefinition.mp4 ├── 033.加载XML配置的两种方式.mp4 ├── 034.BeanDefinitionReader.mp4 ├── 035.PropertiesBeanDefinitionReader.mp4 ├── 036.XmlBeanDefinitionReader.mp4 ├── 037.配置类解析为BeanDefinition.mp4 ├── 038.@Scope注解高级用法.mp4 ├── 039.编程式AOP.mp4 ├── 040.编程式AOP之target方法分析.mp4 ├── 041.TargetSource体系结构.mp4 ├── 042.SimpleBeanTargetSource.mp4 ├── 043.自定义TargetSource.mp4 ├── 044.引介增强.mp4 ├── 045.启动类上的@Scope注解代理原理.mp4 ├── 046.常规类上的@Scope注解.mp4 ├── 047.Java配置中的@Scope代理.mp4 ├── 048.导入配置类上的@Scope注解.mp4 ├── 049.@Configuration注解存在的意义是什么.mp4 ├── 050.@Configuration-Vs-@Component.mp4 ├── 051.@Configuration原理分析.mp4 ├── 052.@Configuration的两种模式Full和Lite.mp4 ├── 053.详细演示Full和Lite模式.mp4 ├── 054.Full模式和Lite模式特点总结.mp4 ├── 055.@Configuration注解解析源码分析.mp4 ├── 056.@Configuration注解解析源码分析-2.mp4 ├── 057.条件注解高级用法.mp4 ├── 058.条件注解高级用法补充.mp4 ├── 059.条件注解原理分析.mp4 ├── 060.beanName自动生成场景.mp4 ├── 061.beanName生成器分析.mp4 ├── 062.AnnotationBeanNameGenerator.mp4 ├── 063.BeanFactoryPostProcessor和BeanPostProcessor.mp4 ├── 064.BeanFactoryPostProcessor案例.mp4 ├── 065.BeanFactoryPostProcessor典型应用场景.mp4 ├── 066.Properties加载原理分析.mp4 ├── 067.BeanDefinitionRegistryPostProcessor.mp4 ├── 068.BeanFactoryPostProcessor作用时机分析.mp4 ├── 069.BeanPostProcessor接口分析.mp4 ├── 070.BeanPostProcessor实践.mp4 ├── 071.BeanPostProcessor实现AOP.mp4 ├── 072.MergedBeanDefinitionPostProcessor.mp4 ├── 073.BeanPostProcessor原理分析.mp4 ├── 074.合并BeanDefinition原理分析.mp4 ├── 075.合并BeanDefinition源码分析.mp4 ├── 076.父子容器原理分析.mp4 ├── 077.事件基本用法.mp4 ├── 078.事件是阻塞还是非阻塞.mp4 ├── 079.手动注册事件监听器.mp4 ├── 080.事件三大组件.mp4 ├── 081.Java类定义的事件监听器.mp4 ├── 082.Java类定义的事件监听器-补充.mp4 ├── 083.通过Java注解定义的事件监听器.mp4 ├── 084.ApplicationEventPublisher.mp4 ├── 085.ApplicationEventMulticaster.mp4 ├── 086.Spring事件补充.mp4 ├── 087.Java国际化.mp4 ├── 088.Spring国际化.mp4 ├── 089.MessageSource层级关系.mp4 ├── 090.getMessage方法原理分析.mp4 ├── 091.解析无参的key.mp4 ├── 092.解析有参key.mp4 ├── 093.Lifecycle基本用法.mp4 ├── 094.SmartLifecycle基本用法.mp4 ├── 095.Lifecycle中start方法执行原理.mp4 ├── 096.Lifecycle中stop方法执行原理.mp4 ├── 097.编程式AOP.mp4 ├── 098.动态代理对象创建流程.mp4 ├── 099.JDK和CGLIB动态代理分析.mp4 ├── 100.Advisor详解.mp4 ├── 101.自定义切面对象Advisor.mp4 ├── 102.重载方法拦截规则.mp4 ├── 103.拦截所有方法.mp4 ├── 104.默认配置的Pointcut对象.mp4 ├── 105.Pointcut经典写法.mp4 ├── 106.Pointcut分类.mp4 ├── 107.StaticMethodMatcherPointcut.mp4 ├── 108.StaticMethodMatcherPointcut-2.mp4 ├── 109.DynamicMethodMatcherPointcut.mp4 ├── 110.AnnotationMatchingPointcut.mp4 ├── 111.ControlFlowPointcut.mp4 ├── 112.ComposablePointcut.mp4 ├── 113.提前返回Bean的机会.mp4 ├── 114.提前AOP的机会.mp4 ├── 115.理解两个关键变量.mp4 ├── 116.特殊的beanName.mp4 ├── 117.自定义TargetSourceCreator.mp4 ├── 118.提前AOP实践.mp4 ├── 119.AOP创建的契机.mp4 ├── 120.AOP对象生成整体思路.mp4 ├── 121.AOP对象创建详细流程分析.mp4 ├── 122.Bean的获取思路.mp4 ├── 123.getBean方法整体思路分析.mp4 ├── 124.从三级缓存中加载Bean.mp4 ├── 125.从parent中加载Bean.mp4 ├── 126.检查@DependOn注解.mp4 ├── 127.不同Scope获取Bean实例.mp4 ├── 128.生成的Bean类型检查.mp4 ├── 129.createBean方法分析.mp4 ├── 130.doCreateBean-1.mp4 ├── 131.循环依赖-二级缓存.mp4 ├── 132.循环依赖-三级缓存.mp4 ├── 133.循环依赖-三级缓存-补充.mp4 ├── 134.循环依赖源码分析-1.mp4 ├── 135.循环依赖源码分析-2.mp4 ├── 136.循环依赖源码分析-3.mp4 ├── 137.Bean的生命周期-1.mp4 ├── 138.Bean的生命周期-2.mp4 ├── 139.Bean的生命周期-3.mp4 ├── 140.Bean的实例化-1.mp4 ├── 141.Bean的实例化-2.mp4 ├── 142.Bean的属性注入.mp4 ├── 143.getBean方法.mp4 └── 144.小结.mp4
|
好啦,5 折 ¥199 抄底就在今天啦!扫码加微信,备注 spring,发红包 199 上车吧~