annotation-config/>
当某个被标注了@Required的Setter方法没有被调用,则Spring在解析的时候会抛出异常,以提醒开发者对相应属性进行设置。
使用@Resource、@Autowired和@Qualifier指定Bean的自动装配策略
自动装配是指,Spring在装配Bean的时候,根据指定的自动装配规则,将某个Bean所需要引用类型的Bean注入进来。
元素提供了一个指定自动装配类型的autowire属性,该属性有如下选项:
no--显式指定不使用自动装配。
byName--如果存在一个和当前属性名字一致的Bean,则使用该Bean进行注入。
如果名称匹配但是类型不匹配,则抛出异常。
如果没有匹配的类型,则什么也不做。
byType--如果存在一个和当前属性类型一致的Bean(相同类型或者子类型),则使用该Bean进行注入。
byType能够识别工厂方法,即能够识别factory-method的返回类型。
如果存在多个类型一致的Bean,则抛出异常。
如果没有匹配的类型,则什么也不做。
constructor--与byType类似,只不过它是针对构造函数注入而言的。
如果当前没有与构造函数的参数类型匹配的Bean,则抛出异常。
使用该种装配模式时,优先匹配参数最多的构造函数。
autodetect--根据Bean的自省机制决定采用byType还是constructor进行自动装配。
如果Bean提供了默认的构造函数,则采用byType;否则采用constructor进行自动装配。
当使用byType或者constructor类型的自动装配的时候,自动装配也支持引用类型的数组或者使用了泛型的集合,这样,Spring就会检查容器中所有类型匹配的Bean,组成集合或者数组后执行注入。
对于使用了泛型的Map类型,如果键是String类型,则Spring也会自动执行装配,将所有类型匹配的Bean作为值,Bean的名字作为键。
我们可以给增加default-autowire属性,设置默认的自动封装策略。
默认值为"no"。
如果使用自动装配的同时,也指定了property或者constructor-arg标签,则显式指定的值将覆盖自动装配的值。
目前的自动封装不支持简单类型,比如基本类型、String、Class,以及它们的数组类型。
在按类型匹配的时候(可能是byType、constructor、autodetect),同一个类型可能存在多个Bean,如果被注入的属性是数组、集合或者Map,这可能没有问题,但是如果只是简单的引用类型,则会抛出异常。
解决方法有如下几种:
取消该Bean的自动装配特性,使用显式的注入。
我们可能不希望某个Bean被当作其他Bean执行自动封装时的候选对象,我们可以给该增加autowire-candidate="false"。
(autowire-candidate属性和autowire属性相互独立,互不相干。
某个Bean可以将autowire-candidate设置为false,同时使用autowire特性。
)另外,我们可以设置的default-autowire-candidates属性,可以在该属性中指定可以用于自动装配候选Bean的匹配模式,比如default-autowire-candidates="*serv,*dao",这表示所有名字以serv或者dao结尾的Bean被列为候选,其他则忽略,相当于其他Bean都指定为autowire-candidate="false",此时可以显式为指定autowire-candidate="true"。
在上指定的设置要覆盖上指定的设置。
如果在多个类型相同的Bean中有首选的Bean,那么可以将该的primary属性设置为"true",这样自动装配时便优先使用该Bean进行装配。
此时不能将autowire-candidate设为false。
如果使用的是Java5以上版本,可以使用注解进行更细粒度的控制。
使用@Autowired和@Qualifier注解执行自动装配
使用@Autowired注解进行装配,只能是根据类型进行匹配。
@Autowired注解可以用于Setter方法、构造函数、字段,甚至普通方法,前提是方法必须有至少一个参数。
@Autowired可以用于数组和使用泛型的集合类型。
然后Spring会将容器中所有类型符合的Bean注入进来。
@Autowired标注作用于Map类型时,如果Map的key为String类型,则Spring会将容器中所有类型符合Map的value对应的类型的Bean增加进来,用Bean的id或name作为Map的key。
@Autowired标注作用于普通方法时,会产生一个副作用,就是在容器初始化该Bean实例的时候就会调用该方法。
当然,前提是执行了自动装配,对于不满足装配条件的情况,该方法也不会被执行。
当标注了@Autowired后,自动注入不能满足,则会抛出异常。
我们可以给@Autowired标注增加一个required=false属性,以改变这个行为。
另外,每一个类中只能有一个构造函数的@Autowired.required()属性为true。
否则就出问题了。
如果用@Autowired同时标注了多个构造函数,那么,Spring将采用贪心算法匹配构造函数(构造函数最长)。
@Autowired还有一个作用就是,如果将其标注在BeanFactory类型、ApplicationContext类型、ResourceLoader类型、ApplicationEventPublisher类型、MessageSource类型上,那么Spring会自动注入这些实现类的实例,不需要额外的操作。
当容器中存在多个Bean的类型与需要注入的相同时,注入将不能执行,我们可以给@Autowired增加一个候选值,做法是在@Autowired后面增加一个@Qualifier标注,提供一个String类型的值作为候选的Bean的名字。
举例如下:
双击代码全选
1
2
3
@Autowired(required=false)
@Qualifier("ppp")
public void setPerson(person p){}
@Qualifier甚至可以作用于方法的参数(对于方法只有一个参数的情况,我们可以将@Qualifer标注放置在方法声明上面,但是推荐放置在参数前面),举例如下:
双击代码全选
1
2
@Autowired(required=false)
public void sayHello(@Qualifier("ppp")Person p,String name){}
我们可以在配置文件中指定某个Bean的qualifier名字,方法如下:
双击代码全选
1
2
3
如果没有明确指定Bean的qualifier名字,那么默认名字就是Bean的名字。
通常,qualifier应该是有业务含义的,例如"domain","persistent"等,而不应该是类似"person"方式。
我们还可以将@Qualifier标注在集合类型上,那么所有qualifier名字与指定值相同的Bean都将被注入进来。
最后,配置文件中需要指定每一个自定义注解的属性值。
我们可以使用标签来代替标签,如果标签和标签同时出现,那么优先使用标签。
如果没有标签,那么会用提供的键值对来封装标签。
示例如下:
双击代码全选
1
2
3
4
5
6
7
8
9
10
@Autowired注解对应的后处理注册与前面相似,只需在配置文件中增加如下一行即可:
双击代码全选
1
annotation-config/>
如果@Autowired注入的是BeanFactory、ApplicationContext、ResourceLoader等系统类型,那么则不需要@Qualifier,此时即使提供了@Qualifier注解,也将会被忽略;而对于自定义类型的自动装配,如果使用了@Qualifier注解并且没有名字与之匹配的Bean,则自动装配匹配失败。
使用JSR-250中的@Resource和@Qualifier注解
如果希望根据name执行自动装配,那么应该使用JSR-250提供的@Resource注解,而不应该使用@Autowired与@Qualifier的组合。
@Resource使用byName的方式执行自动封装。
@Resource标注可以作用于带一个参数的Setter方法、字段,以及带一个参数的普通方法上。
@Resource注解有一个name属性,用于指定Bean在配置文件中对应的名字。
如果没有指定name属性,那么默认值就是字段或者属性的名字。
@Resource和@Qualifier的配合虽然仍然成立,但是@Qualifier对于@Resource而言,几乎与name属性等效。
如果@Resource没有指定name属性,那么使用byName匹配失败后,会退而使用byType继续匹配,如果再失败,则抛出异常。
在没有为@Resource注解显式指定name属性的前提下,如果将其标注在BeanFactory类型、ApplicationContext类型、ResourceLoader类型、ApplicationEventPublisher类型、MessageSource类型上,那么Spring会自动注入这些实现类的实例,不需要额外的操作。
此时name属性不需要指定(或者指定为""),否则注入失败;如果使用了@Qualifier,则该注解将被忽略。
而对于用户自定义类型的注入,@Qualifier和name等价,并且不被忽略。
的primary和autowire-candidate属性对@Resource、@Autowired仍然有效。
使用@Configuration和@Bean进行Bean的声明
虽然2.0版本发布以来,Spring陆续提供了十多个注解,但是提供的这些注解只是为了在某些情况下简化XML的配置,并非要取代XML配置方式。
这一点可以从SpringIoC容器的初始化类可以看出:
ApplicationContext接口的最常用的实现类是ClassPathXmlApplicationContext和FileSystemXmlApplicationContext,以及面向Portlet的XmlPortletApplicationContext和面向web的XmlWebApplicationContext,它们都是面向XML的。
Spring3.0新增了另外两个实现类:
AnnotationConfigApplicationContext和AnnotationConfigWebApplicationContext。
从名字便可以看出,它们是为注解而生,直接依赖于注解作为容器配置信息来源