基于Spring AOP的权限控制应用研究
2009-10-29林华灵
林华灵
摘要:Spring AOP的面向切面编程的能力,解决了传统面向对象程序设计(OOP)在权限控制应用中存在的问题。实现权限控制组件的模块化,业务逻辑组件与权限控制组件的分离和解耦,从而提高组件及代码的复用度。
关键词:OOP;面向切面编程;Spring AOP;权限控制
1 引言
OOP(Object Oriented Programming,面向对象程序设计)中的每个对象均由属性和方法封装构成,是对客观物质的抽象,对比传统的面向结构程序设计思想,OOP思想更加接近于客观世界,是当前最主流的编程思想。基于继承、多态和封装等特性的OOP在解决纵向多层次的对象关系问题,如继承、聚合和泛化等,展示出强大能力。但运用OOP解决一些横向关系的问题,如日志、权限控制、缓存和事务等问题,却无法行之有效。因为此类问题跨越了给定编程模型中的传统职责界限。如果使用面向对象技术程序设计(OOP)来解决这类问题 ,往往会使系统衍生大量冗余代码,组件紧密耦合和可维护性差等问题。为了弥补面向对象编程技术解决“横切”方面问题存在的能力不足, 面向切面编程(Aspect Oriented Programming ,简称AOP)技术便应运而生,它的出现有效解决了上述问题,并使系统设计开发变得简单而高效 ,并从编程方法学的角度提供了一种编写安全程序的有效途径。
2 Spring框架技术与Spring AOP技术原理
SpringFramework是开源的J2EE应用框架。它的核心是个轻量级容器,Spring通过容器管理物件的生命周期、物件的组态、依赖注入等。旨在简化J2EE的开发,降低J2EE项目实施的难度。Spring帮助实现了真正的逻辑层和Web层的分离。它是为解决企业应用开发的复杂性而创建的,Spring使用基本的JavaBeans也就是POJO便可以完成EJB完成的事情。Spring的主要设计目标是设计系统组件就有可重用性、易测试、简单以及松散耦合等特性。
2.1 Spring框架体系结构
Spring 框架是一个分层架构,由 7 个定义良好的模块组成。Spring 模块构建在核心容器之上,核心容器定义了创建、配置和管理 bean 的方式[1]。
2.2 Spring IoC模式
当我们进行项目开发时,我们将一个复杂的系统进行有效的划分,形成多个模块,这样可以使我们有效的理解和控制整个系统,使每个模块都能易于理解和维护。但是模块之间以某种方式进行信息交换的时候,模块和模块之间就不可避免的发生了某种耦合关系。但是,如果模块间过强藕合则会对整个系统来说会造成很大的潜在危害,特别是当需求发生变化时,代码维护的代价相当高。因此我们要尽可能的消解模块间不必要的藕合,尽量提高系统的可维护性和组件的复用度。
Spring的核心是IoC(Inversion of Control,控制反转),就是为了要解决组件间的耦合而产生的,实现组件的构建和使用分开。所谓“控制反转”就是将原先系统中对象间关系的控制权从程序自身转交给IoC容器。借助IoC能够降低系统中各个组件之间的依赖关系,实现解降藕的目的。
Spring IoC主要通过依赖注入的方式实现对象控制的反转。即在组件设计时,避免采用静态编码的形式描述组件间的相互依赖关系,而是在系统运行期间,由Spring IoC容器依据Spring 上下文的描述,动态地将目标对象实例注入到各个关联组件中。
Spring AOP可以解决传统面向对象编程(OOP)中不能够很好解决的“横切关注点”(CrossCut)方面的问题,例如,在应用开发中需要解决的安全、事务、日志等公共功能问题。尽管这些问题的解决与系统业务逻辑实现无关,但解决的好坏影响着系统的健壮和稳定,命运攸关系统开发的成败。而以传统方式解决“横切关注点”问题,通常是将公共功能代码散布并静态嵌入到各个业务逻辑组件中,因此“横切关注点”问题的解决代码与业务逻辑组件紧密耦合。一旦需要对公共功能代码做修改,必须逐个找出应用该代码的业务逻辑组件,再逐一修改。而Spring AOP解决这些问题的方法首先是将业务逻辑方面的解决和“横切关注点”方面问题的解决相分离;其次是将“横切关注点”问题的解决实现集中化、模块化处理。下面是关于Spring AOP的重要概念[1]:
切面(Aspect):一个关注点的模块化,这个关注点可能会横切多个对象。事务管理是J2EE应用中一个关于横切关注点的很好的例子。在Spring AOP中,切面可以使用基于模式)或者基于@Aspect注解的方式来实现。
连接点(Joinpoint):在程序执行过程中某个特定的点,比如某方法调用的时候或者处理异常的时候。在Spring AOP中,一个连接点总是表示一个方法的执行。
通知(Advice):在切面的某个特定的连接点上执行的动作。其中包括了“around”、“before”和“after”等不同类型的通知(通知的类型将在后面部分进行讨论)。许多AOP框架(包括Spring)都是以拦截器做通知模型,并维护一个以连接点为中心的拦截器链。
切入点(Pointcut):匹配连接点的断言。通知和一个切入点表达式关联,并在满足这个切入点的连接点上运行(例如,当执行某个特定名称的方法时)。
织入(Weaving):把切面连接到其它的应用程序类型或者对象上,并创建一个被通知的对象。这些可以在编译时(例如使用AspectJ编译器),类加载时和运行时完成。Spring和其他纯Java AOP框架一样,在运行时完成织入。
因为SpringAOP解决“横切”方面问题采用了动态代理的实现机制,把切面连接到切点上,并创建一个被通知的对象这个过程通常在编译时,类加载时和运行时完成。而并非预先静态嵌入代码的方式,所以我们还需要在Advice(通知)执行的时机预先做好定义。在Spring AOP中,通知切面(Aspect)织入切点(Pointcut)的时机可分为:前置通知、后置通知、异常通知、最终通知和环绕通知。
3基于Spring AOP的权限控制组件实现
权限控制是企业级Web应用系统中不可或缺的功能之一,是Web系统运行的重要的安全保障。Spring AOP在Web系统的用户权限控制方面具有强大的能力。以在线考试系统为例,系统包含了权限控制的实现,不同的用户被授予不同的权限。例如考生的权限仅限于特定时间的考试和成绩查询,系统管理员的权限包含添加考生、删除考生、增加试题等更高层次的操作。因此针对于某些较高权限的操作,我们可以在操作前先进行用户的权限检查。权限检查通过,则用户方可以继续执行持久化操作。权限检查与实际的业务逻辑无关,而属于安全相关的“横切”方面的问题。针对这个案例,我们给出了两种解决方案:
解决方案一:我们在系统的业务逻辑组件中凡是涉及持久化实现的方法都插入权限检查方法的代码,使得当用户进行任何方式的持久化操作之前,都先执行权限检查方法;这是AOP提出之前,解决横切问题的通常做法。但是采用这种大面积嵌入静态代码做法产生的问题是代码冗余了,而且使业务逻辑组件对权限检查组件的紧密耦合,不利于系统的扩展和升级。譬如,当需要对安全代码作变更的时候,需要找出所有业务逻辑方法,手工一一加入权限控制代码,采用这种方案效率低下,且不易维护。
解决方案二:采用AOP(面向切面编程)的解决方案,将散布在各个业务逻辑组件中权限控制代码同业务逻辑代码相分离,并实现权限控制代码的模块化、组件化处理。Spring AOP采用了动态代理的方式,避免了在所有切点上加入静态的权限检查代码,因此解决了代码重复的问题。
在线考试系统中业务逻辑组件ExamServiceImpl的用户权限检查就采用了Spring AOP实现。下面是以业务逻辑组件ExamServiceImpl为例,介绍Spring AOP思想在本应用系统中的实现。Spring上下文中的配置:
这段Spring上下文首先将权限检查组件类AuthorityCheck和业务逻辑组件类ExamServiceImpl定义为Bean类,这样当需要用到这两个组件时候,Spring IoC容器便会向程序注入两个类的实例,实现了控制反转(IoC)。
定义了权限检查组件(AuthorityCheck)为“切面”(aspect),由于上下中前面已声明AuthorityCheck,因此我们将切面声明标签
声明了切点(pointcut)为org.service.ExamServiceImpl类下的所有方法。
声明了前置通知为checkSecurity方法,一旦追踪并捕获目标方法(ExamServiceImpl类下所有方法)即将被执行的消息,权限检查方法(checkSecurity)先被调用执行。权限检查通过,用户方可实现执行ExamServiceImpl类下的添加考生、删除考生、添加试题等所有方法。权限检查失败,抛出异常,提示用户权限等级不够,不能执行相关操作。
因此Spring AOP为解决“横切”方面问题,提供了出色的方案。
结束语
Spring AOP建立在Spring IoC机制之上,Spring AOP的拦截(interception)能力,提供了“在所有对象的方法调用前/后加入自定义行为”的拦截能力。促使软件开发人员对用户权限控制等公共功能实现模块化、组件化,从而消除了OOP引起的代码冗余和混乱问题,增强了系统的可维护性和代码的重用性,并最终实现系统的解降藕的目的。
参考文献
[1]林信良.Spring技术手册.北京:电子工业出版社,2006
[2]刘斌.Java Web整合开发[M].电子工业出版社,2007(11)
[3]刘昆.基于J2EE平台的轻量级框架的应用研究[D]. 武汉理工大学,2008
[4]杨少波,顾益军.J2EE项目实训--Spring框架技术,2008(5)
[5]李刚.整合Struts+Hibernate+Spring应用开发详解,2007(11)