首页 > 其他分享 >Spring AOP(实现,动态原理)详解版

Spring AOP(实现,动态原理)详解版

时间:2024-06-08 16:58:25浏览次数:24  
标签:Object Spring AOP 代理 详解 通知 import public

Spring AOP

1.什么是AOP?

AOP是⾯向切⾯编程切⾯。
什么是⾯向特定⽅法编程呢? ⽐如 登录校验拦截器, 就是对"登录校验"这类问题的统⼀处理. 所以, 拦截器也是AOP的⼀种应⽤. AOP是⼀种思想, 拦截器是AOP思想的⼀种实现. AOP是⼀种思想, 是对某⼀类事情的集中处理

1.1引入AOP依赖

在pom.xml⽂件中添加配置

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>

1.2编写AOP程序

记录Controller中每个⽅法的执⾏时间

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
@Slf4j
@Aspect
@Component
public class TimeAspect {
/**
* 记录⽅法耗时
*/
@Around("execution(* com.example.demo.controller.*.*(..))")
public Object recordTime(ProceedingJoinPoint pjp) throws Throwable {
//记录⽅法执⾏开始时间
long begin = System.currentTimeMillis();
//执⾏原始⽅法
Object result = pjp.proceed();
//记录⽅法执⾏结束时间
long end = System.currentTimeMillis();
//记录⽅法执⾏耗时
log.info(pjp.getSignature() + "执⾏耗时: {}ms", end - begin);
return result;
}

结论:
1.@Aspect: 标识这是⼀个切面类
2. @Around: 环绕通知, 在⽬标⽅法的前后都会被执⾏. 后⾯的表达式表⽰对哪些⽅法进⾏增强.
3. ProceedingJoinPoint.proceed() 让原始⽅法执⾏

2.Spring AOP核⼼概念

2.1 切点(Pointcut)

切点(Pointcut), 也称之为"切⼊点"
Pointcut 的作⽤就是提供⼀组规则, 告诉程序对哪些⽅法来进⾏功能增强.
在这里插入图片描述

2.2连接点(Join Point)

满⾜切点表达式规则的⽅法, 就是连接点. 也就是可以被AOP控制的⽅法
以⼊⻔程序举例, 所有 com.example.demo.controller 路径下的⽅法, 都是连接点

2.3通知(Advice)

通知就是具体要做的⼯作, 指哪些重复的逻辑,也就是共性功能(最终体现为⼀个⽅法)
⽐如上述程序中记录业务⽅法的耗时时间, 就是通知.

2.4 切⾯(Aspect)

切⾯(Aspect) = 切点(Pointcut) + 通知(Advice)
通过切⾯就能够描述当前AOP程序需要针对于哪些⽅法, 在什么时候执⾏什么样的操作.
在这里插入图片描述

3.通知类型

3.1顺序

Spring中AOP的通知类型有以下⼏种:
• @Around: 环绕通知, 此注解标注的通知⽅法在⽬标⽅法前, 后都被执⾏
• @Before: 前置通知, 此注解标注的通知⽅法在⽬标⽅法前被执⾏
• @After: 后置通知, 此注解标注的通知⽅法在⽬标⽅法后被执⾏, ⽆论是否有异常都会执⾏
• @AfterReturning: 返回后通知, 此注解标注的通知⽅法在⽬标⽅法后被执⾏, 有异常不会执⾏
• @AfterThrowing: 异常后通知, 此注解标注的通知⽅法发⽣异常后执⾏
在这里插入图片描述

程序正常运⾏的情况下, @AfterThrowing 标识的通知⽅法不会执⾏
@Around 标识的通知⽅法包含两部分, ⼀个"前置逻辑", ⼀个"后置逻辑".其中"前置逻辑" 会先于 @Before 标识的通知⽅法执⾏, “后置逻辑” 会晚于 @After 标识的通知⽅法执⾏
在这里插入图片描述

@Slf4j
@Aspect
@Component
public class AspectDemo {
//定义切点(公共的切点表达式)
@Pointcut("execution(* com.example.demo.controller.*.*(..))")
private void pt(){}
//前置通知
@Before("pt()")
public void doBefore() {
//...代码省略
}
//后置通知
@After("pt()")
public void doAfter() {
//...代码省略
}
//返回后通知
@AfterReturning("pt()")
public void doAfterReturning() {
//...代码省略
}
//抛出异常后通知
@AfterThrowing("pt()")
public void doAfterThrowing() {
//...代码省略
}
//添加环绕通知
@Around("pt()")
public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
//...代码省略
}
}

当切点定义使⽤private修饰时, 仅能在当前切⾯类中使⽤, 当其他切⾯类也要使⽤当前切点定义时, 就需要把private改为public. 引⽤⽅式为: 全限定类名.⽅法名()

