Sprin中Bean的顺序
一、Bean的加载顺序
spring容器载入bean顺序是不确定的,在一定的范围内bean的加载顺序可以控制。
spring容器载入bean虽然顺序不确定,但遵循一定的规则:
1、按照字母顺序加载(同一文件夹下按照字母数序;不同文件夹下,先按照文件夹命名的字母顺序加载)
2、不同的bean声明方式不同的加载时机,顺序总结:@ComponentScan > @Import > @Bean这里的ComponentScan指@ComponentScan及其子注解,Bean指的是@configuration + @bean同时需要注意的是:(1)Component及其子注解申明的bean是按照字母顺序加载的(2)@configuration + @bean是按照定义的顺序依次加载的(3)@import的顺序,就是bean的加载顺序(4)在xml中,通过<bean id="">方式声明的bean也是按照代码的编写顺序依次加载的(5)同一类中加载顺序:Constructor >> @Autowired >> @PostConstruct >> @Bean(6)同一类中加载顺序:静态变量 / 静态代码块 >> 构造代码块 >> 构造方法(需要特别注意的是静态代码块的执行并不是优先所有的bean加载,只是在同一个类中,静态代码块优先加载)
特别情况下,如果想手动控制部分bean的加载顺序,有如下方法:
方法1:构造方法依赖 (推荐)
@Component
public class CDemo1 {private String name = "cdemo 1";public CDemo1(CDemo2 cDemo2) {System.out.println(name);}
}
@Component
public class CDemo2 {private String name = "cdemo 2";public CDemo2() {System.out.println(name);}
}
CDemo2在CDemo1之前被初始化。
限制
要有注入关系,如:CDemo2通过构造方法注入到CDemo1中,若需要指定两个没有注入关系的bean之间优先级,则不太合适(比如我希望某个bean在所有其他的Bean初始化之前执行)
循环依赖问题,如过上面的CDemo2的构造方法有一个CDemo1参数,那么循环依赖产生,应用无法启动
另外一个需要注意的点是,在构造方法中,不应有复杂耗时的逻辑,会拖慢应用的启动时间
方法2:参数注入
在@Bean标注的方法上,如果你传入了参数,springboot会自动会为这个参数在spring上下文里寻找这个类型的引用。并先初始化这个类的实例。
利用此特性,我们也可以控制bean的加载顺序。
以上结果,beanB先于beanA被初始化加载。
需要注意的是,springboot会按类型去寻找。如果这个类型有多个实例被注册到spring上下文,那你就需要加上@Qualifier(“Bean的名称”)来指定
方法3:@DependsOn(“xxx”)
没有直接的依赖关系的,可以通过@DependsOn注解,我们可以在bean A上使用@DependsOn注解 ,告诉容器bean B应该优先被加载初始化。
不推荐的原因:这种方法是通过bean的名字(字符串)来控制顺序的,如果改了bean的类名,很可能就会忘记来改所有用到它的注解,那就问题大了。
当一个bean需要在另一个bean实例化之后再实例化时,可使用这个注解。
@Component("dependson02")
public class Dependson02 {Dependson02(){System.out.println(" dependson02 Success ");}
}
@Component
@DependsOn("dependson02")
public class Dependson01 {Dependson01(){System.out.println("Dependson01 success");}
}
执行结果:
结果:dependson02 Success
Dependson01 success
方法4:BeanDefinitionRegistryPostProcessor接口
通过实现BeanDefinitionRegistryPostProcessor接口,在postProcessBeanDefinitionRegistry方法中通过BeanDefinitionRegistry获取到所有bean的注册信息,将bean保存到LinkedHashMap中,并从BeanDefinitionRegistry中删除,然后将保存的bean定义排序后,重新再注册到BeanDefinitionRegistry中,即可实现bean加载顺序的控制。
/***配置类*/
@Configuration
@ComponentScan(basePackages = "demo")
public class AppConfig extends WebMvcConfigurationSupport {/*** 注册用于控制bean加载顺序的处理器* @return*/@Beanpublic static DemoProcessor demoProcessor() {return new DemoProcessor();}
}/****/
public class DemoProcessor implements BeanDefinitionRegistryPostProcessor{@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {}@Overridepublic void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {String[] beanDefinitionNames = registry.getBeanDefinitionNames();int index = 0;//保留前n个关键bean的顺序for(;index<beanDefinitionNames.length;index++) {if(AppConfig.class.getName().equals(registry.getBeanDefinition(beanDefinitionNames[index]).getBeanClassName())) {break;}}Map<String, BeanDefinition> beans = new LinkedHashMap<>(beanDefinitionNames.length-index);for(;index<beanDefinitionNames.length;index++) {BeanDefinition beanDefinition = registry.getBeanDefinition(beanDefinitionNames[index]);beans.put(beanDefinitionNames[index], beanDefinition);registry.removeBeanDefinition(beanDefinitionNames[index]);}//TODO ...排序逻辑,注意beans中可能还包含有其他spring自身定义的beanList<String> orderdBeanNames = new ArrayList<>();//将排好序的bean再次注册到容器中orderdBeanNames.forEach(beanName->{registry.registerBeanDefinition(beanName, beans.get(beanName));});}
}
注意:
执行顺序:Constructor > @Autowired > @PostConstruct
所以正常情况下,所有的bean都已经执行了构造器Constructor,也就是bean都已经存在容器中了。
也就是正常情况下,都是可以正常执行了。
Autowired为null的情况如下:
(1)该类没有托管给spring 管理一般在类的上面添加@Component 就可以了
(2)不能new出来的实例,例如:A a = new A();//new的对象不会交给Spring容器管理, 所以是不行的特殊情况:@Configuration + @Bean 这种方式是可以的
二、Bean的执行顺序
注解@Order或者接口Ordered的作用是定义Spring IOC容器中Bean的执行顺序的优先级,而不是定义Bean的加载顺序,Bean的加载顺序不受@Order或Ordered接口的影响。
特别介绍
@PropertySource:用于注解类,告诉当前类使用什么配置文件,配置文件必须是.property或者.xml类型。
@PropertySource(value = {"classpath:config/user1.properties","classpath:config/user2.properties"})
@ImportResource:通过配置文件注入bean,用于注解主配置类,导入一个或多个定义bean的配置文件,配置文件必须是.xml类型。
@ImportResource(value = {"classpath:/beans.xml"})
@SpringBootApplication(scanBasePackages = {"team.seagull.client"})
public class DeployApplication {public static void main(String[] args) {SpringApplication.run(DeployApplication.class, args);}
}
Sprin中Bean的顺序相关推荐
- spring中bean初始化顺序
spring bean 初始化的流程如下: 初始化顺序演示程序 pom文件 <project xmlns="http://maven.apache.org/POM/4.0.0" ...
- 如何正确控制springboot中bean的加载顺序总结
1.为什么需要控制加载顺序 springboot遵从约定大于配置的原则,极大程度的解决了配置繁琐的问题.在此基础上,又提供了spi机制,用spring.factories可以完成一个小组件的自动装配功 ...
- java 中 bean 的生命周期
java 中 bean 的生命周期 本篇中会对涉及到的知识点皆做出描述: 首先,我们先了解先虚拟机的类加载机制: 虚拟机把描述类的数据从Class 文件中加载到内存,并对数据进行校验.转换解析和初始化 ...
- Spring解析,加载及实例化Bean的顺序(零配置)
点击上方蓝色"方志朋",选择"设为星标"回复"666"获取独家整理的学习资料! 作者:jb_hz blog.csdn.net/qq_2752 ...
- Spring Boot 学习系列(09)—自定义Bean的顺序加载
此文已由作者易国强授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. Bean 的顺序加载 有些场景中,我们希望编写的Bean能够按照指定的顺序进行加载.比如,有UserServ ...
- Spring 中 Bean 的生命周期
本文作者: 伯乐在线 - yemengying 智商捉鸡?,实在没办法一下子理解Spring IoC和AOP的实现原理,看的闹心也不太懂,所以...决定拆成小的不能在小的一个个问题,一点点啃.今天先来 ...
- 厉害了,Spring中bean的12种定义方法!
前言 在庞大的java体系中,spring有着举足轻重的地位,它给每位开发者带来了极大的便利和惊喜.我们都知道spring是创建和管理bean的工厂,它提供了多种定义bean的方式,能够满足我们日常工 ...
- 如果你每次面试前都要去背一篇Spring中Bean的生命周期,请看完这篇文章
前言 当你准备去复习Spring中Bean的生命周期的时候,这个时候你开始上网找资料,很大概率会看到下面这张图: 先不论这张图上是否全面,但是就说这张图吧,你是不是背了又忘,忘了又背? 究其原因在于, ...
- spring bean生命周期_Spring中bean的生命周期和扩展点有哪些?
前言 今天和大家分享一下Spring中Bean的生命周期的一些知识.先来说一下什么是生命周期吧,生命周期从其语义上理解就是一个对象从产生到销毁的整个过程,之所以把这个过程称为生命周期是因为其就像一个生 ...
最新文章
- 【 MATLAB 】序列的奇偶分解的 MATLAB 函数编写实践
- terminal怎么运行c语言文件,在mac电脑的terminal里该如何运行c语言
- Web自适应布局你需要知道的所有事儿
- 在微软工作一年,我学会了什么
- ZGrapher 画函数曲线图的工具
- thinking in java(第七章)
- 高性能MySQL(第2版)中文版pdf
- leetcode不同路径-结题( C++、Python、解析式)
- python脚本读书心得_《利用Python进行数据分析》读书笔记(一)Python Basic
- WebView load**方法 加载资源【总结】
- 推荐5款优质的黑科技软件,好不好用你来判断
- Java中将将JPG图片转GIF动画和将GIF转JPG图片
- html5饼图的制作方法,excel2010复合饼图制作方法
- 搭建本地以图搜图服务
- 我们仍处于本轮牛市之中
- 大型游戏行业网络技术解决方案
- 对角矩阵的性质(diagonal matrix)
- 4月3日工作总结及次日计划
- CAD-VB多段线、波浪线、射线、构造线
- 2023最新短视频解析接口
热门文章
- CMIIT ID是什么意思
- opencv usb镜头帧率低 图像卡顿
- 有小孩的30多岁的程序员,过完年是继续在深圳还是回老家省会城市?
- 人工智能 人工智能一种_人工超级智能的最疯狂后果
- 一个爬虫代码价值 7000 万!
- Ubuntu卡在开机[failed]Started GNOME Display Manager 出现failed to start see systemctl status gdm.service
- 元宇宙游戏:新瓶换新酒
- 百度地图怎么添加公司地址标注
- SAP MRP元素代码、描述、缩写及元素说明(中文)
- 计算机仿真还给稿费,国内期刊不需要审稿费和版面费汇总