`

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文件来定义,也就是把工厂和对象生成这两者独立分隔开来,目的就是提高灵活性和可维护性。


分享到:
评论

相关推荐

    Java In Spring

    讲述Spring的ppt,阿里巴巴内部的一个培训资料,讲述的有AOP、IOC、SpringDM、SpringDao 等内容

    Spring in Action中文版 清晰pdf part2

    第一部分展示了Spring框架的两个核心概念:反向控制(Inverstion of Control,IoC)和面向切面编程(Aspect-Oriented Programming,AOP),以便读者理解Spring的基础原理,这些基础原理在本书各个章节都会用到。...

    使用Spring in Guice和Guice in Spring的工具(高分项目).zip

    它包括IoC(Inverse of Control,控制反转)容器、AOP(Aspect-Oriented Programming,面向切面编程)等特性,可以简化开发过程、提高代码的可维护性和可测试性。 2. Spring MVC框架:Spring MVC是基于Spring框架的...

    Pro Spring 5 An In-Depth Guide -Apress(2017)

    • Discover what’s new in Spring Framework 5 • Build Spring-based web applications using Spring MVC and WebSocket • Build Spring web reactive applications with Spring WebFlux • Test Spring ...

    Spring.in.Action(中文版)

    第一部分展示了Spring框架的两个核心概念:反向控制(Inverstion of Control,IoC)和面向切面编程(Aspect-Oriented Programming,AOP),以便读者理解Spring的基础原理,这些基础原理在本书各个章节都会用到。...

    初步理解 Spring IOC 思想

    初步理解 Spring IOC 思想Spring IOC大体思想示例说明并辅助理解示例一(摘自狂神的视频):示例二(买果汁):抽取思想总结 Spring IOC 最近跟着B站的狂神学习了Spring的大概,以前有过写传统JavaWeb的经验,现在也...

    Spring in Action中文版 清晰pdf part1

    第一部分展示了Spring框架的两个核心概念:反向控制(Inverstion of Control,IoC)和面向切面编程(Aspect-Oriented Programming,AOP),以便读者理解Spring的基础原理,这些基础原理在本书各个章节都会用到。...

    Springboot入门——初学者对Spring Ioc技术的理解与运用,包含Bean生命周期

    Spring Ioc Spring所依赖的两个核心理念:控制反转(Ioc)、面向切面编程(AOP) 初学者可能不理解什么叫控制反转,那么我们来进一步描述一下Ioc。 Ioc是一种通过描述来生成或获取对象的技术,这里的对象当然是指...

    Spring 5 Recipes, 4th Edition

    The recipes in Spring 5 Recipes cover Spring fundamentals such as Spring IoC container, Spring AOP/ AspectJ, and more. Other recipes include Spring enterprise solutions for topics such as Spring Java ...

    Spring总结——Spring容器、Spring中的IoC

    文章目录Spring总结Spring容器控制反转(IoC)基于XML的IoC Spring总结 Spring容器 什么是Spring容器 从概念上讲:Spring 容器是 Spring框架的核心,是用来管理对象的。容器将创建对象,把它们连接在一起,配置它们...

    Spring IoC中的基础知识

    Spring的定义:是一个IoC容器  分为: spring core  spring beans: 组件工厂BeanFactory  spring context: 环境,装配  spring expression 3.Spring 组件的作用域 单例(默认):全局唯一 原型:每次获得...

    Pro Spring 3

    How to build transaction engines for your enterprise application and take advantage of other middle-tier features in Spring How to build Spring-based web applications using Spring MVC and more How to ...

    Spring IOC的快速入门案例

    Spring IOC的快速入门案例 &gt;下载Spring的开发包 https://repo.spring.io/libs-release-local/org/springframework/spring/ 目录结构: docs : API文档和开发规范 libs : 开发需要的jar包、源代码和文档 schema : ...

    Spring Recipes: A Problem-Solution Approach, Second Edition

    * Spring fundamentals: Spring IoC container, Spring AOP/ AspectJ, and more * Spring enterprise: Spring Java EE integration, Spring Integration, Spring Batch, jBPM with Spring, Spring Remoting, ...

    Spring.Persistence.with.Hibernate.2nd.Edition.1484202694

    How to work with Spring Framework features such as Inversion of Control (IoC), aspect-oriented programming (AOP), and more How to work with Spring JDBC, use declarative transactions with Spring, and ...

    spring-javaconfig-reference

    This document assumes at least a general familiarity with the Spring IoC container. If you are brand new to Spring (i.e.: have never used Spring's XML configuration language, it is suggested that you ...

    pro Spring

    Learn the fundamentals of IoC in the context of AOP. Become aware of the seamlessness and power of Spring by referencing the easy-to- understand sample application we provide. Learn how to replace ...

    spring in action英文版

    第一部分 Spring基础  第1章 开始Spring之旅  1.1 为什么使用Spring  1.1.1 J2EE开发者的一天  1.1.2 Spring的承诺  1.2 Spring是什么  1.3 开始Spring之旅  1.4 理解反向控制  1.4.1 依赖...

    Spring框架控制反转IOC和依赖注入DI详解

    本文介绍了Spring框架中的控制反转IOC和依赖注入DI,欢迎阅读,共同学习,一起进步。 Spring框架基础参考:深入学习Spring基础 文章目录一.入门程序和IOC简介二.IOC-控制反转三.DI-依赖注入四. IOC和DI五.Spring...

Global site tag (gtag.js) - Google Analytics