通过面向特征的编程减少编码时间和重复。目前编程中最热门的新概念是面向特征的编程(ASpECt-oriented Programming,AOP)。AOP曾经主要用于学术和研发机构,如今开始进入主流开发领域。与OOP在面向过程的编程方法基础上的改进一样,AOP是在面向对象编程(OOP)方法的基础上进行改进而来的一种创新的软件开发方法。OOP引入了封装、继承和多态性等概念来建立一种对象层次结构,用以模拟公共行为的一个集合。然而,OOP在处理范围扩展到一些无关对象的公共行为方面达不到要求。也就是说,OOP允许你定义从上到下的关系,但并不适合定义从左到右的关系。例如,看一下日志功能。日志代码往往水平地散布在所有对象层次中,而与它所散布到的对象的核心功能毫无关系。对于其他类型的代码,如安全性、异常处理和透明的持续性也是如此。这种散布在各处的无关的代码被称为横切(CROSs-cutting)代码,这也是AOP编码方法产生的原因。
AOP提供一种提取横切代码的方法,这种横切代码横跨各个对象层次,但与它所跨越的对象代码在功能上没有相关性。AOP不是在类中嵌入横切代码,而是允许你将横切代码提取到一个单独的模块中,然后在需要的时候动态地应用该代码,这个单独的模块叫做一个"特征代码"("aspect",也译作"标记")。通过在你的对象模型中需要应用横切代码的地方定义特定的位置--切入点(pointcut)--来实现动态的应用横切代码。在运行或编译时,根据你的AOP框架,横切代码被插入指定的切入点。本质上说,AOP允许你在对象中引入新功能,而对象无需了解所引入的功能。这是一个非常有用的概念。
为了进一步理解AOP是如何工作的,请看一个典型的AOP日志例子。代码清单1显示了两个包含日志代码的简单对象:objectA和ObjectB。
通过标准的面向对象的编程,每次你需要时,都要在相应的对象中编写日志代码。在代码清单1的例子中,使用SySTem.out.println()调用来记日志很烦琐。代替System.out.println()调用的另一种方法是使用log4j这样的日志框架,但这会带来额外的开销并给使用它的类带来不必要的杂乱东西。无论是使用System.out.println()调用还是日志框架来实现日志功能,日志代码都与它被嵌入到的类在功能上没有相关性。
通过AOP,你可以动态地将日志代码插入到需要日志功能的类中。这样,对象可以专注于其核心职责。只专注于其核心职责的Java对象往往被称为POJOs(PlAIn Old Java Objects):普通老式Java对象。你可以使用AOP给POJOs增加日志和一些其他类型的公共功能,而无需嵌入不必要的无关功能。
本文将介绍和解释AOP术语,解释不同AOP框架之间的差别,然后逐步说明一个将AOP用于缓存的示例。
AOP术语
AOP 引入了几个新的术语来描述其基本概念。必须切实理解这些术语才可能理解AOP。下面列出了AOP引入的术语及其描述:
1. 建议--是应用到或横切你现有对象模型的代码。建议代码就是修改已有对象的行为或属性的代码。建议通常也被称为引入件(introductions)或混入件(mix-ins)。
2. 切入点-定义在你的模型中要应用建议的位置点。例如,切入点定义在一个类的什么位置应引入代码或哪个方法要在执行前被拦截。切入点也被通称为连接点(joinpoints)。
3. 特征-它将建议和切入点封装到功能单元中,其封装方式与OOP使用类将字段和方法封装到内聚单元(cohesive unit)的方式基本相同。例如,你可能有一个日志特征,它包含了将日志代码应用于对象的所有设置(setter)和获取(getter)方法的建议和切入点。
选择一个框架
在开始使用AOP之前,必须选择一个所用的AOP框架。Java和任何其他主流的面向对象的编程语言都没有对AOP提供内置支持。不过,有一些支持Java的可用的AOP框架,其中大多数都有着相同的核心功能,但在AOP连接到对象模型的方式上有差别。
一些AOP框架使用字节码操作来连接到对象模型,其他一些则使用基于代理的系统进行连接。使用字节码方法的框架在源代码编译为字节码之前修改源代码或在编译后修改字节码。这两种方式都可以有效地得到相同的结果:经过修改的字节码将AOP嵌入到了原始代码。基于代理的框架使用一个代理系统,AOP框架籍此截取所有对具有某特征代码对象的方法调用,然后代理执行对这些框架想要的对象的方法调用。这种代理功能是透明的,而且可以保持字节码总是不变。
各个AOP框架之间的另一个核心区别是特征代码的定义和应用的方式。有些框架中,通过代码来定义和应用特征,而其他一些框架则要求通过XML配置文件来定义和应用特征代码。更好的是,一些框架同时支持用代码和XML配置文件定义和应用特征代码。
因为大多数AOP框架的功能有重叠,究竟使用哪个框架往往取决于某个特定框架的独特功能。本文中的AOP示例应用程序是用一个新的AOP框架dynaop开发的。但是,这个示例应用的基本原理是通用的,可应用于所有的AOP框架。dynaop框架支持用代码定义和应用特征代码,它还提供了一个通过BeanShell脚本框架定义和应用特征代码的独特解决方案。 BeanShell脚本可以使你轻松地编写Java对象脚本,比如示例应用程序所示。
通过dynaop使用AOP
一个简单的缓存特征对方法的结果进行缓存,它说明了AOP的一些基本概念。第一次对方法的调用具有实用的缓存特征代码,它调用该方法并缓存其执行的结果。对这个方法的后续调用将从缓存中返回方法的调用结果。这个基本的缓存特征代码对于运行时间长的方法非常有用,诸如处理大量数据的方法或对某个数据源发出多个查询的方法等。
如代码清单1中的日志例子,在每个需要的类中嵌入缓存功能会导致大量的重复代码。而且,缓存对于大多数对象并不是一个核心功能,而很适合用AOP来实现统一和重复使用。
这个缓存应用程序包括四个文件:
CachingInterceptor.java-包含对方法调用结果进行缓存的AOP代码。这些代码被称为建议。
User.java-一个基本类,其中包含对"name"字段进行设置和获取"getter"和"setter"的方法。 CachingInterceptor AOP代码将被用于这个类。
CacheTest.java-一个说明CachingInterceptor AOP代码使用情况的示例应用程序。
dynaop.bsh-规定在哪里应用CachingInterceptor advice的BeanShell脚本。这些规定被称为切入点(pointcuts)。
以下部分将详细解释每个文件。
CachingInterceptor.java文件。CachingInterceptor类以一种标准、通用的方式将可以应用到任何类的缓存代码进行封装。这个类将方法初次被调用后的结果缓存起来。然后CachingInterceptor类拦截对其结果已被缓存的方法的后续调用,并直接从缓存中返回这些结果,从而为运行时间很长的方法提供快速响应。代码清单2显示了CachingInterceptor类。
CachingInterceptor类包含intercept()、calculateCacheCode()和getFullMethodName()各个方法。intercept()方法实现dynaop.Interceptor接口并包含这个特征的核心建议代码。该方法在具有特征代码的方法被调用之前被调用,然后它负责调用这个具有特征代码的方法。重要的是,intercept()方法是一个代理,用于插入在该方法被代理前执行的功能。另外,intercept()方法控制代理方法是否真正被调用。
CachingInterceptor类的intercept()方法调用calculateCacheCode()方法为将被调用的方法计算一个缓存键值。然后使用这个键值为被调用的方法(在本例中是User类中的getName()方法,在后面部分有定义)查找缓存,查看是否其结果已被缓存。如果结果已经被缓存,则返回被缓存的结果,不再调用User.getName()方法。如果结果没有被缓存,则调用User.getName()方法,并将其结果缓存起来供后续调用使用。这是一个基本的缓存实现,不考虑缓存中的时效数据项和缓存是否超长。
User.java 文件。User类是一个简单的类,只有一个字段以及针对该字段的获取和设置方法。 CachingInterceptor特征代码被用于这个类的getName()方法。代码清单3 显示了User类。
请注意,这个类中的每个方法都有一个System.out.println()调用,指明该方法什么时候被调用。这些调用用来说明示例应用运行时究竟会产生什么结果。 下一步
了解更多AOP信息
aosd.net
eclipse.org/AspectJ
BeanShell
下载
dynaop
本应用程序
阅读更多James Holmes的文章
Java艺术
Struts: 完整的参考手册
CacheTest.java 文件。CacheTest类包含说明CachingInterceptor特征代码如何使用的示例应用程序的代码。这个应用程序只是实例化了一个User对象,并多次调用它的getName()方法,显示出连续调用缓存中的方法结果以及对该方法的直接访问。代码清单4显示了CacheTest类。
CacheTest包含一个main()方法,所以它可以作为一个独立的应用程序来运行。
dynaop框架使用一个基于运行时的编织机制将AOP代码插入对象中,这样来直接实例化User对象,使用这个新的操作符,而不是返回一个具有特征代码的对象。为了在示例应用程序中使用CachingInterceptor特征代码,CacheTest类通过dynaop的ProxyFactory类来实例化User对象。一旦你通过ProxyFactory.getInstance() .extend()实例化了这个对象,你就可以像使用其他任何对象一样正常地使用User对象。从这点来说AOP代码的执行是透明的。
dynaop.bsh文件。dynaop.bsh文件是一个BeanShell脚本,用于指定应用CachingInterceptor建议的切入点。以下是dynaop.bsh文件的内容:
// Apply interceptor to all
// getter methods.
interceptor
(
User.Class,
GET_METHODS,
new CachingInterceptor()
);
这个简单脚本指定了CachingInterceptor建议将应用到User类的所有获取方法。GET_METHODS是dynaop用来方便地指定一组切点的几个常量之一。如果必要,你也可以明确地为一些切点指定各个方法。
编译和运行这个应用程序
最后,编译和运行这个应用程序。假设你将这个应用程序的四个文件放在了你安装的dynaop的目录下,例如c:\java\dynaop,下面的命令行将编译这个应用程序:
javac -classpath .\bsh-2.0b1.jar;
.\cglib-asm-1.0.jar;
.\dynaop-1.0-beta.jar;
.\jakarta-oro-2.0.7.jar
*.java
编译完后,执行以下命令运行它:
java -classpath .\;
.\bsh-2.0b1.jar;
.\cglib-asm-1.0.jar;
.\dynaop-1.0-beta.jar;
.\jakarta-oro-2.0.7.jar
CacheTest
图1显示了这个示例应用程序的运行结果。这个应用程序先调用User类的setName()方法,然后调用getName()方法。这两个调用都在User类中被启用,对getName()的后续调用在缓存中查找到结果,而不再在User类中被启用。
无提示--不好意思!
-----
图1: 命令行提示
结论
AOP提供了一个创建软件的功能丰富的新平台,它去除了类的一些不必要职责,并极大地促进了代码的重用。 AOP的日常实际使用包括提取日志代码、提取安全性和缓存代码等,但AOP的应用远不止于此。随着AOP的日益成熟和发展,它还将会有更多的应用。
相关推荐
在实际应用中,`student-web`可能是一个包含学生管理功能的Web应用,使用Spring AOP和Memcached可以高效地缓存学生的查询结果,提高响应速度,减轻数据库压力。通过不断优化和调整缓存策略,可以进一步提升系统性能...
本示例"ViewFinder"是一个基于APT的实际应用,其灵感来源于ButterKnife,一个流行的视图注入库。 **ButterKnife的原理和目的** ButterKnife是一个流行的Android绑定库,它通过注解简化了UI元素的查找和事件处理。...
此外,`springtest`文件可能包含了一些用于测试Spring AOP性能监控器的示例代码,你可以根据这些代码进一步实践和理解这个主题。记住,理论知识与实际操作相结合才能更好地掌握技术。 总结来说,Spring AOP性能监控...
在实际应用中,一个简单的例子是一个队列(Queue)的公用类。在不使用AOP的情况下,队列类中可能需要包含很多与业务逻辑无关的横切关注点代码,如跟踪、同步、安全检查等。而使用AOP后,这些横切关注点可以抽象为切...
适合人群:具备一定Java和Spring框架基础的研发人员,希望深入理解AOP机制并在实际项目中应用的相关技术人员。 使用场景及目标:① 在业务逻辑中分离横切关注点,如日志记录、性能监控、权限控制等;② 提高代码的可...
在.NET开发环境中,C#语言提供了丰富的特性(Attributes)、依赖注入(DI)和面向切面编程(AOP)等机制,使得我们可以...通过对这些文件的分析和学习,开发者可以进一步理解如何在实际项目中应用C#和AOP来处理异常。
在IT行业中,Spring AOP(面向切面编程)和Ehcache是两个非常重要的概念,它们经常被结合在一起用于实现高效的应用程序缓存系统。在这个"AOP Cache源代码"项目中,我们可以看到如何利用这两者来提升应用性能。下面将...
在实际应用中,这样的工具可以帮助我们优化代码,提升系统性能。 总之,面向切面编程通过将横切关注点与核心业务逻辑分离,提高了代码的可读性、可维护性和复用性。Spring等框架提供的AOP支持,使得在Java环境中...
// 定义一个切点表达式,这里仅给出示例,实际应用中应根据项目需求来定义 @Pointcut("execution(* com.incon.project.zkb.qxgl.qxbmxxxg.service.*.*(..))") public void切入点() { // 切点方法体为空,因为仅...
本学习笔记将深入探讨Spring AOP的核心概念、工作原理以及实际应用。 1. **核心概念** - **切面(Aspect)**:切面是关注点的模块化,包含业务逻辑之外的横切关注点,如日志、事务管理。 - **连接点(Join Point...
此外,Spring的AOP还能与Spring的其他功能,如依赖注入(DI)无缝集成,使得我们可以方便地在切面内部获取并操作bean,进一步增强了代码的灵活性和可扩展性。 总的来说,Spring的AOP提供了强大的工具,让我们能够以...
通过对这个简单的AOP拦截器实现的学习,我们可以进一步探索如何结合注解驱动的AOP、环绕通知(`Around Advice`)、代理模式的实现细节、以及如何在实际项目中利用AOP解决实际问题。AOP是Spring框架的强大工具,理解...
面向切面编程(AOP)是一种编程范式,它允许开发者将横切关注点(cross-cutting concerns)从业务...通过实际的编码实践和问题解决,开发者可以逐步掌握如何有效地在项目中应用AOP,提升项目的结构化水平和代码质量。
同时,结合博客文章(https://joerong666.iteye.com/blog/189357),我们可以了解到实际应用场景和案例,帮助我们更好地掌握如何在项目中运用PostSharp。 总结起来,PostSharp作为一款强大的AOP工具,不仅简化了...
你可以通过解压并运行这个项目来进一步理解和学习Spring AOP的实际应用。 总之,Spring AOP简化了代码的结构,通过将关注点分离,使我们的应用程序更加模块化和易于维护。结合Maven的项目管理能力,我们可以轻松地...
标题 "springaop" 暗示我们关注的是Spring框架中的AOP(面向切面编程)模块。在Spring框架中,AOP是一种强大的工具,它...如果你想要进一步学习,可以尝试创建自己的切面、通知和切入点,然后在实际项目中应用它们。
在IT行业中,Spring框架是Java开发中的核心工具之一,它为开发者提供了许多强大的功能...在提供的"aopLog-demo"项目中,你可以找到更多关于Spring AOP日志管理的实际应用示例,这将有助于你进一步理解和实践这一技术。
在深入理解Spring AOP的基础上,你可以进一步探索更复杂的应用场景,比如事务管理、性能监控等。同时,还可以学习如何结合Spring Boot和Spring Cloud等现代框架,将AOP应用于微服务架构中,以实现更高效、更灵活的...