明明白白AspectJ (1)

 转自: http://www.blogjava.net/orangewhy/archive/2007/07/12/129723.html

http://www.ibm.com/developerworks/cn/java/l-aspectJ/index.html中介绍了What is AspectJ 。

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

看了上面几点,我就想看看它怎么把代码生成了。现在做一个试验。

一个类(包括main函数):Speaker.java

package  test.aspectj;

public   class  Speaker
{
    
public void speak()
    
{
        System.out.println(
"[Speaker] bla bla ");
    }


    
public static void main(String[] args)
    
{
        Speaker speaker 
= new Speaker();
        speaker.speak();
    }

}

 

一个aspect:AspectObserver.aj

package  test.aspectj;

public  aspect AspectObserver
{
    pointcut speakerSpeak():
        call(
void *Speaker.speak());
    before() : speakerSpeak() 
{
        System.out.println(
"[AspectObserver] speaker is about to speak!");
    }

    after() returning() : speakerSpeak() 
{
        System.out.println(
"[AspectObserver] speaker has completed his speech!");
    }

}

以上都是源码部分哦。

运行结果:

[AspectObserver] speaker is about to speak !
[Speaker] bla bla 
[AspectObserver] speaker has completed his speech
!

说明程序是正常运作的哦。

好了,下面,做三个操作:

1、将以上的编译成的class文件打包成apectjtest.jar文件。

      说明:可以使用ajdt的eclipse插件带的导出功能,Export -->  JAR file with ApectJ support

2、新建一个AspectJ工程,将apectjtest.jar加入类路径,使用jad来反编译Speaker.class和AspectObserver.class

 得到反编译后的源码:

Speaker.class

/*jadclipse*/ //  Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.
//  Jad home page:  http://www.kpdus.com/jad.html
//  Decompiler options: packimports(3) radix(10) lradix(10) 
//  Source File Name:   Speaker.java

package  test.aspectj;

import  java.io.PrintStream;

//  Referenced classes of package test.aspectj:
//             AspectObserver

public   class  Speaker
{

    
public Speaker()
    
{
    }


    
public void speak()
    
{
        System.out.println(
"[Speaker] bla bla ");
    }


    
public static void main(String args[])
    
{
        Speaker speaker 
= new Speaker();
        AspectObserver.aspectOf().ajc$before$test_aspectj_AspectObserver$
1$b2b6354();
        speaker.speak();
        AspectObserver.aspectOf().ajc$afterReturning$test_aspectj_AspectObserver$
2$b2b6354();
    }

}

 

AspectObserver.class

/*jadclipse*/ //  Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.
//  Jad home page:  http://www.kpdus.com/jad.html
//  Decompiler options: packimports(3) radix(10) lradix(10) 
//  Source File Name:   AspectObserver.aj

package  test.aspectj;

import  java.io.PrintStream;
import  org.aspectj.lang.NoAspectBoundException;

public   class  AspectObserver
{

    
public AspectObserver()
    
{
    }


    
void ajc$pointcut$$speakerSpeak$44()
    
{
    }


    
public void ajc$before$test_aspectj_AspectObserver$1$b2b6354()
    
{
        System.out.println(
"[AspectObserver] speaker is about to speak!");
    }


    
public void ajc$afterReturning$test_aspectj_AspectObserver$2$b2b6354()
    
{
        System.out.println(
"[AspectObserver] speaker has completed his speech!");
    }


    
public static AspectObserver aspectOf()
    
{
        
if(ajc$perSingletonInstance == null)
            
throw new NoAspectBoundException("test_aspectj_AspectObserver", ajc$initFailureCause);
        
else
            
return ajc$perSingletonInstance;
    }


    
public static boolean hasAspect()
    
{
        
return ajc$perSingletonInstance != null;
    }


    
private static void ajc$postClinit()
    
{
        ajc$perSingletonInstance 
= new AspectObserver();
    }


    
private static Throwable ajc$initFailureCause;
    
public static final AspectObserver ajc$perSingletonInstance;

    
static 
    
{
        
try
        
{
            ajc$postClinit();
        }

        
catch(Throwable throwable)
        
{
            ajc$initFailureCause 
= throwable;
        }

    }

}

3、运行一下Speaker.class

得到结果:

[AspectObserver] speaker is about to speak !
[Speaker] bla bla 
[AspectObserver] speaker has completed his speech
!

 

呵呵,结果跟源码运行是一样的哦(不一样就是你的人品问题咯!!)

分析一下,先理解AspectJ编译器为我们做了什么事情:

首先、AspectJ从文件列表里取出所有的文件名,然后读取这些文件,进行分析。 
二、AspectJ发现一些文件含有aspect的定义,在这个例子里,就是AspectObserver的定义;这些aspect就是代码生成规则。 
三、AspectJ根据这些aspect代码生成规则,修改添加你的源代码。在这个例子里,源码是修改成怎样了?比较一下反编译后的代码和源码便知。 
四、AspectJ读取AspectObserver的定义,发现了一个pointcut
-- speakerSpeak();这个pointcut的定义是call( void   * Speaker.speak()),表示所有对Speaker类的speak方法的执行点。 
五、AspectJ继续读取AspectObserver的定义,发现了一个before(),这在AspectJ中叫做Advice。Advice允许你在某个类的方法的调用之前或调用之后,加入另外的代码。加入的代码是什么?比较一下反编译后的代码和源码吧。 AspectJ继续读取AspectObserver的定义.

好了,回头看看反编译后的Speaker.class,与源码Speaker.java差别在哪呢?主要在main函数中,方法被调用的前后

     public   static   void  main(String args[])
    
{
        Speaker speaker 
= new Speaker();
        AspectObserver.aspectOf().ajc$before$test_aspectj_AspectObserver$
1$b2b6354();//多了这行
        speaker.speak();
        AspectObserver.aspectOf().ajc$afterReturning$test_aspectj_AspectObserver$
2$b2b6354();//多了这行
    }

不同的地方就是多出了两行,虽然有$和数字,但是很容易看出,这同我们平常写的java代码差不了多少。

        AspectObserver.aspectOf().ajc$before$test_aspectj_AspectObserver$ 1 $b2b6354();

这行代码中,看起来不就是AspectObserver类调用了静态方法aspectOf()吗,接着aspectOf()的返回对象又调用ajc$before$test_aspectj_AspectObserver$1$b2b6354()方法吗?

回来看看AspectObserver.class的反编译代码,哈哈,这就对了,aspectOf返回的是AspectObserver的一个实例,返回实例在调用实例方法ajc$before$test_aspectj_AspectObserver$1$b2b6354()。ajc$before$test_aspectj_AspectObserver$1$b2b6354()是干什么的呢?呵呵,不正是我们要的拦截方法所要做的操作吗?

System.out.println( " [AspectObserver] speaker is about to speak! " );

同样,可知

 AspectObserver.aspectOf().ajc$afterReturning$test_aspectj_AspectObserver$ 2 $b2b6354();

是怎么一回事啦。

这正是应了上面所提的两点:

  1. AspectJ是一个代码生成工具(Code Generator)。
  2. AspectJ语法就是用来定义代码生成规则的语法。

用这两点去感受apectj在程序里该如何去运用使用,就清晰多啦!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值