aspectj入门

概述在学习spring aop过程当中,发现有个怎么都绕不过去的坎,就是AspectJ的使用。少了这一部分,一些spring aop的源码总以为少了点什么,看不大懂。因此接下来会写几篇关于AspectJ的入门使用。
安装示例代码一、首先,下载最新的稳定版本(我本身下的是AspectJ 1.9.2, Released 24 Oct 2018 版本)aspectj-1.9.2.jar
http://www.eclipse.org/aspect...
二、安装
aspectJ的安装很简单,运行 java -jar aspectj-1.9.2.jar 而后选下jdk路径及最终aspectj要安装(AspecJ安装路径)到哪里就好
三、安装最后,会提示你要配置环境变量了php

按照环境配下PATH变量 和 CLASSPATH变量就好
export PATH=${JAVA_HOME}/bin:$PATH:/Users/hdj/software/aspectj/binexport CLASSPATH=${CLASSPATH}:/Users/hdj/software/aspectj/lib/aspectjrt.jar四、编译代码示例
进入 ${aspectJ 安装路径}/doc/examples
执行   ajc -argfile telecom/billing.lst
五、运行示例
java telecom.BillingSimulation六、运行结果
[Items [id=1, name=台式机, price=3000.0, pic=null, createtime=Tue Oct 03 23:22:36 CST 2017, detail=该电脑质量很是好!!!!111], Items [id=2, name=笔记本, price=7000.0, pic=null, createtime=Tue Oct 03 23:23:06 CST 2017, detail=笔记本性能好,质量好!!!!!], Items [id=3, name=背包, price=1200.0, pic=null, createtime=Tue Oct 03 23:23:21 CST 2017, detail=名牌背包,容量大质量好!!!!]]java

