3、Bean的生命周期续

1、将上篇的的App1修改如下:

package com.cdtax.beanlife;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.io.ClassPathResource;

public class App1
{
	public static void main(String[] args)
	{
//		ApplicationContext ac = new ClassPathXmlApplicationContext("com/cdtax/beanlife/beans.xml");
		BeanFactory factory = new XmlBeanFactory(new ClassPathResource("com/cdtax/beanlife/beans.xml"));
		
		PersonService ps = (PersonService)factory.getBean("personService");
		
		ps.sayHi();
	}
}

使用bean工厂方式,运行结果:

无参构造函数被调用
setName被调用
setBeanName的arg0: personService
setBeanFactory :org.springframework.beans.factory.xml.XmlBeanFactory@453807: defining beans [personService,personService2,myBeanPostProcessor]; root of factory hierarchy
afterPropertiesSet 被调用
我自己的init()
hello 小明

使用工厂方式,少了很多过程,具体的在工厂方式下bean的生命周期如下图:


2、装配Bean

在Spring容器内拼凑bean叫做装配,装配bean的时候,需要告诉容器哪些bean以及容器如何使用依赖注入将它们配合在一起

基本装配

2.1)使用XML装配

xml是最常见的spring应用系统装配源。
几种spring容器都支持使用xml装配bean,包括:

(1)XmlBeanFactory:调用ClassPathResource载入上下文定义文件(比如applicationContext.xml)
(2)ClassPathXmlApplicationContext:从类路径载入上下文定义文件
(3)XmlWebApplicationContext:从web应用上下文中载入定义文件

上下文定义文件的根元素是<beans>,<beans>有多个<bean>子元素。每个<bean>元素定义了一个bean如何被装配到spring容器中。
<beans>
<bean id="foo" class="...Foo"/>
<bean id="bar" class="...Bar" />
</beans>

对bean的最基本的配置包括bean的ID和它的全称类名。<bean id="foo" class="...Foo"/>bean的id是foo

2.2)基本装配-scope

prototype、singleton、request、session、global-session,spring中的bean缺省情况下是单例模式,始终返回一个实例,若想返回不同的实例的话需要定义成原型模式。

bean的singleton属性告诉上下文该bean是否为单例的,缺省为true,若为false的话,为原型bean。

<bean id="foo" class"...Foo" singleton="false" />

使用原型bean会对性能产生影响,尽量不要设置为prototype,除非有必要

实例化与销毁:spring实例化或销毁bean时,有时需要做一些处理工作,因此spring可以在创建和拆卸bean的时候调用bean的两个生命周期方法
<bean class="...Foo" init-method=""  destory-method="">

如果不通过xml文件配置定制的init和destroy方法,也可以通过注解的方式来配置哪个方法是init-method

@PostConstruct  ——指定init  和@PreDestroy——指定destory

spring也提供了两个接口来实现相同的功能:InitializingBean和DisposableBean。InitializingBean接口提供了一个afterPropertiesSet()方法,DisposableBean接口提供了的story()方法,不推荐使用该接口,它将你的bean和springAPI绑定在一起了。

通过set方法注入依赖:<bean>元素的<property>子元素指明了使用它们的set方法来注入。可以注入任何东西,从基本类型到集合类,甚至是应用系统的bean。

<property>的value,直接配值、ref,对另外一个bean的引用、或者是内部类<bean class="...Bar">

3、如何给集合类型注入值

java中主要的集合有几种:map、set、list / 数组

以下为集合类的注入例子:

package com.cdtax.collection;

public class Employee
{
	private String name;
	private int id;

	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;
	}
	
}

package com.cdtax.collection;

import java.util.List;
import java.util.Map;
import java.util.Set;

