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

重写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.xdnf.cn/news/18898.html

相关文章:

  • 6年前抄写的某品牌集成灶-蒸汽炉
  • Linux笔记10——shell编程基础-4
  • GraphRAG——v0.3.6版本使用详细教程、GraphRAG数据写入Neo4j图数据库、GraphRAG与Dify集成
  • 图像增强和评价
  • 脑电分析——学习笔记
  • 【系统架构设计(一)】系统工程与信息系统基础上:系统工程基础概念
  • 【Ubuntu系统实战】一站式部署与管理MySQL、MongoDB、Redis三大数据库
  • 负载均衡之平滑加权轮询(Smooth Weighted Round Robin)详解与实现
  • MIME类型与文件上传漏洞 - 网络安全视角
  • AI解决生活小事系列——用AI给我的电脑做一次“深度体检”
  • Windows下的异步IO通知模型
  • 一款基于 .NET 开源、功能强大的 Windows 搜索工具
  • C# .NET支持多线程并发的压缩组件
  • 2026 济南玉米深加工展:探索淀粉技术突破与可持续发展解决方案
  • 你真的了解操作系统吗?
  • Feign 调用为服务报 `HardCodedTarget(type=xxxClient, name=xxxfile, url=http://file)`异常
  • 大模型入门实战 | 基于 YOLO 数据集微调 Qwen2.5-VL-3B-Instruct 的目标检测任务
  • YggJS RButton 按钮组件 v1.0.0 使用教程
  • 【vue eslint】报错:Component name “xxxx“ should always be multi-word
  • 云上“安全管家”|移动云以云安全中心为企业数字化升级保驾护航
  • 科技信息差(8.26)
  • 【软考论文】论静态测试方法及其应用
  • PortSwigger靶场之Blind SQL injection with out-of-band interaction通关秘籍
  • 软考-系统架构设计师 计算机系统基础知识详细讲解
  • 【46页PPT】AI智能中台用ABC+IOT重新定义制造(附下载方式)
  • 相机Camera日志实例分析之十五:相机Camx【照片后置HDR拍照】单帧流程日志详解
  • 2-5 倍性能提升,30% 成本降低,阿里云 SelectDB 存算分离架构助力波司登集团实现降本增效
  • 支持向量机核心知识总结
  • Java大厂面试实战:从Spring Boot到微服务架构的深度剖析
  • 宠物智能,是「养宠自由」还是「焦虑税」?