Spring Bean定义继承

时间:2020-01-09 10:44:30  来源:igfitidea点击:

就像面向对象语言中使用OOPS继承概念一样,子类可以继承父类的属性和方法,这与Spring框架中子bean可以从父定义继承配置数据的方式相同。在这篇文章中,我们将看到bean定义继承在Spring中的工作方式。

Spring中的Bean定义继承

Bean定义可以包含许多配置信息,包括构造函数参数,属性值和特定于容器的信息,例如初始化方法,静态工厂方法名称等。子bean定义可以从父bean继承该配置信息,而不必再次定义所有内容。子定义可以覆盖某些值或者根据需要添加其他值。

bean定义继承如何工作

使用<bean>元素的parent属性指定在子bean定义中继承的父bean定义。例如,在以下配置中,empBean使用父属性继承了父bean定义,它从父bean定义继承了属性company,并添加了自己的name属性。

<bean id="baseEmpBean" class="com.theitroad.Employee">
	<property name="company" value="XYZ"/>
</bean> 
    
<bean id="empBean" parent="baseEmpBean">
	<property name="name" value="Hyman" />
</bean>

在配置中,我们可以看到子bean定义未指定bean类。
子bean定义不需要指定bean类,它可以使用父定义中的bean类。尽管子bean定义也可以覆盖bean类,但如果这样做,则子bean类必须与父类兼容(也就是说,它必须接受父类的属性值)。例如

<bean id="parentBean" class="com.theitroad.TestBean">
	<property name="name" value="parent"/>
	<property name="mode" value="inherit"/>
</bean>

<bean id="childBean" class="org.springframework.beans.DerivedTestBean" parent="inheritedTestBean" >
	<property name="name" value="override"/>
	<!--  mode property value will be inherited from parent -->
</bean>

Spring Bean定义继承示例

在示例中,有一个Bean类Employee,其属性为empId,empName,company,dept。在公司属性的父定义值中,分配了由子bean定义继承的值。

public class Employee {
	int empId;
	String empName;
	String company;
	String dept;
	public int getEmpId() {
		return empId;
	}
	public void setEmpId(int empId) {
		this.empId = empId;
	}
	public String getEmpName() {
		return empName;
	}
	public void setEmpName(String empName) {
		this.empName = empName;
	}
	public String getDept() {
		return dept;
	}
	public void setDept(String dept) {
		this.dept = dept;
	}
	public String getCompany() {
		return company;
	}
	public void setCompany(String company) {
		this.company = company;
	}
	
	@Override
	public String toString() {
		return "Id= " + getEmpId() + " Name= " + 
	           getEmpName() + " Dept= "+ getDept()
	           + " Company= " + getCompany();
	}
}

组态

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
          http://www.springframework.org/schema/beans/spring-beans.xsd
          http://www.springframework.org/schema/context
          http://www.springframework.org/schema/context/spring-context.xsd">
    
	<bean id="baseEmpBean" class="com.theitroad.springproject.model.Employee">
		<property name="company" value="XYZ"/>
	</bean> 
	<bean id="empBean" parent="baseEmpBean">
		<property name="empId" value="1" />
		<property name="empName" value="Hyman" />
		<property name="dept" value="HR" />
	</bean>
</beans>

我们可以将以下类与main方法一起使用以读取配置并访问Bean。

public class App {
  public static void main( String[] args ){
    // create context using configuration
    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("appcontext.xml");
    Employee emp =  context.getBean("empBean", Employee.class);
    System.out.println(emp);
    context.close();
  }
}

输出:

20:09:24.009 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'baseEmpBean'
20:09:24.140 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'empBean'
Id= 1 Name= Hyman Dept= HR Company= XYZ

Spring Bean定义继承中的Abstract属性

如果要限制父bean的实例化,则可以将其标记为abstract =" true"来实现。

Spring bean定义中的抽象属性

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xmlns:context="http://www.springframework.org/schema/context"
      xsi:schemaLocation="http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">
  <!-- acts as a template -->
  <bean id="baseEmpBean" abstract="true" class="com.theitroad.springproject.model.Employee">
    <property name="company" value="XYZ"/>
  </bean> 
  <bean id="empBean" parent="baseEmpBean" >
    <property name="empId" value="1" />
    <property name="empName" value="Hyman" />
    <property name="dept" value="HR" />
  </bean>
</beans>

将parent标记为抽象时,尝试访问父bean会导致错误。

Exception in thread "main" org.springframework.beans.factory.BeanIsAbstractException: Error creating bean with name 'baseEmpBean': Bean definition is abstract
	at org.springframework.beans.factory.support.AbstractBeanFactory.checkMergedBeanDefinition(AbstractBeanFactory.java:1335)
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:295)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:204)
	at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1111)
	at com.theitroad.springproject.App.main(App.java:14)

父bean作为Spring bean继承中的模板

通过将父bean定义标记为abstract =" true"而不指定类,我们可以将父仅用作纯模板bean定义,用作子定义的父定义。

注意,如果父定义未指定类,则需要将父bean定义显式标记为抽象。

模板bean定义示例

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
          http://www.springframework.org/schema/beans/spring-beans.xsd
          http://www.springframework.org/schema/context
          http://www.springframework.org/schema/context/spring-context.xsd">
    <!-- acts as a template -->
	<bean id="baseEmpBean" abstract="true">
		<property name="company" value="XYZ"/>
	</bean> 
	<bean id="empBean" parent="baseEmpBean" class="com.theitroad.springproject.model.Employee">
		<property name="empId" value="1" />
		<property name="empName" value="Hyman" />
		<property name="dept" value="HR" />
	</bean>
</beans>