public class Department
{
	private String name;
	private String[] empName;
	private List<Employee> empList;
	private Set<Employee> empSets;
	private Map<String,Employee> empMaps;
	
	
	public Map<String, Employee> getEmpMaps()
	{
		return empMaps;
	}
	public void setEmpMaps(Map<String, Employee> empMaps)
	{
		this.empMaps = empMaps;
	}
	public Set<Employee> getEmpSets()
	{
		return empSets;
	}
	public void setEmpSets(Set<Employee> empSets)
	{
		this.empSets = empSets;
	}
	public List<Employee> getEmpList()
	{
		return empList;
	}
	public void setEmpList(List<Employee> empList)
	{
		this.empList = empList;
	}
	public String getName()
	{
		return name;
	}
	public void setName(String name)
	{
		this.name = name;
	}
	public String[] getEmpName()
	{
		return empName;
	}
	public void setEmpName(String[] empName)
	{
		this.empName = empName;
	}
	
}

<?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:context="http://www.springframework.org/schema/context"
		xmlns:tx="http://www.springframework.org/schema/tx"
		xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
				http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
				http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">

<bean id="department" class="com.cdtax.collection.Department">
	<property name="name" value="财务部"></property>
	
	<!-- 给数组注入值 -->
	<property name="empName">
		<list>
			<value>小明</value>
			<value>大明</value>
			<value>肖大明</value>
		</list>
	</property>

	<!-- 给list注入值  list中可以有重复对象-->
	<property name="empList">
		<list>
			<ref bean="emp1"/>
			<ref bean="emp2"/>
			<ref bean="emp2"/>
			<ref bean="emp2"/>
			<ref bean="emp2"/>
		</list>
	</property>
	
	<!-- 给set注入值 set中不存在重复对象 -->
	<property name="empSets">
		<set>
			<ref bean="emp1"/>
			<ref bean="emp2"/>
			<ref bean="emp2"/>
			<ref bean="emp2"/>
		</set>
	</property>
	
	<!-- 给map注入值  map只有key不一样,就可以装配bean-->
	<property name="empMaps">
		<map>
			<entry key="1" value-ref="emp1"/>
			<entry key="2" value-ref="emp2"/>
		</map>
	</property>
</bean>

<bean id="emp1" class="com.cdtax.collection.Employee">
	<property name="name" value="北京"></property>
	<property name="id" value="1"></property>
</bean>
<bean id="emp2" class="com.cdtax.collection.Employee">
	<property name="name" value="上海"></property>
	<property name="id" value="2"></property>
</bean>
</beans>

package com.cdtax.collection;

import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App1
{
	public static void main(String[] args)
	{
		ApplicationContext ac = new ClassPathXmlApplicationContext("com/cdtax/collection/beans.xml");
		
		Department department = (Department)ac.getBean("department");
		System.out.println(department.getName());
		
		for(String empName : department.getEmpName())
		{
			System.out.println(empName);
		}
		
		System.out.println("=========通过list集合取出数据========");
		for(Employee e : department.getEmpList())
		{
			System.out.println("name : " + e.getName());
		}
		
		System.out.println("=========通过Set集合取出数据========");
		for(Employee e : department.getEmpSets())
		{
			System.out.println("name : " + e.getName());
		}
		System.out.println("=========通过map集合取出数据========");
		//1、迭代器
		Map<String,Employee> employees = department.getEmpMaps();
		Iterator it = department.getEmpMaps().keySet().iterator();
		while(it.hasNext())
		{
			String key = (String)it.next();
			Employee emp = employees.get(key);
			System.out.println("key=" + key + "  " +emp.getName());
		}
		//2、简洁方法
		for(Entry<String,Employee> entry1 :department.getEmpMaps().entrySet())
		{
			System.out.println(entry1.getKey() + " : " + entry1.getValue().getName());
		}
		
		
	}
}

执行结果:

财务部
小明
大明
肖大明
=========通过list集合取出数据========
name : 北京
name : 上海
=========通过Set集合取出数据========
name : 北京
name : 上海
=========通过map集合取出数据========
key=1  北京
key=2  上海
1 : 北京
2 : 上海

