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时,只需添加aspectjrt.jar。
IDEA环境配置
1、安装插件
2、使用专门的编译器
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:
//注意是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表示后置通知。
此种方式很不好用,不推荐。