Bean之间的关系有两种:继承和依赖
继承
Spring 允许继承 bean 的配置, 被继承的 bean 称为父 bean. 继承这个父 Bean 的 Bean 称为子 Bean
子 Bean 从父 Bean 中继承配置, 包括 Bean 的属性配置
子 Bean 也可以覆盖从父 Bean 继承过来的配置
父 Bean 可以作为配置模板, 也可以作为 Bean 实例. 若只想把父 Bean 作为模板, 可以设置 的abstract 属性为 true, 这样 Spring 将不会实例化这个 Bean
并不是 元素里的所有属性都会被继承. 比如: autowire, abstract 等.
也可以忽略父 Bean 的 class 属性, 让子 Bean 指定自己的类, 而共享相同的属性配置. 但此时 abstract 必须设为 true
新建一个bean-relation.xml配置文件
XML配置如下:
<?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:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="address" class="com.atguigu.spring.beans.autowire.Address"
p:city="BeiJing" p:street="WuDaoKou"></bean>
<bean id="address2" class="com.atguigu.spring.beans.autowire.Address"
p:city="BeiJing" p:street="DaZhongsi"></bean>
</beans>
调用该Bean
ApplicationContext ctx = new ClassPathXmlApplicationContext("beans-relation.xml");
Address address = (Address) ctx.getBean("address");
System.out.println(address);
Address address2 = (Address) ctx.getBean("address2");
System.out.println(address2);
输出结果:
Address [city=BeiJing, street=WuDaoKou]
Address [city=BeiJing, street=DaZhongsi]
我们可以看到,address和address2的配置其实很相似,并且city的值是相同的
此时我们可以使用parent属性来简化XML配置
XML配置如下
<bean id="address" class="com.atguigu.spring.beans.autowire.Address"
p:city="BeiJing" p:street="WuDaoKou"></bean>
<!-- bean 配置的继承,使用bean 的parent 属性指定继承那个bean的配置 -->
<bean id="address2" p:street="DaZhongsi" parent="address"></bean>
输出结果
Address [city=BeiJing, street=WuDaoKou]
Address [city=BeiJing, street=DaZhongsi]
将Bean作为一个模板,可以使用abstract=”true”,这是一个抽象bean,抽象bean不能被实例化,就是用来被继承的
XML配置如下
<!-- 抽象bean: bean的abstract属性为true的bean,这样的bean不能被IOC容器实例化,只用来被继承配置-->
<bean id="address" class="com.atguigu.spring.beans.autowire.Address"
p:city="BeiJing" p:street="WuDaoKou" abstract="true"></bean>
<bean id="address2" p:street="DaZhongsi" parent="address"></bean>
调用bean
ApplicationContext ctx = new ClassPathXmlApplicationContext("beans-relation.xml");
Address address = (Address) ctx.getBean("address");
System.out.println(address);
Address address2 = (Address) ctx.getBean("address2");
System.out.println(address2);
遇到如下Error
Exception in thread "main" org.springframework.beans.factory.BeanIsAbstractException: Error creating bean with name 'address': Bean definition is abstract
at org.springframework.beans.factory.support.AbstractBeanFactory.checkMergedBeanDefinition(AbstractBeanFactory.java:1273)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:283)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:195)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.j
可见,abstract=”true”修饰的bean无法被实例化
address这个bean就是用来被继承的
若某一个bean的class属性没有指定,则该bean必须是一个抽象bean
XML配置如下
<bean id="address"
p:city="BeiJing" p:street="WuDaoKou"></bean>
<bean id="address2" p:street="DaZhongsi" parent="address"></bean>
编译时遇到如下error
Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'address' defined in class path resource [beans-relation.xml]: Instantiation of bean failed; nested exception is java.lang.IllegalStateException: No bean class specified on bean definition
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1076)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1021)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:504)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:475)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:304)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:300)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:195)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:700)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:760)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:482)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:83)
at com.atguigu.spring.beans.relation.Main.main(Main.java:11)
Caused by: java.lang.IllegalStateException: No bean class specified on bean definition
at org.springframework.beans.factory.support.AbstractBeanDefinition.getBeanClass(AbstractBeanDefinition.java:354)
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:66)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1069)
... 13 more
所以我们必须将address设置为抽象bean
<bean id="address" p:city="BeiJing" p:street="WuDaoKou" abstract="true"></bean>
<bean id="address2" class="com.atguigu.spring.beans.autowire.Address" p:street="DaZhongsi" parent="address"></bean>
输出结果:
Address [city=BeiJing, street=DaZhongsi]
Note:在继承的时候,abstract并没有被继承,否则address2也无法被实例化
并且,bean之间可以继承多层
XML如下:
<bean id="address" p:city="BeiJing" p:street="WuDaoKou" abstract="true"></bean>
<bean id="address2" class="com.atguigu.spring.beans.autowire.Address" parent="address"></bean>
<bean id="address3" class="com.atguigu.spring.beans.autowire.Address" p:street="DaChongsi" parent="address2"></bean>
输出结果:
Address [city=BeiJing, street=WuDaoKou]
Address [city=BeiJing, street=DaChongsi]
Bean之间的依赖关系
Spring 允许用户通过 depends-on 属性设定 Bean 前置依赖的Bean,前置依赖的 Bean 会在本 Bean 实例化之前创建好
如果前置依赖于多个 Bean,则可以通过逗号,空格或的方式配置 Bean 的名称
现我们配置一个Person的bean,要求必须有一个关联的car,换句话说,person这个bean依赖于Car 这个bean
XML配置如下:
<bean id="person" class="com.atguigu.spring.beans.autowire.Person" p:name="Tom" p:address-ref="address2" depends-on="car"></bean>
运行时出错
Exception in thread "main" org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'car' is defined
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:638)
at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1159)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:282)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:195)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:294)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:195)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:700)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:760)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:482)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:83)
at com.atguigu.spring.beans.relation.Main.main(Main.java:12)
需要配置car
<bean id="car" class="com.atguigu.spring.beans.autowire.Car" p:brand="Audi" p:price="300000"></bean>
可正常编译。