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(); } }
无参构造函数被调用
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()); } }
对于Department类,增加属性:private Properties pp; //Properties的使用
然后再beans.xml中配置:
<!-- 给Properties属性集合配置注入值 --> <property name="pp"> <props> <prop key="pp1">abcd</prop> <prop key="pp2">hello</prop> </props> </property>
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)); }
<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>