spring技巧之bean加载顺序控制

  • 前言
  • 误区
  • 疑问
  • 思路
  • 关键代码示例

前言

某些时候,我们想要控制bean的加载顺序,比如某些资源配置类的bean需要在其他的bean之前被加载,以便其他bean在创建的时候可以使用。

举个例子:我们有一个bean,叫商品管理器GoodsManager,它在项目启动时,从数据库加载所有商品,并且定时刷新商品数据,并且为了便于使用,它提供了static类型方法供调用者使用。这种场景下,由于GoodsManager对外提供的是static方法,所以其他类可以直接调用它的方法,如果它不是最先加载的话,当有人请求商品列表时,商品还没有加载完成,那就就会导致问题的出现。为了避免出现这样的问题,我们必须要保证GoodsManager这个bean最先创建。

误区

  • 期望通过实现Orderd或者Order来控制bean加载顺序
    原因:注解@Order或者接口Ordered的作用是定义Spring IOC容器中Bean的执行顺序的优先级,而不是定义Bean的加载顺序,Bean的加载顺序不受@Order或Ordered接口的影响

疑问

spring bean的加载到底有没有顺序呢?有的话是按照什么方式?
其实,要得到答案,无需猜想,我们可以利用spring的扩展点来验证。

public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {/*** Modify the application context's internal bean definition registry after its* standard initialization. All regular bean definitions will have been loaded,* but no beans will have been instantiated yet. This allows for adding further* bean definitions before the next post-processing phase kicks in.* @param registry the bean definition registry used by the application context* @throws org.springframework.beans.BeansException in case of errors*/void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;}

实现了这个接口的bean,会在所有的bean注册完成之后被调用。那么,我们就可以通过BeanDefinitionRegistry输出所有的bean的定义信息。通过测试,发现spring加载bean是按照其注册bean时的顺序来加载的。以全注解方式为例,按照包名->类名方式排序的

思路

  1. 基于@DependsOn注解控制bean加载顺序;控制能力较弱,不作介绍
  2. 通过实现BeanDefinitionRegistryPostProcessor接口,在postProcessBeanDefinitionRegistry方法中通过BeanDefinitionRegistry获取到所有bean的注册信息,将bean保存到LinkedHashMap中,并从BeanDefinitionRegistry中删除,然后将保存的bean定义排序后,重新再注册到BeanDefinitionRegistry中,即可实现bean加载顺序的控制

注意:BeanDefinitionRegistry中最前面的几个spring自身定义的bean以及你定义的用作配置(@Configuration标注的,并且被context用来当做配置)的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));});}
}
public class Run {public static void main(String[] args) {AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();context.register(AppConfig.class);MockServletConfig config = new MockServletConfig(new MockServletContext(AppConfig.class.getResource("/").getFile(),new FileSystemResourceLoader()),"demo");context.setServletConfig(config);context.refresh();//TODO 这里可以写一些校验用的代码context.close();}
}

spring技巧之bean加载顺序控制相关推荐

  1. Spring容器和Bean加载

    Spring容器的IOC和DI概念 IOC(控制反转):对于组件的控制权进行了转移,传统的程序设计是由客户端new出对象,是程序主动创建所依赖的对象.而IOC是专门将对象的创建交给容器处理,组件的控制 ...

  2. Spring-Bean加载顺序控制/循环依赖控制

    Spring-Bean加载顺序控制/循环依赖控制 1 加载顺序 1.1 @Order Bean上使用@Order注解,如@Order(2).数值越小表示优先级越高.默认优先级最低. 可参考Spring ...

  3. Spring 使用注解@DependsOn控制Bean加载顺序

    文章目录 1. 前言 2. 代码实现 1. 前言 默认情况下,Spring加载Bean的顺序是不确定的(或者可以理解为,按编译后的class文件顺序加载).当我们需要控制Bean加载顺序以满足特定的需 ...

  4. spring bean加载过程_Spring源码剖析3:Spring IOC容器的加载过程

    本文转自五月的仓颉 https://www.cnblogs.com/xrq730 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https ...

  5. 【Spring源码分析】Bean加载流程概览

    代码入口 之前写文章都会啰啰嗦嗦一大堆再开始,进入[Spring源码分析]这个板块就直接切入正题了. 很多朋友可能想看Spring源码,但是不知道应当如何入手去看,这个可以理解:Java开发者通常从事 ...

  6. beaninfo详解源码解析 java_【Spring源码分析】Bean加载流程概览

    代码入口 之前写文章都会啰啰嗦嗦一大堆再开始,进入[Spring源码分析]这个板块就直接切入正题了. 很多朋友可能想看Spring源码,但是不知道应当如何入手去看,这个可以理解:Java开发者通常从事 ...

  7. Spring源码分析:Bean加载流程概览及配置文件读取

    很多朋友可能想看Spring源码,但是不知道应当如何入手去看,这个可以理解:Java开发者通常从事的都是Java Web的工作,对于程序员来说,一个Web项目用到Spring,只是配置一下配置文件而已 ...

  8. Spring的bean加载流程

    IOC容器就像是一个工厂,里面有很多流水线生产出一个个产品(bean).bean的加载流程大概分为: 容器启动阶段 bean加载阶段 容器启动阶段: 1.配置元信息 当你生产物品的时候总得知道产品得规 ...

  9. Spring component-scan类扫描加载过程

    2019独角兽企业重金招聘Python工程师标准>>> https://github.com/javahongxi 有朋友最近问到了spring加载类的过程,尤其是基于annotat ...

最新文章

  1. 【linux】ARM开发板上设置RTC时间,断电重启后,设置失效的原因分析
  2. Python基础概念_8_字符串处理
  3. hadoop-hdfs-ha配置-搭建
  4. 论文浅尝 | PairRE: 通过成对的关系向量实现知识图谱嵌入
  5. python访问注册表_python读取注册表中值的方法
  6. iOS 横竖屏切换解决方案
  7. 可变数据(VDP)软件 数码印刷和传统印刷的区别
  8. 世界著名汽车标志欣赏
  9. ERwin Data Modeler数据库建模工具使用纪要
  10. Android 8.1 Launcher3实现动态指针时钟
  11. 解决Android Studio的ADB连接不到手机问题
  12. Windows Cmd控制台程序会被鼠标单击暂停的解决方法
  13. hdu2203java_HDU2203(KMP入门题)
  14. 学生党高性价比蓝牙耳机有哪些?高性价比学生党蓝牙耳机推荐
  15. 关于updated()函数没有执行
  16. MATLAB用梯度法求解目标函数,机械优化设计作业——梯度法求解
  17. Win10下不能识别Android的MTP模式
  18. rmi反序列化导致rce漏洞修复_RMI反序列化漏洞分析
  19. 【JVM调优工具】JVM调优工具
  20. iOS后台运行机制1

热门文章

  1. 安卓adb是什么?ADB命令大全及使用教程
  2. 如何利用js制作选项卡
  3. 搭建FTP服务器后访问时出现“FTP文件夹错误 无法与服务器建立连接”的解决办法
  4. 商品绑定可用的优惠券(多对多的绑定且一张优惠券只能使用于一个商品)
  5. ps中背影制造以及扣图后换背景的注意事项
  6. pyTorch 图像分类模型训练教程
  7. Halcon矩阵(Matrix)算子详解
  8. 小微企业都在用的一体化管理解决方案
  9. H5 查看大图。缩放图片
  10. 70年代时尚偶像Bianca Jagger