一、IOC容器的实现
1、Spring对IOC容器的实现提供两种方法,一种为Bean工厂(Bean Factory),另一种是应用程序上下文(Application Context)。应用程序上下文比Bean工厂更加高级,推荐使用。
Bean工厂和应用程序上下文的接口分别是BeanFactory和ApplicationContext,其中ApplicationContext是BeanFactory的子接口,实例化一个接口实现时,ClassPathXmlApplicationContext实现从classpath中装入一个xml配置文件,构建一个应用程序上下文。也可以使用FileSystemXmlApplicationContext从文件系统或URL装载XML配置文件,XmlWebApplicationContext和XmlPortletApplicationContext仅能用于Web和入口应用程序。
2、对于配置Ioc容器中的Bean,应该根据其功能(如控制器、DAO和JMS)将他们分割到多个配置文件中。
2.1、Bean的创建(假设开发一个生成序列号的应用程序)
package com.zk.pojo;
/**
* 序列号生成类
* 该类可通过构造程序或者set方法注入
*/
public class SequenceGenerator {
private String prefex; //序列号前缀
private String suffix; //序列号后缀
private int initial; //序列号初始值
private int counter; //保存生成器的当前数值
public SequenceGenerator() {
}
public SequenceGenerator(String prefex, String suffix, int initial) {
this.prefex = prefex;
this.suffix = suffix;
this.initial = initial;
}
public void setPrefex(String prefex) {
this.prefex = prefex;
}
public void setSuffix(String suffix) {
this.suffix = suffix;
}
public void setInitial(int initial) {
this.initial = initial;
}
public void setCounter(int counter) {
this.counter = counter;
}
public synchronized String getSequence(){
StringBuffer buffer = new StringBuffer();
buffer.append(prefex);
buffer.append(initial + counter++);
buffer.append(suffix);
return buffer.toString();
}
}
使用set方式注入
<!-- 通过bean方式注入 -->
<bean name="sequenceGenerator" class="com.zk.pojo.SequenceGenerator">
<!-- 使用简写方式注入 -->
<property name="prefex" value="30" />
<property name="initial" value="10000" />
<!-- 使用完整方式 -->
<property name="suffix">
<value>A</value>
</property>
</bean>
使用构造方式注入
<!-- 使用构造方式注入 -->
<bean id="sequenceGenerator" class="com.zk.pojo.SequenceGenerator">
<!-- 使用简写方式 -->
<constructor-arg name="prefex" value="30"/>
<constructor-arg name="initial" value="10000" />
<!-- 使用完整方式 -->
<constructor-arg name="suffix">
<value>B</value>
</constructor-arg>
</bean>
bean中的标识可以使用name或者id,那么标识可重复,后面的bean将会覆盖前面的bean,没有定义的bean为匿名bean,这类bean通常只用于与spring容器的交互,这种情况下只按类型注入。
2.2、Bean中的集合
1、List集合:<list>标记中所允许的元素可以使<value>指定的常量值、<ref>指定的Bean引用、<bean>指定的内部bean定义、<idref>指定的id引用定义、或者<null>指定的空元素,甚至可以在一个集合中嵌入另一个集合。现将上述prefex改成list集合类型。
<bean id="sequenceGenerator" class="com.zk.pojo.SequenceGenerator">
<property name="prefex">
<list>
<value>A</value>
<bean class="java.net.URL">
<constructor-arg value="http" />
<constructor-arg value="www.csdn.com" />
<constructor-arg value="/" />
</bean>
<null />
</list>
</property>
</bean>
2、Set集合:set中不存在重复元素,如果添加相同的元素,它将替换旧的元素,所允许的元素与list相同,尽管set中的元素是无序的,当spring使用LinkedHashSet保留了元素的顺序。
3、Map集合:<map>中的<entry>标记子项目,每个项目包含一个关键字和值,关键字在<key>中定义,关键字和值没有类型限制,可以使用上述相同的值。
<bean id="sequenceGenerator" class="com.zk.pojo.SequenceGenerator">
<property name="prefex">
<map>
<entry key="type" value="A" />
<entry key="url">
<bean class="java.net.URL">
<constructor-arg value="http" />
<constructor-arg value="www.csdn.com" />
<constructor-arg value="/" />
</bean>
</entry>
</map>
</property>
</bean>
3、解决构造程序的歧义
<constructor-arg>中的type属性,指定参数的预期类型,index属性明确指出参数的索引值。spring会将不指定类型的元素作为字符串对待。
4、bean引用
<ref>元素的bean属性中的Bean名称可以对IoC容器中的任何Bean引用,即使这个Bean不在同一个XML配置文件中,如果引用相同XML文件中的一个Bean,应该使用local属性,此时scheam会帮助完成校验。
5、可以使用@Required注解检查特定的属性是否设置。
@Required
public void setPrefex(String prefex) {
this.prefex = prefex;
}
要使该注解生效,需要在IoC容器中注册一个RequiredAnnotationBeanPostProcessor实例,该类是一个Spring bean后处理器,检查带有@Required注解的所有Bean属性是否设置。
Bean后处理器是一类特殊的Spring bean,能够在每个Bean初始化之前执行附加工作。为了使Bean后处理器工作,必须在Ioc容器中注册它。
<bean class="org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor"/>
如果是Spring2.5或者更高版本,可使用:
<context:annotation-config />
它将自动注册一个RequiredAnnotationBeanPostProcessor实例。
6、自动装配
6.1、用XML配置自动装配Bean
<!-- autowire可选byName、byType、Constructor -->
<bean name="sequenceGenerator" class="com.zk.pojo.SequenceGenerator" autowire="byName">
byName:为每个Bean属性,装配一个与之同名的Bean。
byType:对每个Bean属性,装配类型与之兼容的一个Bean,如果有超出一个Bean,将抛出UnsatisfiedDependencyException异常。
6.2、用注解自动装配Bean
@AutoWired和@Resource(在JSR250:Java平台常见注解中定义),同理,使用这两个注解需要注册一个bean后处理器AutowiredAnnotationBeanPostProcessor,亦可使用:
<context:annotation-config />
6.2.1@AutoWired:按类型装配,可用于set方法,字段,以及构造程序上(为每个字段找一个具有兼容类型的Bean),甚至是具有任意名称和任意参数的方法上,这种情况下,Spring将试图为每个方法参数装配一个类型兼容的Bean,如:
@Autowired
public void inject(SequenceGenerator sg){
...
}
此外,@AutoWired可以应用到数组或集合类型(List,Map)的属性上,Spring会将容器中具有多个相同类型的Bean依次添加,对于Map集合,将在这个Map中添加所有Bean名称与关键字相同的兼容类型Bean。
默认情况下:
1、@AutoWired需要装配的属性都是必须的,可以设置其required属性为false,之后,当Spring找不到匹配的Bean,将不设置该属性,而不会抛出异常。
2、按照类型的自动装配在容器中有超过一个类型兼容的bean时无效,但是,Spring允许你指定一个候选Bean,这个Bean的名称在@Qualifier注解中指定,如:
//此时如果容器中存在多个SequenceGenerator类型兼容的Bean
//Spring会在容器中找我们设置的id为generatorNumOne的Bena进行装配
@Autowired
@Qualifier("generatorNumOne")
private SequenceGenerator generator;
6.2.2@Resource:按名称自动装配,Spring会查找容器中名称与属性名相同的Bean进行装配,也可以显式地在name属性中指定Bean名称:
@Resource(name="generatorNumOne")
private SequenceGenerator generator;
7、组件扫描
Spring提供组件扫描功能,能够利用特殊的典型化注解,从classpath中自动扫描、检测和实例化你的组件。指示Spring管理组件的基本注解是@Component,其他特殊的典型化注解包括@Repository、@Service、@Controller,分别指示持续层、服务层和表现层中的组件。
通过<context:component-scan>要求Spring扫描这些注解,通过指定扫描组件所用的包,然后指定的包和子包都将被扫描,可以使用分好来分隔多个扫描包。如:
<context:component-scan base-package="com.zk.calculate" />
该元素还将注册一个AutowiredAnnotationBeanPostProcessor实例,这个实例能够自动装配带有@AutoWired注解的属性。