Spring AOP与AspectJ
概念
AOP的全称为Aspect-Oriented Programming,即面向切面编程。
想象你是汉堡店的厨师,每一份汉堡都有好几层,这每一层都可以视作一个切面。现在有一位顾客想要品尝到不同风味肉馅的汉堡,如果按照传统的方式,你需要做多个汉堡,每个汉堡只有肉馅是不一样的,但是你每做一个汉堡都要重新制作面包。而聪明的厨师只需做一个汉堡,仅将肉饼那一层分成不同口味的几个区域,这样你就不需要再重复制作面包了。
对于程序员也是一样的,有多少个接口就要写或复制多少代码那一定是无法忍受的,我们只想关心不同的那部分。
尽管想通俗来讲,但是还是要去熟悉专业的概念:
Aspect
:切面,类似于Java类声明,里面会有Pointcut
和Advice
Joint point
:连接点,在程序执行过程中某个阶段点Pointcut
:切入点,切面与程序流的交叉点,往往此处需要处理Advice
:通知或增强,在切入点处所要执行的代码。可以理解为切面类中的方法。Target object
:目标对象,指所有被通知的对象。Proxy
:代理,将通知应用到目标对象后,被动态创建的对象。Weaving
:织入,将切面代码插到目标对象上,从而生成代理对象的过程。
别担心,我们之后会通过代码来慢慢理解。
AOP的实现
AOP的实现主要分为静态代理和动态代理,在本教程中静态代理我们用AspectJ
,而动态代理用Spring AOP
。
静态代理在编译期就确定了代理类,而动态代理需要靠反射机制动态生成代理类。
Spring AOP动态代理有两种实现方式:一种是JDK动态代理,这种方式需要接口;另一种是CGLib动态代理,这种方式不依赖接口。
有了以上的知识,我们开始写代码,首先新创建一个Maven项目top.cairbin.test2
,如果你不会请回去看之前的章节。
然后在pom.xml
的<dependencies></dependencies>
之间添加依赖包
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.16</version>
</dependency>
<!-- https://mvnrepository.com/artifact/cglib/cglib -->
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.4</version>
</dependency>
我们去实现一个IUser
接口,要求接口内有两个方法void addUser()
和void deleteUser()
package top.cairbin.test2;
public interface IUser {
void addUser();
void deleteUser();
}
接下来定义一个实现该接口的User
类
package top.cairbin.test2;
public class User implements IUser{
@Override
public void addUser() {
System.out.println("进行增加用户操作!");
}
@Override
public void deleteUser() {
System.out.println("进行删除用户操作!");
}
}
我们定义一个切面类,该类中的两个方法void check()
和void log()
分别模拟权限检查和日志记录功能。
切面类如下所示
package top.cairbin.test2;
public class MyAspect {
public void check() {
System.out.println("正在模拟权限认证");
}
public void log() {
System.out.println("正在模拟日志记录");
}
}
JDK动态代理
接下来创建代理类JdkProxy
,这个类实现了JDK动态代理的InvocationHandler
接口,并实现代理方法。
package top.cairbin.test2;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class JdkProxy implements InvocationHandler{
private final IUser user;
public JdkProxy(IUser user) {
this.user = user;
}
<