前一篇文章提到,有三个重要的方法把配置元数据提供给 Spring 容器。
一、基于XML配置
1.1 构造函数注入
当容器调用带有一组参数的类构造函数时,基于构造函数的 DI 就完成了,其中每个参数代表一个对其他类的依赖。
TextEditor 类:
package com.tutorialspoint;
public class TextEditor {
private SpellChecker spellChecker;
public TextEditor(SpellChecker spellChecker) {
System.out.println("Inside TextEditor constructor." );
this.spellChecker = spellChecker;
}
public void spellCheck() {
spellChecker.checkSpelling();
}
}
SpellChecker 依赖类:
package com.tutorialspoint;
public class SpellChecker {
public SpellChecker(){
System.out.println("Inside SpellChecker constructor." );
}
public void checkSpelling() {
System.out.println("Inside checkSpelling." );
}
}
配置文件 Beans.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<!-- Definition for textEditor bean -->
<bean id="textEditor" class="com.tutorialspoint.TextEditor">
<constructor-arg ref="spellChecker"/>
</bean>
<!-- Definition for spellChecker bean -->
<bean id="spellChecker" class="com.tutorialspoint.SpellChecker">
</bean>
</beans>
1.2 setter方法注入
当容器调用一个无参的构造函数或一个无参的静态 factory 方法来初始化你的 bean 后,通过容器在你的 bean 上调用设值函数,基于设值函数的 DI 就完成了。
TextEditor 类:
package com.tutorialspoint;
public class TextEditor {
private SpellChecker spellChecker;
// a setter method to inject the dependency.
public void setSpellChecker(SpellChecker spellChecker) {
System.out.println("Inside setSpellChecker." );
this.spellChecker = spellChecker;
}
// a getter method to return spellChecker
public SpellChecker getSpellChecker() {
return spellChecker;
}
public void spellCheck() {
spellChecker.checkSpelling();
}
}
SpellChecker 依赖类:
package com.tutorialspoint;
public class SpellChecker {
public SpellChecker(){
System.out.println("Inside SpellChecker constructor." );
}
public void checkSpelling() {
System.out.println("Inside checkSpelling." );
}
}
配置文件 Beans.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<!-- Definition for textEditor bean -->
<bean id="textEditor" class="com.tutorialspoint.TextEditor">
<property name="spellChecker" ref="spellChecker"/>
</bean>
<!-- Definition for spellChecker bean -->
<bean id="spellChecker" class="com.tutorialspoint.SpellChecker">
</bean>
</beans>
1.3 自动装配
Spring 容器可以在不使用 constructor-arg 和 property 元素的情况下自动装配相互协作的 bean 之间的关系,这有助于减少编写一个大的基于 Spring 的应用程序的 XML 配置的数量。
下列自动装配模式,它们可用于指示 Spring 容器为来使用自动装配进行依赖注入。你可以使用 <bean> 元素的 autowire 属性为一个 bean 定义指定自动装配模式。
| 模式 | 描述 |
|---|---|
| no | 这是默认的设置,它意味着没有自动装配,你应该使用显式的bean引用来连线。你不用为了连线做特殊的事。在依赖注入章节你已经看到这个了。 |
| byName | 由属性名自动装配。Spring 容器看到在 XML 配置文件中 bean 的自动装配的属性设置为 byName。然后尝试匹配,并且将它的属性与在配置文件中被定义为相同名称的 beans 的属性进行连接。 |
| byType | 由属性数据类型自动装配。Spring 容器看到在 XML 配置文件中 bean 的自动装配的属性设置为 byType。然后如果它的类型匹配配置文件中的一个确切的 bean 名称,它将尝试匹配和连接属性的类型。如果存在不止一个这样的 bean,则一个致命的异常将会被抛出。 |
| constructor | 类似于 byType,但该类型适用于构造函数参数类型。如果在容器中没有一个构造函数参数类型的 bean,则一个致命错误将会发生。 |
| autodetect | Spring首先尝试通过 constructor 使用自动装配来连接,如果它不执行,Spring 尝试通过 byType 来自动装配。 |
可以使用 byType 或者 constructor 自动装配模式来连接数组和其他类型的集合。
由构造函数自动装配:
<bean id="user" class="com.fanlan.pojo.User" autowire="constructor">
<constructor-arg name="name" value="张三"/>
</bean>
由setter方法自动装配:
<!-- 手动配置 -->
<bean id="user" class="com.fanlan.pojo.User">
<property name="name" value="泛滥"/>
</bean>
<!-- byName自动配置 -->
<bean id="user" class="com.fanlan.pojo.User" autowire="byName"/>
<!-- byType自动配置 -->
<bean id="user" class="com.fanlan.pojo.User" autowire="byType"/>
二、基于注解配置
Spring 2.5 后提供了一个context的命名空间,它提供了通过扫描类包来加载利用注解定义的Bean的方式。
<context:component-scan
base-package=""
resource-pattern="**/*.class"
name-generator="org.springframework.context.annotation.AnnotationBeanNameGenerator"
use-default-filters="true"
annotation-config="true">
<context:include-filter type="aspectj" expression=""/>
<context:exclude-filter type="regex" expression=""/>
</context:component-scan>
Spring3.0提供了一系列的针对依赖注入的注解,这使得Spring IoC在XML文件之外多了一种可行的选择,主要包含如下注解类型:
- Bean的定义注解
- Bean的生命周期注解
- Bean的依赖检查注解
- Bean的自动装配注解
2.1 Bean的定义注解
Spring自2.0开始,陆续引入了一些注解用于简化Spring的开发。
@Repository注解便属于最先引入的一批,用于将数据访问层(DAO层)的类标识为Spring Bean。
如此的话,我们便不在需要在XML当中显式使用bean来进行bean的配置。Spring容器在初始化的时候便会自动扫描base-package所指定的包以及子包下面的所有class文件。所有标注为Repository的类将被自动注册为bean。
为什么Repository只能标注在DAO类上面呢?
因为该注解的作用不只是将类识别为bean,同时他还能将所标注的类中所抛出的数据访问异常封装为Spring的数据访问异常类型。Spring本身提供了一个丰富的,并且是与具体的访问技术无关的数据访问异常结构,用于封装不同的持久层框架所抛出的异常,使得异常独立与底层的框架。
Spring2.5在@Repository的基础上增加了功能类似的额外三个注解,总共有如下四种注解:
- @Component:一个泛化的概念,表示一个组件(Bean),可作用在任何层次
- @Controller:用于对Controller实现类进行标注,目前该功能与Component相同
- @Repository:用于对DAO实现类进行标注
- @Service:用于对Service实现类进行标注,目前该功能与Component相同
这三个注解除了作用于不同软件层次的类,其使用方式与Repository是完全相同的。
2.2 Bean的生命周期注解
在某些情况下,可能需要我们手工做一些额外的初始化或者销毁操作,例如资源的获取和是否操作,Spring1.x为此提供了两种方式供用户指定执行生命周期回调的方法:
实现Spring提供的两个接口:initializingBean 和 DisposableBean,这种方法是要求bean类实现Spring的接口,但增加了bean和Spring容器的耦合度,因此不推荐使用。
在XML文件中使用<bean>的init-method 和 destory-method 属性,指定初始化之后和回调之前的回调方法。这两个属性的取值是bean中相应的初始化和销毁方法的名称。方法名称任意,但是方法不能有参数。
示例如下:
<bean id="..." class="..."
init-method="init" destory-method="destory">
</bean>
在这里,我们指定了userService 这个bean的初始化方法为:init 销毁方法为:destory
Spring2.5在保留以上两种方式的基础上,提供了对JSR-250的支持。
JSR-250规范定义了两个用于指定声明周期方法的注解:
- @PostConstruct:初始化之后的执行的回调方法
- @PreDestroy:销毁之前的回调方法
2.3 Bean的依赖检查注解
Spring2.0之前使用dependency-check在配置文件中设置属性用于依赖检查(只会检查Setter方法是否被调用),缺点是粒度较粗,该属性的取值包括以下几种:
- none: 默认不执行依赖检查
- simple :对原始基本类型和集合类型进行检查
- objects :对复杂类型进行检查
- all :对所有类型进行检查
使用Spring2.0提供的@Required注解,提供了更细粒度的控制,@Required注解只能标注在Setter方法之上,(标注在其他方法之上会被忽略 )用于检查其是否被调用,当Setter方法未被调用的话会抛出异常。
2.4 Bean的自动装配注解
<context:component-scan> 元素还会自动注册 AutowiredAnnotationBeanPostProcessor 实例, 该实例可以自动装配具有 @Autowired 和 @Resource 、@Inject注解的属性。
| 序号 | 注解 & 描述 |
|---|---|
| 1 | @Required @Required 注解应用于 bean 属性的 setter 方法。 |
| 2 | @Autowired @Autowired 注解可以应用到 bean 属性的 setter 方法,非 setter 方法,构造函数和属性。 |
| 3 | @Qualifier 通过指定确切的将被连线的 bean,@Autowired 和 @Qualifier 注解可以用来删除混乱。 |
| 4 | JSR-250 Annotations Spring 支持 JSR-250 的基础的注解,其中包括了 @Resource,@PostConstruct 和 @PreDestroy 注解。 |
@Autowired 注解自动装配具有兼容类型的单个 Bean属性
- 构造器, 普通字段(即使是非 public), 一切具有参数的方法都可以应用@Authwired 注解
- 默认情况下, 所有使用 @Authwired 注解的属性都需要被设置. 当 Spring 找不到匹配的 Bean 装配属性时, 会抛出异常, 若某一属性允许不被设置, 可以设置 @Authwired 注解的 required 属性为 false
- 默认情况下, 当 IOC 容器里存在多个类型兼容的 Bean 时, 通过类型的自动装配将无法工作. 此时可以在 @Qualifier 注解里提供 Bean 的名称. Spring 允许对方法的入参标注 @Qualifiter 已指定注入 Bean 的名称
- @Authwired 注解也可以应用在数组类型的属性上, 此时 Spring 将会把所有匹配的 Bean 进行自动装配.
- @Authwired 注解也可以应用在集合属性上, 此时 Spring 读取该集合的类型信息, 然后自动装配所有与之兼容的 Bean.
- @Authwired 注解用在 java.util.Map 上时, 若该 Map 的键值为 String, 那么 Spring 将自动装配与之 Map 值类型兼容的 Bean, 此时 Bean 的名称作为键值
三、基于Java容器配置
从Spring 3.0开始,可以使用java代码配置Bean,替代XML配置。
首先让我们看一下基于Java类如何定义Bean配置元数据,具体步骤如下:
- 使用@Configuration注解需要作为配置的类,表示该类将定义Bean的元数据
- 使用@Bean注解相应的方法,该方法名默认就是Bean的名称,该方法返回值就是Bean的对象。
- AnnotationConfigApplicationContext或子类进行加载基于java类的配置
通过@Configuration注解的类将被作为配置类使用,表示在该类中将定义Bean配置元数据,且使用@Configuration注解的类本身也是一个Bean,使用方式如下所示:
@Configuration("ctxConfig")
public class ApplicationContextConfig {
……
}
其中Configuration中的参数值即为该bean的名称。
通过@Bean注解配置类中的相应方法,则该方法名默认就是Bean名,该方法返回值就是Bean对象,并定义了Spring IoC容器如何实例化、自动装配、初始化Bean逻辑,具体使用方法如下:
@Bean(name={},
autowire=Autowire.NO,
initMethod="",
destroyMethod="")
其中name为bean的名称,可以有多个,autowire为是否自动装配,默认值为NO,initMethod为bean的初始化方法,destoryMethod为bean的销毁方法。
注意:使用bean注解的方法不能是private、final、static的。
基于Java方式的配置方式不是为了完全替代基于XML方式的配置,两者可以结合使用,因此可以有两种结合使用方式:
在基于Java方式的配置类中引入基于XML方式的配置文件
在基于XML方式的配置文件中中引入基于Java方式的配置
引入基于XML配置文件:
<bean id="message" class="java.lang.String">
<constructor-arg index="0" value="test"></constructor-arg>
</bean>
@Configuration("ctxConfig")
@ImportResource("classpath:com/jike/***/appCtx.xml")
public class ApplicationContextConfig {
……
}
可以看到在java程序中使用@ImportResource导入了XML的配置文件。
可以通过代码一个个的引入配置类,当然也可以使用@Import注解来引入配置类
引入多个配置类:
@Configuration
@Import(DaoConfig.class)
public class ServiceConfig {……}
四、总结:不同配置方式比较

其实Spring支持这么多的配置方式,那么这些配置方式必然有其自己独特的舞台
- 基于XML的配置主要使用场景:
第三方类库,如DataSource、JdbcTemplate等;
命名空间,如aop、context等;
- 基于注解的配置主要使用场景:
Bean的实现类是当前项目开发的,可直接在Java类中使用注解配置
- 基于Java类的配置主要使用场景:
对于实例化Bean的逻辑比较复杂,则比较适合用基于Java类配置的方式
在日常的开发中我们主要是使用XML配置和注解配置方式向结合的开发方式,一般不推荐使用基于Java类的配置方式。
650

被折叠的 条评论
为什么被折叠?



