Spring AOP面向切面编程

AOP将通用的、与业务无关的功能抽象封装为切面类。
切面可配置在目标方法的执行前、后运行,真正做到即插即用。实现了在不修改源码的情况下对程序行为进行扩展。

Spring AOP与AspectJ的关系:

Eclipse AspectJ 是基于Java平台的面向切面编程的语言。
Spring AOP底层依赖AspectJWeaver实现类和方法的匹配。
Spring AOP利用代理模式实现对象运行时功能扩展。

关键:

在这里插入图片描述

利用XML配置AOP的过程:

  1. 依赖AspectJ
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.5</version>
</dependency>
  1. 实现切面类/方法
    在这里插入图片描述

  2. 配置Aspect Bean

<!--AOP配置-->
<bean id="methodAspect" class="spring.aop.aspect.MethodAspect">
  1. 定义PointCut
<!--PointCut 切点,使用execution表达式描述切面的作用范围-->
<!--execution(public * spring.aop..*.*(..)) 说明切面作用在spring.aop包下的所有类所有方法上-->
<aop:pointcut id="pointcut" expression="execution(public * spring.aop..*.*(..))"></aop:pointcut>
  1. 配置Advice
<!--定义切面类-->
<aop:aspect ref="methodAspect">
<!--before通知(advice),代表在目标方法运行前先执行methodAspect.printExecutionTime()-->
<aop:before method="printExecutionTime" pointcut-ref="pointcut"/>
</aop:aspect>

JoinPoint连接点参数的核心方法

在这里插入图片描述

在这里插入图片描述

PointCut 切点表达式

在这里插入图片描述

public可以去掉,默认调用public类型方法。

<!--        对类约束-->
        <aop:pointcut id="pointcut" expression="execution(* spring.aop..*Service.*(..))"></aop:pointcut>
<!--        对方法名约束-->
        <aop:pointcut id="pointcut1" expression="execution(* spring.aop..*.create*(..))"></aop:pointcut>
<!--        对方法返回值类型约束-->
        <aop:pointcut id="pointcut2" expression="execution(String spring.aop..*.*(..))"></aop:pointcut>
<!--        对方法参数约束-->
        <aop:pointcut id="pointcut3" expression="execution(* spring.aop..*.*(String,*))"></aop:pointcut>

Advice 五种通知类型

在这里插入图片描述

特殊通知:引介增强

引介增强是对类的增强,允许在运行时为目标类增加新属性或方法。允许在运行时改变类的行为,让类随运行环境动态变更。

//切面类
public class MethodAspect {

    public void doAfterReturning(JoinPoint joinPoint,Object ret){
        System.out.println("<---返回后通知:"+ret);
    }
    public void doAfterThrowing(JoinPoint joinPoint,Throwable th){
        System.out.println("<---异常通知:"+th.getMessage());
    }
    public void doAfter(JoinPoint joinPoint){
        System.out.println("<---触发后置通知");
    }
}
<!--定义切面类-->
<aop:aspect ref="methodAspect">
    <aop:after method="doAfter" pointcut-ref="pointcut"/>
    <aop:after-returning method="doAfterReturning" returning="ret" pointcut-ref="pointcut"/>
    <aop:after-throwing method="doAfterThrowing" throwing="th" pointcut-ref="pointcut"/>
</aop:aspect>

返回后通知/异常通知 与 后置通知 的执行顺序由配置顺序决定。

环绕通知的方法返回值为Object,需要返回目标方法的返回值,方法参数为ProceedingJoinPoint。

利用环绕通知计算方法执行时长:

