AOP的实现方式有两种:
  1. AOP框架在编译阶段,就对目标类进行修改,得到的class文件已经是被修改过的。生成静态的AOP代理类(生成*.class文件已经被改掉了,需要使用特定的编译器)。以AspectJ为代表 —— 静态AOP框架。
  2. AOP框架在运行阶段,动态生成AOP代理(在内存中动态地生成AOP代理类),以实现对目标对象的增强。它不需要特殊的编译器。以Spring AOP为代表。—— 动态AOP框架。
动态AOP框架不需要在编译时对目标类进行增强,而是运行时生成目标类的代理类,该代理类要么与目标类实现相同的接口,要么是目标类的子类——总之,代理类的实例可作为目标类的实例来使用。一般来说,编译时增强的 AOP 框架在性能上更有优势——因为运行时动态增强的 AOP 框架需要每次运行时都进行动态增强
 

AspectJ

AspectJ 是一个基于 Java 语言的 AOP 框架,提供了强大的 AOP 功能,其他很多 AOP 框架都借鉴或采纳其中的一些思想。

AspectJ 是 Java 语言的一个 AOP 实现,其主要包括两个部分:第一个部分定义了如何表达、定义 AOP 编程中的语法规范,通过这套语言规范,我们可以方便地用 AOP 来解决 Java 语言中存在的交叉关注点问题;另一个部分是工具部分,包括编译器、调试工具等。

AspectJ 是最早、功能比较强大的 AOP 实现之一,对整套 AOP 机制都有较好的实现,很多其他语言的 AOP 实现,也借鉴或采纳了 AspectJ 中很多设计。在 Java 领域,AspectJ 中的很多语法结构基本上已成为 AOP 领域的标准。

一、下载及安装