4、继承配值:

package com.cdtax.inherit;

public class Student
{
	protected String name;
	protected int 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;
	}
	
}

package com.cdtax.inherit;

public class Gradate extends Student
{
	private String degree;

	public String getDegree()
	{
		return degree;
	}

	public void setDegree(String degree)
	{
		this.degree = degree;
	}
	
}

<?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:context="http://www.springframework.org/schema/context"
		xmlns:tx="http://www.springframework.org/schema/tx"
		xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
				http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
				http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">

<!-- 配置一个学生对象 -->
<bean id="student" class="com.cdtax.inherit.Student">
	<property name="name" value="小明"></property>
	<property name="age" value="30"></property>
</bean>

<!-- 配置Gradate对象 -->
<bean id="gradate" parent="student" class="com.cdtax.inherit.Gradate">
	<!-- 如果自己配置属性name,age,则会替换从父对象继承的数据 -->
	
	<property name="name" value="大明"></property>
	<property name="age" value="40"></property>
	<property name="degree" value="学士"></property>
</bean>
</beans>

package com.cdtax.inherit;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App1
{
	public static void main(String[] args)
	{
		ApplicationContext ac = new ClassPathXmlApplicationContext("com/cdtax/inherit/beans.xml");
		
		Gradate gradate = (Gradate)ac.getBean("gradate");
		
		System.out.println(gradate.getName() + ":" + gradate.getAge()+ ":" + gradate.getDegree());
	}
}

5、装配properties

对于Department类,增加属性:private Properties pp;  //Properties的使用

然后再beans.xml中配置:

<!-- 给Properties属性集合配置注入值 -->
	<property name="pp">
		<props>
			<prop key="pp1">abcd</prop>
			<prop key="pp2">hello</prop>
		</props>
	</property>

然后呢在App1中增加取Properties值得操作:

System.out.println("=========通过Properties集合取出数据========");
		Properties pp = department.getPp();
//		System.out.println(pp.get("pp1").toString());
		for(Entry<Object,Object> entry : pp.entrySet())
		{
			System.out.println(entry.getKey().toString() + entry.getValue().toString());
		}
		
		System.out.println("=========通过枚举Enumeration取出properties数据========");

		Enumeration en = pp.keys();
		while(en.hasMoreElements())
		{
			String key = (String)en.nextElement();
			System.out.println(key + " " +pp.getProperty(key));
		}

若bean的属性是集合类型,按如下处理:设置null

<property name="barlist">

        <null/>

</property>

思考:目前都是通过set方式给bean注入值,spring还提供其他的方式注入值,比如通过构造函数注入值。

6、通过构造函数注入值

<constructor-arg index="0" type="java.lang.String" value="大明"></constructor-arg>
<constructor-arg index="1" type="int" value="30"></constructor-arg>

spring容器会根据constructor-arg的个数,自动调用参数合适的构造函数,如这里有两个,调用有两个参数的构造函数,如果没有有两个参数的构造函数,就会报错。

set注入的缺点是无法清晰表达哪些属性是必须的,哪些是可选的,构造注入的优势是通过构造强制依赖关系,不可能实例化不完全的或无法使用的bean。

package com.cdtax.constructor;

public class Employee
{
	private String name;
	private int age;
	
	public Employee()
	{
		
	}
	
	public Employee(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;
	}
	
}
<?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:context="http://www.springframework.org/schema/context"
		xmlns:tx="http://www.springframework.org/schema/tx"
		xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
				http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
				http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">

<!-- 配置一个雇员对象 -->
<bean id="employee" class="com.cdtax.constructor.Employee">
<!-- 通过构造函数来注入值 -->
	<constructor-arg index="0" type="java.lang.String" value="大明"></constructor-arg>
	<constructor-arg index="1" type="int" value="30"></constructor-arg>

</bean>
</beans>



你可能感兴趣的:(3、Bean的生命周期续)