Spring:面向切面(AOP)

1. 代理模式

二十三种设计模式中的一种,属于结构型模式。它的作用就是通过提供一个代理类,让我们在调用目标方法的时候,不再是直接对目标方法进行调用,而是通过代理类**间接**调用。让不属于目标方法核心逻辑的代码从目标方法中剥离出来——**解耦**。调用目标方法时先调用代理对象的方法,减少对目标方法的调用和打扰,同时让附加功能能够集中在一起也有利于统一维护 

 

 

 

动态代理 

 

 

* 动态代理分为JDK动态代理和cglib动态代理
* 当目标类有接口的情况使用JDK动态代理和cglib动态代理,没有接口时只能使用cglib动态代理
* JDK动态代理动态生成的代理类会在com.sun.proxy包下,类名为$proxy1,和目标类实现相同的接口
* cglib动态代理动态生成的代理类会和目标在在相同的包下,会继承目标类
* 动态代理(InvocationHandler):JDK原生的实现方式,需要被代理的目标类必须实现接口。因为这个技术要求**代理对象和目标对象实现同样的接口**(兄弟两个拜把子模式)。
* cglib:通过**继承被代理的目标类**(认干爹模式)实现代理,所以不需要目标类实现接口。
* AspectJ:是AOP思想的一种实现。本质上是静态代理,**将代理逻辑“织入”被代理的目标类编译得到的字节码文件**,所以最终效果是动态的。weaver就是织入器。Spring只是借用了AspectJ中的注解。 

 

 2. AOP概述

AOP(Aspect Oriented Programming)是一种设计思想,是软件设计领域中的面向切面编程,它是面向对象编程的一种补充和完善,它以通过预编译方式和运行期动态代理方式实现,在不修改源代码的情况下,给程序动态统一添加额外功能的一种技术。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率 

相关术语 

横切关注点

这个概念不是语法层面的,而是根据附加功能的逻辑上的需要:有十个附加功能,就有十个横切关注点。

通知(功能):切入后要新添什么新的功能

切面:将通知(功能)封装成类

目标:被代理对象

代理:调用目标对象的功能,并且有自己的业务功能,即在目标基础上新加业务功能,但不需要修改目标对象的代码

切入点:通俗点来讲就是设置相对应的规则,满足该规则的方法就是要被代理的方法(也可理解为切入点,在哪个点(函数)切入新增功能)

 作用

* 简化代码:把方法中固定位置的重复的代码**抽取**出来,让被抽取的方法更专注于自己的核心功能,提高内聚性。
  
* 代码增强:把特定的功能封装到切面类中,看哪里有需要,就往上套,被**套用**了切面逻辑的方法就被切面给增强了。 

 3. 基于注解的AOP

业务场景模拟

原业务代码只能完成计算功能,在次基础上新增日志功能 

public interface Calculator {int add(int i, int j);int sub(int i, int j);int mul(int i, int j);int div(int i, int j);
}
@Component
public class CalculatorImp implements Calculator{@Overridepublic int add(int i, int j) {int result = i + j;System.out.println("方法内部 result = " + result);return result;}@Overridepublic int sub(int i, int j) {int result = i - j;System.out.println("方法内部 result = " + result);return result;}@Overridepublic int mul(int i, int j) {int result = i * j;System.out.println("方法内部 result = " + result);return result;}@Overridepublic int div(int i, int j) {int result = i / j;System.out.println("方法内部 result = " + result);return result;}
}

 语法及细节

 

/**** 切入点表达式:"execution(权限修饰符. 返回值类型. 全类名. 方法名(形参类型))"* *  可以代表任意修饰符,任意返回值类型,任意方法,任意包,任意类* .. 代表任意方法的形参列表为任意类型* 如: execution(* com.itgyl.annoAop.CalculatorImp.*(..))* 即修饰符和返回类型任意的com.itgyl.annoAop这个包下的CalculatorImp这个类的所有方法形参列表任意的方法 调用时会执行这个前置方法*     execution(public int com.itgyl.annoAop.CalculatorImp.add(int, int))*     即修饰符为public 返回值类型为int 的com.itgyl.annoAop包下 的 CalculatorImp类 执行add(形参为两个int类型)这个方法时会先执行这个前置方法*/

 

