当前位置: 首页 > news >正文

重写BeanFactory初始化方法并行加载Bean

文章目录

      • 背景
      • 实现说明
      • 使用方法
      • 注意事项

背景

spring项目启动过程中,如何通过重写BeanFactory初始化方法,对初始化耗时长的bean进行并行处理
在Spring中,Bean的初始化默认是单线程的,这主要是为了保证Bean之间的依赖关系正确处理。但对于一些初始化耗时长且依赖关系简单的Bean,我们可以通过扩展Spring的BeanFactory来实现并行初始化,通过自定义BeanFactory和扩展ApplicationContext来实现对特定Bean的并行处理,从而提高启动速度。

实现说明

这个方案的核心思路是通过自定义BeanFactory和ApplicationContext,对特定Bean进行并行初始化,主要包含以下几个部分:

  1. 标记机制:通过ParallelBeanMarker接口标记需要并行初始化的Bean,实现该接口的Bean会被自动识别
  2. 并行Bean检测ParallelBeanDetector实现了BeanFactoryPostProcessor,在BeanFactory初始化过程中检测所有标记为并行处理的Bean
  3. 自定义BeanFactoryParallelProcessingBeanFactory重写了createBean方法,对标记的Bean使用线程池进行并行初始化
  4. 扩展ApplicationContextParallelProcessingApplicationContext创建并使用自定义的BeanFactory,实现并行处理能力
/*** 标记接口,实现此接口的Bean将被并行初始化*/
public interface ParallelBeanMarker {
}
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.stereotype.Component;
import java.util.HashSet;
import java.util.Set;/*** 检测需要并行初始化的Bean*/
@Component
public class ParallelBeanDetector implements BeanFactoryPostProcessor {private Set<String> parallelBeanNames = new HashSet<>();@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {// 查找所有实现了ParallelBeanMarker接口的BeanString[] beanNames = beanFactory.getBeanDefinitionNames();for (String beanName : beanNames) {try {Class<?> beanType = beanFactory.getType(beanName);if (beanType != null && ParallelBeanMarker.class.isAssignableFrom(beanType)) {parallelBeanNames.add(beanName);System.out.println("Bean " + beanName + " 标记为并行初始化");}} catch (Throwable e) {// 忽略类型获取失败的情况}}}public Set<String> getParallelBeanNames() {return parallelBeanNames;}
}
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.AbstractBeanFactory;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.stereotype.Component;import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.*;
import java.util.stream.Collectors;/*** 支持并行初始化的BeanFactory*/
public class ParallelProcessingBeanFactory extends DefaultListableBeanFactory {// 线程池用于并行初始化Beanprivate final ExecutorService executorService;// 需要并行处理的Bean名称集合private final Set<String> parallelBeanNames;public ParallelProcessingBeanFactory(ExecutorService executorService, Set<String> parallelBeanNames) {this.executorService = executorService;this.parallelBeanNames = parallelBeanNames;}@Overrideprotected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException {// 检查当前Bean是否需要并行初始化if (parallelBeanNames.contains(beanName) && !isBeanCurrentlyInCreation(beanName)) {try {// 提交到线程池并行处理Future<Object> future = executorService.submit(() -> super.createBean(beanName, mbd, args));return future.get();} catch (InterruptedException | ExecutionException e) {throw new BeanCreationException(beanName, "Error creating bean in parallel", e);}}// 非并行处理的Bean使用默认方式return super.createBean(beanName, mbd, args);}
}
import org.springframework.context.support.AbstractRefreshableApplicationContext;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.ResourcePatternResolver;import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;/*** 扩展ApplicationContext以支持Bean的并行初始化*/
public class ParallelProcessingApplicationContext extends AbstractRefreshableApplicationContext {// 需要并行处理的Bean名称private final Set<String> parallelBeanNames;// 线程池大小private final int threadPoolSize;public ParallelProcessingApplicationContext(Set<String> parallelBeanNames, int threadPoolSize) {this.parallelBeanNames = parallelBeanNames;this.threadPoolSize = threadPoolSize;}@Overrideprotected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) {// 这里可以根据需要加载Bean定义// 实际应用中通常会使用XmlBeanDefinitionReader或ComponentScanBeanDefinitionParser}@Overrideprotected DefaultListableBeanFactory createBeanFactory() {// 创建线程池ExecutorService executorService = Executors.newFixedThreadPool(threadPoolSize);// 返回自定义的支持并行处理的BeanFactoryreturn new ParallelProcessingBeanFactory(executorService, parallelBeanNames);}
}
import org.springframework.context.ApplicationContext;
import java.util.Set;/*** 应用初始化器*/
public class ApplicationInitializer {public ApplicationContext initialize() {// 获取需要并行处理的Bean名称ParallelBeanDetector detector = new ParallelBeanDetector();// 实际应用中,这里应该是Spring正常的初始化流程// 简化示例:创建自定义ApplicationContext并指定并行处理的BeanSet<String> parallelBeanNames = detector.getParallelBeanNames();// 创建应用上下文,设置线程池大小为CPU核心数int threadPoolSize = Runtime.getRuntime().availableProcessors();return new ParallelProcessingApplicationContext(parallelBeanNames, threadPoolSize);}
}

使用方法

