Spring的配置,通常有两种:使用配置文件和注解。那么Spring如何知道各个Bean或者Service、Controller以及Bean中各类属性之间的关系呢?答案肯定是在定义各个Java文件的时候使用了各种注解,它们交织在一起,实现了使用配置文件完成的配置功能。

一、Bean相关的注解

  与SpringBean相关的注解有以下四大类:

  • @Component:标注一个普通的Spring Bean类

  • @Controller:标注一个控制器组件类

  • @Service:标注一个业务逻辑组件类

  • @Repository:标注一个DAO组件类

  如果我们需要定义一个普通的Spring Bean,那么直接使用@Component标注即可。但如果用@Repository、@Service或者@Controller来标注,那么这个Bean类将被作为特殊的JavaEE组件来对待。在Spring的未来版本中,@Controller、@Service和@Repository也许还能携带更多的语义,因此,如果需要在JavaEE应用中使用这些注解时,尽量考虑使用@Controller、@Service和@Repository来代替普通的@Component注解。例如:

@Scope("prototype")
@Component("pp")
public class People {
private int age;
private String name;
//省略getter和setter
} @Service
public class PeopleService {
@Autowired
private PeopleRepo peopleDao; public void addPeople(People p) {
//other business logic here
//...call method in PeopleRepo to complete
}
//省略 peopleDao的setter和getter
} @Repository
public class PeopleRepo {
public void addPeople(PeopleEntity p) {
//...insert data only
}
}

  指定了某些类可以作为Spring Bean后,还需要为Spring指定Bean的搜索路径,便于Spring自动在这个路径下搜索相关的Bean。在指定这个(或这些,如果有多个的话)路径之前,需要在Spring配置文件中导入context Schema:

<!-- 第4,6,7行是用于导入context Schema的 -->
<beans xmlns="
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/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <!-- 指定Spring将要扫描的包 -->
<context:component-scan base-package="com.abc.model" />
<context:component-scan base-package="com.abc.service" />
</bean>

  上面的配置文件中的 comtext:component-scan指定了Spring将把com.abc.model包和com.abc.service包作为扫描目录,搜索其中带了@Component、@Controller、@Repository和@Service等注解的类作为容器中的Bean(某些是特殊的Bean)。

  在基于XML配置方式下,每个Bean实例的名称都由其id属性指定,而在使用注解配置Spring的方式下,Spring将采用约定的方式来为这些Bean实例指定名称,这些Bean实例的名称默认是Bean类的首字母小写,其他部分不变。 当然,Spring也允许使用@Component注解时自定义Bean的名字,如上面的People的注解@Component("pp"),意为把People的Bean实例命名为 "pp" 。

  当使用XML配置Bean时,可以通过scope来指定Bean的作用域,在使用注解时,可通过@Scope注解来标注,只要在该注解中提供作用域的名称即可。例如上面的:

@Scope("prototype")
@Component("pp")
public class People {
private int age;
private String name;
//省略getter和setter
}

  另外,我们还可以通过为<component-scan>元素添加<include-filter>和<exclude-filter>子元素来限制Spring Bean的类。满足<include-filter>定义的规则的Java类,才会被当作Bean处理,满足<exclude-filter>规则的Java类,则不会当作Bean处理。使用这两个属性时,都需要为其指定下面两个元素:

  • type:指定过滤器类型

  • expression:知道你过过滤器所需要的表达式

    Spring支持以下几种过滤器:

  • annotation:Annotation过滤器,该过滤器需要指定一个Annotation名

  • assignable:类名过滤器,该过滤器直接指定一个Java类

  • regex:正则表达式过滤器,该过滤器指定一个正则表达式,匹配该正则表达式的Java类将满足该过滤规则。如:com\.abc\.*

  • aspectj:AspectJ过滤器