@Slf4j
@Aspect
@Component
public class AspectDemo2 {
//前置通知
@Before("com.example.demo.aspect.AspectDemo.pt()")
public void doBefore() {
log.info("执⾏ AspectDemo2 -> Before ⽅法");
}

3.2切⾯优先级 @Order

在这里插入图片描述
@Before 通知:数字越⼩先执⾏
@After 通知:数字越⼤先执⾏

@Order 控制切⾯的优先级, 先执⾏优先级较⾼的切⾯, 再执⾏优先级较低的切⾯, 最终执⾏⽬标⽅法.

3.3 ⾃定义注解 @MyAspect

在这里插入图片描述

import java.lang.annotation.ElementType;
2 import java.lang.annotation.Retention;
3 import java.lang.annotation.RetentionPolicy;
4 import java.lang.annotation.Target;
5
6 @Target(ElementType.METHOD)
7 @Retention(RetentionPolicy.RUNTIME)
8 public @interface MyAspect {
9 
10 }

1.@Target 标识了 Annotation 所修饰的对象范围, 即该注解可以⽤在什么地⽅.
常⽤取值:
ElementType.TYPE: ⽤于描述类、接⼝(包括注解类型) 或enum声明
ElementType.METHOD: 描述⽅法
ElementType.PARAMETER: 描述参数
ElementType.TYPE_USE: 可以标注任意类型
2. @Retention 指Annotation被保留的时间⻓短, 标明注解的⽣命周期

4. Spring AOP 原理

Spring AOP 是基于动态代理来实现AOP的
⽣活中的代理
• 艺⼈经纪⼈: ⼴告商找艺⼈拍⼴告, 需要经过经纪⼈,由经纪⼈来和艺⼈进⾏沟通.
• 房屋中介: 房屋进⾏租赁时, 卖⽅会把房屋授权给中介, 由中介来代理看房, 房屋咨询等服务.
实现
1.Subject: 业务接⼝类. 可以是抽象类或者接⼝(不⼀定有)
2. RealSubject: 业务实现类. 具体的业务执⾏, 也就是被代理对象.
3. Proxy: 代理类. RealSubject的代理.

5 动态代理怎么实现

1. JDK动态代理
2. CGLIB动态代理

5.1 JDK 动态代理类实现步骤

  1. 定义⼀个接⼝及其实现类(静态代理中的 HouseSubject 和 RealHouseSubject )
  2. ⾃定义 InvocationHandler 并重写 invoke ⽅法,在 invoke ⽅法中我们会调⽤⽬标⽅
    法(被代理类的⽅法)并⾃定义⼀些处理逻辑
  3. 通过 Proxy.newProxyInstance(ClassLoader loader,Class<?>[]
    interfaces,InvocationHandler h) ⽅法创建代理对象

定义JDK动态代理类

实现 InvocationHandler 接⼝

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class JDKInvocationHandler implements InvocationHandler {
//⽬标对象即就是被代理对象
private Object target;
public JDKInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Thro
// 代理增强内容
System.out.println("我是中介, 开始代理");
//通过反射调⽤被代理类的⽅法
Object retVal = method.invoke(target, args);
//代理增强内容
System.out.println("我是中介, 代理结束");
return retVal;
}
}

InvocationHandler

InvocationHandler 接⼝是Java动态代理的关键接⼝之⼀, 它定义了⼀个单⼀⽅法 invoke() , ⽤于处理被代理对象的⽅法调⽤.

