﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-★yesjoy★-文章分类-AOP(面向方面编程)</title><link>http://www.blogjava.net/yesjoy/category/22901.html</link><description>&lt;font color="red"&gt;★&lt;/font&gt;&lt;font color="blue"&gt;总在爬山 所以艰辛;总在寻梦 所以苦痛&lt;/font&gt;&lt;font color="red"&gt;★&lt;/font&gt;</description><language>zh-cn</language><lastBuildDate>Sun, 05 Sep 2010 02:34:24 GMT</lastBuildDate><pubDate>Sun, 05 Sep 2010 02:34:24 GMT</pubDate><ttl>60</ttl><item><title>关于AOP的七个猜想 </title><link>http://www.blogjava.net/yesjoy/articles/120861.html</link><dc:creator>★yesjoy★</dc:creator><author>★yesjoy★</author><pubDate>Wed, 30 May 2007 03:41:00 GMT</pubDate><guid>http://www.blogjava.net/yesjoy/articles/120861.html</guid><wfw:comment>http://www.blogjava.net/yesjoy/comments/120861.html</wfw:comment><comments>http://www.blogjava.net/yesjoy/articles/120861.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yesjoy/comments/commentRss/120861.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yesjoy/services/trackbacks/120861.html</trackback:ping><description><![CDATA[<p><strong><font color=#ff0000>1。随处可见猜想。<br></font></strong>在未来的软件开发过程中，AOP将以一种基础编程能力的形式出现，与OOP共同发展，成为主流开发环境的一个组成部分。而目前为止，AOP只是作为一种开发工具、或运行时代码而存在。到了那个时候，可能没有哪个产品声称：&#8220;我使用了AOP&#8221;，因为没有哪个产品没有使用AOP，就像现在没有哪个产品没有使用OOP一样。就算你的源代码中没有应用到编程语言的AOP能力，你也可能调用了某个应用了AOP的基础库。事实上，AOP之父Kiczales认为AOP可能首先在操作系统上有一定规模的应用。</p>
<p><strong><font color=#ffa500>2。语言级猜想。</font></strong><br>AOP的真正实现是在一个特定的语言基础上的。比如数年之后，人类开始普遍使用K语言（K是J的后一个字母），K语言在语言本身上就可以编织和横切。此时AOP才得到真正的成熟，因为程序员在编写代码时可能根本不知道自己用到的是曾经的OO还是现在的AO，只有了解K语言虚拟机构造和背后实现的人才知道。但是，可能由于人固有的思维方式的问题吧，AOP仍然不会比OOP要使用的更多，甚至有可能仍然是Kiczales所提到的15% Solution！但是，从语言的角度去实现AOP也许会给人类的编程观念带来巨大的变化，这种变化就像OO所带来的一样。</p>
<p><strong><font color=#ffff00><font color=#a52a2a>3。存在AOD/AOA猜想。</font><br></font></strong>OOP对人类的影响远不如它的两个弟弟OOA/OOD，后两者已经为整个软件开发行业带来了一次意义深远的革命，它至少使得全世界开发团队的人数扩大了10倍，开发工具和平台的复杂程度增加了10倍，完成客户某些简单要求的成本降低了90%，唯一的遗憾的是，软件开发的效率几乎没有数量级上的变化（依据《没有银弹》）。既然存在AOP，我们猜想也会存在AOD/AOA，比如会存在面向方面的重构手段，面向方面的设计模式，面向方面的最佳实践，面向方面的过程管理，以及在UML的未来版本中看到为面向方向而专门做的改进，甚至添加一个新的UML图类型。当这些东西都产生的时候，AOP才真正发展到了鼎盛时期。</p>
<p><font color=#008000><strong>4。可执行用例猜想。</strong></font><br>AOP是一个广泛适用的充满想象空间的新技术，但是目前人们对AOP的研究方向过于狭窄，大部分声称正在研究AOP的开源项目其实是把AOP当成一个辅助工具来使用，这些项目中又有相当一部分是在做企业开发环境下的容器，他们并没有针对AOP本身进行开发。事实上，依照Jacbson的说法，AOP将直接导致软件的开发分为两种形式——对模块的开发和对用例的开发，现在的用例仅仅是图纸，必须要转变为OO代码才能执行，但是一旦有了AOP，AOP可以直接依据用例的定义，将多个不同的模块（可能来自不同的开发单位）连接起来，形成方面，而方面本身是可以执行的（语言级猜想），所以用例也就不再是图纸而是可以执行的了。这对于以UML为核心的现代软件过程来说，是个极好的信号。</p>
<p><font color=#ffc0cb><strong><font color=#9acd32>5。标准化猜想。</font><br></strong></font>OO的成功经验告诉我们，要想取得最后的胜利，就要一致对外，统一了内部的概念，剩下的争论就只有实现问题了。我个人认为，多数OOP语言在概念上都是一致的，这种概念被语言学称之为语义，多数OOP的语义来自Smalltalk和C++这些早期尝试者，少数来自Java这种在技术的成熟期涌现出的商业产品。AOP目前还面临着这个问题。业界对AOP的标准化过程有两个猜想，一是由AspectJ领头，各大AOP实现都以AspectJ的语义作为研究问题的基本用语，设计和实现沿用现在的思路；另一个猜想是由权威组织，（开源、商业、或全球研究组织），如Eclipse/IBM/OOPSLA等等拿出一个统一的AOP语义内核，所有AOP项目都以该内核为基础开发。Java虚拟机是前一种思路的成功案例，后者则以XML为代表。</p>
<p><strong><font color=#7fffd4><font color=#000080>6。全静态编织猜想。</font><br></font></strong>下面讨论一个实际的技术问题。时下多数AOP项目采用的编织技术无外乎两种：静态编织和动态编织。前者是指在编译前（预编译期）、编译期、和编译后编织，后者是指在运行期编织。Kiczales认为虽然没有明显的技术缺陷，但动态编织可能会面临一些发展远景的问题，他称之为&#8220;软件的演化问题&#8221;。不知道我对大师观点的理解是不是准确，我认为由于被编织的代码是在变化（发展）中的，我们总是希望这种变化对编织本身的影响最小，这时静态编织面临的问题最多就是重新编译，而动态编织可能不会那么简单。此外，全静态编织会导致另一个优点——这听起来有点奇怪——就是能力较弱，因为全静态编织继承了OO语言本身的约束，比如Java的约束和.NET之CLR的约束等等，这对于更规范的使用开发利器是大有好处的。&#8220;应该对人类准备大规模应用的每一种新工具小心钳制。&#8221;</p>
<p><font color=#800080><strong>7。AOP的诞生之迷猜想。</strong></font><br>Kiczales先生在从事AOP的研究和开发之前也曾接触过其它对OOP的改良研究，其中包括反射和元对象技术。事实上，心平气和的说，后两者的变通能力和灵活程度都在前者之上，但是正因为如此，语言学家们认为，这些技术并不能有效的改善OOP的弊端，甚至还有可能引狼入室，带来新的&#8220;狼人问题&#8221;。后来，当Kiczales发现AOP时，他明白这才是人们真正需要的，他认为他们抓住了问题的咽喉。时至今日，AOP的实现技术已经千姿百态，百家争鸣了，但是，AOP创立之初的种种想法也在这种百花争艳中渐渐被人们遗忘，现在利用反射、元对象技术以及种种双刃剑式的技术来实现AOP的想法已经像争抢参院席位一样争夺市场的认可，这是事物的发展还是理想的倒退？AOP何时才能回归它的本原？上天为它安排的命运究竟如何，我们拭目以待。<br><br>最近，我和我的几个朋友正在组织一批开源斗士们合作编写AOP.NET，这是一个开源软件，在博客园上可以看到部分有关该项目的消息。但是由于种种原因，我们对一些基本的问题还没有达成共识，本文来自我对AOP的一贯看法，也是我对社团里很多问题的一个集中性回答吧。</p>
<p>（转载出处：Brian Sun @ 爬树的泡泡[http://www.blogjava.net/briansun]）</p>
<img src ="http://www.blogjava.net/yesjoy/aggbug/120861.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yesjoy/" target="_blank">★yesjoy★</a> 2007-05-30 11:41 <a href="http://www.blogjava.net/yesjoy/articles/120861.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>AOP技术研究——.Net平台AOP技术研究</title><link>http://www.blogjava.net/yesjoy/articles/120859.html</link><dc:creator>★yesjoy★</dc:creator><author>★yesjoy★</author><pubDate>Wed, 30 May 2007 03:39:00 GMT</pubDate><guid>http://www.blogjava.net/yesjoy/articles/120859.html</guid><wfw:comment>http://www.blogjava.net/yesjoy/comments/120859.html</wfw:comment><comments>http://www.blogjava.net/yesjoy/articles/120859.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yesjoy/comments/commentRss/120859.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yesjoy/services/trackbacks/120859.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 4.1.Net平台AOP技术概览.Net平台与Java平台相比，由于它至今在服务端仍不具备与unix系统的兼容性，也不具备类似于Java平台下J2EE这样的企业级容器，使得.Net平台在大型的企业级应用上，常常为人所诟病。就目前而言，.Net平台并没有提供AOP技术的直接实现，而微软在未来对于.Net的发展战略目标，我们仍未可知。但我相信微软对于目前炙手可热的AOP技术应该不会视而不见。也许在...&nbsp;&nbsp;<a href='http://www.blogjava.net/yesjoy/articles/120859.html'>阅读全文</a><img src ="http://www.blogjava.net/yesjoy/aggbug/120859.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yesjoy/" target="_blank">★yesjoy★</a> 2007-05-30 11:39 <a href="http://www.blogjava.net/yesjoy/articles/120859.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>AOP技术研究——Java平台AOP技术研究 </title><link>http://www.blogjava.net/yesjoy/articles/120858.html</link><dc:creator>★yesjoy★</dc:creator><author>★yesjoy★</author><pubDate>Wed, 30 May 2007 03:37:00 GMT</pubDate><guid>http://www.blogjava.net/yesjoy/articles/120858.html</guid><wfw:comment>http://www.blogjava.net/yesjoy/comments/120858.html</wfw:comment><comments>http://www.blogjava.net/yesjoy/articles/120858.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yesjoy/comments/commentRss/120858.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yesjoy/services/trackbacks/120858.html</trackback:ping><description><![CDATA[<p>3.1 Java平台AOP技术概览</p>
<p>3.1.1 AOP技术在Java平台中的应用</p>
<p>AOP在实验室应用和商业应用上，Java平台始终走在前面。从最初也是目前最成熟的AOP工具——AspectJ，到目前已经融和在企业级容器JBoss中的JBoss AOP，均建立在Java平台上。</p>
<p>前面已经描述到，AOP的目的就是将核心关注点和横切关注点分离，实际上这就是一种分散关注（seperation of concerns）的思路。在Java平台下，如果要开发企业级的应用，非J2EE莫属。一个J2EE应用系统只有部署在J2EE容器中才能运行，那么为什么要划分为J2EE容器和J2EE应用系统？ 通过对J2EE容器运行机制的分析，我们发现：实际上J2EE容器分离了一般应用系统的一些通用功能，例如事务机制、安全机制以及对象池或线程池等性能优化机制。这些功能机制是每个应用系统几乎都需要的，因此可以从具体应用系统中分离出来，形成一个通用的框架平台，而且，这些功能机制的设计开发有一定难度，同时运行的稳定性和快速性都非常重要，必须经过长时间调试和运行经验积累而成，因此，形成了专门的J2EE容器服务器产品，如Tomcat JBoss、Websphere、WebLogic等。</p>
<p>从J2EE将应用系统和容器分离的策略，我们能够看到AOP的影子。J2EE应用系统就相当于AOP技术中的核心关注点，它的内容主要包括企业系统的商业逻辑；而J2EE容器则类似于横切关注点，实现的是通用的功能机制。不过业界在选择J2EE容器时，对于EJB这种重量级容器服务器而言，虽然欣赏其高效、稳定及企业级的容器服务，但对于整个容器的高开销、高成本以及过于复杂的解决方案均深怀戒心。因此，随着J2EE的逐步演化，&#8220;轻量级容器架构&#8221;通过开源社区如激流一般的驱动力，逐渐占据了J2EE技术的强势地位。而所谓&#8220;轻量级容器&#8221;与EJB提供的重量级架构的区别，就在于借助了AOP技术和IoC（Inversion of Control，反转模式）机制，降低了代码对于专用接口的依赖性，以简短、轻便、专注、可移植的方式实现业务对象。事实上，我们看到的美好前景是，如果所有企业级服务都可以通过AOP机制提供给普通Java对象，那么深盔重铠的应用服务器就不再有存在的价值了。</p>
<p>正是看到了AOP技术在企业级开发中的巨大潜力，而&#8220;轻量级容器&#8221;也唤起了改革EJB容器的呼声（事实上，最新的 EJB V3.0 标准就使用了轻量级容器模型），越来越多的AOP工具在Java平台下应运而生，从而形成了目前AOP工具百家争鸣的局面。其中，应用最为广泛的主要包括AspectJ、Spring AOP和JBoss AOP等。</p>
<p>3.1.2 Java平台下AOP工具的比较</p>
<p>AOP是一项新技术，而在Java平台下实现该技术的工具也非常多。虽然AOP的技术要素从本质上来讲是一致的，但各种工具的实现方法也各有不同，本节基于AOP的技术要素，对当前应用较广泛的AspectJ、Spring AOP和JBoss AOP进行比较。</p>
<p>3.1.2.1 AOP实现机制的区别</p>
<p>同样是实现AOP，且AOP的技术要素完全相同，但各种AOP工具对于AOP实现的底层机制却是不尽相同的。</p>
<p>AspectJ采用了源代码生成技术来实现AOP。它提供了一套独有的基于Java平台的AOP语法，以及专有的AspectJ编译器。编译器在编译具有AspectJ语法的Java程序时，能够识别诸如aspect，pointcut等特殊关键字，然后利用静态织入的方式，修改需要被截取的方法所属类的源代码，把advice或者introduce的业务逻辑代码注入到正确的位置。利用AspectJ，可以将核心关注点完全独立出来，然后通过AspectJ语法，编写符合核心关注点要求的横切关注点代码，最后通过AspectJ编译器，将这两者在后期结合起来。采用这种静态织入技术，使得运用了AOP技术的系统在运行性能上未受到任何损失，因为它没有利用反射技术或代理技术，而仅仅是程序的静态扩展而已。然而这种源代码生成方式实现的AOP虽然在性能上具备一定的优势，但它同时会给开发带来一定的问题。例如代码的后期修改会给系统带来不可估量的影响。</p>
<p>Spring AOP是Spring框架中的一部分，但可以作为一个独立的模块单独存在。Spring AOP实现AOP技术从本质上来讲，是利用了JDK提供的动态代理技术。而从实际的实现方式来看，则是利用了IoC（Inversion of Control，反转模式）机制，同时采用了AOP联盟（AOP Alliance）的通用AOP接口。首先，Spring AOP通过xml配置文件配置了pointcut，并利用Interceptor（拦截机）作为设定的触发条件。Interceptor是由用户自定义的，它相当于是AOP中的advice，但该Interceptor需要实现AOP联盟的通用AOP接口，例如org.aopalliance.intercept.MethodInterceptor。最后定义一个Spring AOP ProxyFactory用于加载执行AOP组件，并利用IoC机制将advice注入到接口以及实现类中。</p>
<p>JBoss 4.0提供了AOP框架。与Spring一样，这个框架可与JBoss应用服务器紧密结合，也可以单独运行在自己的应用中。JBoss AOP同样需要Interceptor拦截器来完成对方法的拦截，它要求所有的Interceptor都必须实现org.jboss.aop.Interceptor接口。在这个接口中最重要的方法就是invoke()。该方法对元数据直接进行操作，并利用反射的原理去拦截方法的消息。Interceptor相当于AOP的advice，至于pointcut，则在xml配置文件中配置。可以看出，Spring AOP和JBoss AOP在实现上属于动态织入的方式，它们与AspectJ在实现上是迥然不同的两种方式。</p>
<p>3.1.2.2 关于&#8220;Aspect（方面）&#8221;的区别</p>
<p>在对aspect的声明上，可以使用类似Java的代码，注释或xml。考虑一个常用的例子，对Account类的授权策略，如果以AOP技术来实现，运用不同的AOP工具，它们在方面声明技术上的差异，是显而易见的。</p>
<p>Aspect 中的方面声明类似于 Java 语言中的类声明，如图3.1 所示。</p>
<p align=center><img height=222 alt=aop3.1.gif src="http://wayfarer.cnblogs.com/images/cnblogs_com/wayfarer/aop/aop3.1.gif" width=579 border=0><br>图3.1 AspectJ中的方面声明</p>
<p>由于 AspectJ 是 Java 语言语法和语义的扩展，所以它提供了自己的一套处理方面的关键字。除了包含字段和方法之外，AspectJ 的方面声明还包含pointcut和advice成员。示例中的pointcut使用了修饰符（modifier）和通配符（wildcard）模式来表达&#8220;所有公共方法&#8221;。对帐户的访问，由 pointcut 参数提供。advice使用这个参数，而pointcut则用 this(account) 把它绑定。这样做的效果，就是捕获了正在执行的方法所隶属的Account对象。否则，advice的主体与方法的主体相似。advice可以包含认证代码，或者就像在这个示例中一样，可以调用其他方法。</p>
<p>JBoss AOP 基于 XML 的风格来声明方面，如图 3.2 所示。</p>
<p align=center><img height=364 alt=aop3.2.gif src="http://wayfarer.cnblogs.com/images/cnblogs_com/wayfarer/aop/aop3.2.gif" width=588 border=0><br>图3.2 JBoss AOP的方面声明</p>
<p>在 XML 风格中，aspect、pointcut和advice的声明都以 XML 形式表示的。advice的实现，用的是普通的 Java 方法，由JBoss AOP框架调用。pointcut和pointcut到advice的绑定都在方面中用XML注释声明。JBoss 没有显式地绑定 Account 参数，而是提供了对当前正在执行的对象的反射访问，因此需要把类型转换到对应的类型。JBoss AOP还可以通过标签的方式对方面进行声明。标签均以&#8220;@&#8221;字符开始，它的使用有点类似于.Net中的Attribute。</p>
<p>Spring AOP同样是基于 XML 的风格来声明方面，如图3.3所示。</p>
<p align=center><img height=584 alt=aop3.3.gif src="http://wayfarer.cnblogs.com/images/cnblogs_com/wayfarer/aop/aop3.3.gif" width=579 border=0><br>图3.3 Spring AOP的方面声明</p>
<p>与JBoss AOP类似，Spring的advice实现是带有特殊参数的Java方法，由 Spring 框架调用。XML描述accountBean，Spring框架通过它访问 Account 对象，包括通知使用的拦截器 advisor 及其匹配模式，还有应用到模式的向前（before） 通知。</p>
<p>由于Spring AOP利用了IoC机制，因此比较JBoss AOP而言，在xml配置文件中提供了更加精细的配置。而构建、运行和配置 Spring AOP 方面的过程则与JBoss AOP基本相同，不过Spring AOP依赖的是Spring框架方便的、最小化的运行时配置，所以不需要独立的启动器。</p>
<p>3.1.2.3 语言机制的区别</p>
<p>&nbsp;&nbsp;&nbsp; 由于实现机制和语法风格的不同，三种AOP工具在语言机制上也有很大的不同，以下从四个方面来描述AspectJ、JBossAOP和Spring AOP之间的区别。</p>
<p>（1）pointcut匹配和复合：AspectJ和 JBoss AOP 提供了类似的类型模式支持。它们都允许签名方面的匹配，对于 Java 5 应用程序来说，这些匹配包括注释和泛型。AspectJ提供了一种简洁的引用多个类型的技术（例如 Account+ 表示帐户的所有子类型）。所有的工具都支持通配符匹配。Spring AOP 还提供了对正则表达式的支持。虽然这看起来可能是一个强大的优势，但还是要指出其他技术已经选择了放弃正则表达式，好让pointcut读起来不是太难，同时不会存在潜在的损害。pointcut复合操作符基本上都是相同的。Spring AOP 不提供&#8220;非&#8221;操作，这个操作通常与没有在 Spring AOP 连接点模型的容器（containment）连接点结合使用。</p>
<p>（2）advice形式：AspectJ 支持比其他技术更多的advice形式，而 JBoss AOP 只支持一种advice形式。每种通知形式都可以表达成 around advice，所以 JBoss 的技术是无限的，而且它确实提供了额外的简单性。不好的一面是它损失了简洁性。另外，强迫advice去遵守普通的 Java 规则（就像注释和 XML 风格做的那样），在一些情况下容易出问题，因为这些规则是为方法设计的。AspectJ 拥有把被通知方法的异常&#8220;软化&#8221;的能力，这很有用，但是不符合方法异常检测的标准语义。</p>
<p>（3）join point上下文：在 AspectJ中，通过指定和绑定pointcut参数访问动态连接点的状态，类似于在 Java 语言中声明方法参数的技术（请参阅图3.1）。这为连接点上下文提供了静态类型化的好处。JBoss AOP 和 Spring AOP 反射性地访问连接点的状态，这消除了在切入点表达式中参数绑定的复杂性，代价是参数静态类型化。Java 程序员习惯了方法参数静态类型化带来的好处，同时还可以从pointcut参数的静态类型化得到同样的好处。所以，在 JBoss AOP 最近的发行版本中，有提供静态类型化的&#8220;args&#8221;的计划。</p>
<p>（4）扩展性：aspect的扩展性支持库方面的部署，这样可以在日后为特定程序将这些库方面具体化。例如，一个方面库可以提供应用程序监视需要的全部逻辑和基础设施。但是，要采用某个特定项目的库，那么库使用的pointcut必须扩展成应用程序特定的join point。AspectJ 用抽象方面支持扩展性，抽象方面包含抽象的pointcut和具体的advice。扩展抽象方面的子方面必须具体化pointcut。JBoss AOP 使用了完全不同的技术，没有使用抽象切入点机制。扩展是通过生成aspect的子类、并在 XML 中或通过注释定义新的advice绑定而实现的。pointcut到advice的显式绑定为JBoss AOP提供了显著优势，从而可以很容易地把方面扩展到新系统，无需要生成子类。</p>
<p>3.2 Java平台下AOP主流工具研究</p>
<p>3.2.1 AsepctJ研究</p>
<p>AspectJ作为Java编程语言扩展的AOP工具，使得我们运用AOP技术能够像普通的Java编程那样，特殊之处，仅在于我们需要使用AspectJ提供的特殊语法。接下来，我将通过一些实例，介绍如何运用AspectJ实现AOP技术。</p>
<p>3.2.1.1 AspectJ语言特性</p>
<p>设定我们的开发项目中需要应用到日志记录，根据前面介绍的AOP知识，我们已经能够从这个需求中识别出横切关注点——日志记录。因此，我们需要定义关于&#8220;日志记录&#8221;的aspect：</p>
<p>public aspect AutoLog<br>{&nbsp;<br>&nbsp;&nbsp;&nbsp; pointcut publicMethods() : execution(public * org.apache.cactus..*(..));<br>&nbsp;&nbsp;&nbsp; pointcut logObjectCalls() : execution(* Logger.*(..));<br>&nbsp;&nbsp;&nbsp; pointcut loggableCalls() : publicMethods() &amp;&amp; ! logObjectCalls();&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp; before() : loggableCalls()<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Logger.entry(thisJoinPoint.getSignature().toString());<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; after() : loggableCalls()<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Logger.exit(thisJoinPoint.getSignature().toString());<br>&nbsp;&nbsp;&nbsp; }<br>}</p>
<p>如果仅仅熟悉Java编程，会发现有很多关键字是Java语言中不曾包含的，它们均是AspectJ提供的。</p>
<p>分析上述的代码，首先是aspect的声明，它类似于Java中的类声明，定义了一个aspect：AutoLog。在这个方面中分别包含了pointcut和advice。</p>
<p>pointcut共有三个：publicMethod、logObjectCalls和loggableCalls。publicMethod将选择org.apache.cactus包中的所有公共（public）方法的执行。所谓&#8220;选择&#8221;，就意味着它的join point为其选择的方法。当这些方法被调用时，就会执行pointcut的advice代码。而在pointcut中，execution 是一个原始的 Pointcut（就象 int 是一种原始的 Java 类型）。它选择与括号中定义的方法说明匹配的任何方法的执行。方法说明允许包含通配符。logObjectCalls的pointcut则选择Logger 类中的所有方法的执行。第三个pointcut比较特殊，它使用&amp;&amp; !合并了前两个 Pointcut，这意味着它选者了除Logger类中的公共方法以外， org.apache.cactus 中所有的公共方法。</p>
<p>advice在aspect中，被用来完成实际的日志纪录。advice有三种，分别为before、after和around。如上述代码中定义的advice：<br>before() : loggableCalls()<br>{<br>&nbsp;&nbsp;&nbsp; Logger.entry(thisJoinPoint.getSignature().toString());<br>}</p>
<p>该advice的定义表示的含义是，如果org.apache.cactus中所有的公共方法（Logger类的公共方法除外）被执行，则在这些方法执行之前，需要先执行该advice定义的逻辑。</p>
<p>3.2.1.2 AspectJ的高级语言特性</p>
<p>在本文第二部分介绍AOP技术时，提到了横切技术的分类。其中，静态横切技术能够扩展一个对象的结构。使用引入（Introduction），Aspect 可以向类中添加新的方法和变量、声明一个类实现一个接口或将检查异常转换为未检查异常（unchecked exception）。</p>
<p>3.2.1.2.1 向现有类添加变量和方法</p>
<p>假设您有一个表示持久存储的数据缓存的对象。为了测量数据的&#8220;更新程度&#8221;，您可能决定向该对象添加时间戳记字段，以便容易地检测对象是否与后备存储器同步。由于对象表示业务数据，根据AOP的知识，我们应该将这种机制性细节从对象中隔离。使用 AspectJ，可以用如下代码中所显示的语法来向现有的类添加时间戳记：</p>
<p>public aspect Timestamp<br>{<br>&nbsp;&nbsp;&nbsp; private long ValueObject.timestamp;<br>&nbsp;&nbsp;&nbsp; public long ValueObject.getTimestamp()<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return timestamp;<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; public void ValueObject.timestamp()<br>&nbsp;&nbsp;&nbsp; {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.timestamp = System.currentTimeMillis();<br>&nbsp;&nbsp;&nbsp; }<br>}</p>
<p>通过introduction，我们就非常方便的为ValueObject类型添加了timestamp的变量和相关方法。除了必须限定在哪个类上声明引入的方法和成员变量以外，声明引入的方法和成员变量几乎与声明常规类成员相同。</p>
<p>3.2.1.2.2实现多继承功能</p>
<p>利用introduction，AspectJ允许向接口和类添加成员，也突破了Java语言只能单继承的限制，允许程序按C++方式那样实现多继承。如果您希望上述的aspect Timestamp能够泛化 （generalize），以便能够对各种对象重用时间戳记代码，可以定义一个称为 TimestampedObject 的接口，并使用引入（Introduction）来将相同成员和变量添加到接口而不是添加到具体类中，如下所示:<br>public interface TimestampedObject<br>{<br>&nbsp;&nbsp;&nbsp; long getTimestamp();<br>&nbsp;&nbsp;&nbsp; void timestamp();<br>}<br>public aspect Timestamp<br>{<br>&nbsp;&nbsp;&nbsp; private long TimestampedObject.timestamp;<br>&nbsp;&nbsp;&nbsp; public long TimestampedObject.getTimestamp()<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return timestamp;<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; public void TimestampedObject.timestamp()<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.timestamp = System.currentTimeMillis();<br>&nbsp;&nbsp;&nbsp; }<br>}</p>
<p>Timestamp方面由于在TimestampedObject接口中引入（introduction）了方法的实现，使得TimestampedObject接口改变其本质，成为了一个特殊的类类型。特殊之处就在于一个已经继承了一个类的类类型，通过AspectJ的语法，仍然可以再次继承TimestampedObject，这就间接地实现了类的多继承。而这个特殊的AspectJ语法就是declare parents语法。declare parents和其它AspectJ 类型表达一样，可以同时应用于多个类型：<br>declare parents: ValueObject || BigValueObject implements TimestampedObject;</p>
<p>3.2.1.3 编译器及工具支持</p>
<p>&nbsp;&nbsp;&nbsp; 要让aspect能够正常工作，必须将aspect加入到它们要修改的代码中去。这项工作由AspectJ提供的ajc编译器完成。ajc 编译器用来编译类和 Aspect 代码。ajc 既可以作为编译器也可以作为预编译器操作，生成有效的 .class 或 .java 文件，可以在任何标准 Java 环境（添加一个小的运行时 JAR）中编译和运行这些文件。</p>
<p>要使用 AspectJ 进行编译，将需要显式地指定希望在给定编译中包含的源文件（Aspect 和类），ajc不象javac那样简单地为相关导入模块搜索类路径。之所以这样做，是因为标准 Java 应用程序中的每个类都是相对分离的组件。为了正确操作，一个类只要求其直接引用的类的存在。Aspect 表示跨越多个类的行为的聚集。因此，需要将 AOP 程序作为一个单元来编译，而不能每次编译一个类。</p>
<p>AspectJ 当前版本的一个重要限制是其编译器只能将aspect加入到它拥有源代码的代码中。也就是说，不能使用ajc将Advice添加到预编译类中。AspectJ 团队认为这个限制只是暂时的，AspectJ 网站承诺未来的版本（正式版 2.0）将允许字节码的修改。</p>
<p>AspectJ发行版包含了几种开发工具。这预示着 AspectJ 将有美好的前景，因为它表明了作者对这一部分的一个重要承诺，使 AspectJ 对于开发人员将是友好的。对于面向 Aspect 的系统工具支持尤其重要，因为程序模块可能受到它们所未知的模块所影响。</p>
<p>随 AspectJ 一起发布的一个最重要的工具是图形结构浏览器，它展示了 Aspect 如何与其它系统组件交互。这个结构浏览器既可以作为流行的 IDE 的插件，也可以作为独立的工具。图3.4显示了先前讨论的日志记录示例的视图。</p>
<p align=center><img height=451 alt=aop3.4.jpg src="http://wayfarer.cnblogs.com/images/cnblogs_com/wayfarer/aop/aop3.4.jpg" width=593 border=0><br>图3.4 AspectJ提供的&#8220;结构浏览器&#8221;工具</p>
<p>除了结构浏览器和核心编译器之外，您还可以从 AspectJ 网站下载一个 Aspect 支持的调试器、一个javadoc工具、一个Ant任务以及一个Emacs 插件。</p>
<p>3.2.2 JBoss AOP研究</p>
<p>JBoss AOP关于AOP的实现与AspectJ是两种完全不同的风格。由于Java利用元数据来存储有关类型、方法、字段的相关信息，因此，可以通过Java提供的反射功能获得模块相关的元数据，对方法进行拦截，并将被拦截的方法与aspect逻辑进行关联。</p>
<p>3.2.2.1 拦截器（Interceptor）</p>
<p>在JBoss AOP中，是用拦截器来实现advice的。可以自定义拦截器，拦截方法调用、构造函数调用以及对字段的访问，但JBoss要求这些自定义的拦截器，必须实现org.jboss.aop.Interceptor接口：</p>
<p>public interface Interceptor<br>{<br>&nbsp;&nbsp;&nbsp; public String getName();<br>&nbsp;&nbsp;&nbsp; public InvocationResponse invoke(Invocation invocation) throws Throwable;<br>}</p>
<p>在JBoss　AOP中，被拦截的字段、构造器和方法均被转化为通用的invoke方法调用。方法的参数接收一个Invocation对象，而方法的返回值、字段的存取以及构造函数则被填入一个InvocationResponse对象。Invocation对象同时还驱动拦截链。下面我们自定义一个拦截器，它能够拦截构造函数和方法的调用，并将跟踪信息打印到控制台上：<br>import org.jboss.aop.*;<br>import java.lang.reflect.*;</p>
<p>public class TracingInterceptor implements Interceptor<br>{<br>&nbsp;&nbsp;&nbsp; public String getName()<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return TracingInterceptor;<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; public InvocationResponse invoke(Invocation invocation) throws Throwable<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String message = null;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (invocation.getType() == InvocationType.METHOD)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Method method = MethodInvocation.getMethod(invocation);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; message = method: + method.getName();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (invocation.getType() == InvocationType.CONSTRUCTOR)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Constructor c = ConstructorInvocation.getConstructor(invocation);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; message = constructor: + c.toString();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 不对字段作处理，太繁琐；<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return invocation.invokeNext();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(Entering + message);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 继续。调用真正的方法或者构造函数<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; InvocationResponse rsp = invocation.invokeNext();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(Leaving + message);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return rsp;<br>&nbsp;&nbsp;&nbsp; }<br>}</p>
<p>在自定义的TracingInterceptor类中，invoke()方法对invocation的类型作判断，以根据方法、构造函数和字段类型，分别作出不同的操作。而其中，invocation.invokeNext()则表示通过一个拦截链获得下一个invocation。</p>
<p>定义的拦截必须在xml文件配置，使其绑定到具体的类。这个定义即为AOP中的切入点pointcut。例如具体的类为BusinessObject，则该pointcut在xml中的定义如下：<br>&lt;?xml version=&#8221;1.0&#8243; encoding=&#8221;UTF-8&#8243;&gt;<br>&lt;aop&gt;<br>&nbsp;&nbsp;&nbsp; &lt;interceptor-pointcut class=&#8221;BusinessObject&#8221;&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;interceptors&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;interceptor class=&#8221;TracingInterceptor&#8221; /&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/interceptors&gt;<br>&nbsp;&nbsp;&nbsp; &lt;/interceptor-pointcut&gt;<br>&lt;/aop&gt;</p>
<p>上面的pointcut绑定TracingInterceptor到一个叫做BusinessObject的类。如果要将该Interceptor绑定到多个类，还可以利用正则表达式。例如，如果你想绑定由JVM载入的类，类表达式将变为 .*。如果你仅仅想跟踪一个特定的包，那么表达式将是bruce.zhang.mypackge.*。</p>
<p>当JBoss AOP独立运行时，任何符合 META-INF/jboss-aop.xml模式的XML文件将被JBoss AOP 运行期程序载入。如果相关的路径被包含在任何JAR或你的CLASSPATH目录中，该XML文件将在启动时，由JBoss AOP 运行期程序载入。</p>
<p>JBoss AOP还提供了过滤功能，可以通过在xml文件中配置过滤的标志，使一些特定的方法（包括字段的访问）被过滤，从而不再执行Interceptor的相关逻辑。例如，我们要过滤BusinessObject类的所有get()和set()方法，以及main()方法，则可以修改上述的xml文件：<br>&lt;?xml version=&#8221;1.0&#8243; encoding=&#8221;UTF-8&#8243;&gt;<br>&lt;aop&gt;<br>&nbsp;&nbsp;&nbsp; &lt;class-metadata group=&#8221;tracing&#8221; class=&#8221; BusinessObject &#8220;&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;method name=&#8221;(get.*)|(set.*)&#8221;&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;filter&gt;true&lt;/filter&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/method&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;method name=&#8221;main&#8221;&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;filter&gt;true&lt;/filter&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/method&gt;<br>&nbsp;&nbsp;&nbsp; &lt;/class-metadata&gt;<br>&lt;/aop&gt;</p>
<p>相应的，Interceptor代码也应作相关的修改，使其能够识别配置文件中的filter属性：<br>public class TracingInterceptor implements Interceptor<br>{<br>&nbsp;&nbsp;&nbsp; &#8230;&#8230;//getName()方法略；<br>&nbsp;&nbsp;&nbsp; public InvocationResponse invoke(Invocation invocation) throws Throwable<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String filter=(String)invocation.getMetaData(tracing, filter);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (filter != null &amp;&amp; filter.equals(true))<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return invocation.invokeNext();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#8230;&#8230;//后面的代码略；<br>&nbsp;&nbsp;&nbsp; }<br>}</p>
<p>3.2.2.2 引入（Introduction）</p>
<p>JBoss AOP同样提供introduction功能，通过它，就可以为现有的类引入第三方接口或类的API了。例如，我们可以为具体的类如BusinessObject提供Tracing的开关，使得BusinessObject对象能够根据具体的情况打开或关闭aspect的Tracing功能。为实现该功能，可以定义一个Tracing接口：<br>public interface Tracing<br>{<br>&nbsp;&nbsp;&nbsp; void enableTracing();<br>&nbsp;&nbsp;&nbsp; void disableTracing();<br>}</p>
<p>接下来需要定义一个混合类，它实现了接口Tracing。当BusinessObject类被实例化时，该混合类的实例就会被绑定到BusinessObject上。实现方法如下：<br>import org.jboss.aop.Advised;</p>
<p>public class TracingMixin implements Tracing<br>{<br>&nbsp;&nbsp;&nbsp; Advised advised;</p>
<p>&nbsp;&nbsp;&nbsp; Public TracingMixin(Object obj)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.advised = (Advised)obj;<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; public void enableTracing()<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; advised._getInstanceAdvisor().getMetaData().addMetaData(&#8221;tracing&#8221;, &#8220;filter&#8221;, true);<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; public void disableTracing()<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; advised._getInstanceAdvisor().getMetaData().addMetaData(&#8221;tracing&#8221;, &#8220;filter&#8221;, false);<br>&nbsp;&nbsp;&nbsp; }<br>}</p>
<p>enableTracing()方法将filter属性绑定到对象实例。disableTracing()方法作同样的事，但是将filter属性设置为false。</p>
<p>定义了Tracing接口和实现了该接口的混合类后，就可以在xml文件中定义一个pointcut，强制BusinessObject类实现Tracing接口：<br>&lt;?xml version=&#8221;1.0&#8243; encoding=&#8221;UTF-8&#8243;&gt;<br>&lt;aop&gt;<br>&nbsp;&nbsp;&nbsp; &lt;introduction-pointcut class=&#8221;BusinessObject&#8221;&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;mixin&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;interfaces&gt;Tracing&lt;/interfaces&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;class&gt;TracingMixin&lt;/class&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;construction&gt;new TracingMixin(this)&lt;/construction&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/mixin&gt;<br>&nbsp;&nbsp;&nbsp; &lt;/introduction-pointcut&gt;<br>&lt;/aop&gt;</p>
<p>注意xml文件中的标签，它代表的含义是当BusinessObject对象被实例化时，将执行该标签内的代码。以本例而言，当创建BusinessObject对象时，一个TracingMixin类的实例将被创建。任何单行的Java代码都可以放到标签中。</p>
<p>通过&#8220;引入（introduction）&#8221;功能，在处理BusinessObject对象时，就可以视其为Tracing接口类型而进行操作了，如下的示例：</p>
<p>public class BusinessObject<br>{<br>&nbsp;&nbsp;&nbsp; public BusinessObject () {}<br>&nbsp;&nbsp;&nbsp; public void helloWorld() { System.out.println(Hello World!); }</p>
<p>&nbsp;&nbsp;&nbsp; public static void main(String[] args)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BusinessObject bo = new BusinessObject ();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Tracing trace = (Tracing)this;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bo.helloWorld();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(&#8221;Turn off tracing.&#8221;);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; trace.disableTracing();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bo.helloWorld();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(&#8221;Turn on tracing.&#8221;);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; trace.enableTracing();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bo.helloWorld();<br>&nbsp;&nbsp;&nbsp; }<br>}</p>
<p>注意如下代码：<br>Tracing trace = (Tracing)this;</p>
<p>此时this代表的即为BusinessObject，从Java代码的角度来看，由于BusinessObject并没有实现Tracing接口，因此这行代码所示的显式转换为Tracing类型是不成功的。但通过&#8220;引入&#8221;功能，使得BusinessObject通过混合类，实现了Tracing接口，从而使得如上的代码能够顺利执行。隐含的意义就是，我们没有修改BusinessObject的定义，而是通过AOP技术，为BusinessObject扩展实现了第三方提供的接口Tracing。</p>
<p>3.2.3 Spring AOP研究</p>
<p>Spring AOP使用纯Java实现，不需要特别的编译过程，也不需要控制类装载层次。与JBoss AOP相同，它仍然利用了拦截器完成对方法的拦截。然而，Spring AOP实现AOP的主要技术却主要来自于AOP联盟，如拦截器应实现org.aopalliance.intercept.MethodInterceptor 接口，而所有advice必须实现org.aopalliance.aop.Advice标签接口。此外，Spring实现AOP的目标也不同于其他大部分AOP框架，它的目标不是提供及其完善的AOP实现，而是提供一个和Spring IoC紧密整合的AOP实现，帮助解决企业应用 中的常见问题。因此，Spring AOP的功能通常是和Spring IoC容器联合使用的。AOP Advice是用普通的bean定义语法来定义的，Advice和pointcut本身由Spring IoC 管理。这是一个重要的其他AOP实现的区别。</p>
<p>3.2.3.1 切入点（pointcut）</p>
<p>Spring的切入点模型能够使pointcut独立于advice类型被重用。同样的pointcut有可能接受不同的advice。将Pointcut接口分成两个部分有利于重用类和方法的匹配部分，并且组合细粒度的操作（如和另一个方法匹配器执行一个&#8220;并&#8221;的操作）。</p>
<p>在Spring的切入点中，org.springframework.aop.Pointcut接口是重要的接口，它用来指定通知到特定的类和方法目标。完整的接口定义如下:<br>public interface Pointcut<br>{<br>&nbsp;&nbsp;&nbsp; ClassFilter getClassFilter();<br>&nbsp;&nbsp;&nbsp; MethodMatcher getMethodMatcher();<br>}</p>
<p>ClassFilte类型也是一个接口，该接口被用来将切入点限制到一个给定的目标类的集合。 如果matches()永远返回true，所有的目标类都将被匹配。<br>public interface ClassFilter<br>{<br>&nbsp;&nbsp;&nbsp; boolean matches(Class clazz);<br>}</p>
<p>MethodMatcher接口通常更加重要。完整的接口定义如下：<br>public interface MethodMatcher<br>{<br>&nbsp;&nbsp;&nbsp; boolean matches(Method m, Class targetClass);<br>&nbsp;&nbsp;&nbsp; boolean matches(Method m, Class targetClass, Object[] args);<br>&nbsp;&nbsp;&nbsp; boolean isRuntime();<br>}</p>
<p>matches(Method, Class) 方法被用来测试这个切入点是否匹配目标类的给定方法。这个测试可以在AOP代理创建的时候执行，避免在所有方法调用时都需要进行 测试。如果2个参数的matches()方法对某个方法返回true，并且MethodMatcher的isRuntime()也返回true，那么3个参数的matches()方法将在每次方法调用的时候被调用。这使切入点能够在目标advice被执行之前立即查看传递给方法调用的参数。由于大部分MethodMatcher都是静态的，意味着isRuntime()方法会返回false。此种情况下，3个参数的matches()方法永远不会被调用。</p>
<p>Spring AOP提供了几个实用的切入点实现，其中较为常用的是正则表达式切入点：org.springframework.aop.support.RegexpMethodPointcut，它使用Perl 5的正则表达式的语法。使用这个类你可以定义一个模式的列表。如果任何一个匹配，那个切入点将被计算成 true。用法如下：<br>&lt;bean id=&#8221;settersAndAbsquatulatePointcut&#8221;<br>&nbsp;&nbsp;&nbsp; class=&#8221;org.springframework.aop.support.RegexpMethodPointcut&#8221;&gt;<br>&nbsp;&nbsp;&nbsp; &lt;property name=&#8221;patterns&#8221;&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;list&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;value&gt;.*get.*&lt;/value&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;value&gt;.*absquatulate&lt;/value&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/list&gt;<br>&nbsp;&nbsp;&nbsp; &lt;/property&gt;<br>&lt;/bean&gt;</p>
<p>不过，更多情况下是直接使用RegexpMethodPointcut一个实用子类： RegexpMethodPointcutAdvisor。它允许我们同时引用一个advice（在Spring AOP中，advice可以是拦截器，也可以是before advice，throws advice等)。这就简化了bean的装配，因为一个bean可以同时当作pointcut和advice，如下所示：<br>&lt;bean id=&#8221;myPointcutAdvisor&#8221; class=&#8221;org.springframework.aop.support.RegexpMethodPointcutAdvisor&#8221;&gt;<br>&nbsp;&nbsp;&nbsp; &lt;property name=&#8221;advice&#8221;&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;ref local=&#8221;MyInterceptor&#8221; /&gt;<br>&nbsp;&nbsp;&nbsp; &lt;/property&gt;<br>&nbsp;&nbsp;&nbsp; &lt;property name=&#8221;patterns&#8221;&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;list&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;value&gt;.*save.*&lt;/value&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;value&gt;.*do.*&lt;/value&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/list&gt;<br>&nbsp;&nbsp;&nbsp; &lt;/property&gt;<br>&lt;/bean&gt;</p>
<p>注意配置文件中的myPointcutAdvisor，在Spring AOP中，一个advisor就是一个aspect完整的模块化表示。通过advisor，可以将pointcut和advice（在此处即为MyInterceptor）绑定起来。</p>
<p>3.2.3.2 通知（advice）</p>
<p>Spring AOP的advice可以跨越多个被advice对象共享，或者每个被advice对象有自己的advice。要实现advice，最简单的做法就是定义一个拦截器（Interceptor）。它采用了AOP联盟（AOP Alliance）的通用AOP接口（接口定义为aopalliance.jar）。要实现advice，需要实现aopalliance.jar中定义的MethodInterceptor接口。</p>
<p>例如，我们定义了一个业务对象接口BusinessObject及其实现类BusinessObjectImpl，该业务对象能够存储数据，其定义如下：<br>public interface BusinessObject<br>{<br>&nbsp;&nbsp;&nbsp; public void save();<br>}<br>public class BusinessObjectImpl implements BusinessObject<br>{<br>&nbsp;&nbsp;&nbsp; public void save()<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(&#8221;saving domain object&#8230;&#8230;&#8221;);<br>&nbsp;&nbsp;&nbsp; }<br>}</p>
<p>现在需要为业务对象BusinessObject的Save()方法，提供Lock机制。根据Spring AOP的实现方式，我们可以定义一个LockInterceptor来实现MethodInterceptor接口：<br>import org.aopalliance.intercept.MethodInterceptor;<br>import org.aopalliance.intercept.MethodInvocation;</p>
<p>public class LockInterceptor implements MethodInterceptor<br>{<br>&nbsp;&nbsp;&nbsp; public Object invoke(MethodInvocation invocation) throws Throwable<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // TODO Auto-generated method stub<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lock();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Object ret= invocation.proceed();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unlock();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return ret;<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; private void lock()<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(&#8221;lock domain object&#8230;&#8221;);<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; private void unlock()<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(&#8221;unlock domain object&#8230;&#8221;);<br>&nbsp;&nbsp;&nbsp; }<br>}</p>
<p>为将interceptor与具体的advice绑定起来，需要在配置文件中配置bean：<br>&lt;bean id=&#8221;MyInterceptor&#8221; class=&#8221;test.aop.spring.LockInterceptor&#8221;/&gt;</p>
<p>3.2.3.3 AOP代理与IoC容器</p>
<p>由于Spring中提供了IoC容器（例如BeanFactory），因此我们可以通过Ioc机制，利用ProxyFactoryBean来创建AOP代理。ProxyFactoryBean和其他Spring的 FactoryBean实现一样，引入一个间接的层次。如果你定义一个名字为foo的ProxyFactoryBean，引用foo的对象所看到的不是ProxyFactoryBean实例本身，而是由实现ProxyFactoryBean的类的 getObject()方法所创建的对象。这个方法将创建一个包装了目标对象 的AOP代理。</p>
<p>AOP代理利用的是Java的动态代理技术，通过它就可以加载并执行AOP组件。同时，还需要通过IoC的方式将advice注入到接口以及其实现类。以前面的业务对象BusinessObject为例，在xml配置文件中的配置如下：<br>&lt;bean id=&#8221;myAOPProxy&#8221; class=&#8221;org.springframework.aop.framework.ProxyFactoryBean&#8221;&gt;<br>&nbsp;&nbsp;&nbsp; &lt;property name=&#8221;proxyInterfaces&#8221;&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&lt;value&gt;test.aop.spring.BusinessObject&lt;/value&gt;<br>&nbsp;&nbsp;&nbsp; &lt;/property&gt;<br>&nbsp;&nbsp;&nbsp; &lt;property name=&#8221;target&#8221;&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&lt;ref local=&#8221;impl&#8221; /&gt;<br>&nbsp;&nbsp;&nbsp; &lt;/property&gt;<br>&nbsp;&nbsp;&nbsp; &lt;property name=&#8221;interceptorNames&#8221;&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&lt;value&gt;myPointcutAdvisor&lt;/value&gt;<br>&nbsp;&nbsp;&nbsp; &lt;/property&gt;<br>&lt;/bean&gt;<br>&lt;bean id=&#8221;impl&#8221; class=&#8221;test.aop.spring.BusinessObjectImpl&#8221;/&gt;</p>
<p>通过上述对pointcut、advice、advisor和AOP代理的配置，我们就可以轻易地在Spring中实现AOP，例如：<br>import org.springframework.context.ApplicationContext;<br>import org.springframework.context.support.FileSystemXmlApplicationContext;</p>
<p>public class App<br>{<br>&nbsp;&nbsp;&nbsp; private BusinessObject bo = null;<br>&nbsp;&nbsp;&nbsp; public static void main(String[] args)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ApplicationContext ctx=new FileSystemXmlApplicationContext(&#8221;Bean.xml&#8221;);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bo= (BusinessObject) ctx.getBean(&#8221;myAOPProxy&#8221;);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bo.save();<br>&nbsp;&nbsp;&nbsp; }<br>}</p>
<p>首先，通过AOP代理获得BusinessObject对象。当调用BusinessObject对象的save()方法时，拦截器LockInterceptor根据RegexpMethodPointcutAdvisor配置的pointcut和advice之间的关系，判定该方法的调用为join point，从而拦截该方法调用，并注入advice的执行逻辑，即lock()和unlock()，最终实现了AOP。</p>
<p>3.2.3.4 引入（introduction）</p>
<p>在Spring AOP中，将introduction当作advice来处理。与一般的advice一样，introduction advice相当于一种特殊类型的拦截通知，需要实现IntroductionAdvisor和IntroductionInterceptor接口，而IntroductionInterceptor接口继承自MethodInterceptor：<br>public interface IntroductionInterceptor extends MethodInterceptor<br>{<br>&nbsp;&nbsp;&nbsp; boolean implementsInterface(Class intf);<br>}</p>
<p>Introduction通知不能被用于任何pointcut，因为它只能作用于类层次上，而不是方法。我们可以只用InterceptionIntroductionAdvisor来实现导入通知，它有下面的方法：<br>public interface InterceptionIntroductionAdvisor extends InterceptionAdvisor<br>{<br>&nbsp;&nbsp;&nbsp; ClassFilter getClassFilter();<br>&nbsp;&nbsp;&nbsp; IntroductionInterceptor getIntroductionInterceptor();<br>&nbsp;&nbsp;&nbsp; Class[] getInterfaces();<br>}</p>
<p>接下来，我以JBoss AOP一节中的例子来说明introduction在Spring AOP中的应用。我们的目标仍然是为一个已有的业务对象引入第三方接口Tracing：<br>public interface Tracing<br>{<br>&nbsp;&nbsp;&nbsp; void enableTracing();<br>&nbsp;&nbsp;&nbsp; void disableTracing();<br>&nbsp;&nbsp;&nbsp; boolean enabled();<br>}</p>
<p>首先，我们需要一个做大量转化的IntroductionInterceptor。在这里，我们继承 org.springframework.aop.support.DelegatingIntroductionInterceptor 实现类。当然我们可以直接实现IntroductionInterceptor接口，但是大多数情况下 DelegatingIntroductionInterceptor是最合适的。</p>
<p>DelegatingIntroductionInterceptor的设计是将introduction委托到真正实现introduction接口的接口，隐藏完成这些工作的拦截器。委托可以使用构造方法参数设置到任何对象中；默认的委托就是自己（当无参数的构造方法被使用时）。这样在下面的例子里，委托是DelegatingIntroductionInterceptor的子类 TracingMixin。给定一个委托（默认是自身）的 DelegatingIntroductionInterceptor实例寻找被这个委托（而不是IntroductionInterceptor）实现的所有接口，并支持它们中任何一个导入。子类如TracingMixi也可能调用suppressInterflace(Class intf) 方法来隐藏不应暴露的接口。然而，不管IntroductionInterceptor 准备支持多少接口，IntroductionAdvisor将控制哪个接口将被实际暴露。一个导入的接口将隐藏目标的同一个接口的所有实现。</p>
<p>这样，TracingMixin继承DelegatingIntroductionInterceptor并自己实现接口Tracing。父类自动选择支持introduction的Tracing，所以我们不需要指定它。用这种方法我们可以导入任意数量的接口。<br>public class TracingMixin extends DelegatingIntroductionInterceptor implements Tracing<br>{<br>&nbsp;&nbsp;&nbsp; private boolean enabled;<br>&nbsp;&nbsp;&nbsp; public void enableTracing ()<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.enabled = true;<br>&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp; public void disableTracing ()<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this. enabled = false;<br>&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp; public boolean enabled()<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return this.enabled;<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; public Object invoke(MethodInvocation invocation) throws Throwable<br>&nbsp;&nbsp;&nbsp; {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return super.invoke(invocation);<br>&nbsp;&nbsp;&nbsp; }<br>}</p>
<p>通常不要需要改写invoke()方法：实现DelegatingIntroductionInterceptor就足够了，如果是引入的方法，DelegatingIntroductionInterceptor实现会调用委托方法， 否则继续沿着连接点处理。</p>
<p>所需的introduction advisor是很简单的。只需保存一个独立的TracingMixin实例，并指定导入的接口，在这里就是Tracing。此时，TracingMixin没有相关配置，所以我们简单地使用new来创建它。</p>
<p>public class TracingMixinAdvisor extends DefaultIntroductionAdvisor<br>{<br>&nbsp;&nbsp;&nbsp; public TracingMixinAdvisor() {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; super(new TracingMixin(),Tracing.class);<br>&nbsp;&nbsp;&nbsp; }<br>}</p>
<p>我们可以非常简单地使用这个advisor。它不需要任何配置。（但是，有一点是必要的：就是不可能在没有IntroductionAdvisor 的情况下使用IntroductionInterceptor。） 和引入一样，通常 advisor必须是针对每个实例的，并且是有状态的。我们会有不同的TracingMixinAdvisor。每个被通知对象，会有不同的TracingMixin。advisor组成了被通知对象的状态的一部分。</p>
<p>在Spring中，Spring AOP的核心API已经基本稳定了。和Spring的其它部分一样， AOP框架是模块化的，在保留基础设计的同时提供扩展。在Spring 1.1到1.2阶段有很多地方可能会有所提高，但是这些地方也保留了向后兼容性。它们是：</p>
<p>（一）性能的提高：AOP代理的创建由工厂通过策略接口处理。因此能够支持额外的AOP 代理类型而不影响用户代码或核心实现。<br>（二）更具表达力的pointcut：Spring目前提供了一个具有表达力的切入点接口，同时添加了更多的切入点实现。Spring正在考虑提供一个简单但具有强大表达式语言的实现</p>
<br>转贴来自：<a href="http://www.cnblogs.com/wayne-ivan/archive/2006/09/07/496904.html">http://www.cnblogs.com/wayne-ivan/archive/2006/09/07/496904.html</a>
<img src ="http://www.blogjava.net/yesjoy/aggbug/120858.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yesjoy/" target="_blank">★yesjoy★</a> 2007-05-30 11:37 <a href="http://www.blogjava.net/yesjoy/articles/120858.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>AOP技术研究——AOP技术基础 </title><link>http://www.blogjava.net/yesjoy/articles/120857.html</link><dc:creator>★yesjoy★</dc:creator><author>★yesjoy★</author><pubDate>Wed, 30 May 2007 03:36:00 GMT</pubDate><guid>http://www.blogjava.net/yesjoy/articles/120857.html</guid><wfw:comment>http://www.blogjava.net/yesjoy/comments/120857.html</wfw:comment><comments>http://www.blogjava.net/yesjoy/articles/120857.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yesjoy/comments/commentRss/120857.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yesjoy/services/trackbacks/120857.html</trackback:ping><description><![CDATA[<p>2.1 AOP技术起源</p>
<p>AOP技术的诞生并不算晚，早在1990年开始，来自Xerox Palo Alto Research Lab（即PARC）的研究人员就对面向对象思想的局限性进行了分析。他们研究出了一种新的编程思想，借助这一思想或许可以通过减少代码重复模块从而帮助开发人员提高工作效率。随着研究的逐渐深入，AOP也逐渐发展成一套完整的程序设计思想，各种应用AOP的技术也应运而生。</p>
<p>AOP技术在Java平台下是最先得到应用的。就在PARC对于面向方面编程进行研究的同时，美国Northeastern University的博士生Cristina Lopes和其同事也开始了类似的思考。最终，美国国防先进技术研究计划署（Defense Advanced Research Projects Agency即DARPA）注意到了这项工作，并提供了科研经费，鼓励将二者的工作成果结合起来。他们通过定义一套Java语言的扩展系统，使开发者可以方便的进行面向方面的开发，这套扩展系统被称为AspectJ。之后，AspectJ在2002年被转让给Eclipse Foundation，从而成为在开源社区中AOP技术的先锋，也是目前最为流行的AOP工具。</p>
<p>AspectWerkz则是基于Java的动态的、轻量级AOP框架。AspectWerkz仍然是开源社区中的产品，由BEA System提供赞助，开发者则是BEA的两名员工Jonas Bon&#233;r和Alexandre Vasseur。最近版本是AspectWerkz 2.0。2005年1月，AspectJ和AspectWerkz达成协议，同意将二者的成果综合到一起，取其精华创建一个单一的工具。他们合作的第一个发布版本为AspectJ 5，它扩展了AspectJ语言，以支持基于Annotation开发风格而又支持类似AspectJ代码风格。AspectJ 5也为Java 5的语言特性提供完全的AOP支持。</p>
<p>在Java阵营中，商用软件制造商JBoss在其2004年推出的JBoss 4.0中，引入了AOP框架和组件。在JBoss 4.0中，用户可以在JBoss应用服务器外部单独使用JBoss AOP，该版本为JBoss AOP 1.0，是在2004年10月发布的。在2005年，JBoss AOP框架又发布了1.3.0版本，新版本对加载期织入（Weev）和切点（point cut）匹配的性能做了很大的优化，使应用程序的启动时间大大缩短。</p>
<p>作为轻型的Framework，Spring在开发轻量级的J2EE时，应用是非常广泛的。它通过IoC模式（Inversion of Control，控制反转模式）来实现AOP，通常被称为Spring AOP。在2004年，被作为Spring框架的扩展而发布，目前版本已更新到1.1.3。Spring AOP作为一种非侵略性的，轻型的AOP框架，开发者无需使用预编译器或其他的元标签，在Java程序中应用AOP。目前，AOP的功能完全集成到了Spring事务管理、日志和其他各种特性的上下文中。</p>
<p>在.Net的阵营中，AOP技术的应用远不如Java阵营对AOP的关注。2005年1月，微软发布的Enterprise Library提供了7种不同的&#8220;应用程序块（application blocks）&#8221;。有个别专家认为，这些组件可以被认为是方面。但该观点并未得到一致的认同。事实上，在.Net平台下，推动AOP技术发展的原动力并非微软，而是开源社区。虽然，微软的技术专家们亦然听到了在.Net Framework中增加AOP技术的群众呼声，但作为如此巨大的软件公司，要让它灵活地转变战略方向，显然是不太现实的。正因为此，才赐予了开源社区在AOP技术的研究与探索上一个巨大的发展空间。</p>
<p>与Java阵营中的AOP技术不同，目前在.Net平台下的各种AOP工具，基本上还停留在实验室阶段。但一些在技术上领先且逐渐成熟的AOP产品，也在开源社区中渐露峥嵘。这其中主要包括Aspect#，AspectDNG，Eos AOP等。</p>
<p>Aspect#是基于Castle动态代理技术来实现的。Castle源于Apache Avalon项目，其目的在于实现一个轻量级的IoC容器。Aspect#于2005年6月被收录为Castle的其中一个子项目。它是针对CLI（.Net和Mono）实现的AOP框架，利用了反射、代理等机制。目前的Aspect#版本为2.1.1。</p>
<p>AspectDNG目前的版本为0.7，仍然处于beta版的阶段。它的实现技术是基于rail的静态织入。Rail属于IL级别下的代码织入，它自定义的一套xml格式的ILML语言，能够将原有的程序集拆散成ILML格式，以便于对静态程序集进行修改和扩展，从而达到静态织入的目的。因为AspectDNG是属于IL级别下的代码织入，因此在.Net平台下，并不受具体的编程语言限制。</p>
<p>Eos AOP与AspectDNG一样，仍然采用静态织入的方式，但从语法定义上，它更近似于AspectJ关于AOP的实现。它扩展了C#语法，引入了aspect、introduce、before、after等关键字，并且提供了专用的Eos编译器。Eos项目是于2004年9月开始启动，2005年6月推出的0.3.3版本为最新版本，主要的开发人员为Hridesh Rajan和Kevin Sullivan。前者为Virginia大学计算机系的研究生，Eos项目最初是由Hridesh Rajan提出的；而后者则为该计算机系的副教授（Associate Professor）。所以自Eos诞生之初，就带有浓厚的学院派特色。</p>
<p>从AOP技术的整体发展来看，高性能、稳定、可扩展、易用的AOP框架是其趋势与目标。从上述对各种AOP技术的分析来看，AOP技术无疑是具有共同特点的，而各种实现技术就是围绕着这些共性深入与延伸。接下来，我将概要地介绍AOP的本质，以及它的技术要素。</p>
<p>2.2 AOP技术本质</p>
<p>2.2.1 技术概览</p>
<p>AOP（Aspect-Oriented Programming，面向方面编程），可以说是OOP（Object-Oriented Programing，面向对象编程）的补充和完善。OOP引入封装、继承和多态性等概念来建立一种对象层次结构，用以模拟公共行为的一个集合。当我们需要为分散的对象引入公共行为的时候，OOP则显得无能为力。也就是说，OOP允许你定义从上到下的关系，但并不适合定义从左到右的关系。例如日志功能。日志代码往往水平地散布在所有对象层次中，而与它所散布到的对象的核心功能毫无关系。对于其他类型的代码，如安全性、异常处理和透明的持续性也是如此。这种散布在各处的无关的代码被称为横切（cross-cutting）代码，在OOP设计中，它导致了大量代码的重复，而不利于各个模块的重用。</p>
<p>而AOP技术则恰恰相反，它利用一种称为&#8220;横切&#8221;的技术，剖解开封装的对象内部，并将那些影响了多个类的公共行为封装到一个可重用模块，并将其名为&#8220;Aspect&#8221;，即方面。所谓&#8220;方面&#8221;，简单地说，就是将那些与业务无关，却为业务模块所共同调用的逻辑或责任封装起来，便于减少系统的重复代码，降低模块间的耦合度，并有利于未来的可操作性和可维护性。AOP代表的是一个横向的关系，如果说&#8220;对象&#8221;是一个空心的圆柱体，其中封装的是对象的属性和行为；那么面向方面编程的方法，就仿佛一把利刃，将这些空心圆柱体剖开，以获得其内部的消息。而剖开的切面，也就是所谓的&#8220;方面&#8221;了。然后它又以巧夺天功的妙手将这些剖开的切面复原，不留痕迹。</p>
<p>使用&#8220;横切&#8221;技术，AOP把软件系统分为两个部分：核心关注点和横切关注点。业务处理的主要流程是核心关注点，与之关系不大的部分是横切关注点。横切关注点的一个特点是，他们经常发生在核心关注点的多处，而各处都基本相似。比如权限认证、日志、事务处理。Aop 的作用在于分离系统中的各种关注点，将核心关注点和横切关注点分离开来。正如Avanade公司的高级方案构架师Adam Magee所说，AOP的核心思想就是&#8220;将应用程序中的商业逻辑同对其提供支持的通用服务进行分离。&#8221;</p>
<p>实现AOP的技术，主要分为两大类：一是采用动态代理技术，利用截取消息的方式，对该消息进行装饰，以取代原有对象行为的执行；二是采用静态织入的方式，引入特定的语法创建&#8220;方面&#8221;，从而使得编译器可以在编译期间织入有关&#8220;方面&#8221;的代码。然而殊途同归，实现AOP的技术特性却是相同的，分别为：</p>
<p>1、join point（连接点）：是程序执行中的一个精确执行点，例如类中的一个方法。它是一个抽象的概念，在实现AOP时，并不需要去定义一个join point。<br>2、point cut（切入点）：本质上是一个捕获连接点的结构。在AOP中，可以定义一个point cut，来捕获相关方法的调用。<br>3、advice（通知）：是point cut的执行代码，是执行&#8220;方面&#8221;的具体逻辑。<br>4、aspect（方面）：point cut和advice结合起来就是aspect，它类似于OOP中定义的一个类，但它代表的更多是对象间横向的关系。<br>5、introduce（引入）：为对象引入附加的方法或属性，从而达到修改对象结构的目的。有的AOP工具又将其称为mixin。</p>
<p>上述的技术特性组成了基本的AOP技术，大多数AOP工具均实现了这些技术。它们也可以是研究AOP技术的基本术语。</p>
<p>2.2.2 横切技术</p>
<p>&#8220;横切&#8221;是AOP的专有名词。它是一种蕴含强大力量的相对简单的设计和编程技术，尤其是用于建立松散耦合的、可扩展的企业系统时。横切技术可以使得AOP在一个给定的编程模型中穿越既定的职责部分（比如日志记录和性能优化）的操作。</p>
<p>如果不使用横切技术，软件开发是怎样的情形呢？在传统的程序中，由于横切行为的实现是分散的，开发人员很难对这些行为进行逻辑上的实现或更改。例如，用于日志记录的代码和主要用于其它职责的代码缠绕在一起。根据所解决的问题的复杂程度和作用域的不同，所引起的混乱可大可小。更改一个应用程序的日志记录策略可能涉及数百次编辑——即使可行，这也是个令人头疼的任务。</p>
<p>在AOP中，我们将这些具有公共逻辑的，与其他模块的核心逻辑纠缠在一起的行为称为&#8220;横切关注点（Crosscutting Concern）&#8221;，因为它跨越了给定编程模型中的典型职责界限。</p>
<p>2.2.2.1 横切关注点</p>
<p>一个关注点（concern）就是一个特定的目的，一块我们感兴趣的区域，一段我们需要的逻辑行为。从技术的角度来说，一个典型的软件系统包含一些核心的关注点和系统级的关注点。举个例子来说，一个信用卡处理系统的核心关注点是借贷/存入处理，而系统级的关注点则是日志、事务完整性、授权、安全及性能问题等，许多关注点——即横切关注点（crosscutting concerns）——会在多个模块中出现。如果使用现有的编程方法，横切关注点会横越多个模块，结果是使系统难以设计、理解、实现和演进。AOP能够比上述方法更好地分离系统关注点，从而提供模块化的横切关注点。</p>
<p>例如一个复杂的系统，它由许多关注点组合实现，如业务逻辑、性能，数据存储、日志和调度信息、授权、安全、线程、错误检查等，还有开发过程中的关注点，如易懂、易维护、易追查、易扩展等，图2.1演示了由不同模块实现的一批关注点组成一个系统。</p>
<p align=center><img height=361 alt=aop2.1.gif src="http://wayfarer.cnblogs.com/images/cnblogs_com/wayfarer/aop/aop2.1.gif" width=415 border=0><br>图2.1 把模块作为一批关注点来实现</p>
<p>通过对系统需求和实现的识别，我们可以将模块中的这些关注点分为：核心关注点和横切关注点。对于核心关注点而言，通常来说，实现这些关注点的模块是相互独立的，他们分别完成了系统需要的商业逻辑，这些逻辑与具体的业务需求有关。而对于日志、安全、持久化等关注点而言，他们却是商业逻辑模块所共同需要的，这些逻辑分布于核心关注点的各处。在AOP中，诸如这些模块，都称为横切关注点。应用AOP的横切技术，关键就是要实现对关注点的识别。</p>
<p>如果将整个模块比喻为一个圆柱体，那么关注点识别过程可以用三棱镜法则来形容，穿越三棱镜的光束（指需求），照射到圆柱体各处，获得不同颜色的光束，最后识别出不同的关注点。如图2.2所示：</p>
<p align=center><img height=185 alt=aop2.2.gif src="http://wayfarer.cnblogs.com/images/cnblogs_com/wayfarer/aop/aop2.2.gif" width=401 border=0><br>图2.2 关注点识别：三棱镜法则</p>
<p>上图识别出来的关注点中，Business Logic属于核心关注点，它会调用到Security，Logging，Persistence等横切关注点。</p>
<p>public class BusinessLogic<br>{<br>&nbsp;&nbsp;&nbsp; public void SomeOperation()<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //验证安全性；Securtity关注点；<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //执行前记录日志；Logging关注点；</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DoSomething();</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //保存逻辑运算后的数据；Persistence关注点；<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //执行结束记录日志；Logging关注点；<br>&nbsp;&nbsp;&nbsp; }<br>}</p>
<p>AOP的目的，就是要将诸如Logging之类的横切关注点从BusinessLogic类中分离出来。利用AOP技术，可以对相关的横切关注点封装，形成单独的&#8220;aspect&#8221;。这就保证了横切关注点的复用。由于BusinessLogic类中不再包含横切关注点的逻辑代码，为达到调用横切关注点的目的，可以利用横切技术，截取BusinessLogic类中相关方法的消息，例如SomeOperation()方法，然后将这些&#8220;aspect&#8221;织入到该方法中。例如图2.3：</p>
<p align=center><img height=224 alt=aop2.3.gif src="http://wayfarer.cnblogs.com/images/cnblogs_com/wayfarer/aop/aop2.3.gif" width=424 border=0><br>图2.3 将横切关注点织入到核心关注点中</p>
<p>通过利用AOP技术，改变了整个系统的设计方式。在分析系统需求之初，利用AOP的思想，分离出核心关注点和横切关注点。在实现了诸如日志、事务管理、权限控制等横切关注点的通用逻辑后，开发人员就可以专注于核心关注点，将精力投入到解决企业的商业逻辑上来。同时，这些封装好了的横切关注点提供的功能，可以最大限度地复用于商业逻辑的各个部分，既不需要开发人员作特殊的编码，也不会因为修改横切关注点的功能而影响具体的业务功能。</p>
<p>为了建立松散耦合的、可扩展的企业系统，AOP应用到的横切技术，通常分为两种类型：动态横切和静态横切。</p>
<p>2.2.2.2 动态横切</p>
<p>动态横切是通过切入点和连接点在一个方面中创建行为的过程，连接点可以在执行时横向地应用于现有对象。动态横切通常用于帮助向对象层次中的各种方法添加日志记录或身份认证。在很多应用场景中，动态横切技术基本上代表了AOP。</p>
<p>动态横切技术的核心主要包括join point（连接点），point cut（切入点），advice（通知）和aspect（方面）。在前面，我已经概要地介绍了这些术语分别代表的含义。接下来，我将以一个具体的实例来进一步阐述它们在AOP动态横切中实现的意义。</p>
<p>考虑一个电子商务系统，需要对订单进行添加、删除等管理操作。毫无疑问，在实际的应用场景中，这些行为应与权限管理结合，只有获得授权的用户方能够实施这些行为。采用传统的设计方法，其伪代码如下：<br>public class OrderManager<br>{<br>&nbsp;&nbsp;&nbsp; private ArrayList m_Orders;<br>&nbsp;&nbsp;&nbsp; public OrderManager()<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; m_Orders = new ArrayList();<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; public void AddOrder(Order order)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (permissions.Verify(Permission.ADMIN))<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; m_Orders.Add(order);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp; public void RemoveOrder(Order order)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (permissions.Verify(Permission.ADMIN))<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; m_Orders.Remove(order);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; }<br>}</p>
<p>同样的，在该电子商务系统中，还需要对商品进行管理，它采用了同样的授权机制：<br>public class ProductManager<br>{<br>&nbsp;&nbsp;&nbsp; private ArrayList m_Products;<br>&nbsp;&nbsp;&nbsp; public ProductManager()<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; m_Products = new ArrayList();<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; public void AddProduct(Product product)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (permissions.Verify(Permission.ADMIN))<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; m_Products.Add(product);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; public void RemoveProduct(Product product)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (permissions.Verify(Permission.ADMIN))<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; m_Products.Remove(product);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; }<br>}</p>
<p>如此以来，在整个电子商务系统中，核心业务包括订单管理和商品管理，它们都需要相同的权限管理，如图2.4所示：</p>
<p align=center><img height=200 alt=aop2.4.gif src="http://wayfarer.cnblogs.com/images/cnblogs_com/wayfarer/aop/aop2.4.gif" width=311 border=0><br>图2.4 电子商务系统的权限验证实现</p>
<p>毫无疑问，利用AOP技术，我们可以分离出系统的核心关注点和横切关注点，从横向的角度，截取业务管理行为的内部消息，以达到织入权限管理逻辑的目的。当执行AddOrder()等方法时，系统将验证用户的权限，调用横切关注点逻辑，因此该方法即为AOP的join point。对于电子商务系统而言，每个需要权限验证的方法都是一个单独的join point。由于权限验证将在每个方法执行前执行，所以对于这一系列join point，只需要定义一个point cut。当系统执行到join point处时，将根据定义去查找对应的point cut，然后执行这个横切关注点需要实现的逻辑，即advice。而point cut和advice，就组合成了一个权限管理aspect。</p>
<p align=center><img height=381 alt=aop2.5.gif src="http://wayfarer.cnblogs.com/images/cnblogs_com/wayfarer/aop/aop2.5.gif" width=362 border=0><br>图2.5 AOP动态横切的技术实现</p>
<p>由于aspect是一个封装的对象，我们可以定义这样一个aspect：<br>private static aspect AuthorizationAspect{&#8230;&#8230;}</p>
<p>然后在这个aspect中定义point cut，在point cut中，定义了需要截取上下文消息的方法，例如：<br>private pointcut authorizationExecution():<br>execution(public void OrderManager.AddOrder(Order)) ||<br>execution(public void OrderManager.DeleteOrder(Order)) ||<br>execution(public void ProductManager.AddProduct(Product)) ||<br>execution(public void ProductManager.DeleteProduct(Product));</p>
<p>由于权限验证是在订单管理方法执行之前完成，因此在before advice中，定义权限检查：<br>before(): authorizationExecution()<br>{<br>&nbsp;&nbsp;&nbsp; if !(permissions.Verify(Permission.ADMIN))<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throw new UnauthorizedException();<br>&nbsp;&nbsp;&nbsp; }<br>}</p>
<p>通过定义了这样一个完整的aspect，当系统调用OrderManager或ProductManager的相关方法时，就触发了point cut，然后调用相应的advice逻辑。如此以来，OrderManager和ProductManager模块就与权限管理模块完全解除了依赖关系，同时也消除了传统设计中不可避免的权限判断的重复代码。这对于建立一个松散耦合、可扩展的系统软件是非常有利的。</p>
<p>2.2.2.3 静态横切</p>
<p>静态横切和动态横切的区别在于它不修改一个给定对象的执行行为。相反，它允许通过引入附加的方法字段和属性来修改对象的结构。此外，静态横切可以把扩展和实现附加到对象的基本结构中。在AOP实现中，通常将静态横切称为introduce或者mixin。</p>
<p>静态横切在AOP技术中，受到的关注相对较少。事实上，这一技术蕴含的潜力是巨大的。使用静态横切，架构师和设计者能用一种真正面向对象的方法有效地建立复杂系统的模型。静态横切允许您不用创建很深的层次结构，以一种本质上更优雅、更逼真于现实结构的方式，插入跨越整个系统的公共行为。尤其是当开发应用系统时，如果需要在不修改原有代码的前提下，引入第三方产品和API库，则静态横切技术将发挥巨大的作用。</p>
<p>举例来说，当前已经实现了一个邮件收发系统，其中类Mail完成了收发邮件的功能。但在产品交付后，发现该系统存在缺陷，在收发邮件时，未曾实现邮件地址的验证功能。现在，第三方产品已经提供了验证功能的接口IValidatable：<br>public interface IValidatable<br>{<br>&nbsp;&nbsp;&nbsp; bool ValidateAddress();<br>}</p>
<p>我们可以利用设计模式中的Adapter模式，来完成对第三方产品API的调用。我们可以定义一个新的类MailAdapter，该类实现了IValidatable接口，同时继承了Mail类：<br>public class MailAdapter:Mail,IValidatable<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp; public bool ValidateAddress()<br>&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(this.getToAddress() != null)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return true;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return false;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp; }<br>}</p>
<p>通过引入MailAdapter类，原来Mail对象完成的操作，将全部被MailAdapter对象取代。然而，此种实现方式虽然能解决引入新接口的问题，但类似下面的代码，却是无法编译通过的：<br>Mail mail = new Mail();<br>IValidatable validate = ((IValidatable)mail).ValidateAddress();</p>
<p>必须将第一行代码作如下修改：<br>Mail mail = new MailAdapter();</p>
<p>利用AOP的静态横切技术，可以将IValidatable接口织入到原有的Mail类中，这是一种非常形象的introduce功能，其实现仍然是在aspect中完成：<br>import com.acme.validate.Validatable;</p>
<p>public aspect MailValidateAspect<br>{<br>&nbsp;&nbsp;&nbsp; declare parents: Mail implements IValidatable;</p>
<p>&nbsp;&nbsp;&nbsp; public boolean Mail.validateAddress()<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(this.getToAddress() != null)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return true;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return false;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; }<br>}</p>
<p>静态横切的方法，并没有引入类似MailAdapter的新类，而是通过定义的MailValidateAspect方面，利用横切技术为Mail类introduce了新的方法ValidateAddress()，从而实现了Mail的扩展。因此如下的代码完全可行。<br>Mail mail = new Mail();<br>IValidatable validate = ((IValidatable)mail).ValidateAddress();</p>
<p>2.3 AOP技术的优势</p>
<p>AOP技术的优势是显而易见的。在面向对象的世界里，人们提出了各种方法和设计原则来保障系统的可复用性与可扩展性，以期建立一个松散耦合、便于扩展的软件系统。例如GOF提出的&#8220;设计模式&#8221;，为我们提供了设计的典范与准则。设计模式通过最大程度的利用面向对象的特性，诸如利用继承、多态，对责任进行分离、对依赖进行倒置，面向抽象，面向接口，最终设计出灵活、可扩展、可重用的类库、组件，乃至于整个系统的架构。在设计的过程中，通过各种模式体现对象的行为、暴露的接口、对象间关系、以及对象分别在不同层次中表现出来的形态。然而鉴于对象封装的特殊性，&#8220;设计模式&#8221;的触角始终在接口与抽象中大做文章，而对于对象内部则无能为力。</p>
<p>通过&#8220;横切&#8221;技术，AOP技术就能深入到对象内部翻云覆雨，截取方法之间传递的消息为我所用。由于将核心关注点与横切关注点完全隔离，使得我们能够独立的对&#8220;方面&#8221;编程。它允许开发者动态地修改静态的OO模型，构造出一个能够不断增长以满足新增需求的系统，就象现实世界中的对象会在其生命周期中不断改变自身，应用程序也可以在发展中拥有新的功能。</p>
<p>设计软件系统时应用AOP技术，其优势在于：</p>
<p>（一）在定义应用程序对某种服务（例如日志）的所有需求的时候。通过识别关注点，使得该服务能够被更好的定义，更好的被编写代码，并获得更多的功能。这种方式还能够处理在代码涉及到多个功能的时候所出现的问题，例如改变某一个功能可能会影响到其它的功能，在AOP中把这样的麻烦称之为&#8220;纠结（tangling）&#8221;。</p>
<p>（二）利用AOP技术对离散的方面进行的分析将有助于为开发团队指定一位精于该项工作的专家。负责这项工作的最佳人选将可以有效利用自己的相关技能和经验。</p>
<p>（三）持久性。标准的面向对象的项目开发中，不同的开发人员通常会为某项服务编写相同的代码，例如日志记录。随后他们会在自己的实施中分别对日志进行处理以满足不同单个对象的需求。而通过创建一段单独的代码片段，AOP提供了解决这一问题的持久简单的方案，这一方案强调了未来功能的重用性和易维护性：不需要在整个应用程序中一遍遍重新编写日志代码，AOP使得仅仅编写日志方面（logging aspect）成为可能，并且可以在这之上为整个应用程序提供新的功能。</p>
<p>总而言之，AOP技术的优势使得需要编写的代码量大大缩减，节省了时间，控制了开发成本。同时也使得开发人员可以集中关注于系统的核心商业逻辑。此外，它更利于创建松散耦合、可复用与可扩展的大型软件系统。<br><br>转贴来自：<a href="http://www.cnblogs.com/wayne-ivan/archive/2006/09/07/496902.html">http://www.cnblogs.com/wayne-ivan/archive/2006/09/07/496902.html</a></p>
<img src ="http://www.blogjava.net/yesjoy/aggbug/120857.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yesjoy/" target="_blank">★yesjoy★</a> 2007-05-30 11:36 <a href="http://www.blogjava.net/yesjoy/articles/120857.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>AOP技术研究——引言 </title><link>http://www.blogjava.net/yesjoy/articles/120856.html</link><dc:creator>★yesjoy★</dc:creator><author>★yesjoy★</author><pubDate>Wed, 30 May 2007 03:35:00 GMT</pubDate><guid>http://www.blogjava.net/yesjoy/articles/120856.html</guid><wfw:comment>http://www.blogjava.net/yesjoy/comments/120856.html</wfw:comment><comments>http://www.blogjava.net/yesjoy/articles/120856.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yesjoy/comments/commentRss/120856.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yesjoy/services/trackbacks/120856.html</trackback:ping><description><![CDATA[<p>1 引言</p>
<p>软件设计因为引入面向对象思想而逐渐变得丰富起来。&#8220;一切皆为对象&#8221;的精义，使得程序世界所要处理的逻辑简化，开发者可以用一组对象以及这些对象之间的关系将软件系统形象地表示出来。而从对象的定义，进而到模块，到组件的定义，利用面向对象思想的封装、继承、多态的思想，使得软件系统开发可以向搭建房屋那样，循序渐进，从砖石到楼层，进而到整幢大厦的建成。应用面向对象思想，在设计规模更大、逻辑更复杂的系统时，开发周期反而能变的更短。自然其中，需要应用到软件工程的开发定义、流程的过程控制，乃至于质量的缺陷管理。但从技术的细节来看，面向对象设计技术居功至伟。然而，面向对象设计的唯一问题是，它本质是静态的，封闭的，任何需求的细微变化都可能对开发进度造成重大影响。</p>
<p>可能解决该问题的方法是设计模式。GOF将面向对象软件的设计经验作为设计模式纪录下来，它使人们可以更加简单方便地复用成功的设计和体系结构，帮助开发人员做出有利于系统复用的选择。设计模式解决特定的设计问题，使面向对象设计更灵活、优雅，最终复用性更好。然而，设计模式虽然给了我们设计的典范与准则，通过最大程度的利用面向对象的特性，诸如利用继承、多态，对责任进行分离、对依赖进行倒置，面向抽象，面向接口，最终设计出灵活、可扩展、可重用的类库、组件，乃至于整个系统的架构。在设计的过程中，通过各种模式体现了对象的行为，暴露的接口，对象间关系，以及对象分别在不同层次中表现出来的形态。然而鉴于对象封装的特殊性，&#8220;设计模式&#8221;的触角始终在接口与抽象中大做文章，而对于对象内部则无能为力。</p>
<p>Aspect-Oriented Programming（面向方面编程，AOP）正好可以解决这一问题。它允许开发者动态地修改静态的OO模型，构造出一个能够不断增长以满足新增需求的系统，就象现实世界中的对象会在其生命周期中不断改变自身，应用程序也可以在发展中拥有新的功能。AOP利用一种称为&#8220;横切&#8221;的技术，剖解开封装的对象内部，并将那些影响了多个类的行为封装到一个可重用模块，并将其名为&#8220;Aspect&#8221;，即方面。所谓&#8220;方面&#8221;，简单地说，就是将那些与业务无关，却为业务模块所共同调用的逻辑或责任，例如事务处理、日志管理、权限控制等，封装起来，便于减少系统的重复代码，降低模块间的耦合度，并有利于未来的可操作性和可维护性。</p>
<p>面向方面编程（AOP）是施乐公司帕洛阿尔托研究中心（Xerox PARC）在上世纪90年代发明的一种编程范式。但真正的发展却兴起于近几年对软件设计方兴未艾的研究。由于软件系统越来越复杂，大型的企业级应用越来越需要人们将核心业务与公共业务分离。AOP技术正是通过编写横切关注点的代码，即&#8220;方面&#8221;，分离出通用的服务以形成统一的功能架构。它能够将应用程序中的商业逻辑同对其提供支持的通用服务进行分离，使得开发人员从重复解决通用服务的劳动中解脱出来，而仅专注于企业的核心商业逻辑。因此，AOP技术也就受到越来越多的关注，而应用于各种平台下的AOP技术也应运而生。但由于AOP技术相对于成熟的OOP技术而言，在性能、稳定性、适用性等方面还有待完善，同时AOP技术也没有形成一个统一的标准，这使得AOP技术的研究更具有前沿性的探索价值。</p>
转贴来自：<a href="http://www.cnblogs.com/wayne-ivan/archive/2006/09/07/496901.html">http://www.cnblogs.com/wayne-ivan/archive/2006/09/07/496901.html</a>
<img src ="http://www.blogjava.net/yesjoy/aggbug/120856.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yesjoy/" target="_blank">★yesjoy★</a> 2007-05-30 11:35 <a href="http://www.blogjava.net/yesjoy/articles/120856.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>