使用 AspectJ 实现 AOP
AspectJ 下载地址:点击这里;
下载完成之后,得到一个 *.jar 文件,进入该文件所在的路径,执行命令:
java -jar *.jar
这样会出现一个由 java 编写的安装程序,过程都很简单,安装结束。
其中安装路径包含 /bin/、/lib/ 等文件夹,需要配置 CLASSPATH、PATH 环境变量。
模拟业务方法:
public class UserService {
public int login(String username, String password) {
System.out.println("执行 login() 方法");
return 1;
}
}
主程序模拟调用业务方法:
public class AspectJTest {
public static void main(String[] args) {
UserService userService = new UserService();
userService.login("root", "root");
}
}
考虑这种情况:假设客户要求在执行所有业务方法之前先执行权限检查,如果使用传统的编程方式,开发者必须先定义一个权限检查的方法,然后编辑每个业务方法,向其中增加调用权限检查的方法,容易引发新的错误,而且维护成本大。
下面使用 AspectJ 的 AOP 支持,添加如下 Java 类:
public aspect AuthAspect {
before() : execution(* *.*(..)) {
System.out.println("模拟进行权限检查...");
}
}
ps:这并不是一个 Java 类,需要使用到上面 aspectj 安装路径下 /bin/ajc.bat 脚本来编译,这个脚本是 javac.exe 的增强版。
接着,使用 AspectJ 目录下 /bin/ajc.bat 编译:
ajc *.java -encoding UTF-8
ps:所有文件都需要使用 ajc 来进行编译。如果你只是将 aspect 文件使用 ajc 编译,其他使用 javac 来编译是没有效过的;甚至需要使用 *.java 一起进行编译,单独使用 ajc 编译会产生奇怪的错误。
执行如下命令:
java AspectJTest
控制台输出:
模拟进行权限检查...
模拟进行权限检查...
执行 login() 方法
ps:执行了两次权限检查是因为使用了 *,使切面方法自己也算作切入点。
如果需要在执行所有业务方法之后增加记录日志的功能,添加如下类:
public aspect LogAspect {
/* 声明切入点,简化切入点表达式 */
pointcut logPointcut() : execution(* *.*(..));
after() : logPointcut() {
System.out.println("模拟记录日志...");
}
}
编译之后,控制台输出:
模拟进行权限检查...
模拟进行权限检查...
执行 login() 方法
模拟记录日志...
模拟记录日志...
如果需要在业务组件的所有业务方法之前启动事务,并在方法执行结束时关闭事务,添加如下类:
public aspect TxAspect {
Object around() : call(* UserService.login(..)) {
System.out.println("模拟开启事务");
Object rvt = proceed();
System.out.println("模拟结束事务");
return rvt;
}
}
ps:proceed() 代表回调原来的目标方法,这样位于 proceed() 之前的代码就会被添加在目标方法之前,位于 proceed() 方法之后的代码就会被添加在目标方法之后;而且这里不可以再使用 * 通配符匹配所有方法,否则方法自己也会将自己看作切入点,进而产生无限递归,最后栈溢出。
编译之后,控制台输出:
模拟进行权限检查...
模拟开启事务
模拟进行权限检查...
执行 login() 方法
模拟记录日志...
模拟结束事务
模拟记录日志...