1、 本 科 毕 业 设 计 说 明 书 ( 论 文 ) 第 1 页 共 30 页1 引言框架从某种意义上讲是某种应用的半成品,它是由一组组件所构成。对于程序的重用性与所设计的系统的扩展性以达到开发周期的缩减的目的与开发质量的提高等目的,往往是框架一直追求并良好的实现了的。在软件设计中,最终遵循的还是一个设计理念,就是“高内聚,低耦合” 。框架一般是将问题分割成若干子问题进行一一攻破,从而起到易于控制、扩展,易于分配资源的效果。设计过程中,常常引入“层”的概念,及将各个义务分层实现。其间难免会出现耦合,而耦合度过高会降低系统的扩展性和维护性。而框架主要工作在层与层之间,很好的解决了这一问题。在软件
2、设计中有一个概念叫做 IoC,及控制反转,也叫 DI(依赖注入) ,它主要就是实现层与层之间的松耦合。面向对象编程在软件设计中无处不在,非常完美的解决了代码重用。但有时候具体的业务贯穿整个系统,而往往这个业务是重复出现的,利用面向对象已不能很好解决。在这里便出现了 AOP(面向切面编程) ,将其中相同的业务抽取出来进行统一解决。在这里不得不说一下 Spring 框架的强大魅力,Spring 对 IoC 和 AOP 的操作可谓前无古人。本文主要利用 IoC 和 AOP 的概念,解决层与层之间的依赖关系以及重复业务的处理。1.1 研究背景上世纪末与本世纪初,J2EE 开始盛行,主要归功于它对中间层
3、概念提出了系统性标准。但事实上,它并没有取得实质性的成功,原因主要是因为不管从其效率、难度还是性能上来讲都不孚众望。在 J2EE 早期阶段,都是利用 EJB 技术来开发 J2EE 应用的。但是,对于 EJB,其学习成本非常高也难于理解,而且要想应用 EJB 技术也是相当困难的。因为 EJB 强制程序员必须依照它的规范去继续各种不同的接口,这样便会导致代码冗余及相似。此外对于其配置既是纷繁复杂又是味同嚼蜡。对于使用 JNDI 查找对象也是如此。虽然 xdoclet 的应运而生和缓了其中部分的开发工作,但是 EJB 存在的各大问题都造成了对其使用的不方便性。随着 Java 语言的发展,AOP 和
4、IoC 等技术的逐渐成熟,本 科 毕 业 设 计 说 明 书 ( 论 文 ) 第 2 页 共 30 页一种新的 J2EE 解决方案应运而生,即轻量级框架。 11.2 研究平台本文主要是基于 Eclipse 平台,使用 Java 语言编写 IoC 和 AOP 的实现程序。1.2.1 Java 语言Java 是一种面向对象的,由 Sun 公司开发的程序设计语言,具体研发是 James Gosling 及其同事,在上世纪 90 年代末正式推出。Java 的强大之处在于其跨平台性,可在不同操作系统上编写应用软件。Java 语言不同于其他编程语言,其优势主要体现在它具有通用、高效、安全等优点。而且该语言
5、的应用领域也极其广泛。在微型电脑、数据中心、超级计算机以及各种网页应用等都能见到 Java 的身影。虽然 Java的编程风格与之 C、C+非常接近,但与 C 语言不同的是,Java 是完全的面相对象,对于 C+核心的面向对象技术它也是完美的继承了。同时,Java 一改 C 中指针的概念,取而代之的是引用的概念。同时也摒弃了 C 中运算符重载和多继承等特征。在此基础上,Java 也增加了自己的新特性,就是垃圾回收机制,对于不再引用而又一直在内存中的引用进行回收处理。程序员也从中得益而不用手动进行内存管理。1.2.2 EclipseEclipse 是一个开源的软件开发工具,同时也是功能完备,能进行
6、商用的工业开发平台。主要组成为 Eclipse 项目、工具项目、技术项目,具体是指 Eclipse Platform,JDT,CDT,PDE。其中,Eclipse Platform 是可扩展的集成开发环境;JDT 是 Java 开发工具,主要用于 Java 开发;CDT 是 C 语言开发工具,主要用于 C 开发;PDE 则是对插件的开发。Eclipse 为构建 IDE 和建造块建立坚实的基础。对于Eclipse Platform,它允许第三方工具的无缝对接,从而起到无须辨别具体工具的功能体现在哪里的作用。2 IoC 和 AOP2.1 IoC(控制反转)IoC,英文全称为 Inversion o
7、f Control,及控制反转,主要用于降低程序间的耦合度。控制反转一般分为两种类型,依赖注入(Dependency Injection,简称本 科 毕 业 设 计 说 明 书 ( 论 文 ) 第 3 页 共 30 页DI)和依赖查找(Dependency Lookup) 。依赖注入应用比较广泛。 22.1.1 依赖注入依赖注入就是容器全权负责组件,给予其回调接口和上下文条件。EJB 和 Apache Avalon 都使用这种方式。如此看来,对于依赖对象的查找以及资源的查找就必须使用容器提供的接口,控制反转也就体现在了回调接口上。容器提供应用代码资源也是通过回调接口的。 32.1.2 实现方式
8、对于依赖注入,主要的实现方式分别为接口注入(Interface Injection) 、Set方法注入(Setter Injection)和构造注入(Constructor Injection) 。 42.1.2.1 接口注入在接口中定义要注入的信息再通过接口来完成此功能就叫接口注入。具体示例如下:编写一个 IBiz 接口,Dao 层的注入将通过这个接口进行。假设该接口中有一getDao()方法,用于获取数据访问层的对象。public interface IBiz/* param dao 数据访问层对象*/public void getDao(Dao dao);对于想要进行数据库操作的类就必须
9、得实现 IBiz 接口,业务逻辑类 Biz 实现这个接口 IBiz。/*本 科 毕 业 设 计 说 明 书 ( 论 文 ) 第 4 页 共 30 页* 具体实现 IBiz 接口的类,重写了 getDao 方法*/public class Biz implements IBusinessprivate Dao dao;Overridepublic void getDao(Dao dao)this.dao=dao;只有实现 IBiz 接口才能完成依赖注入。2.1.2.2 Set 方法注入Set 方法注入就是在需要属性注入的类中定义一个 Set 方法,并设置注入元素为其参数。假设业务层 Biz 依赖
10、数据访问层,且持有其属性,需定义一个 Set 方法来接受数据访问层的注入。public class Biz/数据访问层对象的引用private Dao dao;public void setDao(Dao dao)this.dao=dao;/其他调用数据访问层的方法及其他操作本 科 毕 业 设 计 说 明 书 ( 论 文 ) 第 5 页 共 30 页2.1.2.3 构造注入构造注入就是在需要属性注入的类中提供一个有参构造,其参数就是注入的元素。假设业务层 Biz 依赖数据访问层,且持有其属性,可通过一个构造器来接受数据访问层的注入。public class Bizprivate Dao dao
11、;public Biz(Dao dao)this.dao=dao;/其他调用数据访问层的方法及其他操作2.1.2.4 IoC 图解IoC 容器待使用已配置好的系统组件POJOs配置信息产生图 2.1 IoC 图解本 科 毕 业 设 计 说 明 书 ( 论 文 ) 第 6 页 共 30 页2.2 AOP(面向切面编程) AOP 就是 Aspect Oriented Programming 的缩写,意为:面向切面编程。具体是指它是一种通过预编译和动态代理来实现程序功能的统一维护的技术。 5AOP 是 OOP的延续,是软件开发中的一个热点,是函数式编程的一种衍生范型。AOP 技术可以使业务逻辑的各个
12、功能模块耦合度降低,从而达到提高程序的重用性和开发效率。 62.2.1 实现技术对于 AOP 技术的实现,主要可通过以下两种方式实现:一种是动态代理,对原有对象的行为通过截取消息,修饰消息,最终执行修饰后的行为;另一种是静态织入,以特定语法创建切面,以达到编译器在编译期织入切面代码的目的。 7然而殊途同归,实现 AOP 的技术特性却是相同的,分别为:(1) join point(连接点):连接点是程序运行过程中具体的执行点,比如它 可以是一个方法。对于连接点并不是一个具体的概念,所以在是实现 AOP 时并不用去定义它。(2) point cut(切入点):对于切入点这个概念,它实质上是一个捕获
13、连接点的一种结构。所以在实现 AOP 中,可通过定义一个切入点来拦截相关方法的调用。(3) advice(通知):本质上是切入点是执行程序,具体执行切面的逻辑。(4) aspect(方面):切点与通知合称切面,虽与面向对象中的类相似,但它更多的表达的是对象间的横向关系。(5) introduce(引入):以附加属性方法的形式达到修改对象结构的目的。有的 AOP 工具又将其称为 mixin。2.2.2 主要目的对于 AOP 的主要目的大致可分为事务处理、性能监测、日志记录、安全控制等。82.2.3 主要意图对逻辑代码中事务处理、性能监测、日志记录、安全控制等的处理从中分离,重新独立到非向导业务方
14、法中。此等做法的好处是在修改这些代码的时候不影响业务逻辑,进一步体现了软件开发的“开闭原则” 。 9本 科 毕 业 设 计 说 明 书 ( 论 文 ) 第 7 页 共 30 页2.3 注解(Annotation)Annotation(注解)是 JDK5.0 及以后版本引入的。对于注解,主要作用大致是监测代码依赖性,创建文档,通过注解甚至可以执行基础的编译检查。 10注解的编写方式是以“”开头加上自定义的注解名,通过其参数个数的不同,大致可分为三类:单值注解、标记注解和完整注解。注解只是作为标识存在,一般不会直接影响到程序的语义,通过反射机制我们可以访问到这些元数据,元数据就是用来描述数据的数据
15、。注解的存在级别一共有三种:RUNTIME,CLASS,SOURCE。RUNTIME 表示运行时存在,CLASS 表示能作用于 class 文件,SOURCE 表示只存在源代码中。程序员可在编译时选择代码的存在级别。 112.3.1 基本作用虽然对于注解的作用还没有明确的定义,但是大致可以分为三种:(1) 编写文档:检查代码中存在的标识注解来生成文档。(2) 代码分析:以代码中标识的注解对代码进行分析。(3) 编译检查:检查标识的注解使编译器能执行基础的编译检查。 122.3.2 基本的内置注解(1) Override:只能用在方法上,用来申明该方法是改写父类的。(2) Deprecated:
16、对于弃用的方法添加的注解。当程序员调用这些方法时, 在编译时将会显示提示信息。该注解可添加在程序的所有元素上。 (3) SuperressWarnings:暂时关闭警告信息。 133 基于注解的 IoC 和 AOP 的实现就 IoC 而言,主要实现是靠设计模式中的工厂模式,工厂模式负责将大量具有Component 注解的类进行实例化,而不必事先知道每次是要实例化哪一个类。换句话说,工厂模式对于具体的 new 的细节都进行了隐藏和封装。对于工厂模式的优点主要分为下列四点:(1) 代码结构清晰,具有良好的封装性。对于对象的创建不是无条件的。假设一个调用者需要一个具体的产品,调用者并不需要知道产品具
17、体是如何被生产的。对于他而言只需要知道产品类名或者产品约束字符串就可以了,从本 科 毕 业 设 计 说 明 书 ( 论 文 ) 第 8 页 共 30 页而降低模块耦合度。(2) 优秀的可扩展性。如果具体需求需要增加产品,不必具体对产品类进行修改,只需适当修改工厂类或者再增加一个工厂就可以了。(3) 屏蔽产品类。对于具体产品是如何生产的,调用者并不用关心,他的关注点主要在于产品的接口。如果产品接口不发生变化,那么系统上层的模块也不会发生改变。具体的产品的实例化主要由工厂类管理,对于不同的产品对象的生产应取决于不同的工厂类。(4) 关于工厂方法的经典应用就是解耦合了。处于较高层的模块只需知道实现类
18、的接口,具体实现类无需关心。对于工厂方法,它也遵循迪米特和依赖倒置法则,仅仅依赖实现类的接口;除此之外,工厂方法也遵循里氏替换原则,子类可以随时随地替换父类。 14而对于 AOP 来说,在扫描系统组件时,如果该组件存在 Interception 注解且已声明需要拦截的方法。那么在调用存在 Interception 注解的类的方法时,如果该方法已被拦截,则该方法执行前和执行后会进行相应的操作。而实现 AOP 技术主要用到了代理模式。对于使用代理模式,只要有点体现在以下几个方面:(1) 职责清晰:具体的产品类实现具体的业务,不必去在意非自身所要实现的业务。如需其他业务可通过后期代理完成附加,此种做
19、法的好处是代码简洁清晰。(2) 高扩展性:对于产品类可能需求不同,但是只要是实现了其接口的,可通过代理手段代理各种产品类,而代理类却不用做任何修改。(3) 智能化:代理对象可在运行时才去调用具体的代理类,换言之就是代理类可以在运行时才确定代理对象。 153.1 注解的编写在本文中,主要用到的注解有Component,Property,Aspect,Interception。Component 注解主要说明该类是一个组件,用于在初始化容器时将其实例创建放入一个 Map 中;Property 注解主要说明该类是组件类的属性,在运行时将注入属性,以便调用该类的方法;Aspect本 科 毕 业 设 计
20、 说 明 书 ( 论 文 ) 第 9 页 共 30 页注解主要用于说明该类是一个切面类,用来执行在拦截方法执行过程中要处理的操作;Interception 注解用于说明该类中的方法需要被拦截,可指定要拦截的方法,拦截下来的方法将先进行其他操作,如事务处理。具体注解的代码如下:Component 注解:public interface Component /组件在HashTable中的名字,当为空时默认为组件类名的小写public String name() default “;/组件是否存在单例,默认为存在public boolean isSingleton() default true;Pr
21、operty 注解:public interface Property /需要注入的属性注入的对象的名称,默认为空时则直接获取组件中属性的名称public String ref() default “;Aspect 注解:public interface Aspect /切面类的名称public String name() default “;Interception 注解:public interface Interception /拦截的方法public Stringmethods();3.2 IoC 实现(对象工厂)首先,在工厂初始化的时候会创建组件的对象,而对于组件类的存放放在对应的包
22、中,对于读取的包及包的扫描则配置在 XML 中。读取 XML 获取包名及子包名代码如下:String packageInfo=“;URL url=XMLParse.class.getResource(“);File file=new File(url.getPath()+xmlName);DocumentBuilder builder=null;try builder=DocumentBuilderFactory.newInstance().newDocumentBuilder();Document doc=builder.parse(file);本 科 毕 业 设 计 说 明 书 ( 论 文
23、 ) 第 10 页 共 30 页Element ele=doc.getDocumentElement();NodeList nls=ele.getChildNodes();Element ce=null;for (int i = 0; i classes) /获取此包的目录建立一个fileFile dir=new File(physicsPath);/如果不存在或者也不是一个目录就直接返回if(!dir.exists()|!dir.isDirectory()return;/如果存在就获取包下的所有文件及目录File dirFiles=dir.listFiles(new FileFilter() Overridepublic boolean accept(File file) /如果可以循环(即包含子目录)或是以 .class结尾的文件(即编译好的java文件)return (recursive);/循环所有文件for (File file : dirFiles) /如果是目录则继续扫描if(file.isDirectory()findAndAddClassesInPackageByFile(packageName+“.“+file.getName(), file.getAbsolutePath(), recursive, classes);else