首页 > WEB开发 > 后台开发 > Spring入门:IoC
2014
10-05

Spring入门:IoC

三、依赖注入(DI)

在HelloWorld一节中只是简单的讲解了利用IoC容器产生和管理bean对象,有时需要在实例化bean时设置其属性(Property),这一过程称为依赖注入(DI),或装配bean。下面分别讲解基于XML和注解方式的DI。

1、XML方式

1)使用构造器注入

public class Person {
	private String name;
	private int age;

	public Person(){
	}

	public Person(String name, int age) {
		this.name = name;
		this.age = age;
	}
}

applicationContext.xml中的相关配置如下:

-------通过参数的顺序注入-----------
<bean id="person" class="org.flyne.domain.Person">
	<constructor-arg index="0" value="flyne" />
	<constructor-arg index="1" value="24"/>
</bean>、

-------通过参数的类型注入(不要用)-----------
<bean id="person" class="org.flyne.domain.Person">
	<constructor-arg type="java.lang.String" value="flyne"/>
	<constructor-arg type="int" value="24"/>
</bean>

2)使用setter方法注入(property)

① 简单类型的装配(基本类型 / String、引用类型)

public class Person {
	private String name;
	private Integer age;
	private Address address;
	//setter/getter方法略
}

applicationContext.xml中的相关配置如下:

<bean id="address" class="org.flyne.domain.Address"/>
<bean id="person" class="org.flyne.domain.Person">
	<property name="name" value="flyne" />
	<property name="age" value="24" />
	<property name="address" ref="address"></property>
</bean>

② 集合类型的装配

下例演示了数组、Set/List集合、Map、Properties等集合相关类型的装配方式。

public class CollectionDIDemo {
	private Object[] objects;
	private Set set;
	private List list;
	private Map map;
	private Properties properties;
	省略getter/setter
}

applicationContext.xml中的相关配置如下:

<bean id="collectionDIDemo" class="org.flyne.domain.CollectionDIDemo">
	<property name="objects">
		<list>
			<value>arrayEle</value>
			<ref bean="person" />
		</list>
	</property>

	<property name="list">
		<list>
			<value>listItem</value>
			<ref bean="person"/>
		</list>
	</property>

	<property name="set">
		<set>
			<value>setItem</value>
			<ref bean="person"/>
		</set>
	</property>

	<property name="map">
		<map>
			<entry key="key1" value="value1"/>
			<entry key]="key2" value-ref="person"></entry>
		</map>
	</property>

	<property name="properties">
		<props>
			<prop key="p1Key">p1Value</prop>
			<prop key="p2Key">p2Value</prop>
		</props>
	</property>
</bean>

<bean name="person" class="org.flyne.domain.Person" />

2、注解方式

另外一种装配bean的方式是在java代码中使用@Autowired或@Resource注解方式进行装配。使用步骤如下:

1)引入jar包

如果要在Java工程使用@Resource、@PostConstruct、@PreDestroy等注解,需要引入spring解压文件夹下的lib\j2ee\common-annotations.jar。注:Java web工程跳过此步。

2)修改配置文件

在applicationContext.xml中引入context命名空间,并加入context:annotation-config标签:

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

	<context:annotation-config />
	<context:component-scan base-package="org.flyne.domain" />
</beans>

说明:

  • <context:annotation-config>:隐式注册了多个对注解进行解析处理的处理器,即反射注解的类。
  • <context:component-scan>:组件自动扫描机制(☆),此处指定扫描org.flyne.domain及其子包中所有类上的@Component注解。注:这里所谓的组件(component),就是需要加入到Spring容器中的类,即bean。

3)在类中使用Spring注解

@Component("p")
public class Person {
	@Autowired
	@Qualifier("address")
	private Address address;

	@PostConstruct
	private void init(){
		System.out.println("person对象初始化了");
	}

	@PreDestroy
	private void destroy(){
		System.out.println("person对象销毁了");
	}
}

@Component
public class Address {
	public Address(){
		System.out.println("address被实例化了");
	}
}

加上这些注解后等同于XML方式的如下配置:

<bean id="address" class="org.flyne.domain.Address" />
<bean id="p" class="org.flyne.domain.Person" init-method="init" destroy-method="destroy">
	<property name="address" ref="address" />
</bean>

相关注解的说明:

  • @Component(☆):对应XML方式中的<bean>元素,可以指定bean元素的id属性,也可保持默认,默认就是类名第一个字母小写。【加在类上】
  • @Autowired:自动装配,按类型装配依赖对象,即去Spring容器中找该类型的对象,所以它要求依赖对象必须存在。【加在字段或setter方法上】
  • @Qualifier:@Autowired会根据依赖类型进行装配,如果想使用按名称装配,可以结合使用@Qualifier注解。【加在字段或setter方法上】
  • @PostConstruct、@PreDestroy:对应初始化和销毁方法。【加在方法上】
  • 另外还有@Resource注解,该注解等同于@Autowired + @Qualifier。
  • @Resource(☆):默认按名称装配,名称可以通过@Resource的name属性指定,如果没有指定name属性,当注解标注在字段上,即默认取字段的名称作为bean名称寻找依赖对象,当注解标注在属性的setter方法上,即默认取属性名作为bean名称寻找依赖对象。

注:如果没有指定name属性,并且按照默认的名称仍然找不到依赖对象时,@Resource注解会回退到按类型装配(@Autowired)。但一旦指定了name属性,就只能按名称装配了。

不难发现,注解只能用于引用类型属性的装配。

3、IoC和DI出现的意义

先看两个案例,最后总结IoC和DI出现的意义。

1)DocumentManager同Document具体实现解耦

案例一涉及到的类及其关系如下,定义了一个Document接口以及它的三个实现,在DocumentManger中会用到Document的实现,并调用Document接口中的方法。

09. Spring入门:IoC11185

如果想要在DocumentManger中不考虑Document的具体实现是哪个,实现面向接口编程,这时就可以用Spring的IoC实现DocumentManger和Document具体实现之间的解耦,达到面向接口编程的目的。在Spring配置文件中的相关配置如下:

<bean id="wordDocument" class="org.flyne.domain.WordDocument" />
<bean id="excelDocument" class="org.flyne.domain.ExcelDocument" />
<bean id="pdfDocument" class="org.flyne.domain.PdfDocument" />
<bean id="documentManager" class="org.flyne.domain.DocumentManager">
	<property name="document" ref="pdfDocument" />
</bean>

2)三层架构中层与层之间的解耦

通过如下配置实现层与层之间的解耦,在Struts2的配置文件中配置action元素时,class属性配置为personAction即可。

<bean id="personDao" class="org.flyne.demo.PersonDaoImpl" />

<bean id="personService" class="org.flyne.demo.PersonServiceImpl">
	<property name="personDao" ref="personDao" />
</bean>

<bean id="personAction" class="org.flyne.demo.PersonAction">
	<property name="personService" ref="personService" />
</bean>

意义总结:使用IoC和DI,实现了程序与具体实现之间的解耦,做到完全面向接口编程,即在编程时不需要考虑具体接口的实现。


留下一个回复

你的email不会被公开。