在Spring的第二篇中主要讲解了Spring Core模块的使用IOC容器创建对象的问题,Spring Core模块主要是解决对象的创建和对象之间的依赖关系,因此本博文主要讲解如何 使用IOC容器来解决对象之间的依赖关系 !
我们来看一下我们以前关于对象依赖,是怎么的历程
class UserService{ UserDao userDao = new UserDao(); }
后来,我们发现service层紧紧耦合了dao层。 我们就写了DaoFactory,在service层只要通过字符串就能够创建对应的dao层的对象了。
public class DaoFactory { private static final DaoFactory factory = new DaoFactory(); private DaoFactory(){} public static DaoFactory getInstance(){ return factory; } public <T> T createDao(String className,Class<T> clazz){ try{ T t = (T) Class.forName(className).newInstance(); return t; }catch (Exception e) { throw new RuntimeException(e); } } }
private CategoryDao categoryDao = DaoFactory.getInstance().createDao("zhongfucheng.dao.impl.CategoryDAOImpl", CategoryDao.class); private BookDao bookDao = DaoFactory.getInstance().createDao("zhongfucheng.dao.impl.BookDaoImpl", BookDao.class); private UserDao userDao = DaoFactory.getInstance().createDao("zhongfucheng.dao.impl.UserDaoImpl", UserDao.class); private OrderDao orderDao = DaoFactory.getInstance().createDao("zhongfucheng.dao.impl.OrderDaoImpl", OrderDao.class);
再后来,我们发现要修 改Dao的实现类,还是得修改service层的源代码 呀.. 于是我们就在DaoFactory中读取关于daoImpl的配置文件,根据配置文件来创建对象,这样一来,创建的是哪个daoImpl对service层就是透明的
public class DaoFactory { private UserDao userdao = null; private DaoFactory(){ try{ InputStream in = DaoFactory.class.getClassLoader().getResourceAsStream("dao.properties"); Properties prop = new Properties(); prop.load(in); String daoClassName = prop.getProperty("userdao"); userdao = (UserDao)Class.forName(daoClassName).newInstance(); }catch (Exception e) { throw new RuntimeException(e); } } private static final DaoFactory instance = new DaoFactory(); public static DaoFactory getInstance(){ return instance; } public UserDao createUserDao(){ return userdao; } }
UserDao dao = DaoFactory.getInstance().createUserDao();
通过上面的历程,我们可以清晰地发现: 对象之间的依赖关系,其实就是给对象上的属性赋值!因为对象上有其他对象的变量,因此存在了依赖 ...
Spring提供了好几种的方式来给属性赋值
UserAction中使用userService变量来维护与Service层之间的依赖关系
userDao
public class UserDao { public void save() { System.out.println("DB:保存用户"); } }
public class UserService { private UserDao userDao; public void save() { userDao.save(); } }
public class UserAction { private UserService userService; public String execute() { userService.save(); return null; } }
其实我们在讲解 创建带参数的构造函数的时候已经讲过了 ...我们还是来回顾一下呗..
我们 测试service和dao的依赖关系就好了 ....在 serice中加入一个构造函数,参数就是userDao
public UserService(UserDao userDao) { this.userDao = userDao; //看看有没有拿到userDao System.out.println(userDao); }
applicationContext.xml配置文件
<!--创建userDao对象--> <bean id="userDao" class="UserDao"/> <!--创建userService对象--> <bean id="userService" class="UserService"> <!--要想在userService层中能够引用到userDao,就必须先创建userDao对象--> <constructor-arg index="0" name="userDao" type="UserDao" ref="userDao"></constructor-arg> </bean>
// 创建容器对象 ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml"); //得到service对象 UserService userService = (UserService) ac.getBean("userService");
我们这里也是测试service和dao层的依赖关系就好了... 在service层通过set方法来把userDao注入到UserService中
public class UserService { private UserDao userDao; public void setUserDao(UserDao userDao) { this.userDao = userDao; //看看有没有拿到userDao System.out.println(userDao); } public void save() { userDao.save(); } }
applicationContext.xml配置文件:通过property节点来给属性赋值
<!--创建userDao对象--> <bean id="userDao" class="UserDao"/> <!--创建userService对象--> <bean id="userService" class="UserService"> <property name="userDao" ref="userDao"/> </bean>
我们刚才是 先创建userDao对象,再由userService对userDao对象进行引用 ...我们还有另一种思维: 先创建userService,发现userService需要userDao的属性,再创建userDao ...我们来看看这种思维方式是怎么配置的:
applicationContext.xml配置文件:property节点内置bean节点
<!-- 1.创建userService,看到有userDao这个属性 2.而userDao这个属性又是一个对象 3.在property属性下又内置了一个bean 4.创建userDao --> <bean id="userService" class="UserService"> <property name="userDao"> <bean id="userDao" class="UserDao"/> </property> </bean>
我们发现这种思维方式和服务器访问的执行顺序是一样的,但是 如果userDao要多次被其他service使用的话,就要多次配置了 ...
p名称控件这种方式 其实就是set方法的一种优化,优化了配置而已 ...p名称空间这个内容 需要在Spring3版本以上才能使用 ...我们来看看:
applicationContext.xml配置文件:使用p名称空间
<bean id="userDao" class="UserDao"/> <!--不用写property节点了,直接使用p名称空间--> <bean id="userService" class="UserService" p:userDao-ref="userDao"/>
Spring还提供了自动装配的功能,能够非常简化我们的配置
自动装载默认是不打开的,自动装配常用的可分为两种:
applicationContext.xml配置文件:使用自动装配,根据名字
<bean id="userDao" class="UserDao"/> <!-- 1.通过名字来自动装配 2.发现userService中有个叫userDao的属性 3.看看IOC容器中没有叫userDao的对象 4.如果有,就装配进去 --> <bean id="userService" class="UserService" autowire="byName"/>
applicationContext.xml配置文件:使用自动装配,根据类型
值得注意的是: 如果使用了根据类型来自动装配,那么在IOC容器中只能有一个这样的类型,否则就会报错!
<bean id="userDao" class="UserDao"/> <!-- 1.通过名字来自动装配 2.发现userService中有个叫userDao的属性 3.看看IOC容器UserDao类型的对象 4.如果有,就装配进去 --> <bean id="userService" class="UserService" autowire="byType"/>
我们这只是测试两个对象之间的依赖关系,如果我们有很多对象,我们也可以 使用默认自动分配
@Autowired注解来实现自动装配:
如果没有匹配到bean,又为了避免异常的出现,我们可以使用required属性上设置为false。【谨慎对待】
@Component public class UserService { private UserDao userDao ; @Autowired public void setUserDao(UserDao userDao) { this.userDao = userDao; } }
顺利拿到userDao的引用
在
import org.springframework.context.annotation.Bean; @org.springframework.context.annotation.Configuration public class Configuration { @Bean() public UserDao userDao() { return new UserDao(); } @Bean public UserService userService() { //直接调用@bean的方法 return new UserService(userDao()); } }
import org.springframework.context.annotation.Bean; @org.springframework.context.annotation.Configuration public class Configuration { @Bean() public UserDao userDao() { return new UserDao(); } @Bean public UserService userService(UserDao userDao) { //通过构造函数依赖注入 return new UserService(userDao); } }
import org.springframework.beans.factory.annotation.Autowire; import org.springframework.context.annotation.Bean; @org.springframework.context.annotation.Configuration public class Configuration { @Bean() public UserDao userDao() { return new UserDao(); } @Bean(autowire = Autowire.BY_TYPE) public UserService userService(UserDao userDao) { return new UserService(userDao); } }
public class Configuration { @Bean() public UserDao userDao() { return new UserDao(); } @Bean(autowire = Autowire.BY_TYPE) public UserService userService() { return new UserService(userDao()); } }
当然了, 最简单直观的方法 还有一种: 在UserService中加入setUser()方法,那么只要set进去就行了 ..
public class UserService { private UserDao userDao ; public UserService() { } public UserService(UserDao userDao) { } public void setUserDao(UserDao userDao) { this.userDao = userDao; } }
import org.springframework.context.annotation.Bean; @org.springframework.context.annotation.Configuration public class Config1 { @Bean(name = "userDao") public UserDao userDao() { return new UserDao(); } @Bean(name="userService") public UserService userService() { UserService userService = new UserService(); userService.setUserDao(userDao()); return userService; } }
扩展阅读:
如果文章有错的地方欢迎指正,大家互相交流。习惯在微信看技术文章,想要获取更多的Java资源的同学,可以 关注微信公众号:Java3y