上篇代码的缺点
上一篇我们以一个简单的例子讲述了Spring的由来,上篇中UserManager调用Dao的时候需要自己去实例化具体的Dao,或者通过工厂创建相应的Dao,最终还是客户端自己去实例化具体的UserManager,UserManager自己去拿到工厂,工厂自己去创建相应的Dao。而Spring框架封装了这创建过程,不再是我们自己手动去new,而是交给Spring的IOC容器去做这件事情,他自己(SpringIOC容器)会找,并且根据配置文件找到后new好直接传递给我们,不需要我们自己拿工厂去找去实例化。
那什么是Spring的IOC容器呢?
IOC(Inversionof Control),这个名词就叫做控制反转,控制反转还有一个名字叫做依赖注入DI(Dependencyinjection)。上篇代码中我们在UserManagerImpl中这样调用Dao层,UserDaouserDao = new UserDaoOracleImpl();这样使用接口编程可以增加代码的稳定和健壮性等等,但是接口一定是需要实现的,迟早要执行这句代码,这样一来耦合关系就产生了。ManagerImpl类与UserDaoOracleImpl类就是依赖关系,当然我们可以使用工厂来创建Dao,如下图所示。
图2.1未使用工厂创建Dao
图2.2使用工厂来创建Dao
使用工厂表面上一定程度解决了以上的问题,但实质上代码耦合没有改变。而通过IOC容器可以彻底解决这种耦合,是把耦合的代码移出去,放到统一的XML文件中,通过一个容器在需要的时候把依赖关系形成,即把需要的接口注入到需要的类中,这就是我们说的“依赖注入”的来源了。IOC容器有很多种,PicoContainer、JBoss、HiveMind、spring,在这里我们主要说的是Spring的IOC容器。
下面是使用Spring IOC容器来控制,如下步骤所示。
1、 导入Spring依赖包(因为在这里使用的是Spring的IOC,所以导入核心包就可以了)
*Spring_home/dist/spring.jar.
*另外引入相关日志记录包,两个,spring-framework-2.0\lib\log4j\log4j-1.2.14.jar spring-framework-2.0\lib\jakarta-commons\commons-logging.jar
直接在UserLibraries中建立userlibraries然后再导入JARs,之后引入到我们的项目中。
2、 提供配置文件applicationContext.xml,放到我们项目的src目录下,我们可以拷贝Spring spring-framework-2.0\samples\jpetstore\war\WEB-INF
applicationContext.xml到我们的src目录下。
3、 提供log4j.propertiers配置文件。
4、 在UserManagerImpl中提供构造方法或setter方法,让Spring将UserDao与UserManagerImpl的关系注入(DI)进来。
5、 让Spring管理对象的创建和依赖,必须将依赖关系配置到Spring的核心配置文件中。
在上一篇代码中,我们的Dao层代码不变,我们的UserManagerImpl代码如下所示。
UserManagerImpl.java
public class UserManagerImpl implements UserManager {
//这样改看不到具体的实现了. 但是在client调用时看到组装的过程.
private UserDao userDao;
//构造方法进行赋值.
// public UserManagerImpl(UserDao userDao) {
//
// this.userDao = userDao;
// }
//
//通过setter方法来把依赖对象注入。
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
@Override
public void addUser(String username, String password) {
userDao.addUser(username, password);
}
}
Spring的依赖注入方法,我们可以通过赋值注入,也就是通过getter和setter方法来获得和设置Bean的属性值,我们一般使用这种方法。在Spring中每个对象在配置文件中,均以<bean>的形式出现,而子元素<property>则指明了使用这个JavaBean的setter方法来注入值,在<property>中,可以定义要配置的属性以及要注入的值,可以将属性注入任何类型的值,不仅是基本类型的java数据类型,也可以是Bean对象,在这就我们注入的就是Bean对象。
另一种是构造器的注入,不常使用,通过标签<constructor-arg>来实例化这个Bean的时候需要注入的参数。
ApplicationContext.xml代码如下所示。
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">
<bean id="userDao4MySql" class="com.bjpowernode.spring.dao.UserDao4MySqlImpl"/>
<bean id="userDao4Oracle" class="com.bjpowernode.spring.dao.UserDao4OracleImpl"/>
<!-- userManager依赖于mysql的实现 -->
<bean id="userManager" class="com.bjpowernode.spring.manager.UserManagerImpl">
<!-- <constructor-arg ref="userDao4MySql"/> -->
<!-- <constructor-arg ref="UserDao4Oracle"/>-->
<property name="userDao" ref="userDao4MySql"/>
</bean>
</beans>
上面这个XML文件就是Spring中用来配置JavaBean的。通过这样的一个方式可以把分散的JavaBean组装一个整体系统,再去实现具体的业务了逻辑。完成了Bean的开发和装配下一步就是要进行调用和测试了。
在客户端进行调用,代码如下所示。
public class client {
public static void main(String[] args) {
//spring中有BeanFactory,是一个接口.
//专门读取applicationContext.xml文件的实现.
//ClassPathXmlApplicationContext类就是对BeanFactory接口的实现.
//会把applicationContext.xml这个文件读进来,并且创建对象.
BeanFactory factory = new ClassPathXmlApplicationContext("applicationContext.xml");
//产品标识.
UserManager userManager = (UserManager)factory.getBean("userManager");
userManager.addUser("张三", "123");
}
}
这样就完成了用SpringIOC容器来解决依赖问题,不需要我们自己去建立工厂,我们只要声明一个接口,具体的实现在配置文件中告诉SpringIOC容器,他会自己找到并进行创建相应的实例,然后传递给我们,本来是由我们自己去控制对象之间的依赖关系,现在由IOC来控制了,这就是控制反转。这样我们很轻松就了解了哦。
Spring coming.....