Spring之IOC的注入方式总结

x33g5p2x  于2021-03-14 发布在 其他  
字(17.3k)|赞(0)|评价(0)|浏览(242)

在定义了 JavaBean 装载信息之后需要对其赋值。一个 JavaBean 的赋值可以通过构造方法完成初始化,或者通过 set()方法初始化和改变属性值。下面分别介绍如何在 XML 中配置 JavaBean 的属性为构造方法和 set()方法传递参数。

本文工程下载

一、构造注入

在类被实例化的时候,它的构造方法被调用并且只能调用一次。所以它被用于类的初始化操作。<constructor-arg>是<bean>标签的子标签。通过其<value>子标签可以为构造
方法传递参数。现在以一个简单的输出学生信息的实例演示如何为构造方法传递参数。

实例程序创建过程如下。
(1)建立 Student 接口,它是对学生类的简单抽象。程序代码如下

package com.linbingwen;

public interface Student {
 public void printInfo();
}

(2)建立实现 Student 接口的 Stu1 类,定义姓名、年龄、性别 3 个属性和包含这 3个参数的构造方法,在实现接口的 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);
	}
}

( 3 ) applicationContext.xml 是 装 配 JavaBean 的 配 置 文 件 , 它 通 过 3 个<constructor-arg>标签为构造方法传递两个 String 类型和一个 int 类型的参数。程序代
码如下。

<?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>

注意:这里要把applicationContext.xml放在src文件夹下。添加Spring和包不懂看这里
(4)创建 Info 类。它是实例的主类,负责载入容器,从容器中获得 Stu1 类的实例,并调用 Stu1 类的 pringInfo()方法打印学生信息。程序代码如下

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>

**index 属性:**用于指定构造方法的参数索引,指定当前<constructor-arg>标签为构造方法的那个参数赋值。因为程序中含有两个 String 类型的参数,type 属性无法做判断,
导致 name 和 sex 参数无法判断正确性。这时需要设置 index 属性定义赋值索引来指定构造方法的参数位置。修改后的 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" 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>

在修改后的代码中,两个 String 类型的参数通过“index”属性指定了在构造方法中的位置,确保了传参的正确性,第 3 个<constructor-arg>标签的 type 属性可以改写成
“index=2”。现在的 3 个<constructor-arg>标签可以随意调换顺序而不会影响到构造方法的正确赋值。<constructor-arg>标签还有“ref”和“value”两个属性,分别用于引用其他 JavaBean和定义新值。由于使用构造方法在配置文件中定义 JavaBean 使用得不多,所以这两个属性不再介绍。

二、设值注入

一个简单的 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;
	}
}

修改 applicationContext.xml 配置文件。添加名称为 Moniter 的 Java Bean 的定义,用<property>标签的“name”属性指定要操作的 JavaBean 的属性,然后通过<property>的子标签<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" 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);
}

②.任何想要使用数据库实例的类都必须实现这个接口,业务逻辑类Business实现这个接口IBusiness。代码如下

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

3.编写测试类TestBusiness。代码如下

package ch3;
public class TestBusiness {
 private Business business = new Business();
// 根据注入的数据库类,从oracle中取得数据库。
 public void getData() {
  business.createDI(new OracleDataBase()); // 注入实际的数据库类型。如要变更式样,只需改变此处即可,达到重用目的。
  business.getData();
 }
}

如果要完成依赖关系注入的对象,必须实现IBusiness接口。

四、JavaBean 的赋值标签

以上只介绍了如何用<value>标签赋值,那么复杂的属性如何赋值呢?例如 Null、对象引用、集合类等。接下来将要介绍对 JavaBean 的复杂属性赋值的标签,它们可以应用到
任何如<constructor-arg>和<property>可以给 JavaBean 的属性赋值的标签中。
1.<value>标签
这是一个普通的赋值标签,可直接在成对的<value>标签中放入数值或其他赋值标签,Spring 会把这个标签提供的属性值注入到指定的 JavaBean 中。语法格式如下。

<value>arg</value>

arg:传递给 JavaBean 的属性值。
2.<ref>标签
这个标签可以引用其他 JavaBean 的实例对象,当传递的参数是其他 JavaBean 的实例对象时使用此标签。语法格式如下。