<!-- 指定Spring将要扫描的包 -->
<context:component-scan base-package="com.abc.model">
<context:include-filter type="regex" expression=".*Peo*" />
<context:exclude-filter type="regex" expression=".*PPP*" />
</context:component-scan>

二、使用@Resource配置依赖

  @Resource注解位于java.annotation包下,是来自JavaEE规范中的一个注解,Spring直接借鉴了该注解,其作用是为目标Bean指定协作者Bean。

  @Resource有一个name属性,在默认情况下,Spring将这个值解释为需要被注入的Bean实例的名字。换句话说:使用@Resource与配置文件中<property>中的ref属性有相同的效果。例如:

@Component
public class People {
private Work work;
@Resource(name="computerWork")
public void setWork(Work work) {
this.work = work;
}
}

  上例就是将 "computerWork" 注入该setWork方法,也就是将容器中的computerWork作为setWork()方法的参数传入。

  @Resource方法不仅可以修饰setter方法,还可以直接修饰Field。如果使用@Resource修饰Field将更加简单,此时Spring将直接使用JavaEE中规范的Field注入,此时连setter方法都可以不要,例如可以将刚刚的例子改写为:

@Component
public class People {
@Resource(name="computerWork")
private Work work;
//do not need setter anymore
}

  使用@Resource注解时,其name属性也可以省略,默认情况下,name属性是该setter方法去掉set子串后,再将首字母小写得到的值。例如:使用@Resource标注setWork方法,则Spring默认会注入容器中名为work的组件。

  当使用@Resource标注一个Field时,如果省略name属性,则name属性默认与被标注的Field同名。例如:使用@Resource标注private Work work域,则Spring将把容器中名为work的组件注入。

三、使用@PostConstruct和@PreDestroy定制Bean的生命周期行为

  @PostConstruct和@PreDestroy两个注解同样位于java.annotation包下,也是来自JavaEE规范的注解,Spring也借鉴了它们,用于定制Spring容器中Bean的生命周期行为。这里介绍了Spring中的Bean可以指定init-method和destroy-method属性,而@PostConstruct和@PreDestroy的作用与此大致相似,他们都用于修饰方法,无需任何属性。其中前者修饰的方法是Bean的初始化方法;而后者修hi的方法是Bean销毁之前将要调用的方法。例如:

@Component
public class People {
@Resource(name="computerWork")
private Work work; @PostConstruct
public void init() {
//...other operations here
System.out.println("init方法:所有依赖注入完成");
} @PreDestroy
public void destroy() {
//...other operations here
System.out.println("destroy方法:销毁之前");
}
}

四、Spring3.0新增的注解

  Spring3.0增加了两个新的注解:@DependsOn和@Lazy ,其中@DependsOn用于强制初始化其他Bean,而@Lazy则用于指定该Bean是否取消预初始化。

  @DependsOn可以修饰Bean类或方法,使用该注解时可以指定一个字符串数组作为参数,每个数组元素对应一个强制初始化的Bean,例如:

@DependsOn({"computerWork","job"})
@Component
public class People {
@Resource(name="computerWork")
private Work work;
@Resource(name="job")
private Job job;
}

  上面的代码使用了@DependsOn修饰了People类,这就指定在初始化People Bean之前,会强制初始化computerWork和job两个Bean。

  @Lazy注解主要用于修饰Spring Bean类,用于指定该Bean的预初始化行为,使用该注解时可以指定一个bool类型的值,该属性决定是否预初始化这个Bean。如果该值为true,则表示该Bean不会预初始化。例如:

@DependsOn(true) //这个Bean不会预初始化
@Component
public class People {
//....
}

五、自动装配与精确装配

  Spring提供了@Autowired注解来指定自动装配,使用@Autowired可以标注setter方法,普通方法,Field和构造器等。例如:

