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注解。例如:
<a href="http://my.oschina.net/itblog/blog/207353#">?</a>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<code>@scope</code><code>(</code><code>"prototype"</code><code>)</code>
<code>@component</code><code>(</code><code>"pp"</code><code>)</code>
<code>public</code> <code>class</code> <code>people {</code>
<code> </code><code>private</code> <code>int</code> <code>age;</code>
<code> </code><code>private</code> <code>string name;</code>
<code> </code><code>//省略getter和setter</code>
<code>}</code>
<code>@service</code>
<code>public</code> <code>class</code> <code>peopleservice {</code>
<code> </code><code>@autowired</code>
<code> </code><code>private</code> <code>peoplerepo peopledao;</code>
<code> </code>
<code> </code><code>public</code> <code>void</code> <code>addpeople(people p) {</code>
<code> </code><code>//other business logic here</code>
<code> </code><code>//...call method in peoplerepo to complete</code>
<code> </code><code>}</code>
<code> </code><code>//省略 peopledao的setter和getter</code>
<code>@repository</code>
<code>public</code> <code>class</code> <code>peoplerepo {</code>
<code> </code><code>public</code> <code>void</code> <code>addpeople(peopleentity p) {</code>
<code> </code><code>//...insert data only</code>
指定了某些类可以作为spring bean后,还需要为spring指定bean的搜索路径,便于spring自动在这个路径下搜索相关的bean。在指定这个(或这些,如果有多个的话)路径之前,需要在spring配置文件中导入context schema:
<code><!-- 第4,6,7行是用于导入context schema的 --></code>
<code><</code><code>beans</code> <code>xmlns=" </code>
<code> </code><code>xmlns:xsi</code><code>=</code><code>"http://www.w3.org/2001/xmlschema-instance"</code>
<code> </code><code>xmlns:context</code><code>=</code><code>"http://www.springframework.org/schema/context"</code>
<code> </code><code>xsi:schemalocation</code><code>=</code><code>"http://www.springframework.org/schema/beans"</code>
<code> </code><code>http://www.springframework.org/schema/context</code>
<code> </code><code>http://www.springframework.org/schema/context/spring-context-3.0.xsd"></code>
<code> </code><code><!-- 指定spring将要扫描的包 --></code>
<code> </code><code><</code><code>context:component-scan</code> <code>base-package</code><code>=</code><code>"com.abc.model"</code> <code>/></code>
<code> </code><code><</code><code>context:component-scan</code> <code>base-package</code><code>=</code><code>"com.abc.service"</code> <code>/></code>
<code></</code><code>bean</code><code>></code>
上面的配置文件中的 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注解来标注,只要在该注解中提供作用域的名称即可。例如上面的:
另外,我们还可以通过为<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过滤器
<code><!-- 指定spring将要扫描的包 --></code>
<code><</code><code>context:component-scan</code> <code>base-package</code><code>=</code><code>"com.abc.model"</code><code>></code>
<code> </code><code><</code><code>context:include-filter</code> <code>type</code><code>=</code><code>"regex"</code> <code>expression</code><code>=</code><code>".*peo*"</code> <code>/></code>
<code> </code><code><</code><code>context:exclude-filter</code> <code>type</code><code>=</code><code>"regex"</code> <code>expression</code><code>=</code><code>".*ppp*"</code> <code>/></code>
<code></</code><code>context:component-scan</code><code>></code>
二、使用@resource配置依赖
@resource注解位于java.annotation包下,是来自javaee规范中的一个注解,spring直接借鉴了该注解,其作用是为目标bean指定协作者bean。
@resource有一个name属性,在默认情况下,spring将这个值解释为需要被注入的bean实例的名字。换句话说:使用@resource与配置文件中<property>中的ref属性有相同的效果。例如:
<code>@component</code>
<code> </code><code>private</code> <code>work work;</code>
<code> </code><code>@resource</code><code>(name=</code><code>"computerwork"</code><code>)</code>
<code> </code><code>public</code> <code>void</code> <code>setwork(work work) {</code>
<code> </code><code>this</code><code>.work = work;</code>
上例就是将“computerwork”注入该setwork方法,也就是将容器中的computerwork作为setwork()方法的参数传入。
@resource方法不仅可以修饰setter方法,还可以直接修饰field。如果使用@resource修饰field将更加简单,此时spring将直接使用javaee中规范的field注入,此时连setter方法都可以不要,例如可以将刚刚的例子改写为:
<code> </code><code>//do not need setter anymore</code>
使用@resource注解时,其name属性也可以省略,默认情况下,name属性是该setter方法去掉set子串后,再将首字母小写得到的值。例如:使用@resource标注setwork方法,则spring默认会注入容器中名为work的组件。
当使用@resource标注一个field时,如果省略name属性,则name属性默认与被标注的field同名。例如:使用@resource标注private work work域,则spring将把容器中名为work的组件注入。
三、使用@postconstruct和@predestroy定制bean的生命周期行为
<code> </code><code>@postconstruct</code>
<code> </code><code>public</code> <code>void</code> <code>init() {</code>
<code> </code><code>//...other operations here</code>
<code> </code><code>system.out.println(</code><code>"init方法:所有依赖注入完成"</code><code>);</code>
<code> </code><code>@predestroy</code>
<code> </code><code>public</code> <code>void</code> <code>destroy() {</code>
<code> </code><code>system.out.println(</code><code>"destroy方法:销毁之前"</code><code>);</code>
四、spring3.0新增的注解
@dependson可以修饰bean类或方法,使用该注解时可以指定一个字符串数组作为参数,每个数组元素对应一个强制初始化的bean,例如:
<code>@dependson</code><code>({</code><code>"computerwork"</code><code>,</code><code>"job"</code><code>})</code>
<code> </code><code>@resource</code><code>(name=</code><code>"job"</code><code>)</code>
<code> </code><code>private</code> <code>job job;</code>
上面的代码使用了@dependson修饰了people类,这就指定在初始化people bean之前,会强制初始化computerwork和job两个bean。
@lazy注解主要用于修饰spring bean类,用于指定该bean的预初始化行为,使用该注解时可以指定一个bool类型的值,该属性决定是否预初始化这个bean。如果该值为true,则表示该bean不会预初始化。例如:
<code>@dependson</code><code>(</code><code>true</code><code>) </code><code>//这个bean不会预初始化</code>
<code> </code><code>//....</code>
五、自动装配与精确装配
spring提供了@autowired注解来指定自动装配,使用@autowired可以标注setter方法,普通方法,field和构造器等。例如:
上面的代码使用了@autowired指定对setwork()方法进行自动装配,spring会将自动搜索器中类型为work的bean实例,并将该bean实例作为setwork()方法的参数传入,注入给people实例。由此可见,当使用@autowired注解标注setter方法时,默认使用的是bytype的自动装配策略。
spring允许使用@autowired来标注同时注入多个参数的普通方法,例如:
<code> </code><code>public</code> <code>void</code> <code>init(work work, job job) {</code>
<code> </code><code>this</code><code>.job = job;</code>
使用@autowired来标注field和构造器的例子:
<code> </code><code>private</code> <code>school school;</code>
<code> </code><code>public</code> <code>people(work work, job job) {</code>
当使用@autowired来标注一个field时,spring将会把容器中与该field类型匹配的bean注入该属性。例如程序中使用@autowired标注了school属性,则spring会自动搜索容器中的school实例,并将该实例设置成该school field的值;如果此时容器中不止一个school类型的bean,则spring将抛出一个beancreateexception异常。
@autowired甚至可以用来修饰数组:
<code> </code><code>private</code> <code>school[] schools;</code>
在这种情况下,spring将会搜集容器中所有类型为school的bean,并用这些bean创建一个数组,最后将这个数组注入给people的schools属性。与此类似的是,@autowired也可以标注集合field,或标注形参类型是集合的方法,spring对这种集合属性,集合形参的处理与前面数组的处理是完全相同的。例如:
<code> </code><code>private</code> <code>set<school> schools;</code>
<code> </code><code>private</code> <code>set<work> works;</code>
<code> </code><code>public</code> <code>void</code> <code>setworks(set<work> works) {</code>
<code> </code><code>this</code><code>.works = works;</code>
对于这种集合类型的参数而言,程序代码中必须使用泛型,正如上面的程序所示,程序制定了该方法参数是set<work>类型,这表明,spring会自动搜索容器中所有的work类型实例,并将这些示例注入到到works属性中。如果程序中没有使用泛型来指明集合元素类型, 则spring将不知所措。
正如上面看到的,@autowired总是采用bytype的自动装配策略,在这种策略下,符合自动装配的类型的候选bean常常有多个,这个时候就可能引起异常了(对于数组,集合类型的参数则不会)。
为了实现精确的自动装配,spring提供了@qualifier注解,通过使用这个注解,允许bean标识来指定自动装配。通常会为@qualifier指定一个名字,表示精确定位id为这个名字的bean,@qualifier通常用于修饰field,例如:
<code> </code><code>@qualifier</code><code>(</code><code>"juniorhighschool"</code><code>)</code>
<code> </code><code>//setter</code>
<code> </code><code>public</code> <code>void</code> <code>setschool(school school) {</code>
<code> </code><code>this</code><code>.shool = school;</code>
上面的配置文件中指定了school将使用自动装配,且精确指定了被装配的bean实例名称为juniorhighschool,这意味着如果spring容器中有多个school类型的bean,只会将一个名为juniorhighschool的bean注入进来。
除此之外,spring还允许使用@qualifier来标注方法的形参,例如:
<code>public</code> <code>class</code> <code>people { </code>
<code> </code><code>public</code> <code>void</code> <code>setschool(</code><code>@qualifier</code><code>(</code><code>"juniorhighschool"</code><code>)school school) {</code>