/**** 通知:* 前置 @Before*      前置通知执行时机为代理方法执行前* 返回 @AfterReturning*      返回通知执行时机为代理方法调用结束正常返回结果后* 异常 @AfterThrowing*      异常通知执行时机为调用方法出现异常时执行* 后置 @After*      后置通知执行时机为代理方法调用完全结束后* 环绕 @Around*      环绕通知可以出现在代理方法前后中或异常等时机都能进行触发*      需手动调用proceed方法才会执行代理方法,并且代理方法的结果必须返回,不然报错*/
@Aspect    //该注解声明该类是一个切面类
@Component //通过该注解可以完成自动注入,放入IoC容器中
public class LogAspect {/**** JoinPoint切入点参数,该参数可以获取执行方法的名称,方法参数等等*///@Before("execution(public int com.itgyl.annoAop.*.*(..))")@Before(value = "execution(public int com.itgyl.annoAop.CalculatorImp.add(..))")public void beforeMethod(JoinPoint joinPoint) {String name = joinPoint.getSignature().getName();Object[] args = joinPoint.getArgs();System.out.println("前置通知执行啦 执行方法为 " + name + " 参数为" + Arrays.toString(args));}@After("execution(* com.itgyl.annoAop.CalculatorImp.*(..))")public void afterMethod(JoinPoint joinPoint) {String name = joinPoint.getSignature().getName();Object[] args = joinPoint.getArgs();System.out.println("后置通知执行啦 执行方法为 " + name + " 参数为" + Arrays.toString(args));}/**** returning:获取方法返回结果,返回结果的变量名随便取,但是下面执行的方法里的形参名要和该结果名保持一致* @param joinPoint 可通过该形参获取代理方法的内容* @param result    可通过该形参获取代理方法最终返回的结果*/@AfterReturning(value = "execution(* com.itgyl.annoAop.CalculatorImp.*(..))", returning = "result")public void afterReturningMethod(JoinPoint joinPoint, Object result) {String name = joinPoint.getSignature().getName();Object[] args = joinPoint.getArgs();System.out.println("返回通知执行啦 执行方法为" + name + " 参数为" + Arrays.toString(args) + "返回结果为 " + result);}/**** 参数Throwable为异常信息,若添加该形参也需要在切入点表达式中绑定相应的形参* @param joinPoint 通过该形参可以获取代理方法的参数* @param e         通过该形参可以获取出现异常的信息*/@AfterThrowing(value = "execution(* com.itgyl.annoAop.CalculatorImp.*(..))", throwing = "e")public void afterThrowingMethod(JoinPoint joinPoint, Throwable e) {String name = joinPoint.getSignature().getName();Object[] args = joinPoint.getArgs();System.out.println("异常通知执行啦 出现异常方法名为" + name + " 参数为" + Arrays.toString(args) + "异常信息为" + e);}@Around(value = "pointCut()")public Object aroundMethod(ProceedingJoinPoint joinPoint) throws Throwable {String name = joinPoint.getSignature().getName();String args = Arrays.toString(joinPoint.getArgs());Object result = null;try {System.out.println("环绕通知执行(调用代理方法前) 方法名为" + name + "参数为 " + args);//调用代理方法后必须返回结果result = joinPoint.proceed();System.out.println("环绕通知执行(调用代理方法后) 方法名为" + name + "参数为 " + args);} catch (Exception e) {System.out.println("环绕通知执行(调用代理方法出现异常)");} finally {System.out.println("环绕通知执行(结束)");}return result;}/***重用切入点表达式:如果要代理方法值都一样时,可以将切入点表达式封装起来,后面可以直接调用该方法不需要每次重复写executing函数* 细节:如果当前切面类重用该切入点表达式可以直接调用该函数使用*      当其他类调用时需要全类名+该函数名才能调用*      如:@Around(value = "pointCut()")*          @Around(value = "com.itgyl.annoAop.LogAspect.pointCut()")*/@Pointcut(value = "execution(* com.itgyl.annoAop.CalculatorImp.*(..))")public void pointCut() {}
}

 测试类

public class TestAnnoAop {@Testpublic void testAdd() {ApplicationContext context =new ClassPathXmlApplicationContext("bean.xml");System.out.println(context);Calculator c = context.getBean(Calculator.class);System.out.println(c);c.add(2,3);}
}

执行结果 

 

