Spring基础 SpringAOP

2024-04-22 23:12
文章标签 java 基础 spring springaop

本文主要是介绍Spring基础 SpringAOP,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言

我们都知道Spring中最经典的两个功能就是IOC和AOP

我们之前也谈过SpringIOC的思想 容器编程思想了

今天我们来谈谈SpringAOP的思想

首先AOP被称之为面向切面编程

实际上面向切面编程是面向对象的编程的补充和完善

重点就是对某一类问题的集中处理

前面我们写的统一异常管理和统一结果返回以及拦截器都是基于这个思想来创建的

我们发现这里的共性就是这些操作都有一个特点,他们都是统一操作的接口...

但是拦截器作用的是接口,AOP这类提供的操作的是方法

概念

切点(Printcut):这里的切点可以理解为切入的点,这里指的是一组规则,告诉程序对哪些方法来进行增强

连接点(Join Point):指的是满足上述切点规则的方法

通知(Advice): 对方法在前面/后面/周围加上一些处理(共性功能)

切面(Aspect): 切点 + 通知  (一类问题的解决方案)

SpringAOP

Spring 提供了一个通用的接口,可以帮助我们实现AOP的功能

比如对应用程序的监控,我们可以对每个接口之间加上计算实际运行时间

从计算的瓶颈解决问题

我们可以记录开始时间和节数时间然后作差,但是如果每个接口都一个一个写就没意思了

如果这里调用链非常长,我们还需要一个一个写,就太难受了呀

于是我们来使用AOP来解决问题

这里我们要先导入aop的依赖

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

这里虽然文件是Aspect包中的,但是却是Spring实现的

简单的实现

