一、构造注入
在类被实例化的时候,它的构造方法被调用并且只能调用一次。所以它被用于类的初始化操作。<constructor-arg>是<bean>标签的子标签。通过其<value>子标签可以为构造
方法传递参数。现在以一个简单的输出学生信息的实例演示如何为构造方法传递参数。实例程序创建过程如下。
(1)建立 Student 接口,它是对学生类的简单抽象。程序代码如下
- package com.linbingwen;
- public interface Student {
- public void printInfo();
- }
- package com.linbingwen;
- public class Stu1 implements Student {
- private String name;
- private String sex;
- private int age;
- public Stu1(String name, String sex, int age) {
- super();
- this.name = name;
- this.sex = sex;
- this.age = age;
- }
- public void printInfo() {
- System.out.println("姓名:" + name);
- System.out.println("年龄:" + age);
- System.out.println("性别:" + sex);
- }
- }
- <?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-3.2.xsd">
- <bean id="stu1" class="com.linbingwen.Stu1">
- <constructor-arg>
- <value>飞龙</value>
- </constructor-arg>
- <constructor-arg>
- <value>男</value>
- </constructor-arg>
- <constructor-arg>
- <value>26</value>
- </constructor-arg>
- </bean>
- </beans>
- package com.linbingwen;
- import org.springframework.context.ApplicationContext;
- import org.springframework.context.support.ClassPathXmlApplicationContext;
- public class Info {
- public static void main(String[] args) {
- ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
- Student student = (Student) applicationContext.getBean("stu1");
- student.printInfo();
- }
- }
通过这个实例,可以看到容器通过多个<constructor-arg>标签完成了对构造方法的传参,但是如果标签的赋值顺序与构造方法中参数的顺序或参数类型不同,程序会产生异常。<constructor-arg>标签可以使用“index”属性和“type”属性解决此类问题。下面分别介绍这两个属性的用法。
type 属性:可以指定参数类型以确定要为构造方法的哪个参数赋值。当需要赋值的属性在构造方法中没有相同的类型时,可以使用这个参数。因此实例中 stu1 的配置信息可以 这样写:
- <?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-3.2.xsd">
- <bean id="stu1" class="com.linbingwen.Stu1">
- <constructor-arg>
- <value>飞龙</value>
- </constructor-arg>
- <constructor-arg>
- <value>男</value>
- </constructor-arg>
- <constructor-arg type="int">
- <value>26</value>
- </constructor-arg>
- </bean>
- </beans>
- <?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-3.2.xsd">
- <bean id="stu1" class="com.linbingwen.Stu1">
- <constructor-arg index="0">
- <value>飞龙</value>
- </constructor-arg>
- <constructor-arg index="1">
- <value>男</value>
- </constructor-arg>
- <constructor-arg type="int">
- <value>26</value>
- </constructor-arg>
- </bean>
- </beans>
二、设值注入
一个简单的 JavaBean 最明显的规则就是以一个私有属性对应 set()和 get()方法,来实现对属性的封装。既然 JavaBean 有 set()方法来设置 Bean 的属性,Spring 就会有相应的支持。除了为构造方法传递参数的<constructor-arg>标签之外,<property>标签可以为JavaBean 的 set()方法传递参数,即通过 set()方法为属性赋值。在上面的实例中再添加一个 Moniter 类。
设置 Moniter 类属性和 set()/get()方法。程序代码如下。
- package com.linbingwen;
- public class Moniter implements Student {
- private String name;
- private String sex;
- private int age;
- public void printInfo() {
- System.out.println("姓名:" + name);
- System.out.println("年龄:" + age);
- System.out.println("性别:" + sex);
- }
- public int getAge() {
- return age;
- }
- public void setAge(int age) {
- this.age = age;
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public String getSex() {
- return sex;
- }
- public void setSex(String sex) {
- this.sex = sex;
- }
- }
- <?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-3.2.xsd">
- <bean id="stu1" class="com.linbingwen.Stu1">
- <constructor-arg index="0">
- <value>飞龙</value>
- </constructor-arg>
- <constructor-arg index="1">
- <value>男</value>
- </constructor-arg>
- <constructor-arg type="int">
- <value>26</value>
- </constructor-arg>
- </bean>
- <bean id="moniter" class="com.linbingwen.Moniter">
- <property name="age">
- <value>26</value>
- </property>
- <property name="name">
- <value>欣欣</value>
- </property>
- <property name="sex">
- <value>女</value>
- </property>
- </bean>
- </beans>
三、接口注入(interface injection)
接口注入指的就是在接口中定义要注入的信息,并通过接口完成注入。
具体步骤如下 ①.编写一个接口IBuniness,各种数据库的注入将通过这个接口进行。代码如下- package ch3;
- public interface IBusiness {
- public void createDI(DataBase db);
- }
- package ch3;
- public class Business implements IBusiness {
- private DataBase db;
- @Override
- public void createDI(DataBase db) { //接口注入
- this.db = db;
- }
- // 根据注入的数据库,从XXX数据库中取得数据。
- public void getData(){
- db.getData();
- }
- }
- package ch3;
- public class TestBusiness {
- private Business business = new Business();
- // 根据注入的数据库类,从oracle中取得数据库。
- public void getData() {
- business.createDI(new OracleDataBase()); // 注入实际的数据库类型。如要变更式样,只需改变此处即可,达到重用目的。
- business.getData();
- }
- }
四、JavaBean 的赋值标签
以上只介绍了如何用<value>标签赋值,那么复杂的属性如何赋值呢?例如 Null、对象引用、集合类等。接下来将要介绍对 JavaBean 的复杂属性赋值的标签,它们可以应用到
任何如<constructor-arg>和<property>可以给 JavaBean 的属性赋值的标签中。 1.<value>标签 这是一个普通的赋值标签,可直接在成对的<value>标签中放入数值或其他赋值标签,Spring 会把这个标签提供的属性值注入到指定的 JavaBean 中。语法格式如下。- <value>arg</value>
- <ref bean="JavaBean"/>
- <null/>
- <null></null>
- <list>
- <value>arg1</value>
- <value>arg2</value>
- </list>
- <bean id="school" class="School">
- <property name="studentList">
- <list>
- <ref bean=" student1"/>
- <value>student2</value>
- </list>
- </property>
- </bean>
- <set>
- <ref bean="arg1"/>
- <value>arg2</value>
- ……
- </set>
- <bean id="school" class="School">
- <property name="student">
- <set>
- <ref bean=" student1"/>
- <value>name</value>
- </set>
- </property>
- <bean>
- <map>
- <entry key="key1">
- <ref bean="arg1" />
- </entry>
- </map>
- <bean id="school" class="School">
- <property name="student">
- <map>
- <entry key="key1">
- <ref bean=" student1" />
- </entry>
- <entry key="key2">
- <value> student2</value>
- </entry>
- </map>
- </property>
- </bean>
- <props>
- <prop key="key1">value</prop>
- </props>
- <bean id="school" class="School">
- <property name="student">
- <props>
- <prop key="key1">student1</prop>
- <prop key="key2">student2</prop>
- </props>
- </property>
- </bean>
- <bean id="school" class="School">
- <property name="student">
- <bean class="Student"/> <!--定义学生匿名内部类-->
- </property>
- </bean>
五、 list、set、map注入使用范例
还是接上面的工程,新建一个School.java,代码如下:
- package com.linbingwen;
- import java.util.Iterator;
- import java.util.List;
- import java.util.Map;
- import java.util.Set;
- public class School {
- private List listStu;
- private Set setStu;
- private Map mapStu;
- public List getListStu() {
- return listStu;
- }
- public void setListStu(List listStu) {
- this.listStu = listStu;
- }
- public Set getSetStu() {
- return setStu;
- }
- public void setSetStu(Set setStu) {
- this.setStu = setStu;
- }
- public Map getMapStu() {
- return mapStu;
- }
- public void setMapStu(Map mapStu) {
- this.mapStu = mapStu;
- }
- public void printSchool(){
- System.out.println("--------list--------");
- for (int i = 0; i < listStu.size(); i++) {
- System.out.println(listStu.get(i));
- }
- System.out.println("--------set--------");
- for(Object s : setStu){
- System.out.println(s);
- }
- System.out.println("--------map--------");
- Iterator it=mapStu.entrySet().iterator();
- System.out.println(mapStu.entrySet().size());
- String key;
- String value;
- while(it.hasNext()){
- Map.Entry entry = (Map.Entry)it.next();
- key=entry.getKey().toString();
- value=entry.getValue().toString();
- System.out.println(key+"===="+value);
- }
- }
- }
- <?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-3.2.xsd">
- <bean id="stu1" name="student1" class="com.linbingwen.Stu1">
- <constructor-arg index="0">
- <value>飞龙</value>
- </constructor-arg>
- <constructor-arg index="1">
- <value>男</value>
- </constructor-arg>
- <constructor-arg type="int">
- <value>26</value>
- </constructor-arg>
- </bean>
- <bean id="moniter" name="student2" class="com.linbingwen.Moniter">
- <property name="age">
- <value>26</value>
- </property>
- <property name="name">
- <value>欣欣</value>
- </property>
- <property name="sex">
- <value>女</value>
- </property>
- </bean>
- <bean id="school" class="com.linbingwen.School">
- <!--List 注入例子 -->
- <property name="listStu">
- <list>
- <ref bean="moniter" /> <!--使用上面已定义好的bean -->
- <ref bean="moniter" /> <!--使用上面已定义好的bean -->
- <ref bean="stu1" /> <!--使用上面已定义好的bean -->
- <bean class="com.linbingwen.Moniter"> <!--定义学生匿名内部类,用setter方法注入 -->
- <property name="age" value="20" />
- <property name="name" value="阿屁" />
- <property name="sex" value="男" />
- </bean>
- <value>1</value>
- <value>hello</value>
- </list>
- </property>
- <!--set 注入例子 -->
- <property name="setStu">
- <set>
- <ref bean="moniter" /> <!--使用上面已定义好的bean -->
- <ref bean="stu1" /> <!--使用上面已定义好的bean -->
- <ref bean="stu1" /> <!--使用上面已定义好的bean -->
- <bean class="com.linbingwen.Stu1"> <!--定义学生匿名内部类,用constructor方法注入 -->
- <constructor-arg value="大平" index="0"></constructor-arg>
- <constructor-arg value="男" index="1"></constructor-arg>
- <constructor-arg value="10" index="2"></constructor-arg>
- </bean>
- <value>333333</value>
- <value>Evankaka</value>
- </set>
- </property>
- <!--map 注入例子 -->
- <property name="mapStu">
- <map>
- <entry key="key1">
- <ref bean="moniter" /> <!--使用上面已定义好的bean -->
- </entry>
- <entry key="key2">
- <bean class="com.linbingwen.Moniter"> <!--定义学生匿名内部类,用setter方法注入 -->
- <property name="age" value="80" />
- <property name="name" value="小王" />
- <property name="sex" value="男" />
- </bean>
- </entry>
- <entry key="key3">
- <value>student2</value>
- </entry>
- <entry key="key4">
- <value>56</value>
- </entry>
- </map>
- </property>
- </bean>
- </beans>
- package com.linbingwen;
- import org.springframework.context.ApplicationContext;
- import org.springframework.context.support.ClassPathXmlApplicationContext;
- public class Info {
- public static void main(String[] args) {
- ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
- Student student = (Student) applicationContext.getBean("stu1");
- student.printInfo();
- Student moniter = (Student) applicationContext.getBean("moniter");
- moniter.printInfo();
- School school=(School) applicationContext.getBean("school");
- school.printSchool();
- }
- }
四月 02, 2015 5:36:38 下午 org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@addb54: startup date [Thu Apr 02 17:36:38 CST 2015]; root of context hierarchy 四月 02, 2015 5:36:38 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions 信息: Loading XML bean definitions from class path resource [applicationContext.xml] 四月 02, 2015 5:36:38 下午 org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons 信息: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@ebcd03: defining beans [stu1,moniter,school]; root of factory hierarchy 姓名:飞龙 年龄:26 性别:男 姓名:欣欣 年龄:26 性别:女 --------list-------- 姓名:欣欣;年龄:26;性别:女 姓名:欣欣;年龄:26;性别:女 姓名:飞龙;年龄:26;性别:男 姓名:阿屁;年龄:20;性别:男 1 hello --------set-------- 姓名:欣欣;年龄:26;性别:女 姓名:飞龙;年龄:26;性别:男 姓名:大平;年龄:10;性别:男 333333 Evankaka --------map-------- 4 key1====姓名:欣欣;年龄:26;性别:女 key2====姓名:小王;年龄:80;性别:男 key3====student2 key4====56
六、 总结
设值注入和构造注入的比较
1、设值注入的优点
(1)与传统的JavaBean的写法更相似,更容易让人理解,依赖关系显得更加直观、自然。
(2)对于复杂的依赖关系,如果采用构造注入会导致构造器过于臃肿,难以阅读。因为Spring在创建Bean实例时,需要同时实例化其依赖的全部实例,因而导致Struts+Spring+Hibernate整合开发性能下降。设值注入可以避免这些问题。
(3)在某些属性可选的情况下,多参数的构造器更加笨重。
2、构造注入的优点
(1) 可以在构造器中决定依赖关系的注入顺序。例如,组件中其他依赖关系的注入,常常需要依赖于Datasource的注入。采用构造注入时,可以在代码中清晰地决定注入顺序,优先依赖先注入。
(2)对于依赖关系无须变化的bean,构造注入更有用处。因为没有setter,所有的关系都在构造器中设定,因此无需担心后续代码对依赖关系产生破坏。
(3) 依赖关系只能在构造器中设定,因为只有组件的创建者才能改变组件的依赖关系。对于组件的调用者而言,组件内部的依赖关系完全透明,更符合高内聚的原则。
建议采用设值注入为主,构造注入为辅的注入策略。
Spring Bean的其他说明
1、 Bean的标识(id,name,class)
id:bean的唯一标识。
2、name:bean的别名,可以有多个。
class:bean的具体实现类
3、 Bean的作用域
(1) singleton:单例,在IOC容器里只有一个实例
- <!-- 默认 -->
- <beanidbeanid="loginAction"class="net.vzhang.spring3.action.LoginAction" scope="singleton"/>
(2) prototype:
- <beanidbeanid="loginAction2"class="net.vzhang.spring3.action.LoginAction2" scope="prototype"/>
每次对bean请求时,都会创建一个新的实例。
对bean的请求:将其注入到另外一个bean中,或者调用BeanFactory的getBean方法。
session:HttpSessio