二、Bean的配置
配置Bean就是告诉Spring的IOC容器将要去管理的对象
1. 配置bean的方式
1.1 传统的XML配置方式
Person.java
public class Person {
private String name;
private int age;
private double money;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public double getMoney() {
return money;
}
public void setMoney(double money) {
this.money = money;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", money=" + money +
'}';
}
}
applicationContext.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--
bean标签:让spring创建一个对象并放置在IOC容器内
属性:
id : 标签该bean对象的唯一标识符,bean的名称,不能重复的
class : 需要创建对象的类型的全限定名,spring通过反射机制创建该类的对象(要求:该类必须拥有无参构造方法)
-->
<bean id="person1" class="com.newcapec.bean.Person"/>
<bean id="person2" class="com.newcapec.bean.Person">
</beans>
属性解析:
- id : bean的名称
在IOC容器中必须是唯一的
若id没有指定,Spring自动将类全限定性类名作为bean的名字 - class : java类的全限定名称
BeanTest.java
public class BeanTest {
@Test
public void test(){
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
Person p1 = (Person) ac.getBean("person1");
System.out.println(p1);
Person p2 = (Person) ac.getBean("person2");
System.out.println(p2);
System.out.println(p1 == p2);
}
}
1.2 基于Java注解的配置
请关注后面的章节
1.3 基于类的Java Config
请关注后面的章节
2. 实例化Bean的方式
2.1 通过构造方法实例化Bean
Spring IoC容器即能使用默认空构造方法也能使用有参数构造,通过反射机制来实例化Bean对象。
2.2 通过工厂实例化Bean
请关注后面的章节
2.3 FactoryBean实例化Bean
请关注后面的章节
3. Spring容器
Spring提供了两种类型的IOC容器实现
3.1 BeanFactory
BeanFactory是Spring框架的基础设施,面向Spring本身,底层父接口
3.2 ApplicationContext
提供了更多的高级特性,它主要面向于Spring框架的使用者,是BeanFactory的子接口
3.3 ApplicationContext的主要实现类
- ClassPathXmlApplicationContext:从类路径上加载配置文件
- FileSystemXmlApplicationContext:从文件系统中加载配置文件
- WebApplicationContext:专门为WEB应用而准备的,它允许从相对于WEB根目录的路径中完成初始化工作
3.4 从容器中获取Bean
- getBean(String name)方法,通过Bean的id从容器中获取Bean对象
- getBean(Class requiredType)方法,通过Bean的Class类型从容器中获取Bean对象
- getBean(String name, Class requiredType)方法,通过Bean的id和Class类型从容器中获取Bean对象
注意:当IOC容器中存放有多个此类型的对象时,不能通过Class类型来获取Bean对象,推荐使用bean的id来获取
BeanTest.java
public class BeanTest {
@Test
public void testGetBean(){
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
//1.参数为字符串类型
Person p1 = (Person) ac.getBean("person1");
System.out.println(p1);
//2.参数为Class类型
Person person = ac.getBean(Person.class);
System.out.println(person);
//3.参数为字符串类型+Class类型
Person p2 = ac.getBean("person2", Person.class);
System.out.println(p2);
System.out.println(p1 == p2);
}
}
4. 依赖注入
4.1 基于属性注入
- 通过setter方法注入Bean的属性值或依赖的对象
- 属性注入使用
<property>
标签,使用name属性指定Bean的属性名称,value属性或<value>
子标签指定属性值 - 属性注入是实际应用中最常用的注入方式
applicationContext.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 通过set方法注入属性值 -->
<bean id="person" class="com.newcapec.bean.Person">
<!--
property标签:表示通过属性的set方法为属性赋值,也叫做依赖注入
属性:
name : 对象中的属性名称
value : 属性值
-->
<property name="name" value="张三"/>
<property name="age" value="20"/>
<property name="money">
<value>3600.5</value>
</property>
</bean>
</beans>
public class DiTest {
@Test
public void testSet(){
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
Person person = ac.getBean("person", Person.class);
System.out.println(person);
}
}
4.2 基于构造方法注入
通过构造方法注入Bean的属性值或依赖的对象,它保证了Bean对象在实例化后就可以使用
Car.java
public class Car {
private String name;
private String type;
private double price;
private int doors;
public Car(String name, String type, double price, int doors) {
this.name = name;
this.type = type;
this.price = price;
this.doors = doors;
}
public Car(String name, String type, int doors) {
this.name = name;
this.type = type;
this.doors = doors;
}
public Car(String name, String type, double price) {
this.name = name;
this.type = type;
this.price = price;
}
public Car(String n, String t) {
this.name = n;
this.type = t;
}
@Override
public String toString() {
return "Car{" +
"name='" + name + '\'' +
", type='" + type + '\'' +
", price=" + price +
", doors=" + doors +
'}';
}
}
applicationContext.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 通过构造方法注入属性值 -->
<bean id="car1" class="com.newcapec.bean.Car">
<!--
constructor-arg : 表示创建该类型的对象时,使用的构造方法的参数
属性:
value : 构造方法的参数值
index : 构造方法参数的索引
type : 构造方法参数的类型
name : 构造方法参数的名称
-->
<constructor-arg value="宝马"/>
<constructor-arg value="轿车"/>
<constructor-arg value="360000"/>
<constructor-arg value="4"/>
</bean>
</beans>
- 按索引匹配构造方法参数
<bean id="car2" class="com.newcapec.bean.Car">
<constructor-arg value="越野" index="1"/>
<constructor-arg value="奔驰" index="0"/>
<constructor-arg value="4" index="3"/>
<constructor-arg value="560000" index="2"/>
</bean>
- 按类型匹配构造方法参数
<bean id="car3" class="com.newcapec.bean.Car">
<constructor-arg value="大众" type="java.lang.String"/>
<constructor-arg value="商务车" type="java.lang.String"/>
<constructor-arg value="290000" type="double"/>
</bean>
- 按参数名称匹配构造方法参数
<bean id="car4" class="com.newcapec.bean.Car">
<constructor-arg value="电动车" name="t"/>
<constructor-arg value="特斯拉" name="n"/>
</bean>
如果该类中有多个构造方法,通过index、type或name对构造方法进行精确选取
public class DiTest {
@Test
public void testConstructor(){
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
Car car1 = ac.getBean("car1", Car.class);
System.out.println(car1);
Car car2 = ac.getBean("car2", Car.class);
System.out.println(car2);
Car car3 = ac.getBean("car3", Car.class);
System.out.println(car3);
Car car4 = ac.getBean("car4", Car.class);
System.out.println(car4);
}
}
5. 注入属性值
5.1 字面值
- 可用字符串表示的值,可以通过
<value>
标签或value属性进行注入 - 基本数据类型及包装类类型,String等类型都可以采取字面值注入的方式。Spring会将字符串自动转换为相应的数据类型
- 如果字面值中包含特殊字符,可以使用
<![CDATA[]]>
把字面值包裹起来
<bean id="p" class="com.newcapec.bean.Person">
<property name="name">
<value><![CDATA[1<2]]></value>
</property>
</bean>
5.2 引用其他的bean
组成应用程序的Bean经常需要相互协作以完成应用程序的功能。要使Bean能够相互访问,就必须在Bean配置文件中指定对Bean的引用
Customer.java
public class Customer {
private String username;
private String password;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "Customer{" +
"username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
}
Order.java
public class Order {
private String orderNum;
private double price;
/**
* 自定义类型的属性
*/
private Customer customer;
public String getOrderNum() {
return orderNum;
}
public void setOrderNum(String orderNum) {
this.orderNum = orderNum;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public Customer getCustomer() {
return customer;
}
public void setCustomer(Customer customer) {
this.customer = customer;
}
@Override
public String toString() {
return "Order{" +
"orderNum='" + orderNum + '\'' +
", price=" + price +
", customer=" + customer +
'}';
}
}
<property>
标签中的ref属性
<bean id="customer1" class="com.newcapec.bean.Customer">
<property name="username" value="tom"/>
<property name="password" value="123456"/>
</bean>
<bean id="order1" class="com.newcapec.bean.Order">
<property name="orderNum" value="20190624001"/>
<property name="price" value="1299"/>
<!-- 通过ref属性来注入属性值:其中ref属性的值为其他bean的name-->
<property name="customer" ref="customer1"/>
</bean>
<property>
标签中的<ref>
子标签
<bean id="customer2" class="com.newcapec.bean.Customer">
<property name="username" value="jerry"/>
<property name="password" value="654321"/>
</bean>
<bean id="order2" class="com.newcapec.bean.Order">
<property name="orderNum" value="20190624002"/>
<property name="price" value="3650"/>
<!-- 通过ref子标签来注入其他的bean对象-->
<property name="customer">
<ref bean="customer2"/>
</property>
</bean>
<property>
标签中的<bean>
子标签,定义一个内部Bean
<bean id="order3" class="com.newcapec.bean.Order">
<property name="orderNum" value="20190624003"/>
<property name="price" value="99.9"/>
<property name="customer">
<!-- 内置bean-->
<bean class="com.newcapec.bean.Customer">
<property name="username" value="chris"/>
<property name="password" value="111111"/>
</bean>
</property>
</bean>
注意:内部Bean不能使用在任何其他地方
@Test
public void testRef(){
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
Order order1 = ac.getBean("order1", Order.class);
System.out.println(order1);
Order order2 = ac.getBean("order2", Order.class);
System.out.println(order2);
Order order3 = ac.getBean("order3", Order.class);
System.out.println(order3);
}
5.3 集合属性
在Spring中可以通过一组内置的xml标签 (例如: <list>
,<set>
,<map>
等) 来配置集合属性
Course.java
public class Course {
private int id;
private String cname;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getCname() {
return cname;
}
public void setCname(String cname) {
this.cname = cname;
}
@Override
public String toString() {
return "Course{" +
"id=" + id +
", cname='" + cname + '\'' +
'}';
}
}
Student.java
public class Student {
private int id;
private String name;
private List<Course> courseList;
private Integer[] ids;
private Set<String> stringSet;
private Map<String, Course> courseMap;
private Properties props;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<Course> getCourseList() {
return courseList;
}
public void setCourseList(List<Course> courseList) {
this.courseList = courseList;
}
public Integer[] getIds() {
return ids;
}
public void setIds(Integer[] ids) {
this.ids = ids;
}
public Set<String> getStringSet() {
return stringSet;
}
public void setStringSet(Set<String> stringSet) {
this.stringSet = stringSet;
}
public Map<String, Course> getCourseMap() {
return courseMap;
}
public void setCourseMap(Map<String, Course> courseMap) {
this.courseMap = courseMap;
}
public Properties getProps() {
return props;
}
public void setProps(Properties props) {
this.props = props;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", courseList=" + courseList +
", ids=" + Arrays.toString(ids) +
", stringSet=" + stringSet +
", courseMap=" + courseMap +
", props=" + props +
'}';
}
}
5.3.1 List集合
配置java.util.List类型的属性,需要指定<list>
标签,在标签里包含一些元素。这些标签可以通过<value>
指定简单的常量值,通过<ref>
指定对其他bean的引用
<bean id="course1" class="com.newcapec.bean.Course">
<property name="id" value="10"/>
<property name="cname" value="Java语言"/>
</bean>
<bean id="course2" class="com.newcapec.bean.Course">
<property name="id" value="20"/>
<property name="cname" value="Oracle数据库"/>
</bean>
<bean id="course3" class="com.newcapec.bean.Course">
<property name="id" value="30"/>
<property name="cname" value="Spring框架"/>
</bean>
<bean id="student" class="com.newcapec.bean.Student">
<property name="id" value="1001"/>
<property name="name" value="小明"/>
<!-- list集合:list子标签,表示配置的属性类型为java.util.List-->
<property name="courseList">
<list>
<ref bean="course1"/>
<ref bean="course2"/>
<ref bean="course3"/>
</list>
</property>
</bean>
@Test
public void testCollection(){
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
Student student = ac.getBean("student",Student.class);
System.out.println(student);
}
5.3.2 Object[]数组
配置数组类型的属性,使用<array>
标签
<bean id="student" class="com.newcapec.bean.Student">
<property name="id" value="1001"/>
<property name="name" value="小明"/>
<!-- 数组:array子标签-->
<property name="ids">
<array>
<value>10</value>
<value>20</value>
<value>30</value>
<value>40</value>
</array>
</property>
</bean>
5.3.3 Set集合
配置java.util.Set类型的属性,使用<set>
标签
<bean id="student" class="com.newcapec.bean.Student">
<property name="id" value="1001"/>
<property name="name" value="小明"/>
<!-- set集合:set子标签-->
<property name="stringSet">
<set>
<value>hello</value>
<value>goodbye</value>
<value>how are you</value>
</set>
</property>
</bean>
5.3.4 Map集合
java.util.Map通过<map>
标签定义,<map>
标签里可以使用多个<entry>
作为子标签。每个<entry>
中包含一个键和一个值。简单类型使用key和value属性来定义,Bean引用通过key-ref和value-ref属性定义
<bean id="student" class="com.newcapec.bean.Student">
<property name="id" value="1001"/>
<property name="name" value="小明"/>
<!-- map集合:map子标签-->
<property name="courseMap">
<map>
<!--
entry标签:表示Map集合中的一组键值对
key : 表示Map集合中的键为字面值
key-ref : 表示Map集合中的键为自定义类型
value : 表示Map集合中的值为字面值
value-ref : 表示Map集合中的值为自定义类型
-->
<entry key="one" value-ref="course3"/>
<entry key="two" value-ref="course1"/>
</map>
</property>
</bean>
5.3.5 Properties
使用<props>
定义java.util.Properties,该标签使用多个<prop>
作为子标签,每个<prop>
标签必须定义key属性
<bean id="student" class="com.newcapec.bean.Student">
<property name="id" value="1001"/>
<property name="name" value="小明"/>
<!-- Properties类型的属性 -->
<property name="props">
<props>
<!-- prop标签,表示Properties集合中的一个键值对,key属性对应的键,prop开始标签与结束标签之后的区域填写值-->
<prop key="hello">你好</prop>
<prop key="goodbye">再见</prop>
</props>
</property>
</bean>
5.3.6 单例集合
单例集合: 供多个Bean使用。使用<util>
标签,将集合定义在Bean的外部
注意:需要导入util命名空间和标签规范
xmlns:util="http://www.springframework.org/schema/util"
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd
<!-- 外部集合:多个集合属性可同时引用 -->
<util:list id="mylist">
<ref bean="car1"/>
<ref bean="car2"/>
</util:list>
5.4 p命名空间
- 为了简化XML文件的配置,越来越多的XML文件采用属性而非子标签配置信息
- 从Spring2.5版本开始引入了一个新的p命名空间,可以通过
<bean>
标签属性的方式配置Bean的属性 - 使用p命名空间后,基于XML的配置方式将进一步简化
xmlns:p="http://www.springframework.org/schema/p"
Dept.java
public class Dept {
private int deptno;
private String dname;
private String loc;
public int getDeptno() {
return deptno;
}
public void setDeptno(int deptno) {
this.deptno = deptno;
}
public String getDname() {
return dname;
}
public void setDname(String dname) {
this.dname = dname;
}
public String getLoc() {
return loc;
}
public void setLoc(String loc) {
this.loc = loc;
}
@Override
public String toString() {
return "Dept{" +
"deptno=" + deptno +
", dname='" + dname + '\'' +
", loc='" + loc + '\'' +
'}';
}
}
Emp.java
public class Emp {
private int empno;
private String ename;
/**
* 关系属性
*/
private Dept dept;
public int getEmpno() {
return empno;
}
public void setEmpno(int empno) {
this.empno = empno;
}
public String getEname() {
return ename;
}
public void setEname(String ename) {
this.ename = ename;
}
public Dept getDept() {
return dept;
}
public void setDept(Dept dept) {
this.dept = dept;
}
@Override
public String toString() {
return "Emp{" +
"empno=" + empno +
", ename='" + ename + '\'' +
", dept=" + dept +
'}';
}
}
applicationContext.xml
<!-- 通过p命名空间的方式,来简化依赖注入 -->
<bean id="dept" class="com.newcapec.bean.Dept" p:deptno="10" p:dname="研发部" p:loc="郑州"/>
<bean id="emp" class="com.newcapec.bean.Emp" p:empno="8000" p:ename="张三" p:dept-ref="dept"/>
DiTest.java
@Test
public void testPNameSpace(){
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
Emp emp = ac.getBean("emp", Emp.class);
System.out.println(emp);
}
5.5 autowire自动装配
SpringIOC容器可以自动装配Bean。需要做的仅仅是在<bean>
标签的autowire属性里指定自动装配的模式,autowire属性的取值如下:
- no:不进行自动装配
- constructor:根据构造方法进行装配,不推荐使用
- byType:根据当前bean中属性的类型与IOC容器中管理的bean的类型进行匹配
如果类型一致则进行自动装配
如果类型不一致不进行装配
注意:如果IOC容器中有一个以上的bean类型与之匹配,则抛出异常 - byName:根据bean的唯一标识符(id)和当前bean属性名称进行匹配
如果名称相同则进行自动装配
如果名称不同则不进行装配 - default:根据
<beans>
标签中的default-autowire属性,进行配置
applicationContext.xml
<!-- 自动装配,自动注入 -->
<bean id="department" class="com.newcapec.bean.Dept" p:deptno="20" p:dname="人力部" p:loc="北京"/>
<bean id="employee" class="com.newcapec.bean.Emp" p:empno="8001" p:ename="李四" autowire="default"/>
DiTest.java
@Test
public void testAutowire(){
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
Emp emp = ac.getBean("employee", Emp.class);
System.out.println(emp);
}
XML配置里的Bean自动装配的缺点
- 在bean配置文件里设置autowire属性进行自动装配将会装配bean的所有属性。然而,若只希望装配个别属性时,autowire属性就不够灵活了
- autowire属性要么根据类型自动装配,要么根据名称自动装配,不能两者兼而有之
- 一般情况下,在实际的项目中很少使用自动装配功能,因为和自动装配功能所带来的好处比起来,明确清晰的配置文档更有说服力一些
6. 使用外部属性文件
加入命名空间和标签规范
xmlns:context="http://www.springframework.org/schema/context"
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
引入外部属性文件
<!-- 读取外部的资源文件-->
<context:property-placeholder location="classpath:db.properties"/>
public class MyDataSource {
private String driver;
private String url;
private String username;
private String password;
public String getDriver() {
return driver;
}
public void setDriver(String driver) {
this.driver = driver;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "MyDataSource{" +
"driver='" + driver + '\'' +
", url='" + url + '\'' +
", username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
}
通过表达式访问属性文件中的数据
<bean id="myDataSource" class="com.newcapec.bean.MyDataSource">
<property name="driver" value="${jdbc.oracle.driver}"/>
<property name="url" value="${jdbc.oracle.url}"/>
<property name="username" value="${jdbc.oracle.username}"/>
<property name="password" value="${jdbc.oracle.password}"/>
</bean>
测试
public class ReadPropertiesTest {
@Test
public void test(){
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
MyDataSource myDataSource = ac.getBean("myDataSource", MyDataSource.class);
System.out.println(myDataSource);
}
}
7. Bean的作用域
在Spring中,可以在<bean>
标签的scope属性里设置Bean的作用域,其取值如下:
- singleton : 单例模式(默认值),IOC容器在初始化时创建bean的实例,在整个容器的生命周期中只创建一个bean实例
- prototype : 原型的,IOC容器在初始化时不创建bean的实例,而是在每次使用时都创建一个新的bean的实例
Book.java
public class Book {
private int id;
private String name;
private double price;
private String author;
public Book(){
System.out.println("Book对象被创建....");
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
@Override
public String toString() {
return "Book{" +
"id=" + id +
", name='" + name + '\'' +
", price=" + price +
", author='" + author + '\'' +
'}';
}
}
applicationContext.xml
<!-- bean的作用域-->
<bean id="book" class="com.newcapec.bean.Book" p:id="101" p:name="西游记"
p:price="98.5" p:author="吴承恩" scope="singleton"/>
<bean id="book" class="com.newcapec.bean.Book" p:id="101" p:name="西游记"
p:price="98.5" p:author="吴承恩" scope="prototype"/>
测试
public class ScopeTest {
@Test
public void test(){
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
System.out.println("------------分割线--------------");
Book book1 = ac.getBean("book",Book.class);
System.out.println(book1);
Book book2 = ac.getBean("book",Book.class);
System.out.println(book2);
System.out.println(book1 == book2);
}
}
8. Bean的生命周期
- SpringIOC容器可以管理Bean的生命周期,Spring允许在Bean生命周期的特定点执行定制的任务
- SpringIOC容器对bean的生命周期进行管理的过程
- 通过构造构造或工厂方法创建bean对象
- 为bean的属性设置值和对其他bean的引用
- 调用bean的初始化方法
- bean可以使用了
- 当容器关闭时,调用bean的销毁方法
- 在bean的声明里设置init-method和destroy-method属性,为bean指定初始化和销毁方法
Dog.java
public class Dog {
private String name;
private String owner;
private int age;
public Dog() {
System.out.println("Dog对象被创建...");
}
public String getName() {
return name;
}
public void setName(String name) {
System.out.println("调用setName方法....");
this.name = name;
}
public String getOwner() {
return owner;
}
public void setOwner(String owner) {
System.out.println("调用setOwner方法....");
this.owner = owner;
}
public int getAge() {
return age;
}
public void setAge(int age) {
System.out.println("调用setAge方法....");
this.age = age;
}
public void init(){
System.out.println("Dog对象的初始化方法...");
}
public void destroy(){
System.out.println("Dog对象的销毁方法...");
}
@Override
public String toString() {
return "Dog{" +
"name='" + name + '\'' +
", owner='" + owner + '\'' +
", age=" + age +
'}';
}
}
applicationContext.xml
<bean id="dog" class="com.newcapec.bean.Dog" p:name="旺财" p:owner="小明" p:age="5"
init-method="init" destroy-method="destroy"/>
测试
public class LifeCycleTest {
@Test
public void test(){
System.out.println("-------容器初始化阶段---------");
ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
System.out.println("-------对象使用阶段---------");
Dog dog = ac.getBean("dog",Dog.class);
System.out.println(dog);
System.out.println("-------容器关闭阶段---------");
//手动关闭容器
ac.close();
}
}
9. Bean之间的关系
9.1 继承关系
- Spring允许继承bean的配置,被继承的bean称为父bean。继承这个父bean的bean称为子bean
- 子bean从父bean中继承配置, 包括bean的属性配置
- 子bean也可以覆盖从父bean继承过来的配置
- 父bean可以作为配置模板,也可以作为bean实例。若只想把父bean作为模板,可以设置
<bean>
的abstract属性为true,这样Spring将不会实例化这个bean - 并不是
<bean>
元素里的所有属性都会被继承。比如: autowire,abstract等 - 也可以忽略父bean的class属性,让子bean指定自己的类,而共享相同的属性配置。但此时abstract必须设为true
Computer.java
public class Computer {
private String name;
private String type;
private double price;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
@Override
public String toString() {
return "Computer{" +
"name='" + name + '\'' +
", type='" + type + '\'' +
", price=" + price +
'}';
}
}
applicationContext.xml
<!-- bean之间的继承关系 -->
<bean id="parentComputer" class="com.newcapec.bean.Computer">
<property name="name" value="联想"/>
<property name="type" value="台式机"/>
<property name="price" value="4500"/>
</bean>
<bean id="childComputer" class="com.newcapec.bean.Computer" parent="parentComputer">
<property name="name" value="戴尔"/>
</bean>
测试
public class RelationTest {
@Test
public void testExtends(){
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
Computer childComputer = ac.getBean("childComputer", Computer.class);
System.out.println(childComputer);
}
}
9.2 依赖关系
- Spring允许用户通过depends-on属性设定bean前置依赖的bean,前置依赖的bean会在本bean实例化之前创建好
- 如果前置依赖于多个bean,则可以通过逗号或空格的方式配置bean的名称
Address.java
public class Address {
public Address() {
System.out.println("Address对象创建了....");
}
}
User.java
public class User {
private Address address;
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
public User() {
System.out.println("User对象创建了....");
}
@Override
public String toString() {
return "User{" +
"address=" + address +
'}';
}
}
applicationContext.xml
<!-- bean之间的依赖关系 -->
<bean id="user" class="com.newcapec.bean.User" p:address-ref="address" depends-on="address"/>
<bean id="address" class="com.newcapec.bean.Address"/>
测试
public class RelationTest {
@Test
public void testDependsOn(){
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
User user = ac.getBean("user", User.class);
System.out.println(user);
}
}
10. 通过工厂实例化Bean
10.1 静态工厂
- 调用静态工厂方法创建bean是将对象创建的过程封装到静态方法中。当客户端需要对象时,只需要简单地调用静态方法,而无需关心创建对象的细节
- 要声明通过静态方法创建的bean,需要在bean的class属性里指定拥有该工厂的方法的类,同时在factory-method属性里指定工厂方法的名称。最后,使用
<constrctor-arg>
元素为该方法传递方法参数
Cat.java
public class Cat {
private String name;
private int age;
public Cat() {
}
public Cat(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Cat{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
CatStaticFactory.java
/**
* 一个用于创建cat对象的静态工厂
*/
public class CatStaticFactory {
/**
* 提供一个创建对象的静态方法
*/
public static Cat getInstance(String name, int age){
return new Cat(name, age);
}
}
applicationContext.xml
<!-- 静态工厂-->
<bean id="cat1" class="com.newcapec.factory.CatStaticFactory" factory-method="getInstance">
<constructor-arg value="汤姆猫"/>
<constructor-arg value="2"/>
</bean>
测试
public class FactoryTest {
@Test
public void testStaticFactory(){
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
Cat cat = ac.getBean("cat1", Cat.class);
System.out.println(cat);
}
}
10.2 实例工厂
- 将对象的创建过程封装到另外一个对象实例的方法里。当客户端需要请求对象时,只需要简单的调用该实例方法而不需要关心对象的创建细节
- 要声明通过实例工厂方法创建的bean,在
<bean>
的factory-bean属性里指定拥有该工厂方法的bean,并且factory-method属性里指定该工厂方法的名称。最后,使用<construtor-arg>
标签为工厂方法传递方法参数
CatInstanceFactory.java
/**
* 一个用于创建cat对象的实例工厂
*/
public class CatInstanceFactory {
/**
* 提供一个创建对象的非静态方法
*/
public Cat getInstance(String name, int age){
return new Cat(name, age);
}
}
applicationContext.java
<!-- 实例工厂-->
<bean id="instanceFactory" class="com.newcapec.factory.CatInstanceFactory"/>
<bean id="cat2" factory-bean="instanceFactory" factory-method="getInstance">
<constructor-arg value="波斯猫"/>
<constructor-arg value="3"/>
</bean>
测试
public class FactoryTest {
@Test
public void testInstanceFactory(){
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
Cat cat = ac.getBean("cat2", Cat.class);
System.out.println(cat);
}
}
11. FactoryBean实例化Bean
- Spring中有两种类型的bean,一种是普通bean,另一种是工厂bean,即FactoryBean
- 工厂bean跟普通bean不同,其返回的对象不是指定类的一个实例,其返回的是该工厂bean的getObject方法所返回的对象
CatFactoryBean.java
public class CatFactoryBean implements FactoryBean<Cat> {
private int age;
private String name;
public void setAge(int age) {
this.age = age;
}
public void setName(String name) {
this.name = name;
}
/**
* 获取对象
*/
@Override
public Cat getObject() throws Exception {
return new Cat(name, age);
}
/**
* 生成对象的Class类型
*/
@Override
public Class<?> getObjectType() {
return Cat.class;
}
/**
* 设置该对象是否为单例模式
*/
@Override
public boolean isSingleton() {
return true;
}
}
applicationContext.xml
<!-- FactoryBean配置bean -->
<bean id="cat3" class="com.newcapec.factory.CatFactoryBean">
<property name="name" value="加菲猫"/>
<property name="age" value="5"/>
</bean>
测试
public class FactoryTest {
@Test
public void testFactoryBean(){
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
Cat cat = ac.getBean("cat3", Cat.class);
System.out.println(cat);
}
}