转载自:http://www.cnblogs.com/sunwke/articles/2568875.html

网上出现了很多讲解 AspectJ 的资料,但大多是从讲解 AspectJ 语法开始,然后讲解如何应用 AspectJ,如何分离软件开发过程的不同方面(Aspect)--Log,Session,Authentication and Authorization,Transaction,等等。

初次接触 AspectJ 的读者看到这些资料(或者语法手册),会感到 AspectJ 有些神秘。他们想知道,AspectJ 是如何做到这些的? AspectJ 是怎样工作的? AspectJ 需要特殊的运行环境吗?

本文从另一个角度讲解 AspectJ,本文从讲解 AspectJ 的设计思路、运行原理入手,回答上述问题。

本文讲解的主要内容,按照概念的重要程度,排列如下:

  1. AspectJ 是一个代码生成工具(Code Generator)。
  2. AspectJ 语法就是用来定义代码生成规则的语法。您如果使用过 Java Compiler Compiler (JavaCC),您会发现,两者的代码生成规则的理念惊人相似。
  3. AspectJ 有自己的语法编译工具,编译的结果是 Java Class 文件,运行的时候,classpath 需要包含 AspectJ 的一个 jar 文件(Runtime lib)。

节简单介绍 AOP 的概念,解释我们为什么需要 AOP。

AOP 是 Object Oriented Programming(OOP)的补充。

OOP 能够很好地解决对象的数据和封装的问题,却不能很好的解决 Aspect("方面")分离的问题。下面举例具体说明。

比如,我们有一个 Bank(银行)类。Bank 有两个方法,deposit(存钱)和 withdraw(取钱)。

类和方法的定义如下:

  1. Code 2.1 Bank.java
  2. class Bank{
  3. public float deposit(AccountInfo account, float money){
  4. // 增加 account 账户的钱数,返回账户里当前的钱数
  5. }
  6. public float withdraw(AccountInfo account, float money){
  7. // 减少 account 账户的钱数,返回取出的钱数
  8. }
  9. };

这两个方法涉及到用户的账户资金等重要信息,必须要非常小心,所以编写完上面的商业逻辑之后,项目负责人又提出了新的要求 -- 给 Bank 类的每个重要方法加上安全认证特性。

于是,我们不得不分别在上面的两个方法中加入安全认证的代码。

类和方法的定义如下:(新增加的代码用不同的背景标出)

  1. Code 2.2 Bank.java
  2. class Bank{
  3. public float deposit(AccountInfo account, float money){
  4. // 验证 account 是否为合法用户
  5. // 增加 account 账户的钱数,返回账户里当前的钱数
  6. }
  7. public float withdraw(AccountInfo account, float money){
  8. // 验证 account 是否为合法用户
  9. // 减少 account 账户的钱数,返回取出的钱数
  10. }
  11. };

这两个方法都需要操作数据库,为了保持数据完整性,项目负责人又提出了新的要求 -- 给 Bank 类的每个操作数据库的方法加上事务控制。

于是,我们不得不分别在上面的两个方法中加入安全认证的代码。

类和方法的定义如下:

  1. Code 2.3 Bank.java
  2. class Bank{
  3. public float deposit(AccountInfo account, float money){
  4. // 验证 account 是否为合法用户
  5. // Begin Transaction
  6. // 增加 account 账户的钱数,返回账户里当前的钱数
  7. // End Transaction
  8. }
  9. public float withdraw(AccountInfo account, float money){
  10. // 验证 account 是否为合法用户
  11. // Begin Transaction
  12. // 减少 account 账户的钱数,返回取出的钱数
  13. // End Transaction
  14. }
  15. };

我们看到,这些与商业逻辑无关的重复代码遍布在整个程序中。实际的工程项目中涉及到的类和函数,远远不止两个。如何解决这种问题?

我们首先来看看 OOP 能否解决这个问题。

我们利用 Design Pattern 的 Template Pattern,可以抽出一个框架,改变上面的例子的整个设计结构。

类和方法的定义如下:

  1. Code 2.4 Base.java
  2. abstract class Base{
  3. public float importantMethod(AccountInfo account, float money){
  4. // 验证 account 是否为合法用户
  5. // Begin Transaction
  6.  
  7. float result = yourBusiness(account, money)
  8. // End Transaction
  9. return result;
  10. }
  11. protected abstract float yourBusiness(AccountInfo account, float money);
  12. };
  13. Code 2.5 BankDeposit.java
  14. class BankDeposit extends Base{
  15. protected float yourBusiness(AccountInfo account, float money){
  16. // 增加 account 账户的钱数,返回账户里当前的钱数
  17. }
  18. };
  19. Code 2.6 BankWithdraw.java
  20. class BankWithdraw extends Base{
  21. protected float yourBusiness(AccountInfo account, float money){
  22. // 减少 account 账户的钱数,返回取出的钱数
  23. }
  24. };