public class MethodChecker {
    //ProceedingJoinPoint 是JoinPoint的升级版,在原有功能外,还可以控制目标方法是否执行
    public Object check(ProceedingJoinPoint pjp) throws Throwable {
        try {
            long startTime = new Date().getTime();
            Object ret = pjp.proceed();//执行目标方法
            long endTime = new Date().getTime();
            long duration = endTime - startTime;
            if(duration >= 1000){
                String className = pjp.getTarget().getClass().getName();
                String methodName =pjp.getSignature().getName();
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
                String now = sdf.format(new Date());
                System.out.println("==="+now+":"+className+"."+methodName+"("+duration+"ms)===");
            }
            return ret;
        } catch (Throwable e) {
            System.out.println("Exception message:"+e.getMessage());
            throw e;
        }
    }
}
<bean id="methodChecker" class="spring.aop.aspect.MethodChecker"></bean>
<aop:config>
      <aop:pointcut id="pointcut" expression="execution(* spring.aop..*.*(..))"/>
      <aop:aspect ref="methodChecker">
      		<!--环绕通知-->
       		<aop:around method="check" pointcut-ref="pointcut"/>
      </aop:aspect>
</aop:config>

利用注解配置Spring AOP

  1. 依赖AspectJ
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.5</version>
</dependency>
  1. 在applicationContext.xml中增加两行
<?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
        https://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">
<!-- 组件扫描:在IOC容器初始化时,去扫描哪个包下的所有组件类型注解-->
    <context:component-scan base-package="spring.aop"/>
<!--启用Spring AOP注解模式-->
    <aop:aspectj-autoproxy/>
</beans>
  1. 在每个组件类上增加组件类型注解,说明当前类需要被IoC实例化
  2. 切面类需要使用两个个注解:@Component @Aspect
  3. 切面方法上使用对应类型的通知注解,并增加对应的切点表达式
@Component //标记当前类为组件
@Aspect //说明当前类是切面类
public class MethodChecker {
    //环绕通知,参数为PointCut切点表达式
    @Around("execution(* spring.aop..*Service.*(..))")
     public Object check(ProceedingJoinPoint pjp) throws Throwable {
     ...
     }
}

Spring AOP实现原理

基于代理模式实现功能动态扩展,包括两种形式:

  • 目标类实现了接口,通过JDK动态代理实现功能扩展
  • 目标类没实现接口,通过CGLib组件实现功能扩展

代理模式:

通过代理对象对原对象实现功能扩展。
在这里插入图片描述
代理类和委托类都实现了相同的接口,代理类持有委托类对象引用,在代理类的实现方法中对原始功能扩展。

弊端:每个委托类至少拥有一个代理类,随着功能的扩展,手动创建的代理类越来越多,导致系统臃肿。

这种需要手动创建代理类的代理模式使用方式称为 静态代理

JDK动态代理

在运行时通过反射技术,按照接口的结构自动生成相应代理类,完成目标方法的扩展。

**
 * InvocationHandlerJDK提供的反射类,用于JDK动态代理中对目标方法进行增强
 * InvocationHandler实现类与切面类对环绕通知类似
 */
public class ProxyInvocationHandler implements InvocationHandler{
    private Object target;//代理类持有目标类对象
    private ProxyInvocationHandler(Object target){//传入目标对象
        this.target=target;
    }
    /**
     * 在invoke()方法对目标方法进行增强
     * @param proxy 代理类对象
     * @param method 目标方法对象
     * @param args 目标方法实参
     * @return 目标方法运行后返回值
     * @throws Throwable 目标方法抛出的异常
     */
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("======"+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS").format(new Date()) +"=======");
        Object ret = method.invoke(target,args);//调用目标方法
        return ret;
    }
}
 public static void main(String[] args) {
        UserService userService = new UserServiceImpl();
        ProxyInvocationHandler invocationHandler = new ProxyInvocationHandler(userService);
        //动态创建代理类
        UserService userServiceProxy =(UserService) Proxy.newProxyInstance //根据已有接口创建代理类
                (userService.getClass().getClassLoader(),//类加载器
                 userService.getClass().getInterfaces(),//类要实现的接口
                 invocationHandler);//如何对目标方法进行扩展

        userServiceProxy.createUser();
 }

在这里插入图片描述

JDK动态创建代理类,只有在目标类实现了接口的情况下才可以。

CGLib实现代理类

CGLib是运行时字节码增强技术。
Spring AOP扩展无接口类使用CGLib。
在运行时生成目标继承类字节码的方式进行扩展。