切入点优先级 

 

4. 基于XML的AOP

<?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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsd"><context:component-scan base-package="com.itgyl.xmlAop"></context:component-scan><aop:config><!--配置切面类--><aop:aspect ref="logAspect"><!--配置切入点--><aop:pointcut id="pointCut" expression="execution(* com.itgyl.xmlAop.CalculatorImp.*(..))"/><!--配置通知--><!--配置前置通知,执行代理方法前要执行的方法为beforeMethod,切入点为上面配置的切入点表达式--><aop:before method="beforeMethod" pointcut-ref="pointCut"></aop:before><!--配置后置通知--><aop:after method="afterMethod" pointcut-ref="pointCut"></aop:after><!--配置异常通知,需绑定抛出异常的值,该值和函数中的异常形参名需保持一致--><aop:after-throwing method="afterThrowingMethod" pointcut-ref="pointCut" throwing="e"></aop:after-throwing><aop:after-returning method="afterReturningMethod" pointcut-ref="pointCut" returning="result"></aop:after-returning><!--配置环绕通知--><aop:around method="aroundMethod" pointcut-ref="pointCut"></aop:around></aop:aspect></aop:config></beans>

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

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

相关文章

【热门话题】Debian常用命令指南

&#x1f308;个人主页: 鑫宝Code &#x1f525;热门专栏: 闲话杂谈&#xff5c; 炫酷HTML | JavaScript基础 ​&#x1f4ab;个人格言: "如无必要&#xff0c;勿增实体" 文章目录 Debian常用命令指南引言1. 文件与目录操作lscdmkdirrmcpmv 2. 包管理aptdpkg 3.…

minaActivatorA12+物主锁完美解信号,可登iCloud,有消息通知,支持iOS17.5.1+

原创 IOS福利部落 IOS福利部落 2024-05-26 19:35 福建 Mina Activator A12是一款绕过物主锁界面的解锁工具&#xff0c;可以激活所有iPhone恢复信号&#xff0c;并且支持插卡接打电话、收发短信、4G流量上网&#xff0c;支持iCloud登录&#xff0c;有消息通知&#xff0c;支持i…

sklearn实现线性回归

sklearn实现线性回归 一、数据集介绍二、使用sklearn实现线性回归一、数据集介绍 本案例使用女性身高体重数据集,数据集如下图所示: 可以看到,数据集有15行2列。 二、使用sklearn实现线性回归 sklearn中的线性模型模块是linear_model。这里使用linear_model下的普通线性…

【Linux】-Redis安装部署[15]

目录 简介 安装 1、配置EPEL仓库 2、安装redis 3、启动redis 4、放行防火墙&#xff0c;redis使用端口6379 5、进入redis服务 简介 redis是一个开源、使用C语言编写的、支持网络互交的、可基于内存也可持久化的Key-Value数据库。redis的特点就是&#xff1a;快&#xf…

安全设计 | CISA:构建默认安全的软件,软件安全设计的未来之路

软件制造商在产品设计和开发过程中应采取安全设计原则和方法&#xff0c;以减少网络安全风险&#xff0c;并转变责任重心&#xff0c;使产品在设计时就内置安全特性&#xff0c;而不是依赖于后期的补丁和修复。为此CISA发布了《软件安全设计的原则和方法》&#xff0c;帮助软件…

python如何把字符串变成小写字母

Python中&#xff0c;将字符串中的字母转换成小写字母&#xff0c;字符串变量提供了2种方法&#xff0c;分别是title()、lower()。 Python title()方法 title()方法用于将字符串中每个单词的首字母转为大写&#xff0c;其他字母全部转为小写&#xff0c;转换完成后&#xff0…

如何在go语言中调用c语言代码

1.安装c语言编译器 要使用cgo&#xff0c;需要安装c语言编译器 gcc 2.检查CGO_ENABLED时候开启 使用以下命令查看&#xff1a; go env CGO_ENABLED 如果go env CGO_ENABLED被禁用(为0),需要将其设置为开启(为1) 3.编写c语言程序&#xff0c;并用go语言调用c语言程序 1&#xff…

AIGC 005-Dreambooth定制化生成,微调文本到图像的扩散模型!

