接上回,由于BeanFactory已经渐渐被人们所遗弃,所以我们可以将应用改写为ApplicationContext容器管理。在使用ApplicationContext我们首先要将spring-context.jar添加到Maven依赖:
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency>
这时候已导入的jar包如下:
修改Car类中main方法:
public static void main(final String[] args) { // final Resource res = new ClassPathResource("applicationContext.xml"); // final BeanFactory bf = new XmlBeanFactory(res); ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); final Car myCar = (Car) ctx.getBean("myCar"); myCar.showInfo(); myCar.launch(); }
再run一次,可以出来同样的结果。
说ApplicationContext的主要目的还是要将我们的应用改写成注解注入的形式。首先,我们以前使用的XMLBeanFactory不能支持注解注入,因为注解注入是通过BeanPostProcessor的postProcessBeforeInitialization完成的,但是BeanFactory并没有继承或者调用BeanPostProcessor,所以我们只能依靠ApplicationContext完成。
我们首先修改Car类,将engine的getter和setter方法去掉,然后在engine上加上@Autowired注解,这个注解会根据成员的类型自动注入实现,并且是反射注入(可以没有getter和setter方法):
public class Car { @Autowired private Engine engine; private List<Wheel> wheels; public List<Wheel> getWheels() { return wheels; } public void setWheels(final List<Wheel> wheels) { this.wheels = wheels; } public void showInfo() { engine.showInfo(); for (final Wheel wheel : wheels) { wheel.showInfo(); } } public void launch() { engine.launch(); } }
由于wheels是一个List,我们现在还不能通过注解解决它,没关系,以后会有好的解决方式的,现在不妨就这样留在这边。
现在去跑以下应用肯定会报错,因为Spring有一个管理注解注入的开关,这个开关默认是关闭的,我们到配置文件中加一句话即可:
<context:annotation-config />
注意在beans标签下应该有如下属性:
xmlns:context=http://www.springframework.org/schema/context
xsi:schemaLocation="…http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.X.xsd">
也就是context的命名空间和xsd引入。
下面我们可以将id为car的bean中的engine给去掉了。
再run一次,就可以出来同样的结果了。
我们还可以再进一步,既然注入可以通过注解完成,那么寻找bean的过程同样可以。
我们在EngineOne和WheelNumOne上加上@Repository注解,然后在配置文件中去掉engine这个bean,然后加入如下标签:
<context:component-scan base-package="com/zrabbit.production.part" />
这个标签的意思是告诉Spring去自动扫描指定包和其所有子包内所有的类中的注解,此时可以将配置文件中的engineOne和wheelNumOne的bean给拿掉了。现在,我们的配置文件就是以下样子了:
<?xml version="1.0" encoding="UTF-8"?> <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-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd"> <context:annotation-config /> <context:component-scan base-package="com/zrabbit.production.part" /> <bean id="myCar" class="com.zrabbit.production.Car"> <property name="wheels" > <list> <ref bean="wheelNumOne" /> <ref bean="wheelNumOne" /> <ref bean="wheelNumOne" /> <ref bean="wheelNumOne" /> </list> </property> </bean> </beans>
我们可以发现,使用了注解可以帮助我们省掉很多代码,并且配置简单,但有时注解注入也会带来不必要的麻烦,比如我们的例子中,Engine和Wheel的实现不可能只有一种,这时单单一个@Autowired注解就不够用了,我们可以使用@Qualifier(name)配合@Autowired使用,来确定名字确定真正注入的对象。