public interface InvocationHandler {
/**
* 参数说明
* proxy:代理对象
* method:代理对象需要实现的⽅法,即其中需要重写的⽅法
* args:method所对应⽅法的参数
*/

```bash
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
}

通过实现 InvocationHandler 接⼝, 可以对被代理对象的⽅法进⾏功能增强.

Proxy

Proxy 类中使⽤频率最⾼的⽅法是: newProxyInstance() , 这个⽅法主要⽤来⽣成⼀个代理对象

public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,InvocationHandler h)
throws IllegalArgumentException
{
//...代码省略
}

5.2CGLIB 动态代理类实现步骤

  1. 定义⼀个类(被代理类)
  2. ⾃定义 MethodInterceptor 并重写 intercept ⽅法, intercept ⽤于增强⽬标⽅
    法,和 JDK 动态代理中的 invoke ⽅法类似
  3. 通过 Enhancer 类的 create()创建代理类

6.总结

  1. AOP是⼀种思想, 是对某⼀类事情的集中处理. Spring框架实现了AOP, 称之为SpringAOP
  2. Spring AOP常⻅实现⽅式有两种: 1. 基于注解@Aspect来实现 2. 基于⾃定义注解来实现, 还有⼀些更原始的⽅式,⽐如基于代理, 基于xml配置的⽅式, 但⽬标⽐较少⻅
  3. Spring AOP 是基于动态代理实现的, 有两种⽅式: 1. 基本JDK动态代理实现 2. 基于CGLIB动态代理实现. 运⾏时使⽤哪种⽅式与项⽬配置和代理的对象有关.
  4. 代理类只能用CGLIB,代理接口,CGLIB和JDK都可以。SpringBoot2.x以后默认使用CGLIB代理。用

spring.aop.proxy-target-class=false

来设置JDK代理。

标签:Object,Spring,AOP,代理,详解,通知,import,public
From: https://blog.csdn.net/m0_64670207/article/details/139512772

相关文章

  • String字符串类----详解
    1.1简介1.String不是基本数据类型,是一种引用类型2.String代表一组不可改变的Unicode字符序列。String类对象的内容一旦被初始化,不能再改变3.String类是final修饰的终结类,不能产生子类2.创建String1.静态方式创建:Stringstr="abc";在方法区常量池中产生唯一一个字符串对......
  • 图文详解Windows系统下搭建mysql开发环境——mysql Community 8 和 navicat Premium 1
    在正式开始学习使用MySQL之前,我们有必要先搭建一个良好的开发环境,让我们的学习和工作效率事半功倍。本文涉及到的软件百度云盘:链接:https://pan.baidu.com/s/1jj_YajEv8adeEjMrXLhOTQ?pwd=1023提取码:1023目录客户机—服务器软件MySQL版本MySQL的下载和安装MySQL服务的......
  • SpringBoot 快速实现 api 加密!
    在项目中,为了保证数据的安全,我们常常会对传递的数据进行加密。常用的加密算法包括对称加密(AES)和非对称加密(RSA),博主选取码云上最简单的API加密项目进行下面的讲解。https://gitee.com/isuperag/rsa-encrypt-body-spring-boot项目介绍该项目使用RSA加密方式对API接口返回的......
  • SpringBoot热部署设置
    在使用SpringBoot进行开发过程中,我们往往会对代码进行反复修改并对项目进行部署查看效果,这时反复重启SpringBoot会很麻烦,因此使用热部署是提高开发效率的必备插件——“spring-boot-starter-test”<!--SpringBoot热部署依赖--><dependency> <groupId>org.springframew......
  • const用法详解以及auto用法详解
    const用法详解:主要用途:定义一个不可修改的常量1、修饰变量:语法:const数据类型变量名=值;示例:constintN=3;说明:const修饰的变量必须在声明时初始化,并且之后不能被修改。2、修饰指针2.1、常量指针:语法:数据类型*constp=&a;示例:int*constp=&a;说明:指针本......
  • 【计算机毕业设计】springboot287基于javaEE的校园二手书交易平台的设计与实现
    信息数据从传统到当代,是一直在变革当中,突如其来的互联网让传统的信息管理看到了革命性的曙光,因为传统信息管理从时效性,还是安全性,还是可操作性等各个方面来讲,遇到了互联网时代才发现能补上自古以来的短板,有效的提升管理的效率和业务水平。传统的管理模式,时间越久管理的内容......
  • 【计算机毕业设计】springboot283图书商城管理系统
    现代经济快节奏发展以及不断完善升级的信息化技术,让传统数据信息的管理升级为软件存储,归纳,集中处理数据信息的管理方式。本图书商城管理系统就是在这样的大环境下诞生,其可以帮助管理者在短时间内处理完毕庞大的数据信息,使用这种软件工具可以帮助管理人员提高事务处理效率,达......
  • 【计算机毕业设计】springboot001基于SpringBoot的在线拍卖系统
    随着社会的发展,社会的各行各业都在利用信息化时代的优势。计算机的优势和普及使得各种信息系统的开发成为必需。在线拍卖系统,主要的模块包括管理员;首页、个人中心、用户管理、商品类型管理、拍卖商品管理、历史竞拍管理、竞拍订单管理、留言板管理、系统管理,用户;首页、个人......
  • 【计算机毕业设计】springboot002基于springboot的医护人员排班系统
    随着信息技术在管理上越来越深入而广泛的应用,管理信息系统的实施在技术上已逐步成熟。本文介绍了医护人员排班系统的开发全过程。通过分析医护人员排班系统管理的不足,创建了一个计算机管理医护人员排班系统的方案。文章介绍了医护人员排班系统的系统分析部分,包括可行性分析......
  • 【计算机毕业设计】springboot003图书个性化推荐系统的设计与实现
    本论文主要论述了如何使用JAVA语言开发一个图书个性化推荐系统,本系统将严格按照软件开发流程进行各个阶段的工作,采用B/S架构,面向对象编程思想进行项目开发。在引言中,作者将论述图书个性化推荐系统的当前背景以及系统开发的目的,后续章节将严格按照软件开发流程,对系统进行各个......