spring的bean加载

2024-06-24 08:18
文章标签 java 加载 spring bean

本文主要是介绍spring的bean加载,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

我们经常使用Spring,并且也都了解其大概原理。我想我们一定会对Spring源码的解读有迫切的渴望。
我也如此。所以,我打算阅读一下Spring的源码。再此之前,我也为此准备了很多。包括,去复习熟练java反射,理解常用的设计模式。当然,这些复习笔记也会在今后的复习中顺便记录在我的csdn博客。(当然,可能写的不好,也可能理解不正确(可以一起交流嘛)。但是乐于分享总归是好的。)

首先看下spring的各个组件。


可以看到,在Core Container(核心容器)中包含有Core、Beans、Context和Spring Expression Language.Core和Beans模块是Spring框架的基础部分,提供IoC控制反转和依赖注入的特性。
Core模块主要包含着Spring框架基本的核心工具类,供其它组件使用。
Beans模块是所有应用都要用到的,它包含访问配置文件、创建和管理bean以及ioc、依赖注入。
Context模块构建于Core和Beans之上。是spring的上下文环境,为Spring核心提供了大量的扩展,天津挨了对国际化、事件传播、资源加载等支持。ApplicationContext接口是Context模块的关键。
Spring Expression Language为Spring提供了一个强大的表达式语言用于在运行时查询草操纵对象 。

现在我们已经了解了Spring的基础组件,我们现在就在代码中跟踪一下Spring Bean的创建和获取过程。
beans.xml
<?xml version="1.0" encoding="UTF-8"?>  
<beans xmlns="http://www.springframework.org/schema/beans"  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">  <bean id="hello" class="bean.HelloSpring" lazy-init="false"></bean>  </beans>  

HelloSpring.java
package bean;  /** * Created by yuyufeng on 2016/11/17. */  
public class HelloSpring {  private String name;  public HelloSpring() {  System.out.println("##HelloSpring.HelloSpring初始化……………………………………");  }  public HelloSpring(String name) {  this.name = name;  }  public void sayHello(String something){  System.out.println("hello"+something);  }  public String getName() {  return name;  }  public void setName(String name) {  this.name = name;  }  @Override  public String toString() {  return "HelloSpring{" +  "name='" + name + '\'' +  '}';  }  
}  