CGLib实现原理:
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/233768.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C //习题10.10 从第9题的“职工工资文件”中删除一个职工的数据,再存回原文件。

C程序设计 &#xff08;第四版&#xff09; 谭浩强 习题10.10 习题10.10 从第9题的“职工工资文件”中删除一个职工的数据&#xff0c;再存回原文件。 IDE工具&#xff1a;VS2010 Note: 使用不同的IDE工具可能有部分差异。 代码块 方法&#xff1a;使用指针&#xff0c;函数…

PyQt下使用OpenCV实现人脸检测与识别

背景&#xff1a; 一 数字图像处理与识别警务应用模型 基于前期所学知识&#xff0c;与公安实践相结合&#xff0c;综合设计数字图像处理与识别警务应用模型,从下列4个研究课题中选择2个进行实验实现&#xff1a;图像增强与复原、人脸检测与识别、虹膜内外圆检测与分割、车牌…

PHP使用mkcert本地开发生成HTTPS证书 PhpEnv集成环境

PHP使用mkcert本地开发生成HTTPS证书 PhpEnv集成环境 前言一、介绍 mkcert二、安装/使用 mkcert1. 安装2. 使用 总结 前言 本地开发时有些功能只有在 https 证书的情况下才能使用, 例如一些 Web API 一、介绍 mkcert Github地址 mkcert 是一个制作本地可信开发证书的简单工具。…

【Docker】Docker Compose,yml 配置指令参考的详细讲解

作者简介&#xff1a; 辭七七&#xff0c;目前大二&#xff0c;正在学习C/C&#xff0c;Java&#xff0c;Python等 作者主页&#xff1a; 七七的个人主页 文章收录专栏&#xff1a; 七七的闲谈 欢迎大家点赞 &#x1f44d; 收藏 ⭐ 加关注哦&#xff01;&#x1f496;&#x1f…

fijkplayer flutter 直播流播放

fijkplayer flutter 直播流播放 fijkplayer 是 ijkplayer 的 Flutter 封装&#xff0c; 是一款支持 android 和 iOS 的 Flutter 媒体播放器插件&#xff0c; 由 ijkplayer 底层驱动。 通过纹理&#xff08;Texture&#xff09;接入播放器视频渲染到 Flutter 中。 前言 目前使用…

redis-学习笔记(string)

redis 中的字符串, 是按照二进制的方式存储和读取的, 即存啥取啥, 所以一般不会出现乱码问题 (乱码问题是因为存储和读取时使用的编码方式不一样, 但是 redis 没有编码转换) redis 限制了 string 的大小 : 512M, 因为 单线程模型 希望进行的操作能够比较快速, 越大越慢 set key…

一文读懂MySQL基础知识文集(8)

&#x1f3c6;作者简介&#xff0c;普修罗双战士&#xff0c;一直追求不断学习和成长&#xff0c;在技术的道路上持续探索和实践。 &#x1f3c6;多年互联网行业从业经验&#xff0c;历任核心研发工程师&#xff0c;项目技术负责人。 &#x1f389;欢迎 &#x1f44d;点赞✍评论…

python3安装lifelines

目录 一、环境 二、安装lifelines 出现问题 三、测试导入 一、环境&#xff1a; jupyter notebook中新建ipynb文件 二、安装lifelines pip install --upgrade --no-deps githttps://github.com/CamDavidsonPilon/lifelines.git出现问题&#xff1a; 缺少模块autograd、f…

1834_emacs_ivy以及counsel的常用功能

Grey 全部学习汇总&#xff1a; GitHub - GreyZhang/editors_skills: Summary for some common editor skills I used. emacs ivy以及counsel的常用功能 主要功能 ivy主要是实现一些emacs的minibuffer的操作增强功能的。如果不进行类似的增强扩展&#xff0c;在进行这方面相…

[文档级关系抽取|ACL论文]文档级关系抽取中语言理解的基础模型

Did the Models Understand Documents? Benchmarking Models for Language Understanding in Document-Level Relation Extraction School of Computer Science, Fudan University | ACL 2023.06 | 原文链接 Background 过去的工作大多数都是从单个句子中收获更多的关系&am…

