五、Bean的自动装配
Spring IOC容器可以自动装配Bean,需要在bean的autowire属性里指定自动装配的模式。
<?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.stuspring.autowire.Address"
p:city="BeiJing" p:street="HuiLongGuan">
</bean>
<bean id="car" class="com.stuspring.autowire.Car" p:brand="AuDi"
p:price="400000">
</bean>
<bean id="car2" class="com.stuspring.autowire.Car" p:brand="AuDi"
p:price="400000">
</bean>
<bean id="person1" class="com.stuspring.autowire.Person" p:name="Tom"
p:address-ref="address" p:car-ref="car"/>
<!--使用autowire属性指定自动装配的方式
byName 根据bean的id和bean的setter风格属性进行自动装配,如果有匹配的,则自动装配。
byType 根据类型自动装配。car和car2都满足,byType会报错。
确定:不够灵活,实际开发中很少使用自动装配。
-->
<bean id="person2" class="com.stuspring.autowire.Person" p:name="Lily"
autowire="byName">
</bean>
</beans>
六、Bean之间的关系
6.1 Bean的继承关系
一个Address类,有city和Street 2个属性。
package com.stuspring.relation;
/**
* Created by bee on 17/4/25.
*/
public class Address {
private String city;
private String street;
//省略setter、getter和toString方法
}
配置2个Bean:
<bean id="address" class="com.stuspring.relation.Address"
p:city="BeiJing" p:street="WuDaoKou"/>
<bean id="address2" class="com.stuspring.relation.Address"
p:city="BeiJing" p:street="XiZhiMen"/>
address2和address除了street属性不一样,其他都相同,可以使用bean的集成属性来简化配置:
<bean id="address" class="com.stuspring.relation.Address"
p:city="BeiJing" p:street="WuDaoKou"/>
<bean id="address2" p:street="XiZhiMen" parent="address"/>
Spring允许继承bean的配置,被继承的bean称为父bean,继承父bean的bean称为子bean。
子bean从父bean中继承配置,包括bean的属性配置
子bean也可以覆盖父bean继承过来的配置
父bean可以作为配置模板,也可以作为bean的实例。若只想把父bean作为模板,可以设置
<bean>
的abstract属性为true,这样spring就不会实例化这个bean可以忽略父bean的class属性,让子bean指定自己的类,共享相同的配置,此时abstract属性必须为true。
抽象bean例子:
<bean id="address" class="com.stuspring.autowire.Address"
p:city="BeiJing" abstract="true"/>
<bean id="address2" p:street="XiZhiMen" parent="address"/>
<!-- 覆盖父bean的配置-->
<bean id="address3" p:city="NanJing" p:street="DaFengChang"
parent="address"/>
忽略父bean的class属性:
<bean id="address" p:city="BeiJing^" p:street="XiZhiMen" abstract="true"/>
<bean id="address2" class="com.stuspring.autowire.Address" parent="address"/>
<!-- 覆盖父bean的配置-->
<bean id="address3" class="com.stuspring.autowire.Address" p:city="NanJing" p:street="DaFengChang"
parent="address"/>
6.2 Bean的依赖关系
Spring允许用户通过depends-on属性设定bean前置的依赖bean,前置依赖的bean会在本bean实例化之前创建好。
如果前置依赖多个bean,可以通过逗号、空格的方式配置bean的名称。
<bean id ="car" class="com.stuspring.autowire.Car" p:brand="Ford"
p:price="200000"/>
<bean id="person" class="com.stuspring.autowire.Person"
depends-on="car"/>
bean person依赖car,car不存在person无法实例化。
七、Bean作用域
定义一个bean:
<bean id="car" class="com.stuspring.autowire.Car"/>
测试:
ApplicationContext ctx=new ClassPathXmlApplicationContext
("beans-scope.xml");
Car car1= (Car) ctx.getBean("car");
Car car2= (Car) ctx.getBean("car");
System.out.println(car1==car2);
打印结果:
true
car1和car2是同一个对象。
把作用域改为prototype:
<bean id="car" class="com.stuspring.autowire.Car" scope="prototype"/>
再次比较car1和car2,运行结果:
false
作用域改成prototype后,car1和car2不再是同一个对象。
在Spring中,可以在<Bean>
元素的scope属性里设置Bean的作用域,默认情况下Spring只为每个在IOC容器中声明的Bean创建唯一一个实例,整个IOC容器范围内都能共享该实例。
类别 | 说明 |
---|---|
singleton | 在Spring的IOC容器中仅存在一个Bean实例,以单例的方式存在 |
prototype | 每次调用getBean()都会返回一个新的实例 |
request | 每次Http请求都会创建一个Bean,该作用域仅适用于WebApplicationContext属性 |
session | 同一个HTTP SESSION共享一个BEAN,不同的HTTP SESSION使用不同的BEAN。该作用域仅适用于WebApplicationContext属性。 |
八、使用外部属性文件
配置文件里配置Bean时,有时需要在Bean的配置里混入系统部署的细节信息,比如文件路径、数据源配置信息等,这些部署细节需要和Bean配置相分离。
Spring提供了一个PropertyPlaceholderConfigurer的BeanFactory后置处理器,这个处理器允许用户将Bean配置的部分内容外移到属性文件中。在Bean配置文件里使用形式为${var}的变量,PropertyPlaceholderConfigurer从属性文件里加载属性并使用这些属性来替换变量。
<bean id="dataSource"
class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="user" value="root"/>
<property name="password" value="123456"/>
<property name="driverClass" value="com.mysql.jdbc.Driver"/>
<property name="jdbcUrl" value="jdbc:mysql:///blog"/>
</bean>
测试:
package com.stuspring.properties;
import javax.sql.DataSource;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* Created by bee on 17/4/25.
*/
public class Main {
public static void main(String[] args) {
ApplicationContext ctx=new ClassPathXmlApplicationContext
("beans-properties.xml");
DataSource dataSources= (DataSource) ctx.getBean("dataSource");
System.out.println(dataSources);
}
}
resource目录下新建db.properties,写入连接数据库的配置信息:
jdbc.username=root
jdbc.password=123456
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/blog?useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull
在Spring Bean的配置文件中引入context命名空间。重新配置:
<bean id="dataSource2" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="user" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<property name="driverClass" value="${jdbc.driverClassName}"/>
<property name="jdbcUrl" value="${jdbc.url}"/>
</bean>
测试连接是否成功:
ApplicationContext ctx=new ClassPathXmlApplicationContext
("beans-properties.xml");
DataSource dataSource= (DataSource) ctx.getBean("dataSource");
DataSource dataSource2= (DataSource) ctx.getBean("dataSource2");
System.out.println(dataSource);
System.out.println(dataSource2);
Connection conn=dataSource.getConnection();
System.out.println(conn);