Spring教程
Email:achqian@yahoo.com.cn
版权所有,如果转载和篡改,请注明出处
Spring的AOP模块也将元数据编程引入了Spring。使用Spring的元数据支持,你可以为你的源代码增加注释,指示Spring在何处以及如何应用切面函数。
JDBC抽象和DAO模块
使用JDBC经常导致大量的重复代码,取得连接、创建语句、处理结果集,然后关闭连接。Spring的JDBC和DAO模块抽取了这些重复代码,因此你可以保持你的数据库访问代码干净简洁,并且可以防止因关闭数据库资源失败而引起的问题。
这个模块还在几种数据库服务器给出的错误消息之上建立了一个有意义的异常层。使你不用再试图破译神秘的私有的SQL错误消息!
另外,这个模块还使用了Spring的AOP模块为Spring应用中的对象提供了事务管理服务。
对象/关系映射集成模块
对那些更喜欢使用对象/关系映射工具而不是直接使用JDBC的人,Spring提供了ORM模块。Spring并不试图实现它自己的ORM解决方案,而是为几种流行的ORM框架提供了集成方案,包括Hibernate、JDO和iBATIS SQL映射。Spring的事务管理支持这些ORM框架中的每一个也包括JDBC。
Spring的Web模块
Web上下文模块建立于应用上下文模块之上,提供了一个适合于Web应用的上下文。另外,这个模块还提供了一些面向服务支持。例如:实现文件上传的multipart请求,它也提供了Spring和其它Web框架的集成,比如Struts、WebWork。
Spring的MVC框架
Spring为构建Web应用提供了一个功能全面的MVC框架。虽然Spring可以很容易地与其它MVC框架集成,例如Struts,但Spring的MVC框架使用IoC对控制逻辑和业务对象提供了完全的分离。
它也允许你声明性地将请求参数绑定到你的业务对象中,此外,Spring的MVC框架还可以利用Spring的任何其它服务,例如国际化信息与验证。
总结
Spring带来了复杂的J2EE开发的春天。它的核心是轻量级的IoC容器,它的目标是为J2EE应用提供了全方位的整合框架,在Spring框架下实现多个子框架的组合,这些子框架之间可以彼此独立,也可以使用其它的框架方案加以代替,Spring希望为企业应用提供一站式(one-stop shop)的解决方案。
Spring的IoC容器
? 主要内容:从最基本的面向接口编程逐步引入IoC设计模式(以银行卡:Card为例,
接口-单例-工厂方法-IoC);详细介绍IoC的三种实现,并对其优、缺点进行比较;之后开始引入Spring的IoC容器,详细介绍如何使用Spring的IoC容器组织业务组件。 ? 目的:使学员真正理解IoC的概念、优点,并掌握Spring IoC容器的使用。
6
Spring教程
Email:achqian@yahoo.com.cn
版权所有,如果转载和篡改,请注明出处
用户注册的例子
我们先看看更进一步的需求:实现一个用户注册信息持久化的类。 功能:
1、 保存用户注册的信息;
2、 根据用户的名称获得该注册用户。
虽然功能简单,但它对持久化方式的要求却非常的灵活:
1、 在内存中持久化,供测试、演示使用。
2、 如果用户的数据很少,将用户信息持据化到文本文件中。
3、 如果用户信息很多,并需要一些灵活的查询,则需要使用JDBC技术将用将用户信息持久化到数据库中。
4、 面对企业复杂关联的数据,甚至需要使用持久层框架来实现用户信息的持久化,比如:
iBATIS、Hibernate等。
如何去设计、实现我们这个持久化类呢?
我们遵循软件开发的原则“首先让它跑起来,再去优化(重构)它”,我们首先实现最简单的在内存中持久化用户信息。
既然我们要保存和取得用户信息,首先应该设计用户类。代码如下: User.java
public class User { private Long id; private String name; private String password; private String group;
public User(String name,String password){ this.name = name;
this.password = password;
}
//相应的get/set方法 ……….. }
持久化类有两个方法,分别在内存中保存和获取User对象。代码如下: MemoryUserPersist.java
public class MemoryUserPersist {
private static Map users = new HashMap(); static{
User defaultAdmin = new User(\ users.put(defaultAdmin.getName(),defaultAdmin); }
public MemoryUserPersist (){
7
Spring教程
Email:achqian@yahoo.com.cn
版权所有,如果转载和篡改,请注明出处
}
public void saveUser(User user){ users.put(user.getName(),user); }
public User LoadUser(String userName){ return (User)users.get(userName); } }
用户持久化类完成之后,我们就可以在客户端UserRegister中使用它了。例如:用户注册时,UserRegister代码片断如下:
MemoryUserPersist userPersist = new MemoryUserPersist (); userPersist.saveUser(user); 可是,现在如果要在文本文件中持久化User,又该如何实现呢?实现一个TextUserPersist类,这个并不困难。但客户端代码将面临重大灾难:找到所有使用过MemoryUserPersist的客户端类,将他们中的MemoryUserPersist逐个手工修改为 TextUserPersist,并且重新编译,当然以前的测试也必须全部从头来过! 人生的浩劫只是刚刚开始,因为根据前面的需求我们至少要分别实现四种持久化方式!这时,你一定和我一样在期待着救世主的早日降临——接口(Interface)。
面向接口编程
什么是接口?
? ?
接口定义了行为的协议,这些行为在继承接口的类中实现。
接口定义了很多方法,但是没有实现它们。类履行接口协议并实现所有定义在接口中的方法。
接口是一种只有声明没有实现的特殊类。
?
接口的优点:
? ? ? ? ?
Client不必知道其使用对象的具体所属类。
一个对象可以很容易地被(实现了相同接口的)的另一个对象所替换。
对象间的连接不必硬绑定(hardwire)到一个具体类的对象上,因此增加了灵活性。 松散藕合(loosens coupling)。 增加了重用的可能性。
接口的缺点:
设计的复杂性略有增加
(用户持久化类)重构第一步——面向接口编程
1、 设计用户持久化类的接口UserDao,代码如下: public interface UserDao {
8
Spring教程
Email:achqian@yahoo.com.cn
版权所有,如果转载和篡改,请注明出处
public void save(User user); public User load(String name); }
2、 具体的持久化来必须要继承UserDao接口,并实现它的所有方法。我们还是首先实现内
存持久化的用户类:
public class MemoryUserDao implements UserDao{ private static Map users = new HashMap();; static{
User user = new User(\ users.put(user.getName(),user); }
public void save(User user) { users.put(user.getId(),user); }
public User load(String name) { return (User)users.get(name);
} }
MemoryUserDao的实现代码和上面的MemoryUserPersist基本相同,唯一区别是MemoryUserDao类继承了UserDao接口,它的save()和load()方法是实现接口的方法。
这时,客户端UserRegister的代码又该如何实现呢?
UserDao userDao = new MemoryUserDao(); userDao.save(user);
(注:面向对象“多态”的阐述)
如果我们再切换到文本的持久化实现TextUserDao,客户端代码仍然需要手工修改。虽然我们已经使用了面向对象的多态技术,对象userDao方法的执行都是针对接口的调用,但userDao对象的创建却依赖于具体的实现类,比如上面MemoryUserDao。这样我们并没有完全实现前面所说的“Client不必知道其使用对象的具体所属类”。
如何解决客户端对象依赖具体实现类的问题呢?
下面该是我们的工厂(Factory)模式出场了!
重构第二步——工厂(Factory)模式
我们使用一个工厂类来实现userDao对象的创建,这样客户端只要知道这一个工厂类就可以了,不用依赖任何具体的UserDao实现。创建userDao对象的工厂类UserDaoFactory代码如下:
public class UserDaoFactory {
public static UserDao createUserDao(){ return new MemoryUserDao(); } }
9
Spring教程
Email:achqian@yahoo.com.cn
版权所有,如果转载和篡改,请注明出处
客户端UserRegister代码片断如下:
UserDao userDao = UserDaoFactory. CreateUserDao(); userDao.save(user);
现在如果再要更换持久化方式,比如使用文本文件持久化用户信息。就算有再多的客户代码调用了用户持久化对象我们都不用担心了。因为客户端和用户持久化对象的具体实现完全解耦。我们唯一要修改的只是一个UserDaoFactory类。
重构第三步——工厂(Factory)模式的改进
到这里人生的浩劫已经得到了拯救。但我们仍不满足,因为假如将内存持久化改为文本文件持久化仍然有着硬编码的存在——UserDaoFactory类的修改。代码的修改就意味着重新编译、打包、部署甚至引入新的Bug。所以,我们不满足,因为它还不够完美!
如何才是我们心目中的完美方案?至少要消除更换持久化方式时带来的硬编码。具体实现类的可配置不正是我们需要的吗?我们在一个属性文件中配置UserDao的实现类,例如: 在属性文件中可以这样配置:userDao = com.test.MemoryUserDao。UserDao的工厂类将从这个属性文件中取得UserDao实现类的全名,再通过Class.forName(className).newInstance()语句来自动创建一个UserDao接口的具体实例。UserDaoFactory代码如下: public class UserDaoFactory {
public static UserDao createUserDao(){ String className = \
// ……从属性文件中取得这个UserDao的实现类全名。 UserDao userDao = null;
try {
userDao = (UserDao)Class.forName(className).newInstance(); } catch (Exception e) { e.printStackTrace(); }
return userDao; }
通过对工厂模式的优化,我们的方案已近乎完美。如果现在要更换持久化方式,不需要再做任何的手工编码,只要修改配置文件中的userDao实现类名,将它设置为你需要更换的持久化类名即可。
我们终于可以松下一口气了?不,矛盾仍然存在。我们引入了接口,引入了工厂模式,让我们的系统高度的灵活和可配置,同时也给开发带来了一些复杂度:1、本来只有一个实现类,后来却要为这个实现类引入了一个接口。2、引入了一个接口,却还需要额外开发一个对应的工厂类。3、工厂类过多时,管理、维护非常困难。比如:当UserDao的实现类是JdbcUserDao,它使用JDBC技术来实现用户信息从持久化。也许要在取得JdbcUserDao实例时传入数据库Connection,这是仍少UserDaoFactory的硬编码。
当然,面接口编程是实现软件的可维护性和可重用行的重要原则已经勿庸置疑。这样,第一个复杂度问题是无法避免的,再说一个接口的开发和维护的工作量是微不足道的。但后面两个复杂度的问题,我们是完全可以解决的:工厂模式的终极方案——IoC模式。
10