下载、安装 AspectJ 比较简单,读者登录 AspectJ 官网(http://www.eclipse.org/aspectj/downloads.php),

即可下载到一个可执行的 JAR 包,我下的是aspectj-1.8.13.jar,使用 java -jar aspectj-1.8.13.jar 命令,

多次单击“Next”按钮即可成功安装 AspectJ。

成功安装了 AspectJ 之后,将会在 C:\aspectj1.8 路径下(AspectJ 的安装路径)看到如下文件结构:

  • bin:该路径下存放了 aj、aj5、ajc、ajdoc、ajbrowser 等命令,其中 ajc 命令最常用,它的作用类似于 javac,用于对普通 Java 类进行编译时增强。
  • docs:该路径下存放了 AspectJ 的使用说明、参考手册、API 文档等文档。
  • lib:该路径下的 4 个 JAR 文件是 AspectJ 的核心类库。
  • 相关授权文件。

环境变量配置

CLASSPATH:.;C:\aspectj1.8\lib\aspectjrt.jar;C:\aspectj1.8\lib\aspectjtools.jar

Path:C:\aspectj1.8\bin

测试是否安装成功用ajc命令:

二、AspectJ简单示例

实际上,AspectJ 的用法非常简单,就像我们使用 JDK 编译、运行 Java 程序一样。下面通过一个简单的程序来示范 AspectJ 的用法,并分析 AspectJ 如何在编译时进行增强。

2.1、示例一:首先编写一个简单的 Java 类,这个 Java 类用于模拟一个业务组件。

清单 1.HelloWorld.java

 public class HelloWorld
{
// 定义一个简单方法,模拟应用中的业务逻辑方法
public void sayHello()
{
System.out.println("Hello AspectJ!");
}
// 主方法,程序的入口
public static void main(String[] args)
{
HelloWorld h = new HelloWorld();
h.sayHello();
}
}

上面 Hello 类模拟了一个业务逻辑组件,编译、运行该 Java 程序,这个结果是没有任何悬念的,程序将在控制台打印“Hello AspectJ”字符串。

假设现在客户需要在执行 sayHello() 方法之前启动事务,当该方法执行结束时关闭事务,在传统编程模式下,我们必须手动修改 sayHello() 方法——如果改为使用 AspectJ,则可以无须修改上面的 sayHello() 方法。

下面我们定义一个特殊的 Java 类。

清单 2.TxAspect.java

public aspect TxAspect
{
// 指定执行 HelloWorld.sayHello() 方法时执行下面代码块
void around():call(void HelloWorld.sayHello())
{
System.out.println("开始事务 ...");
proceed();
System.out.println("事务结束 ...");
}
}

可能读者已经发现了,上面类文件中不是使用 class、interface、enum 在定义 Java 类,而是使用了 aspect ——难道 Java 语言又新增了关键字?没有!上面的 TxAspect 根本不是一个 Java 类,所以 aspect 也不是 Java 支持的关键字,它只是 AspectJ 才能识别的关键字。

上面粗体字代码也不是方法,它只是指定当程序执行 Hello 对象的 sayHello() 方法时,系统将改为执行粗体字代码的花括号代码块,其中 proceed() 代表回调原来的 sayHello() 方法。

正如前面提到的,Java 无法识别 TxAspect.java 文件的内容,所以我们要使用 ajc.exe 命令来编译上面的 Java 程序。为了能在命令行使用 ajc.exe 命令,需要把 AspectJ 安装目录下的 bin 路径(比如 E:\Java\AOP\aspectj1.6\bin 目录)添加到系统的 PATH 环境变量中。接下来执行如下命令进行编译:

D:\work\aspectjwork>ajc -d . HelloWorld.java TxAspect.java

我们可以把 ajc.exe 理解成 javac.exe 命令,都用于编译 Java 程序,区别是 ajc.exe 命令可识别 AspectJ 的语法;从这个意义上看,我们可以将 ajc.exe 当成一个增强版的 javac.exe 命令。

运行该 HelloWorld 类依然无须任何改变。程序使用如下命令运行 HelloWorld类:

java HelloWorld

运行该程序,将看到一个令人惊喜的结果:

D:\work\aspectjwork>java HelloWorld
开始事务 ...
Hello AspectJ!
事务结束 ... D:\work\aspectjwork>

从上面运行结果来看,我们完全可以不对 HelloWorld.java 类进行任何修改,同时又可以满足客户的需求:上面程序只是在控制台打印“开始事务 ...”、“结束事务 ...”来模拟了事务操作,实际上我们可用实际的事务操作代码来代替这两行简单的语句,这就可以满足客户需求了。

2.2、示例二

如果客户再次提出新需求,需要在 sayHello() 方法后增加记录日志的功能,那也很简单,我们再定义一个 LogAspect,程序如下:

清单 3.LogAspect.java

public aspect LogAspect
{
// 定义一个 PointCut,其名为 logPointcut
// 该 PointCut 对应于指定 HelloWorld 对象的 sayHello 方法
pointcut logPointcut():execution(void HelloWorld.sayHello());
// 在 logPointcut 之后执行下面代码块
after():logPointcut()
{
System.out.println("记录日志 ...");
}
}

上面程序的粗体字代码定义了一个 Pointcut:logPointcut - 等同于执行 Hello 对象的 sayHello() 方法,并指定在 logPointcut 之后执行简单的代码块,也就是说,在 sayHello() 方法之后执行指定代码块。使用如下命令来编译上面的 Java 程序:

ajc -d . *.java

再次运行 HelloWorld 类,将看到如下运行结果:

D:\work\aspectjwork>java HelloWorld
开始事务 ...
Hello AspectJ!
记录日志 ...
事务结束 ... D:\work\aspectjwork>

从上面运行结果来看,通过使用 AspectJ 提供的 AOP 支持,我们可以为 sayHello() 方法不断增加新功能。

为什么在对 HelloWorld 类没有任何修改的前提下,而 HelloWorld 类能不断地、动态增加新功能呢?这看上去并不符合 Java 基本语法规则啊。实际上我们可以使用 Java 的反编译工具来反编译前面程序生成的 HelloWorld.class 文件,发现 HelloWorld.class 文件的代码如下:

清单 4.HelloWorld.class

import java.io.PrintStream;
import org.aspectj.runtime.internal.AroundClosure; public class HelloWorld
{
public void sayHello()
{
try
{
System.out.println("Hello AspectJ!"); } catch (Throwable localThrowable) {
LogAspect.aspectOf().ajc$after$LogAspect$1$9fd5dd97(); throw localThrowable; } LogAspect.aspectOf().ajc$after$LogAspect$1$9fd5dd97();
} public static void main(String[] args) {
HelloWorld h = new HelloWorld();
HelloWorld localHelloWorld1 = h; sayHello_aroundBody1$advice(localHelloWorld1, TxAspect.aspectOf(), null); }
private static final void sayHello_aroundBody0(HelloWorld paramHelloWorld) { paramHelloWorld.sayHello();
} private static final void sayHello_aroundBody1$advice(HelloWorld target, TxAspect ajc$aspectInstance, AroundClosure ajc$aroundClosure)
{
System.out.println("开始事务 ...");
AroundClosure localAroundClosure = ajc$aroundClosure;
sayHello_aroundBody0(target);
System.out.println("事务结束 ...");
}
}

不难发现这个 HelloWorld.class 文件不是由原来的 HelloWorld.java 文件编译得到的,该 HelloWorld.class 里新增了很多内容——这表明 AspectJ 在编译时“自动”编译得到了一个新类,这个新类增强了原有的 HelloWorld.java 类的功能,因此 AspectJ 通常被称为编译时增强的 AOP 框架。

实际上,AspectJ 允许同时为多个方法添加新功能,只要我们定义 Pointcut 时指定匹配更多的方法即可。如下片段:

 pointcut xxxPointcut()
:execution(void H*.say*());

上面程序中的 xxxPointcut 将可以匹配所有以 H 开头的类中、所有以 say 开头的方法,但该方法返回的必须是 void;如果不想匹配任意的返回值类型,则可将代码改为如下形式:

pointcut xxxPointcut()

:execution(* H*.say*());

关于如何定义 AspectJ 中的 Aspect、Pointcut 等,读者可以参考 AspectJ 安装路径下的 doc 目录里的 quick5.pdf 文件。

三、AJDT 插件(AspectJ Development Tools)

一些文档、AspectJ 入门书籍,一谈到使用 AspectJ,就认为必须使用 Eclipse 工具,似乎离开了该工具就无法使用 AspectJ 了。

虽然 AspectJ 是 Eclipse 基金组织的开源项目,而且提供了 Eclipse 的 AJDT 插件(AspectJ Development Tools)来开发 AspectJ 应用,但 AspectJ 绝对无须依赖于 Eclipse 工具。

在线安装http://download.eclipse.org/tools/ajdt/45/dev/update

安装成功后,看properties页如下:

Eclipse和AOP现在是比较热的话题,而AOP技术中AspectJ是最成熟的一种,本文就简单介绍一下如何在Eclipse中开发AspectJ应用。AJDT是AspectJ项目为Eclipse开发的插件,用于开发运行AspectJ应用。本文假设已经对Eclipse和AspectJ有一定的了解。
 
一、我们首先设置好开发环境:
 
1、  下载AJDT插件,http://www.eclipse.org/ajdt
2、  当然还得由Eclipse,此版本的AJDT对应Eclipse V3.0.2,配置好jdk
3、  安装插件到Eclipse中,通用的有两种方法:
     方法1:将下载的插件压缩包解压,将对应得plugin和feature文件夹复制到Eclipse中对应的目录
     方法2:选择Help>Software Updates>Find and Install,然后选择刚才的下载包
4、选择windows->custom perspective->在new中选上aspect,这样“新建”中就会出现和aspectJ相关的选项。

二、然后我们来编写一个最简单的HelloWorld
 
1、  新建一个AspectProject,记住在Build Setting 中添加编译AspectJ所需的lib
步骤:Add Variable -> 选择ASPECTJRT_LIB,否则编译不了AspectJ程序
2、  新建一个class,如下:
package myaspect;

public class HelloWorld {

    public static void main(String[] args) {
new HelloWorld().sayHello();
} public void sayHello() {
System.out.println("Hello!");
}
}
3、  新建一个Aspect,如下:
package myaspect;

public aspect AspectHelloWorld {
pointcut greeting():
call(void HelloWorld.sayHello()); after() returning: greeting() {
System.out.println("world");
} }
 

4、  保存,在HelloWorld.java上点右键,选择run->AspectJ/Application,就可以了

能跑起这个程序,说明工具已经没有问题,剩下的就是对AspectJ语法的熟悉了。
反编译HelloWorld.class

AspectJ入门的更多相关文章

  1. Spring AOP @AspectJ 入门基础

    需要的类包: 1.一个简单的例子 Waiter接口: package com.yyq.annotation; public interface Waiter { void greetTo(String ...

  2. spring AOP 之一:spring AOP功能介绍

    一.AOP简介 AOP:是一种面向切面的编程范式,是一种编程思想,旨在通过分离横切关注点,提高模块化,可以跨越对象关注点.Aop的典型应用即spring的事务机制,日志记录.利用AOP可以对业务逻辑的 ...

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

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

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

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

  5. SpringAOP-基于@AspectJ的简单入门

    一.AOP的基本概念: 连接点(Jointpoint):表示需要在程序中插入横切关注点的扩展点,连接点可能是类初始化.方法执行.方法调用.字段调用或处理异常等等,Spring只支持方法执行连接点,在A ...

  6. Spring的入门学习笔记 (AOP概念及操作+AspectJ)

    AOP概念 1.aop:面向切面(方面)编程,扩展功能不通过源代码实现 2.采用横向抽取机制,取代了传统的纵向继承重复代码 AOP原理 假设现有 public class User{ //添加用户方法 ...

  7. Spring入门篇——第7章 Spring对AspectJ的支持

    第7章 Spring对AspectJ的支持 介绍Spring对AspectJ的支持 7-1 AspectJ介绍及Pointcut注解应用 实例 完成了在xml文件的配置 7-2 Advice定义及实例 ...

  8. Spring的AOP开发入门,Spring整合Junit单元测试(基于ASpectJ的XML方式)

    参考自 https://www.cnblogs.com/ltfxy/p/9882430.html 创建web项目,引入jar包 除了基本的6个Spring开发的jar包外,还要引入aop开发相关的四个 ...

  9. 十二 Spring的AOP开发入门,整合Junit单元测试(AspectJ的XML方式)

    创建web项目,引入jar包 引入Spring配置文件

随机推荐

  1. 关于while(cin>>c)语句的理解

    1.while(cin>>c)条件语句,其功能是检测输入流中的输入是否有效,若是文件结束标记或者非法输入,则条件判断为假,否则为真. 2.windows下的文件结束标记是Ctrl+z,Li ...

  2. L1-016 查验身份证

    一个合法的身份证号码由17位地区.日期编号和顺序编号加1位校验码组成.校验码的计算规则如下: 首先对前17位数字加权求和,权重分配为:{7,9,10,5,8,4,2,1,6,3,7,9,10,5,8, ...

  3. Individual work 总结

    不得不说,这是我上大学以来所花时间最长.收获最多的个人项目之一.在此之前,虽然也上过面向对象等课程,课程对编程代码量的要求并不比这个小,但是由于从没有如这次这般,完全靠自己学习新的编程语言并进行编程实 ...

  4. Home Kit框架简介

    重要:本文是针对开发过程中使用的API或者技术的初步文档.苹果提供该文档旨在为开发者使用该技术和苹果产品上的编程接口提供帮助.这些信息可能会发生变化,依据该文档开发的软件应该使用最新的操作系统软件和最 ...

  5. 1.1 Linux中的进程 --fork、孤儿进程、僵尸进程、文件共享分析

    操作系统经典的三态如下: 1.就绪态 2.等待(阻塞) 3.运行态 其转换状态如下图所示: 操作系统内核中会维护多个队列,将不同状态的进程加入到不同的队列中,其中撤销是进程运行结束后,由内核收回. 以 ...

  6. jQuery自动完成点击html元素

    /************************************************************************** * jQuery自动完成点击html元素 * 声 ...

  7. C templet and switch case with serial number

    /************************************************************************** * C templet and switch c ...

  8. chapter02 K近邻分类器对Iris数据进行分类预测

    寻找与待分类的样本在特征空间中距离最近的K个已知样本作为参考,来帮助进行分类决策. 与其他模型最大的不同在于:该模型没有参数训练过程.无参模型,高计算复杂度和内存消耗. #coding=utf8 # ...

  9. 前端css规范

    文章整理了Web前端开发中的各种CSS规范,包括文件规范.注释规范.命名规范.书写规范.测试规范等. 一.文件规范 1.文件均归档至约定的目录中(具体要求以豆瓣的CSS规范为例进行讲解): 所有的CS ...

  10. All the Apache Streaming Projects: An Exploratory Guide

    The speed at which data is generated, consumed, processed, and analyzed is increasing at an unbeliev ...