前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Spring Bean的解析和加载详细解释

Spring Bean的解析和加载详细解释

作者头像
Tim在路上
发布2020-08-04 22:47:55
4520
发布2020-08-04 22:47:55
举报

spring分为以下几个部分:

  1. Core Container

Core Container 包含 Core,Beans,Context,Expression Language 模块 Core 和 Beans 提供 IOC 和 依赖注入特性. Context 提供了类似JNDI注册器的框架, ApplicationContext 接口是Context的关键 EL 用于运行时的查询和操作

beans 的解析

  1. 读取Beans

spring自定义资源加载类

代码语言:javascript
复制
Resource resource=new ClassPathResource( "beanFactoryTest .xml ”), 
InputStream inputStream=resource.getinputStream (); 

而资源加载类的底层也是调用字节流的加载,这样可以加载jar中配置文件

代码语言:javascript
复制
if (this . clazz 1= null ) { 
    is = this clazz getRes urceAsStream(this path)
}else { 
    is= this classLoader . getResourceAsStream(this . path} ; 
}

Resources 完成对xml的封装后,将其交给 XMLBeanDefinitionReader

然后 XMLBeanFactory通过调用this.reader.loadBeanDefinitions(resource); 来进行加载Bean

注意:在调用加载资源文件前会先调用 ignore BeanNameAware 接口, BeanNameAware 接口是什么呢? 我们一般用的Bean都是无知觉的,不知道自己在那个工厂中,或者自己的代号,通过实现BeanNameAware接口,接口中就一个方法setBeanName(). A中有属性B, 那么当Spring在获取A的Beans时候,B还没有初始化,Spring会初始化B,但是B实现BeanNameAware接口,就会忽略再进行初始化.

2.首先对Resource进行EncodedResource封装, EncodedReasource 作用设置编码属性 然后使用 SAX 读取 XML 得到Document

3.根据Document 注册 解析标签

得到root节点,然后首先处理Profile属性的使用 profile 可以表面使用 dev 还是 production test等,这个特性用来配置生产环境和测试环境.

spring-xml中配置两种Bean声明

代码语言:javascript
复制
<bean id=” test” class=” test TestBean ” />

<tx :annotation-driven/> 

spring中默认的标签有四个:

import alias bean beans

  • bean 标签解析
  1. 提取元素中的id以及name属性
  2. 进一步解析其他属性封装 GenericBeanDefinition中,没有name的生成name

spring的配置信息主要以map形式进行保存

3.然后对保存在实体中属性进行解析

代码语言:javascript
复制
<bean id = myTestBea class= "bean.MyTestBean">
    <meta key=” testStr " value= ” aaaaaaaa ” />
</bean>

4.解析子元素meta construct, property,qualifier等

    • AbstractBeanDefinition 属性

GenericBeanDefinition 只是子类实现,大部分保存在 AbstractBeanDefinition 中

    • 注册解析的 Bean Definition

解析Bean进行注册主要分为 通过beanName进行注册,通过别名进行注册两种方式

(1) 通过BeanName进行注册

beanDefinitionMap 是全局变量存在并发访问.

beanDefinitionMap beanName作为key, beanDefinition 作为Value

这里会判断如果已经注册同时设置不允许覆盖,则不进行覆盖,否则覆盖 ,清除之前Bean缓存

(2) 通过别名alias进行注册

如果alias与beanName相同不记录alias,使用beanName走1

如果aliasName已经使用并指向另一个beanName进行设置,避免 A->B 存在 , A -> C -> B进行循环检测

注册alias

    • 通知监听器注册完成
  • alias 标签解析

在对bean进行定义,除了使用 id外,还可以使用别名alias,给bean提供多个名称

代码语言:javascript
复制
<bean id= ”testBean” class= ”com.test” />

可以直接当前位置加别名

代码语言:javascript
复制
<bean id= ” testBean ” name= ” testBean , tescBean 2 ” c lass= ” com test " />

同时可以在别处定义bean别名

代码语言:javascript
复制
<alias name="testBean" alias="testBear,testBean2" /〉

和beanName一样都是将别名和beanName组成一对进行注册

  • import 标签解析
代码语言:javascript
复制
<import resource=” customerContext.xml ” />
<import resource=” systemContext.xml ” />

使用import导入不同模块的配置文件

递归调用解析程序

  • 嵌入式beans标签解析

bean 的加载

  1. 转换为对应的beanName

传入参数可能为alias或者FactoryBean ,返回别名指向的最终beanName

2.尝试从缓存中加载单例

代码语言:javascript
复制
** Cache of singleton objects: bean name --> bean instance */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(256);

/** Cache of singleton factories: bean name --> ObjectFactory */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<String, ObjectFactory<?>>(16);

/** Cache of early singleton objects: bean name --> bean instance */
private final Map<String, Object> earlySingletonObjects = new HashMap<String, Object>(16);

spring 中有三级缓存,singletonFactories : 单例对象工厂的cache earlySingletonObjects :提前暴光的单例对象的Cache singletonObjects:单例对象的cache

spring为了避免循环依赖注入,采用三级缓存,在创建bean中不等bean创建完成就将创建bean的ObjectFactory提前曝光到缓存中,下一个bean需要依赖这个bean就可以直接使用ObjectFactory

3.bean 的实例化

如果得到的原始状态,就需要对bean进行实例化. 通过工厂获得bean,还未返回bean中factory-method 返回的bean

原型模式需要依赖检测 , 在单例情况下才会尝试解决循环依赖

4.如果缓存中没有数据,同时容器中有父类工厂,且不为null,通过父类工厂加载bean

6.根据不同scope进行创建bean

  • FactoryBean 的使用

一般情况下通过配置bean的class的反射来实例化bean, 某些情况bean实例比较复杂,spring可以通过实现FactoryBean接口,定制Bean的实例化逻辑

如果要获取工厂的Bean 可以使用 getBean("&car")

  • 缓存中获取单例bean

单例在spring的同一个容器中只会被创建一次,后序再获取bean直接从单利的缓存中获取bean

singletomObjects: 用于保存BeanName 和 创建bean 实例之间的关系

singletonFactories: 用于保存 BeanName 和 Bean工厂之间的关系

earlySingletonObjects :也是保存 BeanName 和创建 bean 实例之间的关系,与 singletonO ects 的不同之处在于,当一个单 bean 被放到这里面后,那么当 bean 在创建过程中,就可以通过 getBean 方法获取到了,其目的是用来检测循环引用

registeredSingletons :用来保存当前所有巳注册的 bean

spring中的循环依赖

(1). 构造器的循环依赖

通过构造器注入构成的循环依赖,此依赖无法解决,抛出异常

代码语言:javascript
复制
<bean id=”testA” class="com.bean.TestA”>
<constructor- arg index="0" ref="testB" /〉
</bean> 
<bean id=”testB” class=” com.bean.TestB”> 
<constructor arg index ="0" ref="testC" /〉
</bean> 
<bean id=”tesi::C ” class=” com.bean.TestC”> 
<constructor- arg index="0" ref="testA" /〉
</bean> 

spring在创建bean的时候会去 "当前正在创建Bean池" ,查找是否正在创建,如果发现依赖正在创建 报循环依赖

(2). setter循环依赖

通过提前暴露一个单例工厂方法,从而使其他 bean 能引用到bean

代码语言:javascript
复制
addSingletonFactory (beanName , new 0:0] ectFactory() { 
    public Object getobject () throws BeansException { 
        return getEarlyBeanReference(beanName,mbd,bean) ; 
    }
});

(3). prototype 范围的依赖处理

对于“prototype ”作用域 bean, Spring 容器无法完成依赖注入,因为 Spring 容器不进行缓 存“prototype ”作用域的 bean ,因此无法提前暴露一个创建中的 bean.

6.创建Bean

(1) 如果是单例需要首先清除缓存 (2) 实例化Bean ,将BeanDefinition 转换为BeanWrapper 如果工厂使用工厂,有构造函数使用构造,否则默认 (3) MergedBeanDefinitionPostProcessor 应用 bean合并后处理, Autowired 注解通过此方法实现预解析 (4) 依赖处理,属性填充 (5) 注册DisposableBean (6) 完成并返回

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • beans 的解析
  • bean 的加载
    • spring中的循环依赖
    相关产品与服务
    容器服务
    腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档