BeanFactoryTest.java
package spring.ioc;  import bean.HelloSpring;  
import org.springframework.beans.factory.BeanFactory;  
import org.springframework.beans.factory.xml.XmlBeanFactory;  
import org.springframework.core.io.ClassPathResource;  
import org.springframework.core.io.Resource;  /** * Created by yuyufeng on 2016/11/18. * Spring中Bean的加载过程 */  
public class BeanFactoryTest {  public static void main(String[] args) {  //spring如何初始化有两种方式 beanFactory applicationContext  Resource resource = new ClassPathResource("spring/ioc/beans.xml");  BeanFactory beanFactory = new XmlBeanFactory(resource);  HelloSpring helloSpring = (HelloSpring) beanFactory.getBean("hello");  helloSpring.sayHello("张三");  }  
}  

先从表面上可以看到 bean的加载可大致可以分为:从xml读取bean的信息加载到Spring容器中,通过xml配置的id从Spring容器反射得到这个类的实例对象。
现在,我们进行详细分析
1.Resource resource = new ClassPathResource("spring/ioc/beans.xml");
我们通过Sring Core模块的工具从本地获得了xml资源,并生成Resource对象。这一过程就不详细跟进了。
2.通过XmlBeanFactory来创建BeanFactory对象。
直接debug进入


3.首先我们会跟进 DefaultSingletonBeanRegistry 其中有静态对象需要实例化。至于为什么会跟进这个类,我们来看下类的继承关系就知道了(为什么会先实例其中的静态类,可以复习以下java对象的实例顺序)


4.接着会进入DefaultListableBeanFactory创建里面的静态对象实例以及执行里面的静态模块



5.通过类加载器注入DefaultListableBeanFactory对象
然后又实例化了一个存放DefaultListableBeanFactory的map


6.接着再执行XmlBeanFactory的构造方法,其中把配置文件Resource赋值给了resource


7.执行this.reader.loadBeanDefinitions(resource); //可以看到这个步骤是要把resource加载到容器中去了。这里是整个资源加载进入的切入点。

8.接着再跟进,直到进入public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException ;方法


9.对导入资源再进行一定包装处理后进入doLoadBeanDefinitions(inputSource, encodedResource.getResource()); //对于encode我们是比较熟悉的 肯定是处理编码相关的


10.现在已经进入到了XmlBeanDefinitionReader.java,
再包装处理(毕竟xml文件规则什么的验证啊 获取比较麻烦,不知道你晕了没有)
xml还是包装成了Document委托给DocumentLoader去处理执行



11.现在又进入public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException ;
程序结果以上的处理,已经获取了xml文档的document,已经可以准备提取注册bean了。


12.经过documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
最终我们获取到了root,protected void doRegisterBeanDefinitions(Element root)这个方法,开始真正的解析已经处理过的资源。


13.解析完成后就是注册了,
debug到如下代码


14.可以看到在这里,把bean存到了beanDefinitionMap中,

对于beanDefinitionMap是什么,就是存在内存中的map,bean就存在里面供外部获取。


跟踪了这么多的源代码,肯定有点乱。做下总结吧。
Spring中bean的加载过程
1.获取配置文件资源
2.对获取的xml资源进行一定的处理检验
3.处理包装资源
4.解析处理包装过后的资源
5.加载提取bean并注册(添加到beanDefinitionMap中)

至于bean的获取,那就比上面的简单多了。
断点进入AbstractBeanFactory


入口
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
进入之后
protected RootBeanDefinition getMergedLocalBeanDefinition(String beanName) throws BeansException {// Quick check on the concurrent map first, with minimal locking.
   RootBeanDefinition mbd = this.mergedBeanDefinitions.get(beanName);
   if (mbd != null) {return mbd;
   }return getMergedBeanDefinition(beanName, getBeanDefinition(beanName));
}
再进入
return getMergedBeanDefinition(beanName, getBeanDefinition(beanName));
我们发现又进入了
DefaultListableBeanFactory.java,是不是有种熟悉的感觉。
当你看到这条语句,你就豁然开朗了,
BeanDefinition bd = this.beanDefinitionMap.get(beanName);
就是之前加载bean放入到的map吗?
其实整个过程还是比较容易理解的,就是里面的包装解析很复杂

这篇关于spring的bean加载的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1089603

相关文章

springboot集成easypoi导出word换行处理过程

《springboot集成easypoi导出word换行处理过程》SpringBoot集成Easypoi导出Word时,换行符n失效显示为空格,解决方法包括生成段落或替换模板中n为回车,同时需确... 目录项目场景问题描述解决方案第一种:生成段落的方式第二种:替换模板的情况,换行符替换成回车总结项目场景s

SpringBoot集成redisson实现延时队列教程

《SpringBoot集成redisson实现延时队列教程》文章介绍了使用Redisson实现延迟队列的完整步骤,包括依赖导入、Redis配置、工具类封装、业务枚举定义、执行器实现、Bean创建、消费... 目录1、先给项目导入Redisson依赖2、配置redis3、创建 RedissonConfig 配

SpringBoot中@Value注入静态变量方式

《SpringBoot中@Value注入静态变量方式》SpringBoot中静态变量无法直接用@Value注入,需通过setter方法,@Value(${})从属性文件获取值,@Value(#{})用... 目录项目场景解决方案注解说明1、@Value("${}")使用示例2、@Value("#{}"php

SpringBoot分段处理List集合多线程批量插入数据方式

《SpringBoot分段处理List集合多线程批量插入数据方式》文章介绍如何处理大数据量List批量插入数据库的优化方案:通过拆分List并分配独立线程处理,结合Spring线程池与异步方法提升效率... 目录项目场景解决方案1.实体类2.Mapper3.spring容器注入线程池bejsan对象4.创建

线上Java OOM问题定位与解决方案超详细解析

《线上JavaOOM问题定位与解决方案超详细解析》OOM是JVM抛出的错误,表示内存分配失败,:本文主要介绍线上JavaOOM问题定位与解决方案的相关资料,文中通过代码介绍的非常详细,需要的朋... 目录一、OOM问题核心认知1.1 OOM定义与技术定位1.2 OOM常见类型及技术特征二、OOM问题定位工具

基于 Cursor 开发 Spring Boot 项目详细攻略

《基于Cursor开发SpringBoot项目详细攻略》Cursor是集成GPT4、Claude3.5等LLM的VSCode类AI编程工具,支持SpringBoot项目开发全流程,涵盖环境配... 目录cursor是什么?基于 Cursor 开发 Spring Boot 项目完整指南1. 环境准备2. 创建

Spring Security简介、使用与最佳实践

《SpringSecurity简介、使用与最佳实践》SpringSecurity是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架,本文给大家介绍SpringSec... 目录一、如何理解 Spring Security?—— 核心思想二、如何在 Java 项目中使用?——

SpringBoot+RustFS 实现文件切片极速上传的实例代码

《SpringBoot+RustFS实现文件切片极速上传的实例代码》本文介绍利用SpringBoot和RustFS构建高性能文件切片上传系统,实现大文件秒传、断点续传和分片上传等功能,具有一定的参考... 目录一、为什么选择 RustFS + SpringBoot?二、环境准备与部署2.1 安装 RustF

springboot中使用okhttp3的小结

《springboot中使用okhttp3的小结》OkHttp3是一个JavaHTTP客户端,可以处理各种请求类型,比如GET、POST、PUT等,并且支持高效的HTTP连接池、请求和响应缓存、以及异... 在 Spring Boot 项目中使用 OkHttp3 进行 HTTP 请求是一个高效且流行的方式。

java.sql.SQLTransientConnectionException连接超时异常原因及解决方案

《java.sql.SQLTransientConnectionException连接超时异常原因及解决方案》:本文主要介绍java.sql.SQLTransientConnectionExcep... 目录一、引言二、异常信息分析三、可能的原因3.1 连接池配置不合理3.2 数据库负载过高3.3 连接泄漏