spectJ是Java的一个AOP框架,可以单独使用,也可以整合到其它框架中。

单独使用AspectJ时需要使用专门的编译器ajc。

java的编译器是javac,AspectJ的编译器是ajc,aj是首字母缩写,c即compiler。

此处介绍如何单独使用AspectJ。


  

下载AspectJ所需的jar包

https://www.eclipse.org/aspectj/downloads.php

下载得到的是一个jar包,不能直接使用,解压,得到3个jar包:

AspectJ-LMLPHP

单独使用AspectJ时,只需添加aspectjrt.jar。


IDEA环境配置

1、安装插件

AspectJ-LMLPHP

2、使用专门的编译器

AspectJ-LMLPHP


Demo

(1)新建Java项目,添加aspectjrt.jar。只添加这一个jar包就ok。

(2)新建包com.chy.dao,包下新建接口UserDao、实现类UserDaoImpl:

public interface UserDao {
    public void addUser(int i,String str);
    public void deleteUser();
}
public class UserDaoImpl implements UserDao {
    @Override
    public void addUser(int i,String str) {
        System.out.println("正在添加用户...");
    }

    @Override
    public void deleteUser() {
        System.out.println("正在删除用户...");
    }
}

(3)新建包com.chy.aspect,包下新建类UserDaoAspect:

//需要用@Aspect标注
@org.aspectj.lang.annotation.Aspect
public class UserDaoAspect {
    /*
    配置全局切入点
    返回值类型  类|接口名.方法名(参数表)
    参数表可使用具体类型,比如(int,String),也可用(..)表示任意类型、个数的参数
     */
    @Pointcut("execution(* com.chy.dao.UserDao.*(..))")
    private void pointCut(){}

    /*
    前置通知
    可以引用全局切入点,也可以现配:
    @Before("execution(void com.chy.dao.UserDao.*(..))")
     */
    @Before("pointCut()")
    public void before(){
        System.out.println("正在执行前置通知...");
    }

    //后置通知
    @After("pointCut()")
    public void after(){
        System.out.println("正在执行后置通知...");
    }

    //返回通知
    @AfterReturning("pointCut()")
    public void afterReturning(){
        System.out.println("正在执行返回通知...");
    }

    //异常通知
    @AfterThrowing("pointCut()")
    public void  afterThrowing(JoinPoint point){
        System.out.println("正在执行异常通知...");

        //获取目标对象,返回值是Object类型
        Object target = point.getTarget();

        //目标方法名,String
        System.out.println("目标方法:"+point.getSignature());

        //需要转换一下才能得到具体的实参
        List<Object> args = Arrays.asList(point.getArgs());
        System.out.println("实参表:"+args);
    }

}

方法名任意,因为要用注解标注此方法是用来实现哪种通知的。

可传入一个JointPoint类型的参数,表示连接点。

环绕通知:

/*
    环绕通知
    需要传入一个ProceedingJoinPoint类型的参数,用于调用目标方法。
    如果要代理多个方法,返回值最好声明为Object,因为多个方法的返回值类型可能不相同
    */
    @Around("pointCut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        //前增强
        System.out.println("正在执行前增强...");
        //调用目标方法
        Object obj = point.proceed();
        //后增强
        System.out.println("正在执行后增强...");
        //返回目标方法的返回值
        return obj;
    }

环绕通知与其它通知有重叠,不能一起使用。

(4)使用

UserDao user=new UserDaoImpl();
user.addUser();

AspectJ增强的是方法,调用方法时,会自动调用对应的通知来增强。


切面的另一种写法(了解)

包下新建Aspect:

AspectJ-LMLPHP

//注意是aspect,不是class
public aspect UserDaoAspect {
    //配置全局切入点
    @Pointcut("execution(* com.chy.dao.UserDao.*(..))")
    private void pointCut(){}

    /*
    前置通知
    可以使用引用切入点,也可以现配:
    before():execution(void com.chy.dao.UserDao.*(..)){     }
     */
    before():pointCut(){
        System.out.println("正在执行前置通知...");
    }

    //后置通知
    after():pointCut(){
        System.out.println("正在执行后置通知...");
    }
}

方法名是固定的:before、after,都是关键字,before表示前置通知,after表示后置通知。

此种方式很不好用,不推荐。

08-28 11:35