@Component
public class People {
private Work work; @Autowired
public void setWork(Work work) {
this.work = work;
}
}

  上面的代码使用了@Autowired指定对setWork()方法进行自动装配,Spring会将自动搜索器中类型为Work的Bean实例,并将该Bean实例作为setWork()方法的参数传入,注入给People实例。由此可见,当使用@Autowired注解标注setter方法时,默认使用的是byType的自动装配策略。

  Spring允许使用@Autowired来标注同时注入多个参数的普通方法,例如:

@Component
public class People {
private Work work;
private Job job; @Autowired
public void init(Work work, Job job) {
this.work = work;
this.job = job;
}
}

使用@Autowired来标注Field和构造器的例子:

@Component
public class People {
@Autowired
private School school;
private Work work;
private Job job; @Autowired
public People(Work work, Job job) {
this.work = work;
this.job = job;
}
}

  当使用@Autowired来标注一个Field时,Spring将会把容器中与该Field类型匹配的Bean注入该属性。例如程序中使用@Autowired标注了school属性,则Spring会自动搜索容器中的School实例,并将该实例设置成该school Field的值;如果此时容器中不止一个School类型的Bean,则Spring将抛出一个BeanCreateException异常。

  @Autowired甚至可以用来修饰数组:

@Component
public class People {
@Autowired
private School[] schools;
}

  在这种情况下,Spring将会搜集容器中所有类型为School的Bean,并用这些Bean创建一个数组,最后将这个数组注入给People的schools属性。与此类似的是,@Autowired也可以标注集合Field,或标注形参类型是集合的方法,Spring对这种集合属性,集合形参的处理与前面数组的处理是完全相同的。例如:

@Component
public class People {
@Autowired
private Set<School> schools; private Set<Work> works;
@Autowired
public void setWorks(Set<Work> works) {
this.works = works;
}
}

  对于这种集合类型的参数而言,程序代码中必须使用泛型,正如上面的程序所示,程序制定了该方法参数是Set<Work>类型,这表明,Spring会自动搜索容器中所有的Work类型实例,并将这些示例注入到到works属性中。如果程序中没有使用泛型来指明集合元素类型, 则Spring将不知所措。

  正如上面看到的,@Autowired总是采用byType的自动装配策略,在这种策略下,符合自动装配的类型的候选Bean常常有多个,这个时候就可能引起异常了(对于数组,集合类型的参数则不会)。

  为了实现精确的自动装配,Spring提供了@Qualifier注解,通过使用这个注解,允许Bean标识来指定自动装配。通常会为@Qualifier指定一个名字,表示精确定位id为这个名字的Bean,@Qualifier通常用于修饰Field,例如:

@Component
public class People {
@Autowired
@Qualifier("juniorHighSchool")
private School school; //setter
public void setSchool(School school) {
this.shool = school;
}
}

  上面的配置文件中指定了school将使用自动装配,且精确指定了被装配的Bean实例名称为juniorHighSchool,这意味着如果Spring容器中有多个School类型的Bean,只会将一个名为juniorHighSchool的Bean注入进来。

  除此之外,Spring还允许使用@Qualifier来标注方法的形参,例如:

@Component
public class People {
private School school; //setter
public void setSchool(@Qualifier("juniorHighSchool")School school) {
this.shool = school;
}
}

本文转自:http://my.oschina.net/itblog/blog/207353

