1. AOP
面向切面编程(Aspect Oriented Programming),通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,调高程序的可重用性,提高开发效率。
即可以在不修改原有功能的前提下,在执行某功能时给其添加新的功能。
这里以登录为例:
-
原有登录功能
-
在原有登录功能的前提下,新增鉴权功能:
1.1 实现原理
AOP使用动态代理方式实现。
-
有接口:JDK动态代理实现。
这里依然使用登录来模拟。
接口类:public interface UserService { void login(); }
实现类:
public class UserServiceImpl implements UserService{ @Override public void login() { // 模拟已经实现登录功能 System.out.println("登录成功"); } }
代理过程: 创建接口实现类的代理对象来增强对象的方法,通过代理对象来实现增强的功能。
- 无接口:CGLIB动态代理。
创建被代理类的子类代理对象从而实现方法增强。
1.1.1 JDK动态代理实现
- 接口
/**
* @Description
* @date 2022/5/28 20:00
*/
public interface UserService {
void login();
}
- 实现类
/**
* @Description
* @date 2022/5/28 20:00
*/
public interface UserService {
void login();
}
- 代理实现
/**
* @Description JDK 动态代理实现类
* @date 2022/5/28 19:59
*/
public class JdkMain {
public static void main(String[] args) {
// 接口数组
Class[] interfaces = {UserService.class};
// 定义被增强的接口
UserService user = (UserService) Proxy.newProxyInstance(JdkMain.class.getClassLoader(), interfaces, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 实现增强过程:
// 1. 创建当前接口的实现类对象
UserServiceImpl userService = new UserServiceImpl();
// 2. 被增强方法执行之前
System.out.println("执行之前 - before" + method.getName());
// 3. 执行被增强方法
Object obj = method.invoke(userService);
// 4. 执行增强方法之后执行
System.out.println("执行之后 - after" + method.getName());
return obj;
}
});
user.login();
}
}
1.2 AOP常见术语
- 连接点:可以被被增强的方法;
- 切入点:实际被增强的方法;
- 通知(增强):增强实现的功能;
类型:- 前置通知:方法前面执行,对应:
@Before
; - 后置通知:方法后面执行,对应
@AfterReturning
; - 环绕通知:方法前后都执行,对应
@Around
; - 异常通知:方法出现异常时执行,对应
@AfterThrowing
; - 最终通知:无论是否存在异常都会执行,对应
@After
。
- 前置通知:方法前面执行,对应:
- 切面:把通知应用到切入点的过程。
1.3 AspectJ
不属于Spring的组成部分,是一个独立的AOP框架,但通常与Spring连用来实现AOP。
- 依赖
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>5.2.8.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.8.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.2.8.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>5.2.8.RELEASE</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.8</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.2.8.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.7</version>
</dependency>
</dependencies>
- 切入点表达式:声明对类和方法进行增强。
语法结构:execution([权限修饰符][返回类型][全路径类名][方法名称]([参数列表]))
。- 返回类型可以省略;
*
可以表示全部;..
表示参数。
1.4 注解实现
- 配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation=
"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<context:component-scan base-package="com.jm.spring.*"/>
<aop:aspectj-autoproxy/>
</beans>
- 被增强类
@Component
public class User {
public void testVoid(){
System.out.println("void");
}
}
- 代理类:
/**
* @Description 代理增强类
* @date 2022/5/28 20:44
*/
@Component
@Aspect
@Order(1) // 指定优先级,越小优先级越高
public class UserProxy {
// 定义切入点
@Pointcut(value = "execution(* com.jm.spring.AOP.annotation.User.testVoid())")
public void userPoint(){
}
@Before("userPoint()")
public void before(){
System.out.println("前置增强");
}
@After("userPoint()")
public void after(){
System.out.println("最终增强");
}
@AfterReturning("userPoint()")
public void afterReturning(){
System.out.println("后置增强");
}
@AfterThrowing("userPoint()")
public void afterThrowing(){
System.out.println("异常增强");
}
@Around("userPoint()")
public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("环绕增强 - 前");
// 执行被增强方法
proceedingJoinPoint.proceed();
System.out.println("环绕增强 - 后");
return null;
}
}
- 测试类
/**
* @Description
* @date 2022/5/28 20:48
*/
public class AOPMain {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("scan.xml");
User user = context.getBean("user", User.class);
user.testVoid();
}
}
1.5 xml方式
没学,不看,用不到。