触摸屏网站如何做,网站config配置教程,邢台手机网站建设地方,苏州个人网站建设一、什么是 Spring AOP#xff1f; 在介绍 Spring AOP 之前#xff0c;首先要了解一下什么是 AOP #xff1f; AOP #xff08; Aspect Oriented Programming #xff09;#xff1a;面向切面编程#xff0c;它是一种思想#xff0c; 它是对某一类事情的集中处 理 。…一、什么是 Spring AOP 在介绍 Spring AOP 之前首先要了解一下什么是 AOP AOP Aspect Oriented Programming 面向切面编程它是一种思想 它是对某一类事情的集中处 理 。比如用户登录权限的效验没学 AOP 之前我们所有需要判断用户登录的页面中的方法都要各自实现或调用用户验证的方法然而有了 AOP 之后我们只需要在某一处配置一下所有需要判断用户登录页面中的方法就全部可以实现用户登录验证了不再需要每个方法中都写相同的用户登录验证了。 而 AOP 是一种思想而 Spring AOP 是一个框架提供了一种对 AOP 思想的实现它们的关系和 IoC与 DI 类似。 二、为什要用 AOP 想象一个场景我们在做后台系统时除了登录和注册等几个功能不需要做用户登录验证之外其他几乎所有页面调用的前端控制器 Controller 都需要先验证用户登录的状态那这个时候我们要怎么处 理呢 我们之前的处理方式是每个 Controller 都要写一遍用户登录验证然而当你的功能越来越多那么你要写的登录验证也越来越多而这些方法又是相同的这么多的方法就会代码修改和维护的成本。那有没有简单的处理方案呢答案是有的对于这种功能统一且使用的地方较多的功能就可以考虑 AOP 来统一处理了 。 除了统一的用户登录判断之外 AOP 还可以实现 统一日志记录 统一方法执行时间统计 统一的返回格式设置 统一的异常处理 事务的开启和提交等 也就是说 使用 AOP 可以扩充多个对象的某个能力 所以 AOP 可以说是 OOP Object Oriented Programming 面向对象编程的补充和完善。 三、Spring AOP 应该怎么学习呢 Spring AOP 学习主要分为以下 3 个部分 1. 学习 AOP 是如何组成的也就是学习 AOP 组成的相关概念。 2. 学习 Spring AOP 使用。 3. 学习 Spring AOP 实现原理。 下面我们分别来看。 3.1 AOP 组成
3.1.1 切面Aspect 切面 Aspect 由切点 Pointcut 和通知 Advice 组成它既包含了横切逻辑的定义也包括了连接点的定义。 切面是包含了通知、切点和切面的类相当于 AOP 实现的某个功能的集合。 3.1.2 连接点Join Point 应用执行过程中能够插入切面的一个点这个点可以是方法调用时抛出异常时甚至修改字段时。切面代码可以利用这些点插入到应用的正常流程之中并添加新的行为。 连接点相当于需要被增强的某个 AOP 功能的所有方法。 3.1.3 切点Pointcut Pointcut 是匹配 Join Point 的谓词。 Pointcut 的作用就是提供一组规则使用 AspectJ pointcut expression language 来描述来匹配 Join Point给满足规则的 Join Point 添加 Advice 。 切点相当于保存了众多连接点的一个集合如果把切点看成一个表而连接点就是表中一条一条的 数据。 3.1.4 通知Advice 切面也是有目标的 —— 它必须完成的工作。在 AOP 术语中 切面的工作被称之为通知 。 通知定义了切面是什么何时使用其描述了切面要完成的工作还解决何时执行这个工作的问题。 Spring 切面类中可以在方法上使用以下注解会设置方法为通知方法在满足条件后会通知本方法进行调用 前置通知使用 Before通知方法会在目标方法调用之前执行。 后置通知使用 After通知方法会在目标方法返回或者抛出异常后调用。 返回之后通知使用 AfterReturning通知方法会在目标方法返回后调用。 抛异常后通知使用 AfterThrowing通知方法会在目标方法抛出异常后调用。 环绕通知使用 Around通知包裹了被通知的方法在被通知的方法通知之前和调用之后执行自定义的行为。 切点相当于要增强的方法。 AOP 整个组成部分的概念如下图所示以多个页面都要访问用户登录权限为例 3.2 Spring AOP 实现 接下来我们使用 Spring AOP 来实现一下 AOP 的功能完成的目标是拦截所有 UserController 里面的方法每次调用 UserController 中任意一个方法时都执行相应的通知事件。 Spring AOP 的实现步骤如下 1. 添加 Spring AOP 框架支持。 2. 定义切面和切点。 3. 定义通知。 3.2.1 添加 AOP 框架支持 在 pom.xml 中添加如下配置 !-- https://mvnrepository.com/artifact/org.springframework.boot/spring-bootstarter-aop --
dependency
groupIdorg.springframework.boot/groupId
artifactIdspring-boot-starter-aop/artifactId
/dependency 3.2.2 定义切面和切点 切点指的是具体要处理的某一类问题比如用户登录权限验证就是一个具体的问题记录所有方法的执行日志就是一个具体的问题切点定义的是某一类问题。 Spring AOP 切点的定义如下在切点中我们要定义拦截的规则具体实现如下 import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
Aspect // 表明此类为一个切面
Component
public class UserAspect {
// 定义切点这里使用 AspectJ 表达式语法
Pointcut(execution(* com.example.demo.controller.UserController.*(..)))
public void pointcut(){ }
} 其中 pointcut 方法为空方法它不需要有方法体此方法名就是起到一个 “ 标识 ” 的作用标识下面的通知方法具体指的是哪个切点因为切点可能有很多个。 切点表达式说明 AspectJ 支持三种通配符 * 匹配任意字符只匹配一个元素包类或方法方法参数。 * .. 匹配任意字符可以匹配多个元素 在表示类时必须和 * 联合使用。 表示按照类型匹配指定类的所有类必须跟在类名后面如 com.cad.Car ,表示继承该类的所有子类包括本身。 切点表达式由切点函数组成其中 execution() 是最常用的切点函数用来匹配方法语法为 execution( 修饰符 返回类型 包 . 类 . 方法 ( 参数 ) 异常 ) 修饰符 和 异常 可以省略。 表达式示例 3.2.3 定义相关通知 通知定义的是被拦截的方法具体要执行的业务比如用户登录权限验证方法就是具体要执行的业务。 Spring AOP 中可以在方法上使用以下注解会设置方法为通知方法在满足条件后会通知本方法进行调用 前置通知使用Before通知方法会在目标方法调用之前执行。 后置通知使用After通知方法会在目标方法返回或者抛出异常后调用。 返回之后通知使用AfterReturning通知方法会在目标方法返回后调用。 抛异常后通知使用AfterThrowing通知方法会在目标方法抛出异常后调用。 环绕通知使用Around通知包裹了被通知的方法在被通知的方法通知之前和调用之后执行自 定义的行为。 具体实现如下 import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
Aspect
Component
public class UserAspect {
// 定义切点方法
Pointcut(execution(* com.example.demo.controller.UserController.*(..)))
public void pointcut(){ }
// 前置通知
Before(pointcut())
public void doBefore(){
System.out.println(执行 Before 方法);
}
// 后置通知
After(pointcut())
public void doAfter(){
System.out.println(执行 After 方法);
}
// return 之前通知
AfterReturning(pointcut())
public void doAfterReturning(){
System.out.println(执行 AfterReturning 方法);
}
// 抛出异常之前通知
AfterThrowing(pointcut())
public void doAfterThrowing(){
System.out.println(执行 doAfterThrowing 方法);
}
// 添加环绕通知
Around(pointcut())
public Object doAround(ProceedingJoinPoint joinPoint){
Object obj null;
System.out.println(Around 方法开始执行);
try {
// 执行拦截方法
obj joinPoint.proceed();
} catch (Throwable throwable) {
throwable.printStackTrace();
}
System.out.println(Around 方法结束执行);
return obj;
}
} 经过以上的代码我们就能实现 Spring AOP 了。 3.3 Spring AOP 实现原理 Spring AOP 是构建在 动态代理 基础上因此 Spring 对 AOP 的支持局限于方法级别的拦截 。 Spring AOP 支持 JDK Proxy 和 CGLIB 方式实现动态代理。默认情况下实现了接口的类使用 AOP 会基于 JDK 生成代理类没有实现接口的类会基于 CGLIB 生成代理类。 织入Weaving代理的生成时机 织入是把切面应用到目标对象并创建新的代理对象的过程切面在指定的连接点被织入到目标对象中。在目标对象的生命周期里有多个点可以进行织入 编译期切面在目标类编译时被织入。这种方式需要特殊的编译器。AspectJ的织入编译器就是以这种方式织入切面的。 类加载器切面在目标类加载到JVM时被织入。这种方式需要特殊的类加载器ClassLoader,它可以在目标类被引入应用之前增强该目标类的字节码。AspectJ5的加载时织入load-time weaving. LTW就支持以这种方式织入切面。 运行期切面在应用运行的某一时刻被织入。一般情况下在织入切面时AOP容器会为目标对象动态创建一个代理对象。SpringAOP就是以这种方式织入切面的。 动态代理 此种实现在设计模式上称为动态代理模式在实现的技术手段上都是在 class 代码运行期动态的织 入字节码。 我们学习 Spring 框架中的AOP主要基于两种方式JDK 及 CGLIB 的方式。这两种方式的代理目标都是被代理类中的方法在运行期动态的织入字节码生成代理类。 CGLIB是Java中的动态代理框架主要作用就是根据目标类和方法动态生成代理类。 Java中的动态代理框架几乎都是依赖字节码框架如 ASMJavassist 等实现的。 字节码框架是直接操作 class 字节码的框架。可以加载已有的class字节码文件信息修改部分信息或动态生成一个 class。 JDK 动态代理实现 JDK 实现时先通过实现 InvocationHandler 接口创建方法调用处理器再通过 Proxy 来创建代理类。 以下为代码实现 import org.example.demo.service.AliPayService;
import org.example.demo.service.PayService;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
//动态代理使用JDK提供的apiInvocationHandler、Proxy实现此种方式实现要求被代理类必
须实现接口
public class PayServiceJDKInvocationHandler implements InvocationHandler {
//目标对象即就是被代理对象
private Object target;
public PayServiceJDKInvocationHandler( Object target) {
this.target target;
}
//proxy代理对象
Override
public Object invoke(Object proxy, Method method, Object[] args) throws
Throwable {
//1.安全检查
System.out.println(安全检查);
//2.记录日志
System.out.println(记录日志);
//3.时间统计开始
System.out.println(记录开始时间);
//通过反射调用被代理类的方法
Object retVal method.invoke(target, args);
//4.时间统计结束
System.out.println(记录结束时间);
return retVal;
}
public static void main(String[] args) {
PayService target new AliPayService();
//方法调用处理器
InvocationHandler handler
new PayServiceJDKInvocationHandler(target);
//创建一个代理类通过被代理类、被代理实现的接口、方法调用处理器来创建
PayService proxy (PayService) Proxy.newProxyInstance(
target.getClass().getClassLoader(),
new Class[]{PayService.class},
handler
);
proxy.pay();
}
} CGLIB 动态代理实现 import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import org.example.demo.service.AliPayService;
import org.example.demo.service.PayService;
import java.lang.reflect.Method;
public class PayServiceCGLIBInterceptor implements MethodInterceptor {
//被代理对象
private Object target;
public PayServiceCGLIBInterceptor(Object target){
this.target target;
}
Override
public Object intercept(Object o, Method method, Object[] args, MethodProxy
methodProxy) throws Throwable {
//1.安全检查
System.out.println(安全检查);
//2.记录日志
System.out.println(记录日志);
//3.时间统计开始
System.out.println(记录开始时间);
//通过cglib的代理方法调用
Object retVal methodProxy.invoke(target, args);
//4.时间统计结束
System.out.println(记录结束时间);
return retVal;
}
public static void main(String[] args) {
PayService target new AliPayService();
PayService proxy (PayService) Enhancer.create(target.getClass(),new
PayServiceCGLIBInterceptor(target));
proxy.pay();
}
} JDK 和 CGLIB 的区别 1. JDK 实现要求被代理类必须实现接口之后是通过 InvocationHandler 及 Proxy 在运行时动态的在内存中生成了代理类对象该代理对象是通过实现同样的接口实现类似静态代理接口实现的方式只是该代理类是在运行期时动态的织入统一的业务逻辑字节码来完成。 2. CGLIB 实现被代理类可以不实现接口是通过继承被代理类在运行时动态的生成代理类对象。 总结 AOP 是对某方面能力的统一实现它是一种实现思想 Spring AOP 是对 AOP 的具体实现 Spring AOP 可通过 AspectJ 注解的方式来实现 AOP 的功能 Spring AOP 的实现步骤是 1. 添加 AOP 框架支持。 2. 定义切面和切点。 3. 定义通知。 Spring AOP 是通过动态代理的方式在运行期将 AOP 代码织入到程序中的它的实现方式有两种 JDK Proxy 和 CGLIB 。