先来看一个案例
ServiceA.java
package com.javacode2018.lesson001.demo12;
public class ServiceA {
}
ServiceB.java
package com.javacode2018.lesson001.demo12;
public class ServiceB {
private String name;
private ServiceA serviceA;
public String getName() {<br /> return name;<br /> }
public void setName(String name) {<br /> this.name = name;<br /> }
public ServiceA getServiceA() {<br /> return serviceA;<br /> }
public void setServiceA(ServiceA serviceA) {<br /> this.serviceA = serviceA;<br /> }
@Override<br /> public String toString() {<br /> return "ServiceB{" +<br /> "name='" + name + '\'' +<br /> ", serviceA=" + serviceA +<br /> '}';<br /> }<br />}
上面类中有2个属性,下面我们再创建一个ServiceC类,和ServiceB中的内容一样。
ServiceC.java
package com.javacode2018.lesson001.demo12;
public class ServiceC {
private String name;
private ServiceA serviceA;
public String getName() {<br /> return name;<br /> }
public void setName(String name) {<br /> this.name = name;<br /> }
public ServiceA getServiceA() {<br /> return serviceA;<br /> }
public void setServiceA(ServiceA serviceA) {<br /> this.serviceA = serviceA;<br /> }
@Override<br /> public String toString() {<br /> return "ServiceC{" +<br /> "name='" + name + '\'' +<br /> ", serviceA=" + serviceA +<br /> '}';<br /> }<br />}
beanExtend.xml
<?xml version=”1.0” encoding=”UTF-8”?>
xsi:schemaLocation=”http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd">
<bean id="serviceA" class="com.javacode2018.lesson001.demo12.ServiceA"/>
<bean id="serviceB" class="com.javacode2018.lesson001.demo12.ServiceB"><br /> <property name="name" value="程序员路人"/><br /> <property name="serviceA" ref="serviceA"/><br /> </bean>
<bean id="serviceC" class="com.javacode2018.lesson001.demo12.ServiceB"><br /> <property name="name" value="程序员路人"/><br /> <property name="serviceA" ref="serviceA"/><br /> </bean>
BeanExtendTest.java
package com.javacode2018.lesson001.demo12;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/*
公众号:程序员路人
bean定义继承案例
/
public class BeanExtendTest {
@Test
public void normalBean() {
String beanXml = “classpath:/com/javacode2018/lesson001/demo12/normalBean.xml”;
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(beanXml);
System.out.println(“serviceB:” + context.getBean(ServiceB.class));
System.out.println(“serviceC:” + context.getBean(ServiceC.class));
}
}
运行输出
serviceB:ServiceB{name=’程序员路人’, serviceA=com.javacode2018.lesson001.demo12.ServiceA@222114ba}
serviceC:ServiceC{name=’程序员路人’, serviceA=com.javacode2018.lesson001.demo12.ServiceA@222114ba}
通过继承优化代码
我们再回头去看一下上面xml中,serviceB和serviceC两个bean的定义如下:
这2个bean需要注入的属性的值是一样的,都需要注入name和serviceA两个属性,并且2个属性的值也是一样的,我们可以将上面的公共的代码抽取出来,通过spring中继承的方式来做到代码重用。
可以将上面xml调整一下,我们来新建一个extendBean.xml,内容如下:
<?xml version=”1.0” encoding=”UTF-8”?>
xsi:schemaLocation=”http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd">
<bean id="serviceA" class="com.javacode2018.lesson001.demo12.ServiceA"/>
<bean id="baseService" abstract="true"><br /> <property name="name" value="程序员路人"/><br /> <property name="serviceA" ref="serviceA"/><br /> </bean>
<bean id="serviceB" class="com.javacode2018.lesson001.demo12.ServiceB" parent="baseService"/>
<bean id="serviceC" class="com.javacode2018.lesson001.demo12.ServiceC" parent="baseService"/>
上面多了一个baseService的bean,这个bean没有指定class对象,但是多了一个abstract=”true”的属性,表示这个bean是抽象的,abstract为true的bean在spring容器中不会被创建,只是会将其当做bean定义的模板,而serviceB和serviceC的定义中多了一个属性parent,用来指定当前bean的父bean名称,此处是baseService,此时serviceB和serviceC会继承baseService中定义的配置信息。
来个测试用例看一下效果:
@Test
public void extendBean() {
String beanXml = “classpath:/com/javacode2018/lesson001/demo12/extendBean.xml”;
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(beanXml);
System.out.println(“serviceB:” + context.getBean(ServiceB.class));
System.out.println(“serviceC:” + context.getBean(ServiceC.class));
}
运行输出:
serviceB:ServiceB{name=’程序员路人’, serviceA=com.javacode2018.lesson001.demo12.ServiceA@222114ba}
serviceC:ServiceC{name=’程序员路人’, serviceA=com.javacode2018.lesson001.demo12.ServiceA@222114ba}
输出和上面案例的输出基本一致。
但是这次bean xml中bean的定义简化了很多,将公共的bean配置提取出来了,通过parent属性来配置需要继承的bean。
子bean中也可以重新定义父bean中已经定义好的配置,这样子配置会覆盖父bean中的配置信息,我们将extendBean.xml中serviceC的定义改一下:
运行extendBean输出:
serviceB:ServiceB{name=’程序员路人’, serviceA=com.javacode2018.lesson001.demo12.ServiceA@222114ba}
serviceC:ServiceC{name=’欢迎和【程序员路人】一起学些spring!’, serviceA=com.javacode2018.lesson001.demo12.ServiceA@222114ba}
从输出中可以看出serviceC中的name对父bean中name的值进行了覆盖。
我们再来从容器中获取一下baseService,如下:
System.out.println(context.getBean(“baseService”));
运行输出:
org.springframework.beans.factory.BeanIsAbstractException: Error creating bean with name ‘baseService’: Bean definition is abstract
at org.springframework.beans.factory.support.AbstractBeanFactory.checkMergedBeanDefinition(AbstractBeanFactory.java:1412)
会报BeanIsAbstractException异常,因为baseService是抽象的,不能够创建这个bean实例。
总结
- bean元素的abstract属性为true的时候可以定义某个bean为一个抽象的bean,相当于定义了一个bean模板,spring容器并不会创建这个bean,从容器中查找abstract为true的bean的时候,会报错BeanIsAbstractException异常
2. bean元素的parent属性可以指定当前bean的父bean,子bean可以继承父bean中配置信息,也可以自定义配置信息,这样可以覆盖父bean中的配置