1-2、Java环境搭建

语雀原文链接 文章目录 1、JDK安装2、Hello World2-1、Hello World示例2-2、类名和文件名2-3、注释2-4、javadoc 3、环境变量3-1、Path作用3-2、classpath3-3、JAVA_HOME 4、Java组成5、跨平台原理5-1、Java跨平台原理5-2、C语言的跨平台原理 1、JDK安装 下载地址&#xff1a…

(JAVA)-IDEA导第三方包

1.下载好第三方的包 2.将jar包复制&#xff0c;上图中的第一个数字jar包是我们要选择的 3.模块下新建外包文件 4.将复制的jar文件粘贴进去 . 5.右键jar包将文件与jar包关联 注意&#xff1a;第三方库中有些名字跟java包中重名&#xff0c;导包时候注意不要导错了。

数据结构算法-归并排序

引言 小明和小森是超市的货架管理人员&#xff0c;他们每天都要确保货架上的商品摆放整齐、有序。一天&#xff0c;他们发现一个货架上的商品有些混乱&#xff0c;需要尽快进行补货。由于该货架上的商品种类繁多&#xff0c;不同种类的商品之间还要考虑价格、销量等因素&#…

data_loader返回的每个batch的数据大小是怎么计算得到的?

data_loader是一个通用的术语&#xff0c;用于表示数据加载器或数据批次生成器。它是在机器学习和深度学习中常用的一个概念。 一、data loader 数据加载器&#xff08;data loader&#xff09;是一个用于加载和处理数据集的工具&#xff0c;它可以将数据集划分为小批次&#…

【2023高教社杯】C题 蔬菜类商品的自动定价与补货决策 52页论文及代码

【2023高教社杯】C题 蔬菜类商品的自动定价与补货决策 52页论文及代码 1 题目 C题蔬菜类商品的自动定价与补货决策 在生鲜商超中&#xff0c;一般蔬菜类商品的保鲜期都比较短&#xff0c;且品相随销售时间的增加而变差&#xff0c; 大部分品种如当日未售出&#xff0c;隔日就…

2023.12.10 homework

五年级一元一次方程

Autosar通信入门系列07-CanNM状态机切换详解

本文框架 1. 概述2. NM状态机时间参数及常用接口介绍2.1 涉及时间参数说明2.2 状态机切换涉及接口介绍 3 NM状态机及其切换介绍3.1 NM状态机概览3.2 NM状态机切换过程详解 1. 概述 本文为Autosar通信入门系列介绍&#xff0c;如您对AutosarMCAL配置&#xff0c;通信&#xff0…

P13 Linux进程间通信——管道

前言 &#x1f3ac; 个人主页&#xff1a;ChenPi &#x1f43b;推荐专栏1: 《Linux C应用编程&#xff08;概念类&#xff09;_ChenPi的博客-CSDN博客》✨✨✨ &#x1f525; 推荐专栏2: 《C_ChenPi的博客-CSDN博客》✨✨✨ &#x1f6f8;推荐专栏3: ​​​​​​《链表_C…

什么是双亲委派模型

一、定义 双亲委派模型是 Java 类加载器的一种工作模式&#xff0c;通过这种工作模式&#xff0c;Java 虚拟机将类文件加载到内存中&#xff0c;这样就保证了 Java 程序能够正常的运行起来。 二、类加载器 双亲委派模型针对的是 Java 虚拟机中三个类加载器的&#xff0c;这三…

NSSCTF-Crypto靶场练习--第11-20题wp

文章目录 [SWPUCTF 2021 新生赛]traditional[LitCTF 2023]梦想是红色的 (初级)[SWPUCTF 2021 新生赛]crypto2[羊城杯 2021]Bigrsa[LitCTF 2023]Hex&#xff1f;Hex&#xff01;(初级)[SWPU 2020]happy[AFCTF 2018]BASE[安洵杯 2019]JustBase[鹤城杯 2021]Crazy_Rsa_Tech[SWPUCT…