这里我们用一种很勉强的方法实现了认证和事务代码的重用。而且,有心的读者可能会注意到,这种方法的前提是,强制所有的方法都遵守同样的 signature。

如果有一个转账方法 transfer(AccountInfo giver, AccountInfo receiver, float money),由于 transfer 方法的 signature 不同于 yourBusiness 的 signature,这个方法无法使用上面的框架。

这个例子中提到的认证,事务等方面,就是 AOP 所关心的 Aspect。

AOP 就是为了解决这种问题而出现的。AOP 的目的就是 --Separation of Aspects (or Separation of Concerns).

使用 AspectJ,我们不用对原有的代码做任何修改,就可以为代码提供不同的 Aspect(方面)-- 比如,认证,事务等。

我们只需要提供两个不同的 Aspect-- 认证 Aspect 和事务 Aspect。

  1. Code 4.1 AuthAspect.java
  2. aspect AuthAspect{
  3. pointcut bankMethods() : execution (* Bank.deposit( )) ||
  4. execution (* Bank. withdraw ( ));
  5. Object around(): bankMethods(){
  6. // 验证 account 是否为合法用户
  7. return proceed();
  8. }
  9. };
  10. Code 4.2 TransactionAspect.java
  11. aspect TransactionAspect{
  12. pointcut bankMethods() : execution(* Bank.deposit( )) ||
  13. execution (* Bank. withdraw ( ));
  14. Object around(): bankMethods(){
  15. // Begin Transaction
  16. Object result = proceed();
  17. // End Transaction
  18. return result;
  19. }
  20. };

如果您暂时不能理解这段代码,没有关系,后面会讲到,这些 aspect 的定义,不过是定义了一些代码生成规则。

我们用 AspectJ 编译器编译 Bank 文件和含有 aspect 的这个文件,出来的结果就是带有安全认证和事务处理的 Bank 类。编译出来的这个 Bank 类调用了 AspectJ Runtime Lib,所以,如果你要运行这个 Bank 类,你需要把 AspectJ Runtime Lib 设置在你的 classpath 里面。

我们来看看,AspectJ 编译器为我们做了什么事情。

  1. 首先,AspectJ 从文件列表里取出所有的文件名,然后读取这些文件,进行分析。
  2. AspectJ 发现一些文件含有 aspect 的定义,在这个例子里,就是 AuthAspect 和 TransactionAspect 的定义;这些 aspect 就是代码生成规则。
  3. AspectJ 根据这些 aspect 代码生成规则,修改添加你的源代码。在这个例子里,就是修改添加 Bank 文件。
  4. AspectJ 读取 AuthAspect 的定义,发现了一个 pointcut--bankMethods();这个 pointcut 的定义是 execution(* Bank.deposit( … )) || execution(* Bank. withdraw ( … )),表示所有对 Bank 类的 deposit 和 withdraw 方法的执行点。
  5. AspectJ 继续读取 AuthAspect 的定义,发现了一个 around(),这在 AspectJ 中叫做 Advice,我不明白为什么叫这个名字,不过没关系,我们只要知道它是干什么的就行了。Advice 允许你在某个类的方法的调用之前或调用之后,加入另外的代码。Code 4.1 所示代码中的 around() 的" // 验证 account 是否为合法用户"部分,就是要加入的代码。这段代码要加在哪里呢? around() 后面跟了一个 pointcut--bankMethods()。根据这个 pointcut,AspectJ 会把这段代码加入到 Bank.deposit 和 Bank.withdraw 两个方法的执行之前。达到的效果就如同 Code 2.2 所示。
  6. AspectJ 读取 TransactionAspect 的定义,象第(4)步一样,发现了发现了一个 pointcut--bankMethods()。
  7. AspectJ 继续读取 AuthAspect 的定义,发现了一个 around()。这次 AspectJ 把"Begin Transaction"和"End Transaction"两段代码加在 Bank.deposit 和 Bank. withdraw 两个方法的执行前后。达到的效果就如同 Code 2.3 所示。

如何验证这一点?您可以到 http://www.eclipse.org/aspectj/下载安装 AspectJ,编译里面的 Sample,把编译结果反编译一下,就可以看到 AspetJ 自动生成的代码。

我们看到,AspectJ 是一种代码自动生成工具。你编写一段通用的代码,比如认证方面的代码,事务方面的代码,然后根据 AspectJ 语法定义一套代码生成规则(aspect 定义),AspectJ 就会帮助你自动把这段通用代码分布到对应的代码里面去,简单快捷.

转载自:http://www.cnblogs.com/sunwke/articles/2568875.html