  1. 让耗时长的Bean实现ParallelBeanMarker接口
@Component
public class TimeConsumingBean implements ParallelBeanMarker {// 耗时的初始化逻辑
}
  1. 在应用启动时使用自定义的ParallelProcessingApplicationContext
  2. 根据系统情况调整线程池大小(通常设置为CPU核心数)

注意事项

  1. 依赖关系:并行初始化的Bean之间应避免相互依赖,否则可能导致初始化顺序问题
  2. 线程安全:确保并行初始化的Bean是线程安全的,其初始化逻辑不会产生竞态条件
  3. 事务管理:对于需要事务管理的Bean,并行初始化可能会导致事务边界问题
  4. 测试:并行处理可能引入复杂的并发问题,需要充分测试
  5. Spring版本兼容性:不同版本的Spring内部实现可能不同,需要根据实际使用的版本调整代码

这种方式可以显著提高包含多个耗时初始化Bean的Spring应用的启动速度,特别是当这些Bean之间没有复杂依赖关系时效果更佳。

http://www.dtcms.com/a/351283.html

相关文章:

  • 信息网络安全视角下的在线问卷调查系统设计与实践(国内问卷调查)
  • 记一个Mudbus TCP 帮助类
  • Linux 内核 Workqueue 原理与实现及其在 KFD SVM功能的应用
  • LeetCode - 844. 比较含退格的字符串
  • LeetCode 438. 找到字符串中所有的字母异位词
  • 微算法科技(NASDAQ:MLGO)通过修改 Grover 算法在可重构硬件上实现动态多模式搜索
  • LeetCode - 946. 验证栈序列
  • 智慧园区:从技术赋能到价值重构,解锁园区运营新范式
  • 透视光合组织大会:算力生态重构金融AI落地新实践
  • 亚马逊类目合规风暴:高压清洗机品类整顿背后的运营重构与风险防御
  • 便携屏选购指南:常见作用、移动性优势及多场景应用详解
  • 前端性能优化新维度:渲染流水线深度解析
  • 【前端开发实战】从零开始开发Chrome浏览器扩展 - 快乐传播者项目完整教程
  • DeepSeek分析
  • spring如何通过实现BeanPostProcessor接口计算并打印每一个bean的加载耗时
  • 【数据结构】树和二叉树——二叉树
  • pytorch_grad_cam 库学习笔记—— Ablation-CAM 算法的基类 AblationCAM 和 AblationLayer
  • OneCode RAD:揭秘前端开发的配置化魔法
  • 【RAGFlow代码详解-14】知识图谱处理
  • Linux之SELinux 概述、SSH 密钥登录、服务器初始化
  • IUV5G专网排障(下)
  • 开源大模型本地部署
  • [Mysql数据库] 知识点总结3
  • 基于Android的电影院订票选座系统、基于Android的电影院管理系统app#基于Android的电影在线订票系统
  • 玩转QEMU硬件模拟器 - vexpress-a9开发板模拟开发
  • 深入浅出理解支持向量机:从原理到应用,解锁分类算法的核心密码
  • 宝石组合(蓝桥杯)
  • UX 设计入门终章:让洞察落地!用用户流程图、IA 和旅程图,设计用户与产品的互动故事
  • 介绍一下 bev fusion 网络结构
  • 微服务-27.配置管理-什么是配置管理