5.1 注解概述
用注解进行数据的配置似乎是现在越来越流行的方式,struts2、springmvc都有提供了一套基于注解的数据配置方式,这的确为我们编写代码提供了极大的便利。不过我个人还是不喜欢用注解的方式,我觉得注解的方式不够直观,而且如果类很多,需要的注解也很多,那么对于随着代码的增加,就会增加其他人阅读和维护代码的难度(纯属个人观点,也许随着工作经验的增加观点也会变化吧)。
5.1.1 注解的使用
在上一篇中我们提到过一下bean的生命周期,spring容器产生bean的第一步就是读取配置xml文件,如果我们配置了注解的方式,那么容器这时候还会读取注解的信息,产生配置元数据。那么,我们需要做什么才能让容器去读取注解的配置呢?
很简单,在xml文件中加入
<context:annotation-config/>
完整的xml文件如下(比没有用注解的xml文件多了几行xmlns和xsi)
<beansxmlns="http://www.springframework.org/schema/beans"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/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
beans>
在文档里面还有一段note,我觉得以后可能会用到,如下:
only looks for annotations on beans in the same application context in which it is defined. This means that, if you put in a WebApplicationContext for a DispatcherServlet, it only checks for @Autowired beans in your controllers, and not your services.
这个注解配置是context级别的,也就是说如果你在
WebApplicationContext中配置,只会对Controller有用,对其他的bean没用。
5.2 @Required
用在set方法上,一旦用了这个注解,那么容器在初始化bean的时候必须要进行set,也就是说必须对这个值进行依赖注入。
例子:(下面的Zoo和Dog类在以后的例子中都要用到)
动物园类Zoo
public class Zoo {
private Dog dog ;
public Dog getDog() {
return dog;
}
@required
public void setDog(Dog dog) {
this.dog = dog;
}
}
Dog类:
public class Dog {
private String name ;
private double weight ;
//get set
}
xml文件:
<beans xmlns="http://www.springframework.org/schema/beans"
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/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config>context:annotation-config>
<bean id="zoo" class="com.example.iocContainer.Zoo">bean>
<bean id="dog" class="com.example.iocContainer.Dog">bean>
beans>
测试代码:
ApplicationContext app = new ClassPathXmlApplicationContext("spring-main.xml");
Zoo zoo = (Zoo) app.getBean("zoo");
结果:
Property 'dog' is required for bean 'zoo'
5.3@Autowired
5.3.1使用方法
在第三节里面讲到过xml文件中bean的一个属性:autowire(自动装配),这个Autowired注解和autowire也很相似,就是可以不写依赖注入的配置让容器自己寻找依赖并注入,不过这个Autowired注解只能用类别来寻找依赖并注入,不像autowire属性可以自己配置依赖寻找的方式。
例子:(Dog类如上)
Zoo类:
public class Zoo {
@Autowired
private Dog dog ;
public Dog getDog() {
return dog;
}
public void setDog(Dog dog) {
this.dog = dog;
}
}
配置文件xml:
<beans xmlns="http://www.springframework.org/schema/beans"
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/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config>context:annotation-config>
<bean id="zoo" class="com.example.iocContainer.Zoo">bean>
<bean id="dog" class="com.example.iocContainer.Dog">
<property name="name" value="lili"/>
<property name="weight" value="28.9"/>
bean>
beans>
测试代码:
ApplicationContext app = new ClassPathXmlApplicationContext("spring-main.xml");
Zoo zoo = (Zoo) app.getBean("zoo");
System.out.println(zoo.getDog().getName()+" "+zoo.getDog().getWeight());
结果:
lili 28.9
从结果可以看出,spring已经完成对Zoo中依赖Dog的注入。
我们修改xml配置文件,将dog的名字改为pitdog,发现也同样可以进行依赖注入,证明@Autowired注解的确应该是利用类型来寻找依赖的。
5.3.2 对集合使用@Autowired
显然,动物园里面不可能只有一条狗,那么我们改变Zoo类:里面增加了一种ZhongHuaDog的狗,是Dog的子类。
public class Zoo {
@Autowired
private Dog dog ;
public Dog getDog() {
return dog;
}
public void setDog(Dog dog) {
this.dog = dog;
}
@Autowired
private Dog[] dogs;
public Dog[] getDogs() {
return dogs;
}
public void setDogs(Dog[] dogs) {
this.dogs = dogs;
}
@Autowired
private ZhongHuaDog[] zhongHuaDogs ;
public ZhongHuaDog[] getZhongHuaDogs() {
return zhongHuaDogs;
}
public void setZhongHuaDogs(ZhongHuaDog[] zhongHuaDogs) {
this.zhongHuaDogs = zhongHuaDogs;
}
}
ZhongHuaDog类:
public class ZhongHuaDog extends Dog {
private String color ;
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
}
配置文件
id="zoo" class="com.example.iocContainer.Zoo">
id="dog" class="com.example.iocContainer.Dog">
<property name="name" value="lili"/>
<property name="weight" value="28.9"/>
id="zhonghuadog1" class="com.example.iocContainer.ZhongHuaDog" parent="dog">
<property name="name" value="zhonghua1"/>
<property name="weight" value="23.2"/>
<property name="color" value="red"/>
id="zhonghuadog2" class="com.example.iocContainer.ZhongHuaDog" parent="dog">
<property name="color" value="red"/>
<property name="weight" value="22.1"/>
<property name="name" value="zhuonghua2"/>
测试代码:
ApplicationContext app = new ClassPathXmlApplicationContext("spring-main.xml");
Zoo zoo = (Zoo) app.getBean("zoo");
Dog[] dogs = zoo.getDogs();
ZhongHuaDog[] zhongHuaDogs = zoo.getZhongHuaDogs();
System.out.println("动物园里有Dog:"+dogs.length+"只");
for(int i=0;i
System.out.println(dogs[i].getName());
}
System.out.println("有ZhongHuaDog:"+zhongHuaDogs.length+"只");
for(int i=0;i
System.out.println(zhongHuaDogs[i].getName());
}
结果:
动物园里有Dog:3只
lili
zhonghua1
zhuonghua2
有ZhongHuaDog:2只
zhonghua1
zhuonghua2
从结果里看:
使用Autowired对集合进行依赖注入的时候,会将相应类型的子类也同样进行依赖注入。
5.4 @qualifier
5.4.1 用法
假设容器里面有很多的ZhongHuaDog,但是我们的动物园里只有一条ZhongHuaDog,那么在进行依赖注入的时候就需要进行甄别,这时候就用到了@qualifier
例子:
将xml配置文件改成:(注意两个qualifier属性)
id="zoo" class="com.example.iocContainer.Zoo">
id="dog" class="com.example.iocContainer.Dog">
<property name="name" value="lili"/>
<property name="weight" value="28.9"/>
id="zhonghuadog1" class="com.example.iocContainer.ZhongHuaDog">
"zoo"/>
<property name="name" value="zhonghua1"/>
<property name="weight" value="23.2"/>
<property name="color" value="red"/>
id="zhonghuadog2" class="com.example.iocContainer.ZhongHuaDog" parent="dog">
"yesheng"/>
<property name="color" value="red"/>
<property name="weight" value="22.1"/>
<property name="name" value="zhuonghua2"/>
Zoo文件改成:
public class Zoo {
private ZhongHuaDog zhongHuaDog ;
public ZhongHuaDog getZhongHuaDog() {
return zhongHuaDog;
}
@Autowired
public void setZhongHuaDog(@Qualifier("zoo") ZhongHuaDog zhongHuaDog) {
this.zhongHuaDog = zhongHuaDog;
}
}
测试代码:
ApplicationContext app = new ClassPathXmlApplicationContext("spring-main.xml");
Zoo zoo = (Zoo) app.getBean("zoo");
System.out.println(zoo.getZhongHuaDog().getName());
结果:
zhonghua1
这说明配置了qualifier的注解,那么容器就会去寻找和注解中qualifier值相同的bean去进行注入
5.5 @Resource
我觉得这就是一个可以使用bean id进行依赖注入的Autowired。看看用法就知道了
把5.4中的zoo改一下:
@Resource(name = "zhonghuadog2")
private ZhongHuaDog zhongHuaDog ;
public ZhongHuaDog getZhongHuaDog() {
return zhongHuaDog;
}
public void setZhongHuaDog( ZhongHuaDog zhongHuaDog) {
this.zhongHuaDog = zhongHuaDog;
}
测试代码:
ApplicationContext app = new ClassPathXmlApplicationContext("spring-main.xml");
Zoo zoo = (Zoo) app.getBean("zoo");
System.out.println(zoo.getZhongHuaDog().getName());
结果:
zhonghua2