示例总结简单总结下:
1)安装配置aspectJ环境
2)使用 ajc -argfile  编译类
3)运行编译后的字节码
上述的例子是aspectJ 官方的例子 ,为了说明如何使用aspectJ的使用,咱们看另外一个例子
另外一个例子知道如何运行aspectJ给的官方示例后,咱们继续学习官网给的另外一个例子,例子路径
${aspectJ 路径}/doc/examples/tjp/Demo.java
咱们先来看看原始类
public class Demo {    static Demo d;    public static void main(String[] args){        new Demo().go();    }    void go(){        d = new Demo();        //调用foo方法        d.foo(1,d);        //调用bar方法        System.out.println(d.bar(new Integer(3)));    }    void foo(int i, Object o){        //打印foo        System.out.println("Demo.foo(" + i + ", " + o + ")n");    }    String bar (Integer j){        System.out.println("Demo.bar(" + j + ")n");        return "Demo.bar(" + j  + ")";    }}再来看看一个随着Demo.java一块儿被 ajc编译的特殊的类GetInfo.java:
package tjp;import org.aspectj.lang.JoinPoint;import org.aspectj.lang.reflect.CodeSignature;aspect GetInfo {  static final void println(String s){ System.out.println(s); }    pointcut goCut(): cflow(this(Demo) && execution(void go()));  pointcut demoExecs(): within(Demo) && execution( (..));  Object around(): demoExecs() && !execution(* go()) && goCut() {     println("Intercepted message: " +         thisJoinPointStaticPart.getSignature().getName());     println("in class: " +         thisJoinPointStaticPart.getSignature().getDeclaringType().getName());     printParameters(thisJoinPoint);     println("Running original method: n" );     Object result = proceed();     println("  result: " + result );     return result;  }  // 打印参数  static private void printParameters(JoinPoint jp) {     println("Arguments: " );     Object[] args = jp.getArgs();     String[] names = ((CodeSignature)jp.getSignature()).getParameterNames();     Class[] types = ((CodeSignature)jp.getSignature()).getParameterTypes();     for (int i = 0; i < args.length; i++) {        println("  "  + i + ". " + names +            " : " +            types.getName() +            " = " +            args);     }  }}这里和spring aop的使用不少方面很是相似,最后执行的结果以下:spring

这里说明一下几点:
GetInfo.java 含有的特殊关键词GetInfo.java含有不少特殊的关键词,这些关键词java是没法识别的,须要经过ajc编译才能织入到字节码中
切入点表达式spring的切入点表达式咱们很是熟悉,使用aspectJ时,也须要配置切入点,须要配置有哪些方法须要被切入
//表示Demo类的go方法调用过程当中的方法须要被加强pointcut goCut(): cflow(this(Demo) && execution(void go()));//每个Demo类定义的方法pointcut demoExecs(): within(Demo) && execution( (..));// 因为 goCut() 这个切入点还包含go()方法本身的调用,所以须要把本身给排掉Object around(): demoExecs() && !execution(* go()) && goCut();可能会问,既然为啥要同时配置
demoExecs() 以及 !execution(* go()) && goCut() 单独有一个不够么?
1)demoExecs()表示拦截Demo类的全部方法,若是不加后面的限制,会同时拦截main方法,以及go()方法
2)若是只有!execution(* go()) && goCut(),直接编译时候会报错(warning)执行后直接会报java.lang.StackOverflowError
3)若是只有!execution(* go()) && goCut(),能够执行,可是只会拦截go方法
thisJoinPointStaticPart 和 thisJoinPointthisJoinPoint 包含了关于当前切入点的一些信息(经过反射获取的)
thisJoinPointStaticPart 包含一些静态信息,参考官方文档
经过配置切入点,咱们实现了不改变Demo.java源码的前提下,往Demo.java方法的先后插入了一段代码。
与Spring 切面写法的对比对比下以前在学习Spring时候,配置的切面
//声明这是一个组件@Component//声明这是一个切面Bean@Aspect@Slf4jpublic class ServiceAspect {    //配置切入点,该方法无方法体,主要为方便同类中其余方法使用此处配置的切入点    @Pointcut("execution( com.hdj.learn.spring.aop.service..(..))")    public void aspect() {    }    /      配置前置通知,使用在方法aspect()上注册的切入点      同时接受JoinPoint切入点对象,能够没有该参数     /    @Before("aspect()")    public void before(JoinPoint joinPoint) {        log.info("before " + joinPoint);    }    //配置后置通知,使用在方法aspect()上注册的切入点    @After("aspect()")    public void after(JoinPoint joinPoint) {        log.info("after " + joinPoint);    }    //配置环绕通知,使用在方法aspect()上注册的切入点    @Around("aspect()")    public void around(JoinPoint joinPoint) {        long start = System.currentTimeMillis();        try {            ((ProceedingJoinPoint) joinPoint).proceed();            long end = System.currentTimeMillis();            log.info("around " + joinPoint + "tUse time : " + (end - start) + " ms!");        } catch (Throwable e) {            long end = System.currentTimeMillis();            log.info("around " + joinPoint + "tUse time : " + (end - start) + " ms with exception : " + e.getMessage());        }    }    //配置后置返回通知,使用在方法aspect()上注册的切入点    @AfterReturning("aspect()")    public void afterReturn(JoinPoint joinPoint) {        log.info("afterReturn " + joinPoint);    }    //配置抛出异常后通知,使用在方法aspect()上注册的切入点    @AfterThrowing(pointcut = "aspect()", throwing = "ex")    public void afterThrow(JoinPoint joinPoint, Exception ex) {        log.info("afterThrow " + joinPoint + "t" + ex.getMessage());    }}其实很是相似,有切面、有通知、有目标类等等,切入点的表达式也很是相似。
总结下初步了解了aspectJ的使用,咱们能够了解如下几点:
1)aspectJ的使用是在编译期,经过特殊的编译器能够在不改变代码的前提下织入代码(固然能不能在运行期,我尚未确认)
2)aspectJ的使用,也是配置切入点、通知eclipse

相关文章
相关标签/搜索