@Aspect
@Component
@Slf4j
public class TimeRecordAspect {@Around("execution(* com.example.bookmanager.controller.*.*(..))")public Object recordTime(ProceedingJoinPoint joinPoint) throws Throwable {//记录开始时间long startTime = System.currentTimeMillis();//目标方法Object proceed = joinPoint.proceed();//结束时间long endTime = System.currentTimeMillis();//打印日志log.info("方法执行时间"+(endTime-startTime)+"ms");return proceed;}
}

这样我们就可以在调用接口的时候打印其执行的时间了

以上的@Around注解表示就是环绕

在目标函数执行的前后都会执行

通知类型有如下几种

@Around: 环绕通知, 此注解标注的通知⽅法在⽬标⽅法前, 后都被执⾏
@Before: 前置通知, 此注解标注的通知⽅法在⽬标⽅法前被执⾏
@After: 后置通知, 此注解标注的通知⽅法在⽬标⽅法后被执⾏, ⽆论是否有异常都会执⾏
@AfterReturning: 返回后通知, 此注解标注的通知⽅法在⽬标⽅法后被执⾏, 有异常不会执⾏
@AfterThrowing: 异常后通知, 此注解标注的通知⽅法发⽣异常后执⾏
1.切点:这里的规则就是上面的Around里面的切点表达式
2.与切点表达式匹配的都是他描述的方法,也称之为连接点
3.通知 目标方法前后要做的操作
那么多包两层会怎么样呢????
比如先使用@Around再使用@Before和@After.....
这里就像一个栈一样,先进后出
注意:Around一定是要有返回值的,因为其有目标方法的执行
        Around的优先级高于其他

接口正常时

接口异常时

我们发现before和after在接口正常和异常的情况下都是会执行的

切点

注意需要一个空参方法
我们可以使用@Pointcut注解来代替大量重复的注解,后面的切点表达式就可以实现复用了
注意,如果切点是private的,在其他的类还是不能使用,声明为public并且使用全限定名即可
注:默认执行顺序为字典序,不可取,我们可以使用一个@Order来改变其优先级
数字越大优先级越低
下面我们来介绍一下切点表达式的内容
execution(* com.example.bookmanager.controller.*.*(..))
execution + 访问修饰符(可省略) + 返回类型 + 全类名 + 参数 + 异常(可省略)
这里的*表示任意单词可以替换返回类型,包名,类名方法等
..表示匹配多个任意符号
假设我们想对不同的类中的不同的方法来执行对应的连接
这个时候使用切点表达式就不能很好的完成问题了 我们就需要使用自定义注解对需要进行通知的方法进行修饰了

自定义注解

首先我们需要创建一个注解

我们需要声明他的作用域和生命周期

然后我们需要去做他的配置类/实现类

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface MyAspect {}

我们暂时只实现一个Around功能

这里的@annotation就表示对什么注解生效

@Aspect
@Component
@Slf4j
public class MyAspectDemo {@Around("@annotation(com.example.springaop.config.MyAspect)")public Object doAround(ProceedingJoinPoint joinPoint) {log.info("do around before");Object o = null;try {o = joinPoint.proceed();} catch (Throwable e) {throw new RuntimeException(e);}log.info("do around after");return  o;}
}

后面我们可以用@MyAspect注解来修饰对应的方法

这样在调用的时候就可以实现其Around功能

SpringAOP的实现方式??

1.使用Aspect注解来实现

2.使用自定义注解来实现

3.基于XML文件使用api来实现  config:aop

4.基于代理来实现(比较久远)

代理模式(重点)

定义:

为其他对象提供⼀种代理以控制对这个对象的访问. 它的作⽤就是通过提供⼀个代理类, 让我们在调⽤⽬标⽅法的时候, 不再是直接对⽬标⽅法进⾏调⽤, ⽽是通过代理类间接调⽤.
代理前
代理后
生活中的代理也有很多
比如中介,经纪人,经销商,秘书........
主要角色:
Subject:业务接口类
RealSubject:业务实现类 具体的业务执行,也可以是被代理对象
Proxy:代理类,为RealSubject的代理
适用场景:
1.无法直接调用目标对象
2.目标对象给我们提供的功能不够,我们希望对目标对象已提供的方法进行功能增强
代理模式分为静态代理和动态代理
我们以生活中的中介来举例
静态代理就是我选好想看的房源之后,房源已经绑定了对应的中介了
动态代理就是我们选好想看的房源之后,平台自动分配中介
这种提前分配就称之为静态代理
运行时分配的就是动态代理

静态代理代码实现

接口
public interface Subject {void rentHouse();
}

房东

public class RealHouseSubject implements  Subject{@Overridepublic void rentHouse() {System.out.println("我要卖房子");}
}

中介

public class HouseProxy implements  Subject{private RealHouseSubject target;public HouseProxy(RealHouseSubject target) {this.target = target;}@Overridepublic void rentHouse() {System.out.println("开始代理");target.rentHouse();System.out.println("结束代理");}
}

类似于适配器模式,这里也是持有了第三方的房东授权

缺点是代码都写死了

动态代理实现

//JDK代理
public class JDKInvocationHandler implements InvocationHandler {private RealHouseSubject target;public JDKInvocationHandler(RealHouseSubject target) {this.target = target;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("开始代理");Object o = method.invoke(target, args);System.out.println("结束代理");return o;}
}//main方法RealHouseSubject subject = new RealHouseSubject();Subject proxy= (Subject)Proxy.newProxyInstance(subject.getClass().getClassLoader(),new Class[]{Subject.class},new JDKInvocationHandler(subject));proxy.rentHouse();

这里有两种  CGLib和 JDK动态代理

这里就不做要求了

注意代理是基于反射实现的

主要记得这里的两个区别

JDK可以代理接口 不能代理类

CGLib可以代理接口也可以代理类

但是性能我不太确认,网上说两个性能谁高的都有,可能有硬件的影响  

博主可以后面测测看

注意Spring和SpringBoot在这里AOP的实现也是有差异的

代理工厂中有一个参数 proxyTargetClass  

默认Spring是false   默认实现接口使用JDK代理

SpringBoot从2.x之后设置为true     默认全部使用CGLib实现代理

proxyTargetClass⽬标对象代理⽅式
false实现了接⼝jdk代理
false未实现接⼝(只有实现类)cglib代理
true实现了接⼝cglib代理
true未实现接⼝(只有实现类)cglib代理

小总结