AIGC 005-Dreambooth定制化生成&#xff0c;微调文本到图像的扩散模型&#xff01; 文章目录 0 论文工作1 论文方法2 效果 0 论文工作 DreamBooth 论文 (DreamBooth: Fine-Tuning Text-to-Image Diffusion Models for Subject-Driven Generation) 提出了一种新颖的技术&#x…

【开源】大学生竞赛管理系统 JAVA+Vue+SpringBoot+MySQL

目录 一、系统介绍 学生管理模块 教师管理模块 竞赛信息模块 竞赛报名模块 二、系统截图 三、核心代码 一、系统介绍 基于Vue.js和SpringBoot的大学生竞赛管理系统&#xff0c;分为管理后台和用户网页端&#xff0c;可以给管理员、学生和教师角色使用&#xff0c;包括学…

mysql实战——xtrabackup全量备份/增量备份及恢复

一、测试前准备 mysql数据库 端口3306数据文件目录 /data/mysql/3306/data 安装目录/usr/lcoal/mysql配置文件/etc/my.cnf 创建数据库 testXtra 创建备份目录 备份目录/data/backup/备份恢复数据文件目录/data/mysql/3307/data备份恢复配置文件/etc/my_3307.cnf 二、开始…

linux查看是否被入侵(一)

1、查看当前系统状态 [rootbastion-IDC ~]#top #一般挖矿等病毒点用CPU比较大 2、查看当前登录用户(w\who) 3、检查系统日志 检查系统错误登陆日志&#xff0c;统计IP重试次数 [rootbastion-IDC ~]# lastb 4、查看近期用户登录情况 [rootkvm01 ~]# last -n 5 #-n 5 表示…

将list对象里的某一个属性取出组成一个新的list

使用Java8将对象里的某一个属性取出组成一个新的list List<Spgg1> listnew ArrayList<>();Spgg1 spgg1new Spgg1();spgg1.setSpdm("测试");spgg1.setGgdm("001");list.add(spgg1);Spgg1 spgg2new Spgg1();spgg2.setSpdm("测试2");sp…

Mysql 找出未提交事务的SQL及死锁

未提交事务&#xff1a; 通过查看information_schema.INNODB_TRX视图,您可以了解当前系统中正在运行的事务情况,从而进行问题排查和性能优化。 SELECT * FROM information_schema.innodb_trx; 通过trx_state为RUNNIG,trx_started判断是否有一直RUNNING的事务。 如果有未提交…

千帆【API接入】自定义组件简明教程

千帆【API接入】自定义组件简明教程 大家好&#xff0c;我是 JavaRoom&#xff0c;今天来给大家做一个自定义API接入来是心啊遣返组件创建案例简明教学。 1.准备工作 1.1 一个不欠费的千帆账号 财务总览地址&#xff1a;https://console.bce.baidu.com/billing/#/account/i…

“现代汽车中国前瞻软件赛杯” 牛客周赛 Round 43

A. 小红平分糖果&#xff08;签到&#xff09; // Problem: 小红平分糖果 // Contest: NowCoder // URL: https://ac.nowcoder.com/acm/contest/82394/A // Memory Limit: 524288 MB // Time Limit: 2000 ms // // Powered by CP Editor (https://cpeditor.org)#include<b…

以前:不会用电脑;现在:不会用AI

购买特价商务机票需要一些策略和灵活性。、 提前规划&#xff1a;商务舱票价通常在出发日期的2-3个月前最便宜。尽早规划您的行程并开始关注票价。 使用比价工具&#xff1a;使用Skyscanner、Kayak等比价网站来比较不同航空公司的商务舱票价。这些网站可以显示多个航空公司的价…

Jeecg | 如何解决 ERR Client sent AUTH, but no password is set 问题

最近在尝试Jeecg低代码开发&#xff0c;但是碰到了超级多的问题&#xff0c;不过总归是成功运行起来了。 下面说说碰到的最后一个配置问题&#xff1a;连接redis失败 Error starting ApplicationContext. To display the conditions report re-run your application with deb…

近期阅读论文

Exploring Hybrid Active-Passive RIS-Aided MEC Systems: From the Mode-Switching Perspective abstract 移动边缘计算&#xff08;MEC&#xff09;被认为是支持延迟敏感和计算密集型服务的有前途的技术。 然而&#xff0c;随机信道衰落特性导致的低卸载率成为制约MEC性能的…