<ref bean="JavaBean"/>

bean:指定引用的 JavaBean。
3.<null>标签
这是为 JavaBean 赋 Null 空值的标签。当 JavaBean 的某个属性暂不使用,要将其设置为 Null 值时使用此标签。语法格式如下。

<null/>

<null></null>

4.<list>标签
这是为 List 集合类或数组赋值的标签。当 JavaBean 的某个属性是 List 集合类型或数组时,需要使用此标签为 List 集合类型或数组的每一个元素赋值。语法格式如下。

<list>
    <value>arg1</value>
    <value>arg2</value>
</list>

<value>:赋值标签,为<list>标签指定的属性赋值。也可以使用其他赋值标签作为集合类赋值标签的子标签,例如<ref>或 3.2.7 节中介绍的使用<bean>标签定义匿名内部
JavaBean 的方法。此标签应用在<bean>标签中定义 JavaBean 的完整代码举例如下。

<bean id="school" class="School">
    <property name="studentList">
      <list>
        <ref bean=" student1"/>
        <value>student2</value>
      </list>
     </property>
</bean>

5.<set>标签
和<list>标签类似,<set>标签也是为集合对象赋值,不过赋值的对象是 Set 类型的属性。语法格式如下。

<set>
    <ref bean="arg1"/>
    <value>arg2</value>
……
</set>

此标签应用在<bean>标签中定义 JavaBean 的完整代码举例如下

<bean id="school" class="School">
    <property name="student">
      <set>
        <ref bean=" student1"/>
        <value>name</value>
      </set>
    </property>
<bean>

6.<map>标签
此标签为 Map 集合赋值。因为 Map 以键值对(key/value)的方式存放数据,所以需要使用<entry>子标签装载 key 与 value 数据。Map 集合的 key 可以是任何类型的对象,而<entry>标签的属性 key 是以 String 类型表示的,所以限制了 Spring 中 Map 的 key 只能用 String 来表示。语法格式如下。

<map>
    <entry key="key1">
    <ref bean="arg1" />
    </entry>
</map>

<entry>:<map>标签的子标签,其“key”属性用于指定 Map 集合类的键值(key)。此标签应用在<bean>标签中定义 JavaBean 的完整代码举例如下。

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

7.<props>标签
这是为 java.util.Properties 类型属性赋值的标签,和<map>标签类似,但是它的(key/value)键值全都是 String 类型的,无法赋予 Object 对象类型。语法格式如下。

<props>
<prop key="key1">value</prop>
</props>

<prop>:<props>的子标签,其“key”属性用于指定 Properties 类的键值(key)。此标签应用在<bean>标签中定义 JavaBean 的完整代码举例如下。

<bean id="school" class="School">
    <property name="student">
        <props>
          <prop key="key1">student1</prop>
          <prop key="key2">student2</prop>
         </props>
     </property>
</bean>

8 匿名内部 JavaBean 的创建
通过前面的介绍,读者应该对如何使用 XML 装配 JavaBean 有了一定的了解。但是编程中经常遇到匿名的内部类,在 Spring 中该如何利用 XML 装配呢?其实非常简单,在需要匿名内部类的地方直接用<bean>标签定义一个内部类即可。如果要使这个内部类匿名,可以不指定<bean>标签的 id 或 name 属性。例如下面这段代码:

<bean id="school" class="School">
 <property name="student">
    <bean class="Student"/> <!--定义学生匿名内部类-->
 </property>
</bean>

代码中定义了匿名的 Student 类,将这个匿名内部类赋给了 school 类的实例对象。

五、 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);                    
        }   
	}
}

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" 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容器里只有一个实例

<!-- 默认 -->
<beanid="loginAction"class="net.vzhang.spring3.action.LoginAction" scope="singleton"/>

(2) prototype:
**

<beanid="loginAction2"class="net.vzhang.spring3.action.LoginAction2" scope="prototype"/>

request:针对Web应用的每次请求都生成一个新的实例

每次对bean请求时,都会创建一个新的实例。

对bean的请求:将其注入到另外一个bean中,或者调用BeanFactory的getBean方法。

session:HttpSessio

本文工程下载

林炳文Evankaka原创作品。转载请注明出处http://blog.csdn.net/evankaka

相关文章