浅析Spring中的注解的更多相关文章

  1. Spring中@Autowired注解、@Resource注解的区别 (zz)

    Spring中@Autowired注解.@Resource注解的区别 Spring不但支持自己定义的@Autowired注解,还支持几个由JSR-250规范定义的注解,它们分别是@Resource.@ ...

  2. Spring中Value注解的使用

    Spring中Value注解的使用 分类: Spring2014-08-16 17:28 2985人阅读 评论(0) 收藏 举报 有的时候我们定义了Properties文件,并且使用Spring的Pr ...

  3. 全面解析Spring中@ModelAttribute注解的用法

    本文不再更新,可能存在内容过时的情况,实时更新请移步我的新博客:全面解析Spring中@ModelAttribute注解的用法: @ModelAttribute注解用于将方法的参数或方法的返回值绑定到 ...

  4. EnableAutoConfiguration注解 Spring中@Import注解的作用和使用

    EnableAutoConfiguration注解 http://www.51gjie.com/javaweb/1046.html springboot@EnableAutoConfiguration ...

  5. Spring中常用注解的介绍

    spring中使用注解时配置文件的写法: <?xml version="1.0" encoding="UTF-8"?> <span style ...

  6. Spring中使用注解时启用<context:component-scan/>

    在spring中使用注解方式时需要在spring配置文件中配置组件扫描器:http://blog.csdn.net/j080624/article/details/56277315 <conte ...

  7. Spring中异步注解@Async的使用、原理及使用时可能导致的问题

    前言 其实最近都在研究事务相关的内容,之所以写这么一篇文章是因为前面写了一篇关于循环依赖的文章: <面试必杀技,讲一讲Spring中的循环依赖> 然后,很多同学碰到了下面这个问题,添加了S ...

  8. Spring中@Import注解的使用

    Spring中@Import注解的使用 @Import注解算是SpringBoot自动配置原理中一个很重要的注解 认识@Import注解 先看一下源码 @Target(ElementType.TYPE ...

  9. Spring中常用注解

    1.@Component 创建类对象,相当于配置<bean/> 2.@Service @Service与@Component功能相同,写在ServiceImpl类上 3.@Reposito ...

随机推荐

  1. 使用PHPExcel导入Excel到MySql

    .连接数据库的connection.php文件 <?php //修改下面代码来联接数据库 // mysql_connect打开一个到 MySQL 服务器的连接,如果成功则返回一个 MySQL 连 ...

  2. 在Salesforce中将 Decimal 数据转换成美元格式

    闲言少叙,直接上代码(Apex Class 中的方法): private string ConvertToMoneyFormat(decimal price){ if (price == null | ...

  3. Codeforces VK Cup 2012 Round 3 A. Variable, or There and Back Again(dfs)

    题目链接:http://codeforces.com/problemset/problem/164/A 思路:用vector分别保留原图和发图,然后分别从val值为1的点正向遍历,va值为2的点反向遍 ...

  4. 编译原理实习(应用预测分析法LL(1)实现语法分析)

    #include<iostream> #include<fstream> #include<iomanip> #include<cstdio> #inc ...

  5. Java学习笔记(五)——数组

    一.数组使用方法 1. 声明数组 语法: 数据类型[ ] 数组名: 或者   数据类型 数组名[ ]: 其中,数组名可以是任意合法的变量名 2. 分配空间 简单地说,就是指定数组中最多可存储多少个元素 ...

  6. 通信原理实践(一)——音频信号处理

    一.信号的离散化 1.采样定理: –如果信号是带限的,并且采样频率fs超过信号最高频率的两倍,那么,原来的连续信号可以从采样样本中完全重建出来. 因此在仿真过程中,采样率(fs)是一个非常重要的参数. ...

  7. RMI的概念

    RMI(Remote Method Invocation)远程方法调用是一种计算机之间利用远程对象互相调用实现双方通讯的一种通讯机制.使用这种机制,某一台计算机上的对象可以调用另外一台计算机上的对象来 ...

  8. Android 退出Activity

    在一个Process或一个处理线程中退出Activity可以用context来退出,如下: ((Activity)context).finish(); Android程序有很多Activity,比如说 ...

  9. 【转】最近搞Hadoop集群迁移踩的坑杂记

    http://ju.outofmemory.cn/entry/237491 Overview 最近一段时间都在搞集群迁移.最早公司的hadoop数据集群实在阿里云上的,机器不多,大概4台的样子,据说每 ...

  10. 关于本地存储构成数组以及jquery的inArray方法的使用

    for (var i=0, j = _self.sessionStorage.length; i < j; i++){ var key = _self.sessionStorage.key(i) ...