AspectJ AOP 简单示例2

转自 http://blog.sina.com.cn/s/blog_46d0362d0100mmzy.html
有时候调试一些程序会牵涉到第三方的类库,但由于它们都是以class或者jar形式发布的,不大可能改变其行为,所以不是特别方便。这个时候唯一可以利用的就是AOP的技术,常用的就是AspectJ
首先是几个概念:
1.aspect(层面) 2.pointcut(切入点) 3.advice(建议)4.weave(织入)5.LTW(加载期织入 load time weave)
按照aspectj的语法规则,一个aspect就是很多pointcut和advice的集合,也就是一个*.aj的文件
一个pointcut就是对target class的切入点定义,类似Java class定义中的field
一个advice就是对target class的行为改变,类似Java class中的method
weave就是aspectj runtime库把aspect织入到target class的行为。
LTW就是指运行期间动态织入aspect的行为,它是相对静态织入行为(包括对源文件、二进制文件的修改)。
一般来讲,从运行速度上来说,静态织入比动态织入要快些。因为LTW需要使用aspectj本身的classloader,
它的效率要低于jdk的classloader,因此当需要load的class非常多时,就会很慢的。

举个例子来说明aspectj的使用:
scenario: Example工程需要使用一个类Line存在于第三方库Line.jar中,但是Line本身没有实现Serializable接口,并且其toString方法输出也不完善。因此这两点都需要修改。
Line的实现:

package bean;
public class Line {
    protected int x1 = 0;
    protected int x2 = 0;

    public int getX1(){
        return x1;
    }

    public int getX2(){
        return x2;
    }

    public void setLength(int newX, int newY){
        setX1(newX);
        setX2(newY);
    }

    public void setX1(int newX) {
        x1 = newX;
    }

    public void setX2(int newY) {
        x2 = newY;
    }

    public String toString(){
        return "(" + getX1() + ", " + getX2() + ")" ;
    }
}

Main entry :

public class MyExample {
 private Line line = null;
 public MyExample() {
  line = new Line();
  System.err.println("Line implement serializable interface : "
    + (line instanceof Serializable));
 }
 public void showMe() {
  System.out.println("Show all about me ...");
  System.out.println(line.toString());
 }

 public static void main(String[] args) {
  MyExample demo = new MyExample();
  // i want to change the action of show me, but i cannot get line source.
  // so i will trying load-time weaving
  demo.showMe();
 }
}

output :

Line implement serializable interface : true
Show all about me ...
(0, 0)

定义一个aspect :由于1.5之后可以直接支持annotation,所以对于不复杂的aspect定义可以直接使用标签表示。但是目前aspectj支持的标签相对其语法来讲功能要弱些,因此可以根据实际情况选择

@Aspect
public class DynamicPrinter {
 @Pointcut("call(void example.aop.weaver.MyExample.showMe())")
 void printTitle() {}; //此处定义一个切入点--发生调用MyExample的showMe()方法的时刻

 @Before("printTitle()")//此处定义了一个advice,其直接引用到前面定义的切入点
 public void printStartMessage() {
  System.out.println("***************************************");
 }
 @After("printTitle()")//此处定义了一个advice,其直接引用到前面定义的切入点
 public void printOverMessage() {
  printStartMessage();
 }

 @Around("call(String bean.Line.toString())") //此处定义了一个替换方法的advice,由于没有已定义的切入点可以引用,因此写出切入点原始信息call(String bean.line.toString()) 
public String redirectMessage() {
  return "This is a hack action!!!";
 }

 @DeclareParents("bean.Line")
 private Serializable i;
}

编译aj和源文件

由于aspectj提供了ant的task,所以使用比较方便

<taskdef resource="org/aspectj/tools/ant/taskdefs/aspectjTaskdefs.properties">
  <classpath>
   <path refid="My Aop Example.classpath">
   </path>
  </classpath>
 </taskdef>

 <target name="iajc">
  <iajc sourceroots="${basedir}/src" inpath="${basedir}/lib/Line.jar" destdir="${basedir}/bin" classpathref="My Aop Example.classpath" source="1.5" />
 </target>

new output :

Line implement serializable interface : true
***************************************
Show all about me ...
This is a hack action!!!
***************************************

后记 :

把iajc编译后的源文件反编译之后,就可以参考静态织入的源码道理了

public class MyExample
{

    private Line line;
    private static final org.aspectj.lang.JoinPoint.StaticPart ajc$tjp_0;

    public MyExample()
    {
        line = null;
        line = new Line();
        System.err.println((new StringBuilder("Line implement serializable interface : ")).append(line instanceof Serializable).toString());
    }

    public void showMe()
    {
        System.out.println("Show all about me ...");
        Line line1;
        System.out.println(toString_aroundBody1$advice(this, line1 = line, DynamicPrinter.aspectOf()));
    }

    public static void main(String args[])
    {
        MyExample demo = new MyExample();
        demo;
        DynamicPrinter.aspectOf().printStartMessage();
        showMe();
        break MISSING_BLOCK_LABEL_30;
        Throwable throwable;
        throwable;
        DynamicPrinter.aspectOf().printOverMessage();
        throw throwable;
        DynamicPrinter.aspectOf().printOverMessage();
        return;
    }

    private static final String toString_aroundBody0(MyExample myexample, Line line1)
    {
        return line1.toString();
    }

    private static final String toString_aroundBody1$advice(DynamicPrinter this, Line line1, DynamicPrinter dynamicprinter)
    {
        return "This is a hack action!!!";
    }

    static
    {
        Factory factory = new Factory("MyExample.java", Class.forName("example.aop.weaver.MyExample"));
        ajc$tjp_0 = factory.makeSJP("method-call", factory.makeMethodSig("1", "toString", "bean.Line", "", "", "", "java.lang.String"), 26);
    }
}
public class DynamicPrinter
{

    private Serializable i;
    private static Throwable ajc$initFailureCause;
    public static final DynamicPrinter ajc$perSingletonInstance;

    public DynamicPrinter()
    {
    }

    void printTitle()
    {
    }

    public void printStartMessage()
    {
        System.out.println("***************************************");
    }

    public void printOverMessage()
    {
        printStartMessage();
    }

    public String redirectMessage()
    {
        return "This is a hack action!!!";
    }

    public static DynamicPrinter aspectOf()
    {
        if(ajc$perSingletonInstance == null)
            throw new NoAspectBoundException("example.aop.hook.DynamicPrinter", ajc$initFailureCause);
        else
            return ajc$perSingletonInstance;
    }

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

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

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

但是反编译jar中Line.class的时候,发现其结构没有变化,不知为何能够在运行时刻将serializable接口和toString方发织入进去的?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值