【示例】Spring-AOP理解

前言

本文不仅介绍Spring中AOP的几种实现方式。还整体介绍一下:静态代理、JDK API动态代理和CGLIB动态代理

文中示例的代码地址:

GitHubhttps://github.com/Web-Learn-GSF/Java_Learn_Examples
父工程Java_Framework_Spring

静态代理、动态代理*2

他人文章参考

这三个示例可以直接看文章:https://segmentfault.com/a/1190000011291179#item-4

自己编写示例

下边示例是自己写的,有空再补充吧:

示例在上述工程的具体Module里面
静态代理AOP_0_Static_Proxy
JDK API动态代理暂无
CGLIB动态代理暂无

三种方式优缺点对比

静态代理:

  • 特点:实现简单,只需要代理对象对目标对象封装,即可实现功能增强。

  • 缺点:静态代理只能为一个目标对象服务,目标对象过多,就会产生很多的代理类

    这个缺点存疑。如果将目标对象实例化在代理类中,即一个静态代理类代理一个目标对象,那肯定是目标对象越多,代理类就越多。但如果通过在代理对象中定义set方法,就可以实现:一个代理类代理同一个接口下的多个目标对象,就没有这个缺点了。

动态代理 | JDK API:

  • 特点:动态代理必须实现InvocationHandler接口,且要求目标对象有接口实现。通过反射代理方法,实现对目标对象的增强
  • 缺点:目标对象必须要有接口,不然无法应用

动态代理 | CGLIB:

  • 特点:无需目标对象有接口实现,通过生成类字节码实现代理,比反射稍快,不存在性能问题。
  • 缺点:代理类需要继承目标对象,即目标对象不能被final修饰

Spirng中实现AOP

Spring中实现AOP有如下几种方式:

实现方式在上述工程中的Module位置
xml + 实现Spring的APIAOP_1_Xml_SpringAPI
xml + 自定义类AOP_2_Xml_CustomClass
xml + 注解 + 自定义类AOP_3_Xml_Annotation
注解 + 自定义类暂空

下边展示每种实现方式里面的关键部分代码。

xml + 实现Spring的API

public class LogAfterMethod implements AfterReturningAdvice {@Overridepublic void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {System.out.println("AOP后置通知:" + "在" + target.getClass().getName() + "的" + method.getName() + "方法调用后执行。目标对象-方法-参数,都可以获取到");}
}
public class LogBeforeMethod implements MethodBeforeAdvice {@Overridepublic void before(Method method, Object[] args, Object target) throws Throwable {System.out.println("AOP前置通知:" + "在" + target.getClass().getName() + "的" + method.getName() + "方法调用前执行。目标对象-方法-参数,都可以获取到");}
}
<?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:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsd"><!--  注册bean  --><bean id="userService" class="GSF.Example.Service.UserServiceImpl" /><bean id="logBefore" class="GSF.Example.Log.LogBeforeMethod" /><bean id="logAfter" class="GSF.Example.Log.LogAfterMethod"/><!-- Aop的设置--><aop:config><!-- 切入点--><aop:pointcut id="pointcut" expression="execution(* GSF.Example.Service.UserServiceImpl.*(..))"/><!-- 执行前置通知--><aop:advisor advice-ref="logBefore" pointcut-ref="pointcut" /><aop:advisor advice-ref="logAfter" pointcut-ref="pointcut" /></aop:config>
</beans>

xml + 自定义类