 AOP是⼀种思想,是对某⼀类事情的集中处理.Spring框架实现了AOP,称之为SpringAOP
2. SpringAOP常⻅实现⽅式有两种:

1.基于注解@Aspect来实现

2.基于⾃定义注解来实现,还有⼀些更原始的⽅式,⽐如基于代理,基于xml配置的⽅式,但⽬标⽐较少⻅
3. SpringAOP是基于动态代理实现的,有两种⽅式:

1.基本JDK动态代理实现

2.基于CGLIB动态代理
实现.运⾏时使⽤哪种⽅式与项⽬配置和代理的对象有关

这篇关于Spring基础 SpringAOP的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/927127

相关文章

JavaScript中的isTrusted属性及其应用场景详解

《JavaScript中的isTrusted属性及其应用场景详解》在现代Web开发中,JavaScript是构建交互式应用的核心语言,随着前端技术的不断发展,开发者需要处理越来越多的复杂场景,例如事件... 目录引言一、问题背景二、isTrusted 属性的来源与作用1. isTrusted 的定义2. 为

Java循环创建对象内存溢出的解决方法

《Java循环创建对象内存溢出的解决方法》在Java中,如果在循环中不当地创建大量对象而不及时释放内存,很容易导致内存溢出(OutOfMemoryError),所以本文给大家介绍了Java循环创建对象... 目录问题1. 解决方案2. 示例代码2.1 原始版本(可能导致内存溢出)2.2 修改后的版本问题在

Java CompletableFuture如何实现超时功能

《JavaCompletableFuture如何实现超时功能》:本文主要介绍实现超时功能的基本思路以及CompletableFuture(之后简称CF)是如何通过代码实现超时功能的,需要的... 目录基本思路CompletableFuture 的实现1. 基本实现流程2. 静态条件分析3. 内存泄露 bug

Java中Object类的常用方法小结

《Java中Object类的常用方法小结》JavaObject类是所有类的父类,位于java.lang包中,本文为大家整理了一些Object类的常用方法,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1. public boolean equals(Object obj)2. public int ha

SpringBoot项目中Maven剔除无用Jar引用的最佳实践

《SpringBoot项目中Maven剔除无用Jar引用的最佳实践》在SpringBoot项目开发中,Maven是最常用的构建工具之一,通过Maven,我们可以轻松地管理项目所需的依赖,而,... 目录1、引言2、Maven 依赖管理的基础概念2.1 什么是 Maven 依赖2.2 Maven 的依赖传递机

SpringBoot实现动态插拔的AOP的完整案例

《SpringBoot实现动态插拔的AOP的完整案例》在现代软件开发中,面向切面编程(AOP)是一种非常重要的技术,能够有效实现日志记录、安全控制、性能监控等横切关注点的分离,在传统的AOP实现中,切... 目录引言一、AOP 概述1.1 什么是 AOP1.2 AOP 的典型应用场景1.3 为什么需要动态插

Java实现Excel与HTML互转

《Java实现Excel与HTML互转》Excel是一种电子表格格式,而HTM则是一种用于创建网页的标记语言,虽然两者在用途上存在差异,但有时我们需要将数据从一种格式转换为另一种格式,下面我们就来看看... Excel是一种电子表格格式,广泛用于数据处理和分析,而HTM则是一种用于创建网页的标记语言。虽然两

java图像识别工具类(ImageRecognitionUtils)使用实例详解

《java图像识别工具类(ImageRecognitionUtils)使用实例详解》:本文主要介绍如何在Java中使用OpenCV进行图像识别,包括图像加载、预处理、分类、人脸检测和特征提取等步骤... 目录前言1. 图像识别的背景与作用2. 设计目标3. 项目依赖4. 设计与实现 ImageRecogni

Java中Springboot集成Kafka实现消息发送和接收功能

《Java中Springboot集成Kafka实现消息发送和接收功能》Kafka是一个高吞吐量的分布式发布-订阅消息系统,主要用于处理大规模数据流,它由生产者、消费者、主题、分区和代理等组件构成,Ka... 目录一、Kafka 简介二、Kafka 功能三、POM依赖四、配置文件五、生产者六、消费者一、Kaf

Java访问修饰符public、private、protected及默认访问权限详解

《Java访问修饰符public、private、protected及默认访问权限详解》:本文主要介绍Java访问修饰符public、private、protected及默认访问权限的相关资料,每... 目录前言1. public 访问修饰符特点:示例:适用场景:2. private 访问修饰符特点:示例: