先來看一個案例
ServiceA.java
package com.javacode2018.lesson001.demo12;public class ServiceA {}1234
ServiceB.java
package com.javacode2018.lesson001.demo12;public class ServiceB {
private String name;
private ServiceA serviceA;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public ServiceA getServiceA() {
return serviceA;
}
public void setServiceA(ServiceA serviceA) {
this.serviceA = serviceA;
}
@Override
public String toString() {
return "ServiceB{" +
"name='" + name + '\'' +
", serviceA=" + serviceA +
'}';
}}123456789101112131415161718192021222324252627282930
上面類中有2個屬性,下面我們再建立一個ServiceC類,和ServiceB中的內容一樣。
ServiceC.java
package com.javacode2018.lesson001.demo12;public class ServiceC {
private String name;
private ServiceA serviceA;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public ServiceA getServiceA() {
return serviceA;
}
public void setServiceA(ServiceA serviceA) {
this.serviceA = serviceA;
}
@Override
public String toString() {
return "ServiceC{" +
"name='" + name + '\'' +
", serviceA=" + serviceA +
'}';
}}123456789101112131415161718192021222324252627282930
下面我們使用spring來建立上面3個類對應的bean。
beanExtend.xml
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="
xmlns:xsi="
xsi:schemaLocation="
/spring-beans-4.3.xsd">
<bean id="serviceA" class="com.javacode2018.lesson001.demo12.ServiceA"/>
<bean id="serviceB" class="com.javacode2018.lesson001.demo12.ServiceB">
<property name="name" value="路人甲Java"/>
<property name="serviceA" ref="serviceA"/>
</bean>
<bean id="serviceC" class="com.javacode2018.lesson001.demo12.ServiceB">
<property name="name" value="路人甲Java"/>
<property name="serviceA" ref="serviceA"/>
</bean></beans>12345678910111213141516171819
建立測試用例。
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));
}}1234567891011121314151617
執行輸出
serviceB:ServiceB{name='路人甲Java', serviceA=com.javacode2018.lesson001.demo12.ServiceA@222114ba}serviceC:ServiceC{name='路人甲Java', serviceA=com.javacode2018.lesson001.demo12.ServiceA@222114ba}12
透過繼承最佳化程式碼
我們再回頭去看一下上面xml中,serviceB和serviceC兩個bean的定義如下:
<bean id="serviceB" class="com.javacode2018.lesson001.demo12.ServiceB">
<property name="name" value="路人甲Java"/>
<property name="serviceA" ref="serviceA"/></bean><bean id="serviceC" class="com.javacode2018.lesson001.demo12.ServiceC">
<property name="name" value="路人甲Java"/>
<property name="serviceA" ref="serviceA"/></bean>123456789
這2個bean需要注入的屬性的值是一樣的,都需要注入name和serviceA兩個屬性,並且2個屬性的值也是一樣的,我們可以將上面的公共的程式碼抽取出來,透過spring中繼承的方式來做到程式碼重用。
可以將上面xml調整一下,我們來新建一個extendBean.xml,內容如下:
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="
xmlns:xsi="
xsi:schemaLocation="
/spring-beans-4.3.xsd">
<bean id="serviceA" class="com.javacode2018.lesson001.demo12.ServiceA"/>
<bean id="baseService" abstract="true">
<property name="name" value="路人甲Java"/>
<property name="serviceA" ref="serviceA"/>
</bean>
<bean id="serviceB" class="com.javacode2018.lesson001.demo12.ServiceB" parent="baseService"/>
<bean id="serviceC" class="com.javacode2018.lesson001.demo12.ServiceC" parent="baseService"/></beans>123456789101112131415161718
上面多了一個baseService的bean,這個bean沒有指定class物件,但是多了一個abstract="true"的屬性,表示這個bean是抽象的,abstract為true的bean在spring容器中不會被建立,只是會將其當做bean定義的模板,而serviceB和serviceC的定義中多了一個屬性parent,用來指定當前bean的父bean名稱,此處是baseService,此時serviceB和serviceC會繼承baseService中定義的配置資訊。
來個測試用例看一下效果:
@Testpublic 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));}1234567
執行輸出:
serviceB:ServiceB{name='路人甲Java', serviceA=com.javacode2018.lesson001.demo12.ServiceA@222114ba}serviceC:ServiceC{name='路人甲Java', serviceA=com.javacode2018.lesson001.demo12.ServiceA@222114ba}12
輸出和上面案例的輸出基本一致。
但是這次bean xml中bean的定義簡化了很多,將公共的bean配置提取出來了,透過parent屬性來配置需要繼承的bean。
子bean中也可以重新定義父bean中已經定義好的配置,這樣子配置會覆蓋父bean中的配置資訊,我們將extendBean.xml中serviceC的定義改一下:
<bean id="serviceC" class="com.javacode2018.lesson001.demo12.ServiceC" parent="baseService">
<property name="name" value="歡迎和【路人甲Java】一起學些spring!"/></bean>123
執行extendBean輸出:
serviceB:ServiceB{name='路人甲Java', serviceA=com.javacode2018.lesson001.demo12.ServiceA@222114ba}serviceC:ServiceC{name='歡迎和【路人甲Java】一起學些spring!', serviceA=com.javacode2018.lesson001.demo12.ServiceA@222114ba}12
從輸出中可以看出serviceC中的name對父bean中name的值進行了覆蓋。
我們再來從容器中獲取一下baseService,如下:
System.out.println(context.getBean("baseService"));1
執行輸出:
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)123
會報BeanIsAbstractException異常,因為baseService是抽象的,不能夠建立這個bean例項。
總結
bean元素的abstract屬性為true的時候可以定義某個bean為一個抽象的bean,相當於定義了一個bean模板,spring容器並不會建立這個bean,從容器中查詢abstract為true的bean的時候,會報錯BeanIsAbstractException異常
bean元素的parent屬性可以指定當前bean的父bean,子bean可以繼承父bean中配置資訊,也可以自定義配置資訊,這樣可以覆蓋父bean中的配置
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/30239065/viewspace-2731827/,如需轉載,請註明出處,否則將追究法律責任。