package GSF.Example.Log;public class CustomLogClass {public void before(){System.out.println("---------基于XML自定义类方式实现,前置通知:方法执行前---------");}public void after(){System.out.println("---------基于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:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsd"><!--  注册bean  --><bean id="userService" class="GSF.Example.Service.UserServiceImpl" /><bean id="customLogClass" class="GSF.Example.Log.CustomLogClass" /><!--Aop的设置--><aop:config><!-- 切入点--><aop:aspect ref="customLogClass"><aop:pointcut id="pointcut" expression="execution(* GSF.Example.Service.UserServiceImpl.*(..))"/><aop:before method="before" pointcut-ref="pointcut"/><aop:after method="after" pointcut-ref="pointcut" /></aop:aspect></aop:config>
</beans>

xml + 注解 + 自定义类

package GSF.Example.Log;import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;@Aspect
public class AnnotationClass {@Before("execution(* GSF.Example.Service.UserServiceImpl.*(..))")public void before(){System.out.println("---------基于注解方式实现,前置通知:方法执行前---------");}@After("execution(* GSF.Example.Service.UserServiceImpl.*(..))")public void after(){System.out.println("---------基于注解方式实现,后置通知:方法执行后---------");}@Around("execution(* GSF.Example.Service.UserServiceImpl.*(..))")public void around(ProceedingJoinPoint jp) throws Throwable{System.out.println("环绕通知:环绕前");System.out.println(jp.getSignature());// 执行目标方法Object proceed = jp.proceed();System.out.println(proceed);System.out.println("环绕通知:环绕后");}
}
<?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:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsd"><!-- 注册bean  --><bean id="userService" class="GSF.Example.Service.UserServiceImpl" /><bean id="annotationPointcut" class="GSF.Example.Log.AnnotationClass" /><!-- 自动代理 --><aop:aspectj-autoproxy/></beans>

注解 + 自定义类

在上述:xml+注解+自定义类的实现方式中,xml文件的作用已经弱化为只有:注册bean + 开启允许注解实现AOP

只需要通过注解取代上述两种方法,就可以抛弃xml文件,完成仅:注解+自定义类实现AOP。

有空再写。

理解AOP中的概念

通过该参考文章,理解AOP中的相关概念:https://www.cnblogs.com/aduner/p/14656427.html

接下来相关概念的解释,也都用上述文章中的示例来讲。

概念 | 连接点

  • Spring是方法级的AOP,一般对某个方法进行增强。选择的这个方法就是连接点的意思
  • 这里选择的切入点就是:Landlord类的service()方法
@Component
public class Landlord {public void service() {System.out.println("签合同");System.out.println("收钱");}
}

概念 | 切面

  • 切面可以理解一个拦截器,在切面上,我们对连接点的前边、后边进行方法增强。
  • 切面对应一个类,也是Spring中的一个Bean
  • 这里选择的切面就是Broker类,通过@Aspect注解定义该类为一个切面
@Component
@Aspect
class Broker {@Before("execution(* com.aduner.demo03.pojo.Landlord.service())")public void before(){System.out.println("带租客看房");System.out.println("谈钱");}@After("execution(* com.aduner.demo03.pojo.Landlord.service())")public void after(){System.out.println("给钥匙");}
}

概念 | 切入点

  • 切面中的方法都对一个连接点进行增强,有些重复的代码。可以定义一个切入点。

  • 切面中的方法想要对某个切入点进行增强,就使用该切入点

  • 上述代码可以修改为:

@Component
@Aspect
class Broker {// 切入点@Pointcut("execution(* com.aduner.demo03.pojo.Landlord.service())")public void pointcut() {}// 使用上述切入点@Before("pointcut()")public void before() {System.out.println("带租客看房");System.out.println("谈钱");}@After("pointcut()")public void after() {System.out.println("给钥匙");}
}

概念 | 通知、目标、代理、横切关注点

  • 通知:上述代码中已经体现。before()方法就是一个前置通知(通过注解@Before赋予该方法前置通知的功能)
  • 目标:Spring的AOP是对方法进行增强,被增强的方法叫做:连接点。那连接点所属的类就是目标
  • 代理:Spring AOP的实现是动态代理,会有一个代理对象,代码中没有体现,但这个概念好理解
  • 横切关注点:又是一个宏观的概念。日志、安全、权限都可以认为是横切关注点。示例中的横切关注点可以理解为:租房的准备工作

其余问题

  • 多个切面:如果不同切面的切点相同,那就有多个切面,需要规定每个切面的执行顺序

  • 通知Advice的类别(5种):

通知类型连接点实现接口
前置通知方法前org.springframework.aop.MethodBeforeAdvice
后置通知方法后org.springframework.aop.AfterReturningAdvice
环绕通知方法前后org.springframework.aop.MethodInterceptor
异常抛出通知方法抛出异常org.springframework.aop.ThrowsAdvice
引介通知类中增加新的方法属性org.springframework.aop.IntroductionInterceptor

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

c++ - 运算符重载

文章目录 一、运算符重载的关键字和注意点二、重载 运算符三、重载 运算符四、重载 运算符五、重载前置 和 后置 运算符六、重载 << >>运算符 一、运算符重载的关键字和注意点 C为了增强代码的可读性引入了运算符重载&#xff0c;运算符重载是具有特殊函数名的函…

CANFD通讯数据64字节,强制成结构体类型的做法---用C语言

在处理通信数据时&#xff0c;特别是当数据按照特定结构体的布局在网络上传输时&#xff0c;你可能需要将接收到的字节流转换为相应的结构体类型。这里是如何在C语言中强制将接收到的64字节数据转换为结构体类型的一个示例&#xff1a; #include <stdio.h> #include <…

【JavaEE】浅谈线程(一)

线程 前言线程的由来线程是什么线程的属性线程更高效的原因举个例子&#xff08;线程便利性的体现&#xff09; 多线程代码线程并发执行的代码jconsole(观测多线程) 线程的调度问题创建线程的几种方法1&#xff09;通过继承Thread 重写run2&#xff09;使用Runnable接口 重写ru…

MySQL 上亿大表,如何深度优化?

背景 分析 测试 实施 索引优化后 delete大表优化为小批量删除 总结 前段时间刚入职一家公司&#xff0c;就遇上这事&#xff01; 背景 XX实例&#xff08;一主一从&#xff09;xxx告警中每天凌晨在报SLA报警&#xff0c;该报警的意思是存在一定的主从延迟&#xff08;…

【Node】Node的配置文件的使用,dotenv框架的使用

&#x1f601; 作者简介&#xff1a;一名大四的学生&#xff0c;致力学习前端开发技术 ⭐️个人主页&#xff1a;夜宵饽饽的主页 ❔ 系列专栏&#xff1a;Node.js &#x1f450;学习格言&#xff1a;成功不是终点&#xff0c;失败也并非末日&#xff0c;最重要的是继续前进的勇…

Kotlin基础学习

学习 Kotlin 是一个很好的选择&#xff0c;它是一种现代的、静态类型的编程语言&#xff0c;旨在与 Java 和 Android 平台无缝集成&#xff0c;并提供更简洁、更安全的语法。以下是你可以开始学习 Kotlin 的基础知识的步骤&#xff1a; 了解 Kotlin 的基础语法&#xff1a; 学习…

linux-docker安装nginx

1.拉取镜像&#xff1a; docker pull nginx2.创建挂在路径&#xff1a; mkdir -p /usr/local/nginx/conf mkdir -p /usr/local/nginx/logs mkdir -p /usr/local/nginx/www mkdir -p /usr/local/nginx/conf.d 3.启动镜像:为了拿到位置文件&#xff0c;先启动下 docker run -…

2024 EasyRecovery易恢复 帮你轻松找回回收站删除的视频

随着数字化时代的到来&#xff0c;我们的生活和工作中越来越依赖于电子设备。然而&#xff0c;电子设备中的数据丢失问题也随之而来。数据丢失可能是由各种原因引起的&#xff0c;如硬盘故障、病毒感染、误删除等。面对这种情况&#xff0c;一个高效、可靠的数据恢复工具变得尤…

智慧农场牧场认养系统畜牧养殖积分签到直播监控农资商城养鸡APP小程序支持定制

每日签到&#xff1a;用户每天签到可以获取积分&#xff0c;连续签到7天还有惊喜奖品&#xff0c;这有助于增加用户粘性和活跃度。 我的鸡崽&#xff1a;这一功能以动画形式展示用户的鸡崽状态&#xff0c;新用户可以通过购物满额获得鸡苗&#xff0c;并通过饲喂动作参与鸡的成…

Netty NioEventLoop详解

文章目录 前言类图主要功能NioEventLoop如何实现事件循环NioEventLoop如何处理多路复用Netty如何管理Channel和Selector管理Channel管理Selector注意事项 前言 Netty通过事件循环机制(EventLoop)处理IO事件和异步任务&#xff0c;简单来说&#xff0c;就是通过一个死循环&…

vue3 开发中遇到的问题

1. element-plus的el-popover内置el-select组件&#xff0c;如何避免关闭el-popover 在el-select内置上面添加:teleported"false"就可以避免在点击el-select时候&#xff0c;把el-popver给关闭了 2. validate-on-rule-change&#xff1a;是否在 rules 属性改变后…

串行通信总线IIC通信原理

I2C&#xff08;Inter-Integrated Circuit&#xff09;是一种串行通信总线&#xff0c;用于在集成电路之间进行数字通信。它由飞利浦公司&#xff08;现在的NXP半导体&#xff09;于1982年开发&#xff0c;并于2006年成为公共领域协议。 I2C总线使用两根信号线&#xff1a;串行…

【堡垒机】堡垒机的介绍

目前&#xff0c;常用的堡垒机有收费和开源两类。 收费的有行云管家、纽盾堡垒机&#xff1b; 开源的有jumpserver&#xff1b; 这几种各有各的优缺点&#xff0c;如何选择&#xff0c;大家可以根据实际场景来判断 什么是堡垒机 堡垒机&#xff0c;即在一个特定的网络环境下&…

李沐23_LeNet——自学笔记

手写的数字识别 知名度最高的数据集&#xff1a;MNIST 1.训练数据&#xff1a;50000 2.测试数据&#xff1a;50000 3.图像大小&#xff1a;28✖28 4.10类 总结 1.LeNet是早期成功的神经网络 2.先使用卷积层来学习图片空间信息 3.使用全连接层来转换到类别空间 代码实现…

【oracle数据库安装篇一】Linux5.6基于LVM安装oracle10gR2单机

说明 本篇文章主要介绍了Linux5.6基于LVM安装oracle10gR2单机的配置过程&#xff0c;比较详细&#xff0c;基本上每一个配置部分的步骤都提供了完整的脚本&#xff0c;安装部分都提供了简单的说明和截图&#xff0c;帮助你100%安装成功oracle数据库。 安装过程有不明白的地方…

二维相位解包理论算法和软件【全文翻译- DCT相位解包裹(5.3.2)】

5.3.2 基于 DCT 的方法 在本节中,我们将详细介绍如何通过 DCT 算法解决非加权最小二乘相位解缠问题,而不是通过FFT.我们将使用公式 5.53 所定义的二维余弦变换。我们开发的算法等同于 FFT 方法 2(第 5.3.1 节)。与 FFT 方法 I 等价的 DCT 算法也可以推导出来,但我们将其作…

PlayerSettings.WebGL.emscriptenArgs设置无效的问题

1&#xff09;PlayerSettings.WebGL.emscriptenArgs设置无效的问题 2&#xff09;多个小资源包合并为大资源包的疑问 3&#xff09;AssetBundle在移动设备上丢失 4&#xff09;Unity云渲染插件RenderStreaming&#xff0c;如何实现多用户分别有独立的操作 这是第381篇UWA技术知…

Meta 的 Llama 模型系列即将迎来第三次大更新

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

linux启动流程(s3c2400)

概述 大致流程&#xff1a;内核&#xff08;kernel&#xff09;都是由bootloader程序引导启动的&#xff0c;所以我们应该先烧进去bootloader程序。然后可以通过保存的内核代码或者通过远程连接&#xff08;nfs/tftp&#xff09;的主机下载再运行&#xff0c;再挂载根文件系统。…

ppt从零基础到高手【办公】

第一章&#xff1a;文字排版篇01演示文稿内容基密02文字操作规范03文字排版处理04复习&作业解析第二章&#xff1a;图形图片图表篇05图形化表达06图片艺术化07轻松玩转图表08高效工具&母版统一管理09复习&作业解析10轻松一刻-文字图形小技巧速学第三章&#xff1a;…