用Spring来实现IOC
在上节中我们自定义了一个接口BeanFactory和类ClassPathXmlApplicationContext来模拟Spring,其实它们在Spring中确实是存在的,下面我们具体来看看Spring的控制反转是如何操作的
其他代码一样,只是配置文件和单元测试的代码有点不同,注意引用其他bean配置的是"ref"属性
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd"> <bean id="u" class="com.bjsxt.dao.impl.UserDAOImpl"> </bean> <bean id="userService" class="com.bjsxt.service.UserService"> <property name="userDAO" ref="u" /> </bean> </beans>
package com.bjsxt.service; import org.junit.Test; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.xml.XmlBeanFactory; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.core.io.ClassPathResource; import com.bjsxt.model.User; //Dependency Injection //Inverse of Control public class UserServiceTest { @Test public void testAdd() throws Exception { BeanFactory ctx = new ClassPathXmlApplicationContext("beans.xml"); UserService service = (UserService)ctx.getBean("userService"); User u = new User(); u.setUsername("zhangsan"); u.setPassword("zhangsan"); service.add(u); } }
注:ClassPathXmlApplicationContext继承ApplicationContext,ApplicationContext又继承BeanFactory,所以也可以这样写ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");推荐使用这种写法。其构造函数也可以传入String数组,适用于多个配置文件的情况
三种注入方式(setter,构造函数,接口)
setter已经见过了,接口注入很少用,故此忽略,下面来看一下构造函数注入,在UserService中添加一个构造函数初始化UserDAO属性
package com.bjsxt.service; import com.bjsxt.dao.UserDAO; import com.bjsxt.model.User; public class UserService { private UserDAO userDAO; public void add(User user) { userDAO.save(user); } public UserDAO getUserDAO() { return userDAO; } public void setUserDAO(UserDAO userDAO) { this.userDAO = userDAO; } public UserService(UserDAO userDAO) { super(); this.userDAO = userDAO; } }
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd"> <bean id="u" class="com.bjsxt.dao.impl.UserDAOImpl"> </bean> <bean id="userService" class="com.bjsxt.service.UserService"> <!-- <property name="userDAO" ref="u" /> --> <constructor-arg> <ref bean="u"/> </constructor-arg> </bean> </beans>
注意用的是constructor-arg标签,如果构造函数有多个参数,就按照顺序写,或者指定index
Bean的Scope属性
配置文件中bean有个scope属性,如果配置为singleton,表示该bean只有一个实例,如果配置为prototype,每次取出该bean都会创建一个新的对象。bean的scope属性配置为singleton和prototype,在下面的代码中会分别输出true和false
package com.bjsxt.service; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.bjsxt.model.User; //Dependency Injection //Inverse of Control public class UserServiceTest { @Test public void testAdd() throws Exception { ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml"); UserService service = (UserService)ctx.getBean("userService"); UserService service2 = (UserService)ctx.getBean("userService"); System.out.println(service == service2); User u = new User(); u.setUsername("zhangsan"); u.setPassword("zhangsan"); service.add(u); } }