Spring parent 属性
Spring Framework Reference Documentation 6.7. Bean definition inheritance
注:本文中bean和definition意思等同
该节详细介绍了 bean的继承关系(bean标签的parent属性),下面简单翻译一下:https://docs.spring.io/spring/docs/4.2.9.RELEASE/spring-framework-reference/htmlsingle/#beans-child-bean-definitions
6.7 Bean definition inheritance
A bean definition can contain a lot of configuration information, including constructor arguments, property values, and container-specific information such as initialization method, static factory method name, and so on. A child bean definition inherits configuration data from a parent definition. The child definition can override some values, or add others, as needed. Using parent and child bean definitions can save a lot of typing. Effectively, this is a form of templating.
If you work with an ApplicationContext
interface programmatically, child bean definitions are represented by the ChildBeanDefinition
class. Most users do not work with them on this level, instead configuring bean definitions declaratively in something like the ClassPathXmlApplicationContext
. When you use XML-based configuration metadata, you indicate a child bean definition by using the parent
attribute, specifying the parent bean as the value of this attribute.
<bean id="inheritedTestBean" abstract="true"
class="org.springframework.beans.TestBean">
<property name="name" value="parent"/>
<property name="age" value="1"/>
</bean> <bean id="inheritsWithDifferentClass"
class="org.springframework.beans.DerivedTestBean"
parent="inheritedTestBean" init-method="initialize">
<property name="name" value="override"/>
<!-- the age property value of 1 will be inherited from parent -->
</bean>
A child bean definition uses the bean class from the parent definition if none is specified, but can also override it. In the latter case, the child bean class must be compatible with the parent, that is, it must accept the parent’s property values.
A child bean definition inherits scope, constructor argument values, property values, and method overrides from the parent, with the option to add new values. Any scope, initialization method, destroy method, and/or static
factory method settings that you specify will override the corresponding parent settings.
The remaining settings are always taken from the child definition: depends on, autowire mode, dependency check, singleton, lazy init.
The preceding example explicitly marks the parent bean definition as abstract by using the abstract
attribute. If the parent definition does not specify a class, explicitly marking the parent bean definition as abstract
is required, as follows:
<bean id="inheritedTestBeanWithoutClass" abstract="true">
<property name="name" value="parent"/>
<property name="age" value="1"/>
</bean> <bean id="inheritsWithClass" class="org.springframework.beans.DerivedTestBean"
parent="inheritedTestBeanWithoutClass" init-method="initialize">
<property name="name" value="override"/>
<!-- age will inherit the value of 1 from the parent bean definition-->
</bean>
The parent bean cannot be instantiated on its own because it is incomplete, and it is also explicitly marked as abstract
. When a definition is abstract
like this, it is usable only as a pure template bean definition that serves as a parent definition for child definitions. Trying to use such an abstract
parent bean on its own, by referring to it as a ref property of another bean or doing an explicit getBean()
call with the parent bean id, returns an error. Similarly, the container’s internalpreInstantiateSingletons()
method ignores bean definitions that are defined as abstract.
|
A bean definition can contain a lot of configuration information,
including constructor arguments, property values, and container-specific
information such as initialization method, static factory method name, and so on.
A child bean definition inherits configuration data from a parent definition.
The child definition can override some values, or add others, as needed.
Using parent and child bean definitions can save a lot of typing.
Effectively, this is a form of templating.
我们知道,BeanDefinition是 bean标签的抽象,BeanDefinition和bean标签中的属性是一一对应的。BeanDefinition中存储大量的配置信息。子BeanDefinition能够从父BeanDefinition中继承配置信息。当然子BeanDefinition也可以覆盖或者新增一些新的配置信息。使用父子BeanDefinition能少打很多字(?),更加高效,这是一种模板方式。
If you work with an ApplicationContext interface programmatically,
child bean definitions are represented by the ChildBeanDefinition class.
Most users do not work with them on this level,
instead configuring bean definitions declaratively in something like the ClassPathXmlApplicationContext.
When you use XML-based configuration metadata,
you indicate a child bean definition by using the parent attribute,
specifying the parent bean as the value of this attribute.
在spring中,子BeanDefinition用ChildBeanDefinition表示。但是大家一般不这么使用,而是直接使用ClassPathXmlApplicationContext来配置BeanDefinition。
当使用XML配置子BeanDefinition时,可以使用bean标签的parent属性来表示这个bean是个子bean。parent的属性值就是父bean。
<bean id="inheritedTestBean" abstract="true"
class="org.springframework.beans.TestBean">
<property name="name" value="parent"/>
<property name="age" value="1"/>
</bean>
<bean id="inheritsWithDifferentClass"
class="org.springframework.beans.DerivedTestBean"
parent="inheritedTestBean" init-method="initialize">
<property name="name" value="override"/>
<!-- the age property value of 1 will be inherited from parent -->
</bean>
A child bean definition uses the bean class from the parent definition if none is specified,
but can also override it.
In the latter case, the child bean class must be compatible with the parent,
that is, it must accept the parent’s property values.
如果子bean的class没有指定,则使用使用父bean的class。如果子bean有指定class,则会覆盖父bean的class。后一种情况(子bean指定了class),子bean的class必须要和父bean的class兼容,也就是说能够接受父bean的配置。
A child bean definition inherits scope, constructor argument values,
property values, and method overrides from the parent, with the option to add new values.
Any scope, initialization method, destroy method,
and/or static factory method settings that you specify will override the corresponding parent settings.
子BeanDefinition继承父BeanDefinition的scorp、constructor 、property 、method overrides,并添加新配置。子BeanDefinition会覆盖父子BeanDefinition的配置有:initialization method、destroy method、static factory method settings。
The remaining settings are always taken from the child definition:
depends on, autowire mode, dependency check, singleton, lazy init.
子BeanDefinition有些配置始终不会继承父BeanDefinition:depends on、autowire mode、dependency check、singleton、lazy init。
The preceding example explicitly marks the parent bean definition as abstract by using the abstract attribute.
If the parent definition does not specify a class,
explicitly marking the parent bean definition
as abstract is required,
as follows:
<bean id="inheritedTestBeanWithoutClass" abstract="true">
<property name="name" value="parent"/>
<property name="age" value="1"/>
</bean>
<bean id="inheritsWithClass" class="org.springframework.beans.DerivedTestBean"
parent="inheritedTestBeanWithoutClass" init-method="initialize">
<property name="name" value="override"/>
<!-- age will inherit the value of 1 from the parent bean definition-->
</bean>
前一个例子通过abstract属性将一个bean定义为抽象的。如果父bean没有指定class,则需要将其定义为抽象的。
The parent bean cannot be instantiated on its own because it is incomplete,
and it is also explicitly marked as abstract.
When a definition is abstract like this,
it is usable only as a pure template bean definition that serves as a parent definition for child definitions.
Trying to use such an abstract parent bean on its own,
by referring to it as a ref property
of another bean or doing an explicit getBean() call with the parent bean id, returns an error.
Similarly, the container’s internal preInstantiateSingletons() method ignores
bean definitions that are defined as abstract.
如果bean被定义为抽象,则不能初始化该bean。如果一个bean被指定为抽象,那么也就可以认为该bean就是一个模板,子bean通用配置的抽象。如果通过ref属性引用抽象bean,或者通过getBean获取抽象bean,则会返回错误。而且,spring的内部方法preInstantiateSingletons会忽略被定义为抽象的bean。
二、获取RootBeanDefinition
如果缓存中不存在已经加载的单例bean,就需要从头开始bean的加载过程了。
而加载bean的第一步就是获取bean的RootBeanDefinition,获取RootBeanDefinition的过程就是子bean合并父bean配置信息的过程
我们知道bean标签在spring内部的表现的BeanDefinition。
回忆下,在注册bean标签的时候,不论是子bean还是父bean都是用的GenericBeanDefinition表示。子bean为什么不使用ChildBeanDefinition?
进入ChildBeanDefinition源码,发现这样一段注释:
NOTE:Since Spring 2.5, the preferred way to register bean definitions programmatically
is the {@link GenericBeanDefinition} class,which allows to dynamically define parent dependencies through the
{@link GenericBeanDefinition#setParentName} method. This effectively
supersedes the ChildBeanDefinition class for most use cases.
- 1
- 2
- 3
- 4
从spring2.5起,注册bean的首选是GenericBeanDefinition,GenericBeanDefinition允许动态的定义父bean(通过setParentName方法)。
下面分析代码:
protected RootBeanDefinition getMergedLocalBeanDefinition(String beanName) throws BeansException {
// Quick check on the concurrent map first, with minimal locking.
//查看mergedBeanDefinitions集合中是否存在,如果存在直接返回。最小化的同步mergedBeanDefinitions
RootBeanDefinition mbd = this.mergedBeanDefinitions.get(beanName);
if (mbd != null) {
return mbd;
}
return getMergedBeanDefinition(beanName, getBeanDefinition(beanName));
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
protected RootBeanDefinition getMergedBeanDefinition(String beanName, BeanDefinition bd)
throws BeanDefinitionStoreException {
return getMergedBeanDefinition(beanName, bd, null);
}
protected RootBeanDefinition getMergedBeanDefinition(
String beanName, BeanDefinition bd, BeanDefinition containingBd)
throws BeanDefinitionStoreException {
synchronized (this.mergedBeanDefinitions) {
RootBeanDefinition mbd = null;
// Check with full lock now in order to enforce the same merged instance.
if (containingBd == null) {
mbd = this.mergedBeanDefinitions.get(beanName);
}
if (mbd == null) {
if (bd.getParentName() == null) {
// Use copy of given root bean definition.
if (bd instanceof RootBeanDefinition) {
mbd = ((RootBeanDefinition) bd).cloneBeanDefinition();
}
else {
mbd = new RootBeanDefinition(bd);
}
}
else {
// Child bean definition: needs to be merged with parent.
BeanDefinition pbd;
try {
String parentBeanName = transformedBeanName(bd.getParentName());
if (!beanName.equals(parentBeanName)) {
pbd = getMergedBeanDefinition(parentBeanName);
}
else {
BeanFactory parent = getParentBeanFactory();
if (parent instanceof ConfigurableBeanFactory) {
pbd = ((ConfigurableBeanFactory) parent).getMergedBeanDefinition(parentBeanName);
}
else {
throw new NoSuchBeanDefinitionException(parentBeanName,
"Parent name '" + parentBeanName + "' is equal
to bean name '" + beanName +
"': cannot be resolved without an AbstractBeanFactory parent");
}
}
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanDefinitionStoreException(bd.getResourceDescription(), beanName,
"Could not resolve parent bean definition '" + bd.getParentName() + "'", ex);
}
// Deep copy with overridden values.
mbd = new RootBeanDefinition(pbd);
mbd.overrideFrom(bd);
}
// Set default singleton scope, if not configured before.
if (!StringUtils.hasLength(mbd.getScope())) {
mbd.setScope(RootBeanDefinition.SCOPE_SINGLETON);
}
// A bean contained in a non-singleton bean cannot be a singleton itself.
// Let's correct this on the fly here, since this might be the result of
// parent-child merging for the outer bean, in which case the original inner bean
// definition will not have inherited the merged outer bean's singleton status.
if (containingBd != null && !containingBd.isSingleton() && mbd.isSingleton()) {
mbd.setScope(containingBd.getScope());
}
// Only cache the merged bean definition if we're already about to create an
// instance of the bean, or at least have already created an instance before.
if (containingBd == null && isCacheBeanMetadata()) {
this.mergedBeanDefinitions.put(beanName, mbd);
}
}
return mbd;
}
}
public BeanDefinition getMergedBeanDefinition(String name) throws BeansException {
String beanName = transformedBeanName(name);
// Efficiently check whether bean definition exists in this factory.
if (!containsBeanDefinition(beanName) && getParentBeanFactory() instanceof ConfigurableBeanFactory) {
return ((ConfigurableBeanFactory) getParentBeanFactory()).getMergedBeanDefinition(beanName);
}
// Resolve merged bean definition locally.
return getMergedLocalBeanDefinition(beanName);
}
一提到父子bean,那么代码中肯定就是递归。不断的合并父bean的配置。
如果parentName 等于当前beanName,则需要到parentFactory中寻找parentName。如果找不到则抛出NoSuchBeanDefinitionException。
如果beanName不存在当前beanFactory中,则取parentFactory中寻找。
Spring parent 属性的更多相关文章
- Spring中 bean定义的parent属性机制的实现分析
在XML中配置bean元素的时候,我们常常要用到parent属性,这个用起来很方便就可以让一个bean获得parent的所有属性 在spring中,这种机制是如何实现的? 对于这种情况 tra ...
- 【Spring源码解读】bean标签中的属性(二)你可能还不够了解的 abstract 属性和 parent 属性
abstract 属性说明 abstract 在java的语义里是代表抽象的意思,用来说明被修饰的类是抽象类.在Spring中bean标签里的 abstract 的含义其实也差不多,表示当前bean是 ...
- spring bean parent属性详解
必要条件:1.子bean必须与父bean保持兼容,也就是说子bean中必须有父bean定义的所有属性. 2.父bean必须是抽象bean或者定义lazy-init=true也就是不让bean工厂实例化 ...
- spring配置属性的两种方式
spring配置属性有两种方式,第一种方式通过context命名空间中的property-placeholder标签 <context:property-placeholder location ...
- Spring中属性文件properties的读取与使用
实际项目中,通常将一些可配置的定制信息放到属性文件中(如数据库连接信息,邮件发送配置信息等),便于统一配置管理.例中将需配置的属性信息放在属性文件/WEB-INF/configInfo.propert ...
- Spring MVC 属性文件读取注入到静态字段
目录(?)[-] servlet-contextxml configproperties 示例属性 ConfigInfo 对应的配置bean 使用 在项目中,有些参数需要配置到属性文件xxx.pr ...
- Spring Boot 属性配置和使用
Spring Boot 属性配置和使用 Spring Boot 允许通过外部配置让你在不同的环境使用同一应用程序的代码,简单说就是可以通过配置文件来注入属性或者修改默认的配置. Spring Boot ...
- Spring Boot 属性配置和使用(转)
Spring Boot 属性配置和使用 Spring Boot 允许通过外部配置让你在不同的环境使用同一应用程序的代码,简单说就是可以通过配置文件来注入属性或者修改默认的配置. Spring Boot ...
- 【转】spring管理属性配置文件properties——使用PropertiesFactoryBean|spring管理属性配置文件properties——使用PropertyPlaceholderConfigurer
spring管理属性配置文件properties--使用PropertiesFactoryBean 对于属性配置,一般采用的是键值对的形式,如:key=value属性配置文件一般使用的是XXX.pr ...
随机推荐
- 解决Git Clone速度过慢的方法
Git Clone速度慢,原因很简单,默认的源是国外的,只需要使用国内源,速度就起飞了(当然,也没有太快,至少可以忍受了).使用方法很简单,在clone某个项目的时候将github.com替换为git ...
- SpringBoot通过Ajax批量将excel中数据导入数据库
Spring Boot通过Ajax上传Excel并将数据批量读取到数据库中 适合场景:需要通过excel表格批量向数据库中导入信息 操作流程 [1]前端上传一个excel表格 [2] 后端接收这个ex ...
- Spring RestTemplate 之中文乱码
由于RestTemplate的默认构造方法初始化的StringHttpMessageConverter的默认字符集是ISO-8859-1,所以导致RestTemplate请求的响应内容会出现中文乱码. ...
- 【爬虫系列】0. 无内鬼,破解前端JS参数签名
PS:这是一个系列,坐等我慢慢填坑. PS:不太会直接能跑的代码,抛砖引玉. PS:那些我也不太熟练的就不搞了,包括(破滑块.验证码..) PS: 反编译搞Apk会有很长的几个文章,稍后慢慢更. 最近 ...
- java String转List<Device>集合
// 从Redis中获得正常设备的数量 String success = redisService.get(RedisKey.CULTIVATION_RECORD_SUCCESS); //建立一个li ...
- Python基础之实现界面和代码分离
第一步:用QT Designer画一个TreeWidget,存为treeview4.ui,这个处理前面TreeWidget那一节讲过,这里不细讲 treeview4.py # -*- coding: ...
- (python函数03)zip()函数
(python函数03)zip()函数 zip是用来压缩的,它接受一系列可迭代的对象作为参数,将对象中对应的元素打包成一个个元组(tuple),然后返回有这些tuples组成的对象,可强制转化为列表和 ...
- 每日三道面试题,通往自由的道路14——MySQL
茫茫人海千千万万,感谢这一秒你看到这里.希望我的面试题系列能对你的有所帮助!共勉! 愿你在未来的日子,保持热爱,奔赴山海! 每日三道面试题,成就更好自我 昨天我们是不是聊到了锁,而你提到了MySQL? ...
- mongodb使用场景及与mysql区别
MySQL是关系型数据库. 优势: 在不同的引擎上有不同 的存储方式. 查询语句是使用传统的sql语句,拥有较为成熟的体系,成熟度很高. 开源数据库的份额在不断增加,mysql的份额页在持续增长. 缺 ...
- 论文笔记:(ICML2020)On Learning Sets of Symmetric Elements
目录 摘要 一.引言 二.先前的工作 三.基础 3.1 符号和基本定义 3.2 G-不变网络 3.3 描述等变层 3.4 Deep sets 四.DSS层 4.1 对称元素集合 4.2 等变层的表征 ...