`

IOC in spring

 
阅读更多

Spring的IoC控件主要专注于如何利用classes、对象和服务去组成一个企业级应用,通过规范的方式,将各种不同的控件整合成一个完整的应用。

l 用户注册的例子

我们先看看更进一步的需求:实现一个用户注册信息持久化的类。

功能:

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("Moxie","pass");

users.put(defaultAdmin.getName(),defaultAdmin);

}

public MemoryUserPersist (){

}

public void saveUser(User user){

users.put(user.getName(),user);

}

public User LoadUser(String userName){

return (User)users.get(userName);

}

}

用户持久化类完成之后,我们就可以在客户端UserRegister中使用它了。例如:用户注册时,UserRegister代码片断如下:

MemoryUserPersistuserPersist = new MemoryUserPersist ();

userPersist.saveUser(user);

可是,现在如果要在文本文件中持久化User,又该如何实现呢?实现一个TextUserPersist类,这个并不困难。但客户端代码将面临重大灾难:找到所有使用过MemoryUserPersist的客户端类,将他们中的MemoryUserPersist逐个手工修改为 TextUserPersist,并且重新编译,当然以前的测试也必须全部从头来过!

人生的浩劫只是刚刚开始,因为根据前面的需求我们至少要分别实现四种持久化方式!这时,你一定和我一样在期待着救世主的早日降临——接口(Interface)。

l 面向接口编程

什么是接口?

¨ 接口定义了行为的协议,这些行为在继承接口的类中实现。

¨ 接口定义了很多方法,但是没有实现它们。类履行接口协议并实现所有定义在接口中的方法。

¨ 接口是一种只有声明没有实现的特殊类。

接口的优点:

¨ Client不必知道其使用对象的具体所属类。

¨ 一个对象可以很容易地被(实现了相同接口的)的另一个对象所替换。

¨ 对象间的连接不必硬绑定(hardwire)到一个具体类的对象上,因此增加了灵活性。

¨ 松散藕合(loosens coupling)。

¨ 增加了重用的可能性。

接口的缺点:

设计的复杂性略有增加

l 重构第一步——面向接口编程

1、设计用户持久化类的接口UserDao,代码如下:

public interface UserDao {

public void save(User user);

public User load(String name);

}

2、具体的持久化来必须要继承UserDao接口,并实现它的所有方法。我们还是首先实现内存持久化的用户类:

public class MemoryUserDao implementsUserDao{

private static Map users = new HashMap();;

static{

User user = new User("Moxie","pass");

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)模式出场了!

l 重构第二步――工厂模式

我们使用一个工厂类来实现userDao对象的创建,这样客户端只要知道这一个工厂类就可以了,不用依赖任何具体的UserDao实现。创建userDao对象的工厂类UserDaoFactory代码如下:

public class UserDaoFactory {

public static UserDao createUserDao(){

return new MemoryUserDao();

}

}

客户端UserRegister代码片断如下:

UserDao userDao= UserDaoFactory. CreateUserDao();

userDao.save(user);

现在如果再要更换持久化方式,比如使用文本文件持久化用户信息。就算有再多的客户代码调用了用户持久化对象我们都不用担心了。因为客户端和用户持久化对象的具体实现完全解耦。我们唯一要修改的只是一个UserDaoFactory类。

l 重构第三步——工厂(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模式。

l 重构第四步――IoC容器

使用IoC容器,用户注册类UserRegister不用主动创建UserDao实现类的实例。由IoC容器主动创建UserDao实现类的实例,并注入到用户注册类中。我们下面将使用Spring提供的IoC容器来管理我们的用户注册类。

用户注册类UserRegister的部分代码如下:

public class UserRegister {

private UserDao userDao =null;//由容器注入的实例对象

public voidsetUserDao(UserDao userDao){

this.userDao =userDao;

}

// UserRegister的业务方法

}

在其它的UserRegister方法中就可以直接使用userDao对象了,它的实例由Spring容器主动为它创建。但是,如何组装一个UserDao的实现类到UserRegister中呢?哦,Spring提供了配置文件来组装我们的组件。Spring的配置文件applicationContext.xml代码片断如下:

<beanid="userRegister" class="com.dev.spring.simple.UserRegister">

<propertyname="userDao"><reflocal="userDao"/></property>

</bean>

<beanid="userDao"class="com.dev.spring.simple.MemoryUserDao"/>

-----------------------------------------------

这是Spring中得有特点的一部份。IoC又被翻译成“控制反转”,也不知道是谁翻译得这么别扭,感觉很深奥的词。其实,原理很简单,用一句通俗的话来说:就是用XML来定义生成的对象。IoC其实是一种设计模式,Spring只是实现了这种设计模式。

这种设计模式是怎么来的呢?是实践中逐渐形成的。

第一阶段:用普通的无模式来写Java程序。一般初学者都要经过这个阶段。
第二阶段:频繁的开始使用接口,这时,接口一般都会伴随着使用工厂模式。
第三阶段:使用IoC模式。工厂模式还不够好:(1)因为的类的生成代码写死在程序里,如果你要换一个子类,就要修改工厂方法。(2)一个接口常常意味着一个生成工厂,会多出很多工厂类。
可以把IoC模式看做是工厂模式的升华,可以把IoC看作是一个大工厂,只不过这个大工厂里要生成的对象都是在XML文件中给出定义的,然后利用Java的“反射”编程,根据XML中给出的类名生成相应的对象。从实现来看,IoC是把以前在工厂方法里写死的对象生成代码,改变为由XML文件来定义,也就是把工厂和对象生成这两者独立分隔开来,目的就是提高灵活性和可维护性。


分享到:
评论

相关推荐

    spring练习AOP与IOC

    在这个“spring练习AOP与IOC”的主题中,我们将深入探讨这两个关键概念。 **依赖注入(IOC)** 依赖注入是Spring框架的基础,它是一种设计模式,允许对象在运行时通过外部源获取其依赖,而不是自行创建或查找。...

    Spring in Action 使用Maven 构建Spring 工程

    《Spring in Action》一书是Spring框架的实践指南,它深入介绍了如何使用Maven构建Spring工程。Maven是一个流行的项目管理和综合工具,它通过提供一套标准化的构建过程,简化了Java项目的构建、依赖管理和部署。在...

    Spring in action中文版(第4版)

    6. 依赖管理和配置(Dependency Management and Configuration):Spring的依赖注入是其核心特性之一,能够通过控制反转(IoC)原则减少组件之间的耦合。通过使用Spring管理依赖,开发者可以轻松地构建、测试和修改...

    spring in action & 精通spring

    5. **IoC容器**:Bean Factory是Spring的基本容器,负责管理对象的生命周期和依赖关系。ApplicationContext扩展了Bean Factory,提供了更多企业级服务,如国际化、事件传播等。 6. **AOP模块**:提供了基于代理的...

    学习Spring笔记_IoC(控制反转)简介

    - 书籍推荐:《Spring in Action》和《Spring Boot in Practice》等书籍提供了详细的实践指导。 通过理解并熟练掌握Spring的IoC和依赖注入,开发者可以编写出更易于维护和扩展的代码,提高软件的灵活性和可测试性。...

    Spring+in+action+中文版(第4版)

    - **1.2.1 IoC 容器**:Spring 的IoC容器是其核心组件之一,用于管理对象的生命周期和依赖关系。 - **1.2.2 AOP 支持**:Spring 提供了面向切面编程的支持,使得横切关注点如日志记录、事务管理等可以与业务逻辑分离...

    Spring in action 2nd

    ### Spring in Action 第二版 —— 详尽解析与学习指南 #### 一、书籍概述 《Spring in Action》第二版是一本深受开发者喜爱的技术书籍,由Craig Walls和Ryan Breidenbach共同撰写,并由Manning出版社出版。这本书...

    myeclipse spring IOC和AOP 例子

    Spring框架是Java开发中的核心组件,它通过控制反转(IOC)和面向切面编程(AOP)等特性,极大地简化了企业级应用的构建。在本教程中,我们将深入探讨这两个概念以及如何在MyEclipse环境中使用它们。下面将详细阐述...

    Spring in Action 2nd Edition

    ### Spring in Action 2nd Edition 关键知识点解析 #### 一、书籍概述与评价 《Spring in Action》第二版是一本深入浅出介绍Spring框架的书籍。本书在第一版的基础上进行了大量的更新和完善,旨在帮助读者更好地...

    Spring in Action Second Edition

    在书中,作者首先会介绍Spring的基础知识,包括如何设置Spring项目、配置IoC容器以及如何使用依赖注入来管理对象的生命周期。接着,会深入讲解Spring MVC,这是一个强大的用于构建Web应用程序的模型-视图-控制器...

    Spring_in_Action

    《Spring in Action》是一本深度剖析Spring框架的权威著作,旨在帮助读者全面理解并熟练运用Spring进行企业级应用开发。该书深入浅出地讲解了Spring的核心概念、配置方式、依赖注入、AOP(面向切面编程)、数据访问...

    spring in action 英文原版

    根据提供的信息,我们可以推断出这是一本关于Spring框架的专业书籍——《Spring in Action》英文原版。本书由Craig Walls和Ryan Breidenbach撰写,并由Manning Publications出版。以下是基于书名、描述、标签以及...

    spring in action英文原版

    1. **依赖注入**:Spring的核心特性之一,通过IoC(Inversion of Control)容器来管理对象及其相互依赖关系,降低了代码的耦合度,增强了可测试性。 2. **AOP**:Spring的另一个关键特性,允许开发者定义和实现切面...

    Spring In action 4

    - **IoC容器**:Spring的核心组件,负责创建对象、管理对象间的依赖关系以及配置对象的生命周期。 - **Bean**:在Spring中,被容器管理的对象被称为Bean,可以通过XML、Java注解或基于Java的配置来定义。 2. **...

    Spring in Action(第二版)中文版.pdf(2-3)

    《Spring in Action》是关于Spring框架的一本权威指南,由Manning出版社出版,作者是Craig Walls。这本书的第二版深入浅出地介绍了Spring框架的核心概念和技术,为Java开发者提供了全面的Spring应用实践指导。"2-3...

    【Spring in Action 3rd Edition】 pdf

    《Spring in Action 3rd Edition》是一本专为Java开发者设计的权威指南,全面深入地讲解了Spring框架的使用和实践。这本书英文原版的发布,对于想要掌握Spring框架核心特性和J2EE开发的程序员来说,是一份极其宝贵的...

Global site tag (gtag.js) - Google Analytics