`
fangjieke
  • 浏览: 45947 次
最近访客 更多访客>>
文章分类
社区版块
存档分类
最新评论

结合Spring框架学习IOC和AOP(一)

阅读更多
说明:学习笔记主要内容来自spring技术手册,如有侵权,请联系fangjieke@163.com
参考目录
编号
名称
出处
作者
1
IoC 容器和Dependency Injection 模式
DependencyInjection.pdf
Martin Fowler
2
Spring开发指南
Spring开发指南.pdf
夏昕
3
Spring技术手册
《Spring技术手册》
林信良
4
Expert One-on-One J2EE Development Without EJB
《Expert One-on-One J2EE Development Without EJB》
Rod Johnson
Juergen Hoeller
5
文中示例项目源代码
http://zlsunnan.edudisk.cn
林信良
1.      依赖注入和服务定位器
J2EE开发者常遇到的一个问题就是如何组装不同的程序元素:如果web控制器体系结构和数据库接口是由不同的团队所开发的,彼此几乎一无所知,应该如何让它们配合工作?很多框架尝试过解决这个问题,有几个框架索性朝这个方向发展,提供了更通用的“组装各层组件”的方案。这样的框架通常被称为“轻量级容器”,PicoContainer和Spring都在此列。在这些容器背后,一些有趣的设计原则发挥着作用。这些原则已经超越了特定容器的范畴,甚至已经超越了Java平台的范畴。
要消除应用程序对插件实现的依赖,可以有两种选择:Dependency Injection和Service Locater模式。我们先来看一个Spring中使用IOC的示例程序:
1.1.       spring程序示例(SpringDemo项目
Action接口:
public interface Action {
public String execute(String str);
}
Action的两个实现
public class UpperAction implements Action {
private String message;
public String getMessage() {
return message;
}
public void setMessage(String string) {
message = string;
}
public String execute(String str) {
return (getMessage() + str).toUpperCase();
}
}
 
public class LowerAction implements Action {
private String message;
public String getMessage() {
return message;
}
public void setMessage(String string) {
message = string;
}
public String execute(String str) {
return (getMessage()+str).toLowerCase();
}
}
 
配置文件bean.xml
<beans>
<description>Spring Quick Startdescription>
<bean id="TheAction"
class="com.raykey.spring.qs.UpperAction">
<property name="message">
<value>HeLLovalue>
property>
bean>
beans>
(请确保配置bean.xml位于工作路径之下,注意工作路径并不等同于CLASSPATH ,eclipse的默认工作路径为项目根路径,也就是.project文件所在的目录,而默认输出目录/bin是项目CLASSPATH的一部分,并非工作路径。)
 
测试代码:
public void testQuickStart() {
ApplicationContext ctx=new FileSystemXmlApplicationContext("bean.xml");
Action action = (Action) ctx.getBean("TheAction");
System.out.println(action.execute("Rod Johnson"));
}
 
仔细观察一下上面的代码,可以看到:
1. 我们的所有程序代码中(除测试代码之外),并没有出现Spring中的任何组件。
2. UpperAction和LowerAction的Message属性均由Spring通过读取配置文件(bean.xml)动态设置。
3. 客户代码(这里就是我们的测试代码)仅仅面向接口编程,而无需知道实现类的具体名称。同时,我们可以很简单的通过修改配置文件来切换具体的底层实现类。
上面所说的这些,对于我们的实际开发有何帮助?
Ø 首先,我们的组件并不需要实现框架指定的接口,因此可以轻松的将组件从Spring中脱离,甚至不需要任何修改(这在基于EJB框架实现的应用中是难以想象的)。
Ø 其次,组件间的依赖关系减少,极大改善了代码的可重用性。现在假设我们回到传统的实现模式,应该如何处理?一般的处理办法也就是编写一个Helper类(辅助类),完成配置文件读写功能,然后在各个Action的构造函数中,调用这个Helper类设置message属性值。此时,我们的组件就与这个Helper类库建立了依赖关系,之后我们需要在其他系统中重用这个组件的话,也必须连同这个Helper类库一并移植。实际开发中,依赖关系往往并非如此简单,组件与项目基层代码之间复杂的关联,使得组件重用性大大下降。Spring通过依赖注入模式,将依赖关系从编码中脱离出来,从而大大降低了组件之间的耦合,实现了组件真正意义上的即插即用。这也是Spring最具价值的特性之一。
Ø 面向接口编程。诚然,即使没有Spring,实现面向接口的设计也不困难。Spring对于面向接口设计的意义,在于它为面向接口编程提供了一个更加自然的平台。基于Spring开发,程序员会自然而然倾向于使用接口来定义不同层次之间的关联关系,这种自发的倾向性,来自于Spring所提供的简单舒适的依赖注入实现。Spring使得接口的定义和使用不再像传统编码过程中那么繁琐(传统编码过程中,引入一个接口,往往也意味着同时要引入一个Factory类,也许还有一个额外的配置文件及其读写代码)。
1.2.       依赖注入
1.2.1. 何为依赖注入?
IoC,用白话来讲,就是由容器控制程序之间的关系,而非传统实现中,由程序代码直接操控。这也就是所谓“控制反转”的概念所在:控制权由应用代码中转到了外部容器,控制权的转移,是所谓反转。
正在业界为IoC争吵不休时,大师级人物Martin Fowler也站出来发话,以一篇经典文章《Inversion of Control Containers and the Dependency Injection pattern》为IoC正名,至此,IoC又获得了一个新的名字:“依赖注入 (Dependency Injection)”。相对IoC 而言,“依赖注入”的确更加准确的描述了这种古老而又时兴的设计理念。从名字上理解,
所谓依赖注入,即组件之间的依赖关系由容器在运行期决定,形象的来说,即由容器动态的将某种依赖关系注入到组件之中。相信大家对下面图片中的设备不会陌生:
图中三个设备都有一个共同点,都支持USB 接口。当我们需要将数据复制到外围存储设备时,可以根据情况,选择是保存在U盘还是USB硬盘,下面的操作大家也都轻车熟路,无非接通USB接口,然后在资源浏览器中将选定的文件拖放到指定的盘符。
笔记本电脑与外围存储设备通过预先指定的一个接口(USB)相连,对于笔记本而言,只是将用户指定的数据发送到USB接口,而这些数据何去何从,则由当前接入的USB设备决定。在USB备加载之前,笔记本不可能预料用户将在USB接口上接入何种设备,只有USB设备接入之后,这种设备之间的依赖关系才开始形成。
对应上面关于依赖注入机制的描述,在运行时(系统开机,USB 设备加载)由容器(运行在笔记本中的Windows操作系统)将依赖关系(笔记本依赖USB设备进行数据存取)注入到组件中(Windows文件访问组件)。这就是依赖注入模式在现实世界中的一个版本。
在不使用Dependency Injection模式以前,我们的模式的效果如下:
MovieLister 类既依赖于MovieFinder接口,也依赖于具体的实现类。我们当然希望MovieLister 类只依赖于接口,但我们要如何获得一个MovieFinder子类的实例呢?这里的问题就是:如何设计这个连接过程,使MovieLister 类在不知道实现类细节的前提下与其实例协同工作。以下是使用了依赖注入后的效果:
Dependency Injection的基本思想是:用一个单独的对象(装配器)来获得MovieFinder的一个合适的实现,并将其实例赋给MovieLister类的一个字段。
1.2.2. 实现方式
依赖注入的形式主要有三种,我分别将它们叫做构造子注入(Constructor Injection)、设值方法注入(Setter Injection)和接口注入(Interface Injection)。
1.2.2.1.   构造子注入(PicoContainer)
注入过程:
class MovieLister...
public MovieLister(MovieFinder finder) {
this.finder = finder;
}
class ColonMovieFinder...
public ColonMovieFinder(String filename) {
this.filename = filename;
}
//通过另一个类对其关系进行配置
private MutablePicoContainer configureContainer() {
MutablePicoContainer pico = new DefaultPicoContainer();
Parameter[] finderParams = {new ConstantParameter("movies1.txt")};
pico.registerComponentImplementation(MovieFinder.class,ColonMovieFinder.class, finderParams);
pico.registerComponentImplementation(MovieLister.class);
return pico;
}
使用过程:
public void testWithPico() {
MutablePicoContainer pico = configureContainer();
MovieLister lister = (MovieLister)
pico.getComponentInstance(MovieLister.class);
Movie[] movies = lister.moviesDirectedBy("Sergio Leone");
assertEquals("Once Upon a Time in the West",movies[0].getTitle());
}
尽管在这里我使用了构造子注入,实际上PicoContainer 也支持设值方法注入,不过该项目的开发者更推荐使用构造子注入。
1.2.2.2.   设值方法注入(Spring)
Spring 框架是一个用途广泛的企业级Java 开发框架,其中包括了针对事务、持久化框架、web应用开发和JDBC 等常用功能的抽象。和PicoContainer 一样,它也同时支持构造子注入和设值方法注入,但该项目的开发者更推荐使用设值方法注入——恰好适合这个例子。
注入过程:
class MovieLister...
private MovieFinder finder;
public void setFinder(MovieFinder finder) {
this.finder = finder;
}
class ColonMovieFinder...
public void setFilename(String filename) {
this.filename = filename;
}
//通过配置文件将其关联起来
<beans></beans>
<bean class="spring.MovieLister" id="MovieLister"></bean>
<property name="finder"></property>
<ref local="MovieFinder"></ref>
<bean class="spring.ColonMovieFinder" id="MovieFinder"></bean>
<property name="filename"></property>
<value></value>movies1.txt
使用过程:
public void testWithSpring() throws Exception {
ApplicationContext ctx = new FileSystemXmlApplicationContext("spring.xml");
MovieLister lister = (MovieLister) ctx.getBean("MovieLister");
Movie[] movies = lister.moviesDirectedBy("Sergio Leone");
assertEquals("Once Upon a Time in the West",movies[0].getTitle());
}
1.2.2.3.   接口注入
除了前面两种注入技术,还可以在接口中定义需要注入的信息,并通过接口完成注入。Avalon框架就使用了类似的技术。
接口注入要求组件实现容器所规定的接口,这就使得组件依赖于容器的API,如果日后组件打算脱离目前这个容器到其它的容器或是框架的时候就必须修改程序,在更复杂的依赖关系中将产生更多复杂的接口,组件和容器(框架)的依赖会更复杂,最后使得组件无法从窗口中脱离。
1.2.2.4.   几种依赖注入模式的对比总结
接口注入模式因为具备侵入性,它要求组件必须与特定的接口相关联,因此并不被看好,实际使用有限。
Type3 构造子注入的优势:
1 “在构造期即创建一个完整、合法的对象”,对于这条Java设计原则,Type3无疑是最好的响应者。
2. 避免了繁琐的setter方法的编写,所有依赖关系均在构造函数中设定,依赖关系集中呈现,更加易读。
3. 由于没有setter方法,依赖关系在构造时由容器一次性设定,因此组件在被创建之后即处于相对“不变”的稳定状态,无需担心上层代码在调用过程中执行setter方法对组件依赖关系产生破坏,特别是对于Singleton模式的组件而言,这可能对整个系统产生重大的影响。
4. 同样,由于关联关系仅在构造函数中表达,只有组件创建者需要关心组件内部的依赖关系。对调用者而言,组件中的依赖关系处于黑盒之中。对上层屏蔽不必要的信息,也为系统的层次清晰性提供了保证。
5. 通过构造子注入,意味着我们可以在构造函数中决定依赖关系的注入顺序,对于一个大量依赖外部服务的组件而言,依赖关系的获得顺序可能非常重要,比如某个依赖关系注入的先决条件是组件的DataSource及相关资源已经被设定。
Type2 设值注入的优势:
1. 对于习惯了传统JavaBean开发的程序员而言,通过setter方法设定依赖关系显得更加直观,更加自然。
2. 如果依赖关系(或继承关系)较为复杂,那么Type3模式的构造函数也会相当庞大(我们需要在构造函数中设定所有依赖关系),此时Type2模式往往更为简洁。
3. 对于某些第三方类库而言,可能要求我们的组件必须提供一个默认的构造函数(如Struts中的Action),此时Type3类型的依赖注入机制就体现出其局限性,难以完成我们期望的功能。
可见,Type2和Type3模式各有千秋,而Spring、PicoContainer都对Type2和Type3类型的依赖注入机制提供了良好支持。这也就为我们提供了更多的选择余地。理论上,以Type3类型为主,辅之以Type2类型机制作为补充,可以达到最好的依赖注入效果,不过对于基于Spring Framework开发的应用而言,Type2使用更加广泛。
1.3.       服务定位器(Service Locator)
依赖注入的最大好处在于:它消除了MovieLister类对具体MovieFinder实现类的依赖。这样一来,我就可以把MovieLister类交给朋友,让他们根据自己的环境插入一个合适的MovieFinder实现即可。不过,Dependency Injection模式并不是打破这层依赖关系的唯一手段,另一种方法是使用Service Locator 模式。这里不对服务定位器的实现形式做进一步的分析,请参阅参考目录是编号为1的资料。
分享到:
评论
3 楼 tanguojun 2007-07-09  
还不错!
2 楼 zhou7707 2007-06-15  
什么呀?AOP在哪里?!!
1 楼 zfigo_000 2007-05-04  
  很好

相关推荐

    Spring的Aop和Ioc示例

    Spring框架是Java开发中不可或缺的一部分,它以其强大的依赖注入(IOC)和面向切面编程(AOP)功能闻名。在本示例中,我们将深入理解这两个核心概念。 **依赖注入(IOC)** 依赖注入(Inversion of Control)是...

    SOA实践 -- 使用IoC和AOP重构SOA应用

    4. **Spring框架的应用**:Spring作为实现IoC和AOP的常用工具,会详细讲解如何配置和使用Spring容器。 5. **重构过程**:分享重构从旧版CurrencyExchange到使用IoC和AOP的新版CurrencyExchange2的具体步骤和考虑因素...

    Spring IOC和Spring AOP_spring aop_springIOC

    Spring框架是Java开发中最常用的轻量级框架之一,它的核心特性包括依赖注入(Dependency Injection,简称DI)和面向切面编程(Aspect-Oriented Programming,简称AOP)。这两个概念是Spring框架的基石,极大地简化了...

    spring ioc和aop讲解项目demo

    Spring框架是Java开发中不可或缺的一部分,它以其强大的依赖注入(IOC)和面向切面编程(AOP)功能而闻名。本项目"spring ioc和aop讲解项目demo"旨在通过实际操作来帮助开发者深入理解这两个核心概念。 首先,让...

    Spring核心IoC和AOP的理解

    Spring核心IoC和AOP的理解 本文主要介绍了Spring核心IoC和AOP的相关知识,涵盖了IoC和AOP的概念、特点、优点和应用场景等方面的内容。...Spring框架的 IoC和AOP机制使得程序更加灵活、更加易于维护和扩展。

    IOC和AOP深刻理解基础代码测试

    在“spring-1”、“spring-2”和“spring-3”这三个文件中,很可能是包含了一系列关于Spring框架使用、IOC和AOP实践的示例代码。这些代码可能涵盖了如何定义bean、如何进行依赖注入、如何声明切面以及如何在实际项目...

    Spring IOC AOP MVC 简单例子

    Spring框架是Java开发中不可或缺的一部分,它以依赖注入(DI)和控制反转(IOC)为核心,简化了企业级应用的开发。AOP(面向切面编程)和MVC(模型-视图-控制器)模式是Spring框架的重要组成部分,用于处理业务逻辑...

    spring学习指南+IOC+AOP

     Spring 是一种轻量级、非侵入式的java / java EE应用框架  Spring是分层的Java SE/EE应用一站式的轻量级开源框架  以IOC和AOP为核心  提供了表示层的MVC解决方案  提供了持久层JDBC的封装

    Spring IOC和AOP代码与笔记整理

    Spring框架是Java开发中不可或缺的一部分,它以IoC(Inversion of Control,控制反转)和AOP(Aspect Oriented Programming,面向切面编程)为核心,极大地简化了企业级应用的开发工作。本篇将深入探讨Spring的这两...

    helloAop.zip 内含spring ioc,aop例子

    本压缩包"helloAop.zip"包含了Spring框架的两个关键特性:IOC(Inversion of Control,控制反转)和AOP(Aspect Oriented Programming,面向切面编程)的示例。下面将详细介绍这两个概念及其在实际开发中的应用。 *...

    spring net IOC+AOP 源码 网络收集

    Spring.NET是一个开源的.NET框架,它为.NET开发者提供了与Java Spring框架类似的功能,包括依赖注入(Dependency Injection,DI)和面向切面编程(Aspect-Oriented Programming,AOP)。在这个"spring net IOC+AOP ...

    Spring AOP、IOC、cxf、任务调度所需jar包以及配置文件

    在IT领域,Spring框架是Java开发中的核心工具,它提供了许多功能来简化应用程序的构建,如依赖注入(IOC)、面向切面编程(AOP)以及服务整合。本资源包聚焦于Spring的这些关键特性,同时也涉及到CXF服务、任务调度...

    Spring核心学习IOC部分

    在Spring框架中,IOC(Inversion of Control,控制反转)是其核心概念之一,它改变了传统应用程序中的对象创建和管理方式。本学习资料主要聚焦于Spring的IOC容器,特别是从最基本的BeanFactory开始,逐步深入理解...

    Spring IOC、AOP实现代码,可调试查看内部原理,简单易懂

    Spring框架是Java开发中不可或缺的一部分,它通过提供Inversion of Control (IOC)和Aspect-Oriented Programming (AOP)两大核心特性,极大地简化了企业级应用的开发工作。本资源包含Spring IOC和AOP的实现代码,使得...

    Java Framework 关于IOC、AOP、Log的案例源码

    该源码是课程 Java Spring案例精讲 ---- Spring框架 的源码,包含Java Spring的最简单的Hello World、IOC、AOP及Log的源码 Spring整体框架中的核心功能,例如:IOC、AOP、Bean生命周期、上下文、作用域、资源处理等...

    spring教程 ioc aop

    Spring框架是Java开发中的核心组件,它为应用程序提供了一个轻量级的容器,负责管理和装配对象,以及提供各种服务。本教程围绕“Spring教程:IOC(控制反转)和AOP(面向切面编程)”展开,同时涵盖了与Hibernate的...

    spring IOC AOP simulation.rar

    Spring框架是Java开发中不可或缺的一部分,它通过IoC(Inversion of Control,控制反转)和AOP(Aspect Oriented Programming,面向切面编程)两大核心特性,极大地简化了应用程序的构建和维护。在这个名为"spring ...

    自己写的类struts的简易的mvc实现+一个类Spring的IOC和简单AOP

    标题中的“自己写的类Struts的简易的MVC实现+一个类Spring的IOC和简单AOP”揭示了这个压缩包包含两个主要部分:一个模仿Struts框架实现的简单...一个类似Spring框架的轻量级依赖注入(IOC)和面向切面编程(AOP)的实现...

Global site tag (gtag.js) - Google Analytics