Aspectj是什么的更多相关文章

  1. Springl利用Aspectj的扩展实现Aop

    1. Spring为什么要使用Aspectj Spring Aop:Spring自己原生的Aop,只能用一个词来形容:难用. 你需要实现大量的接口,继承大量的类,所以spring aop一度被千夫所指 ...

  2. Spring AspectJ基于注解的AOP实现

    对于AOP这种编程思想,很多框架都进行了实现.Spring就是其中之一,可以完成面向切面编程.然而,AspectJ也实现了AOP的功能,且实现方式更为简捷,使用更加方便,而且还支持注解式开发.所以,S ...

  3. Spring AOP支持的AspectJ切入点语法大全

    原文出处:http://jinnianshilongnian.iteye.com/blog/1420691 Spring AOP支持的AspectJ切入点指示符 切入点指示符用来指示切入点表达式目的, ...

  4. 【Spring实战】—— 12 AspectJ报错:error at ::0 can't find referenced pointcut XXX

    今天在使用AspectJ进行注解切面时,遇到了一个错误. 切点表达式就是无法识别——详细报错信息如下: Exception can't find referenced pointcut perform ...

  5. Spring @AspectJ 实现AOP 入门例子(转)

    AOP的作用这里就不再作说明了,下面开始讲解一个很简单的入门级例子. 引用一个猴子偷桃,守护者守护果园抓住猴子的小情节. 1.猴子偷桃类(普通类): package com.samter.common ...

  6. [原创]java WEB学习笔记105:Spring学习---AOP介绍,相关概念,使用AOP,利用 方法签名 编写 AspectJ 切入点表达式

    本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...

  7. Java AOP nested exception is java.lang.NoClassDefFoundError: org/aopalliance/aop/Advice || Error creating bean with name 'org.springframework.aop.aspectj.AspectJPointcutAdvisor#0' 两个异常解决办法

    贴出applicationContext.xml <?xml version="1.0" encoding="UTF-8"?> <beans ...

  8. (转)实例简述Spring AOP之间对AspectJ语法的支持(转)

    Spring的AOP可以通过对@AspectJ注解的支持和在XML中配置来实现,本文通过实例简述如何在Spring中使用AspectJ.一:使用AspectJ注解:1,启用对AspectJ的支持:通过 ...

  9. Aspectj 实现Method条件运行

    最近我花了半个小时实现了一个Method的按自定义条件运行的plugin,Condition-Run.实现场景是由于我所工作的客户经常会是在同一个代码集上实现多个Brand,所以有些功能只会限制是几个 ...

  10. [Spring框架]Spring AOP基础入门总结二:Spring基于AspectJ的AOP的开发.

    前言: 在上一篇中: [Spring框架]Spring AOP基础入门总结一. 中 我们已经知道了一个Spring AOP程序是如何开发的, 在这里呢我们将基于AspectJ来进行AOP 的总结和学习 ...

随机推荐

  1. json 数组转换为js数组

    $(function(){ var json = '[{"id":"1","tagName":"apple"},{&qu ...

  2. ssi服务器端指令

    SSI使用详解 你是否曾经或正在为如何能够在最短的时间内完成对一个包含上千个页面的网站的修改而苦恼?那么可以看一下本文的介绍,或许能够对你有所帮助.什么是SSI?SSI是英文Server Side I ...

  3. c语言学习感想

    接触c语言已经2个多月了,在这段期间按时的完成了作业,上课能够较好的听讲,因此我获得了老师奖励的小黄衫. 同时,希望自己能够学好c语言! 学习感受与心得 因为兴趣,选择了计算机这专业,我从遥远的南方来 ...

  4. HDFS的联盟Federation

    一:概述 1.单个namenode的局限性 namespace的限制 单个namenode所能存储的对象受到JVM中的heap size的限制 namenode的扩张性 不可以水平扩张 隔离性 单个n ...

  5. Windows下一个比较完美的线程池实现(使用线程池实现的Http上传下载实现)

    http://blog.csdn.net/fishjam/article/details/8632049 http://download.csdn.net/user/fishjam

  6. Qt 之 自定义窗口标题栏(非常完善)

    http://blog.csdn.net/goforwardtostep/article/details/53494800

  7. 逻辑运算符——逻辑与&&、逻辑或||

    一直以来,都是认为逻辑运算符返回的是布尔值,却突然发现:并不是这样. 对于||来说,如果条件判断结果为true就返回第一个操作数的值,如果为false就返回第二个操作数的值. &&则相 ...

  8. JS中注意原型链的“指向”

    昨天压缩Js文件时发现了项目中的一个prototype的问题代码如下所示: 1. <script> var XXX = function(){ }; var x1 = new XXX(); ...

  9. .Net程序员安卓学习之路6:等待条

    一般在需要访问网络或者长时间操作的时候避免界面无响应才使用:等待条 本例将实现一个无框架的等待条,效果如下: 点击后,使线程Sleep5秒,就出现如下效果: 实现代码如: private Progre ...

  10. TermServDevices报错导致服务器死机(远程服务使用者必读)

    事件类型: 错误 事件来源: TermServDevices 事件 ID: 1111 描述:打印机 !!192.168.99.6!HP LaserJet 3050 Series PCL 5e 所需的驱 ...