Spring 用法学习总结(三)之 AOP

Spring学习

  • 7 bean的生命周期
  • 8 AOP面向切面编程
    • 8.1 AOP相关术语
    • 8.2 AOP使用


7 bean的生命周期

bean的生命周期主要为bean实例化、bean属性赋值、bean初始化、销毁bean,其中在实例化和初始化前后都使用后置处理器方法,而InstantiationAwareBeanPostProcessor 继承了BeanPostProcessor
可以看下这篇博客大致了解一下:
一文读懂 Spring Bean 的生命周期
在这里插入图片描述
bean的作用域

  • 单例(Singleton):在整个应用中,只创建bean的一个实例
  • 原型(Prototype):每次注入或者通过Spring的应用上下文获取的时候,都会创建一个新的bean实例
  • 会话(Session):在Web应用中,为每个会话创建一个bean实例
  • 请求(Rquest):在Web应用中,为每个请求创建一个bean实例

8 AOP面向切面编程

AOP(Aspect Oriented Programming)面向切面编程,利用 AOP 可以使得业务模块只需要关注核心业务的处理,不用关心其他的(如安全管理)。可以不通过修改源代码的方式,在主干功能里面添加新功能。

使用AOP相关的包:百度网盘
在这里插入图片描述

8.1 AOP相关术语

通知(Advice)
通知定义了何时使用切面,有以下五种类型的通知

  • 前置通知(Before):在目标方法被调用之前调用通知功能
  • 后置通知(After):在目标方法完成之后调用通知,此时不会关心方法的输出是什么
  • 返回通知(After-returning):在目标方法成功执行之后调用通知
  • 异常通知(After-throwing):在目标方法抛出异常后调用通知
  • 环绕通知(Around):通知包裹了被通知的方法,在被通知的方法调用之前和调用之后执行自定义的行为

连接点(Join point)

连接点是在应用执行过程中能够插入切面的一个点。这个点可以是调用方法时、抛出异常时、甚至修改一个字段时。切面代码可以利用这些点插入到应用的正常流程之中,并添加新的行为。

切点(Pointcut)

切点定义了何处使用切面。会匹配通知(Advice)所要织入的一个或多个连接点。我们通常使用
明确的类和方法名称,或利用正则表达式定义所匹配的类和方法名称来指定这些切点。

切面(Aspect)

切面是通知和切点的结合。通知和切点共同定义了切面的全部内容——它是什么,在何时和何处完成其功能。

引入(Introduction)

引入允许我们向现有的类添加新方法或属性。

目标对象(Target)

Target是织入 Advice 的目标对象

织入(Weaving)

织入就是把通知(Advice)添加到目标对象具体的连接点上的过程

在这里插入图片描述

8.2 AOP使用

切入点表达式语法结构: execution([权限修饰符] [返回类型] [类全路径] [方法名称]([参数列表]) ),此外还可以对切入点进行限制,因为“&”在XML中有特殊含义,所以在Spring的XML配置里面描述切点时,我们可以使用and来代替“&&”。同样,or和not可以分别用来代替“||”和“!”

在这里插入图片描述
在这里插入图片描述

基于注解

创建配置类ConfigAop

package springstudy2;import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;//创建ConfigAop配置类
@Configuration //@Configuration标记类作为配置类替换xml配置文件
@EnableAspectJAutoProxy(proxyTargetClass = true) //启用自动代理
@ComponentScan(basePackages = {"springstudy2"}) //开启注解扫描
public class ConfigAop {
}

@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = true)
@ComponentScan(basePackages = {“springstudy2”})

三个注解相当于以下代码

<?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:jdbc="http://www.springframework.org/schema/jdbc"  xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx"xmlns:util="http://www.springframework.org/schema/util" xmlns:task="http://www.springframework.org/schema/task" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsdhttp://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-4.0.xsdhttp://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.0.xsdhttp://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsdhttp://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsdhttp://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.0.xsd" default-lazy-init="false"><!-- 开启注解扫描 --><context:component-scan base-package="springstudy2"></context:component-scan><!-- 开启 Aspect 生成代理对象--><aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>

创建User类

package springstudy2;import org.springframework.stereotype.Component;//创建User对象
@Component
public class User {public void add() {//int a = 10 / 0;System.out.println("调用add方法...");}public void test() {System.out.println("调用test方法...");}
}

创建代理 UserProxy

如果有多个代理,可以通过@Order注解指定优先级,数字越小,优先级越高

package springstudy2;import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;//创建UserProxy对象
//增强的类
@Component
@Aspect //生成代理对象
@Order(1)//代理优先级,数字越小,优先级越高
public class UserProxy {//相同切入点抽取@Pointcut(value = "execution(* springstudy2.User.add(..))")public void pointdemo() { //pointdemo()方法的内容并不重要,在这里它实际上应该是空的}//前置通知//@Before 注解表示作为前置通知@Before(value = "pointdemo()")public void before() {System.out.println("在目标方法被调用之前调用通知功能.........");}@Before(value = "execution(* springstudy2.User.test(..))")public void before1() {System.out.println("test 在目标方法被调用之前调用通知功能.........");}//后置通知@After(value = "execution(* springstudy2.User.add(..))")public void after() {System.out.println("在目标方法完成之后调用通知.........");}//返回通知@AfterReturning(value = "pointdemo()")public void afterReturning() {System.out.println("在目标方法成功执行之后调用通知.........");}//异常通知@AfterThrowing(value = "execution(* springstudy2.User.add(..))")public void afterThrowing() {System.out.println("在目标方法抛出异常后调用通知.........");}//环绕通知@Around(value = "execution(* springstudy2.User.add(..))")public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {System.out.println("环绕之前,在被通知的方法调用之前.........");//被增强的方法执行proceedingJoinPoint.proceed();System.out.println("环绕之后,在被通知的方法调用之后.........");}
}

上述代码中,@afterReturning 和 @after 注解的执行顺序存在版本问题(有争议),据说从Spirng 5.2.7那一版开始,通知注解的执行顺序如下(不知道后面改没改。。。我的Spring5.3.9是这样):

  1. @Around注解方法的前半部分业务逻辑
  2. @Before注解方法的业务逻辑
  3. 目标方法的业务逻辑
  4. @AfterThrowing(若目标方法有异常,执行@AfterThrowing注解方法的业务逻辑)
  5. @AfterReturning(若目标方法无异常,执行@AfterReturning注解方法的业务逻辑)
  6. @After(不管目标方法有无异常,都会执行@After注解方法的业务逻辑)
  7. @Around注解方法的后半部分业务逻辑(@Around注解方法内的业务逻辑若对ProceedingJoinPoint.proceed()方法没做捕获异常处理,直接向上抛出异常,则不会执行Around注解方法的后半部分业务逻辑;若做了异常捕获处理,则会执行)

创建 PersonProxy 代理

package springstudy2;import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;//创建PersonProxy对象
//增强的类
@Component
@Aspect //生成代理对象
@Order(2)//代理优先级,数字越小,优先级越高
public class PersonProxy {@Before(value = "execution(* springstudy2.User.add(..))")public void before() {System.out.println("person 在目标方法被调用之前调用通知功能.........");}
}

测试类Test

package springstudy2;import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class Test {public static void main(String[] args) {ApplicationContext context = new AnnotationConfigApplicationContext(ConfigAop.class);//ConfigAop为配置类User user = context.getBean("user", User.class);user.add();user.test();}
}

执行结果
在这里插入图片描述

基于XML

在src目录下创建bean3.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/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"><!--创建对象--><bean id="user" class="springstudy2.User"></bean><bean id="userproxy" class="springstudy2.UserProxy"></bean><bean id="personproxy" class="springstudy2.PersonProxy"></bean><aop:config><!--切入点--><aop:pointcut id="p" expression="execution(* springstudy2.User.add(..))"/><!--配置切面--><aop:aspect ref="userproxy" order="1"> <!--通过 orde r确定优先级--><!--增强作用在具体的方法上--><!--method="before"中 before 是UserProxy类中的方法名--><aop:before method="before" pointcut-ref="p"/><aop:before method="before" pointcut="execution(* springstudy2.User.test(..))"/><aop:after method="after" pointcut-ref="p"/><aop:after-returning method="afterReturning" pointcut-ref="p"/><aop:after-throwing method="afterThrowing" pointcut-ref="p"/><aop:around method="around" pointcut-ref="p"/></aop:aspect><aop:aspect ref="personproxy" order="2"><!--增强作用在具体的方法上--><aop:before method="before" pointcut-ref="p"/></aop:aspect></aop:config>
</beans>

修改Test类

package springstudy2;import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class Test {public static void main(String[] args) {ApplicationContext context = new ClassPathXmlApplicationContext("bean3.xml");User user = context.getBean("user", User.class);user.add();user.test();}
}

基于XML的AOP执行结果
在这里插入图片描述
基于注解的AOP执行结果
在这里插入图片描述

注:与注解执行顺序不一致,原因是两者使用的AOP代理不同,在基于注解的AOP中,通知的执行顺序是确定的,而多个切面执行顺序由@Order注解来控制,当没有指定@Order注解时,Spring会按照切面类的类名进行排序,从字母顺序最小的切面开始执行,依次递增;在XML配置中,@around注解声明在@before注解前面,则@around注解先执行,否则,@before注解先执行

<aop:after method="after" pointcut-ref="p"/>
<aop:after-returning method="afterReturning" pointcut-ref="p"/>
<aop:after-throwing method="afterThrowing" pointcut-ref="p"/>
<aop:around method="around" pointcut-ref="p"/>
<aop:before method="before" pointcut-ref="p"/>
<aop:before method="before" pointcut="execution(* springstudy2.User.test(..))"/>

在这里插入图片描述

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

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

相关文章

浅析Linux内核线程监测机制:Hung Task

文章目录 概述Hung Task配置Hung Task机制初始化Hung Task监测线程 相关参考 概述 Hung Task机制周期性地监测系统中处于TASK_UNINTERRUPTIBLE状态&#xff08;即D状态&#xff09;的进程&#xff0c;如果超过120s&#xff08;时间可配&#xff09;&#xff0c;进程状态还没有…

Ambiguous Medical Image Segmentation using Diffusion Models利用扩散模型分割模糊医学图像

摘要&#xff1a; 事实证明&#xff0c;在临床任务中&#xff0c;来自一组专家的集体见解总是优于个人的最佳诊断。对于医学图像分割任务&#xff0c;现有的基于人工智能的替代研究更多地侧重于开发能够模仿最佳个体的模型&#xff0c;而不是利用专家组的力量。 在本文中&…

实战案例:将已有的 MySQL8.0 单机架构变成主从复制架构

操作步骤 修改 master 主节点 的配置&#xff08; server-id log-bin &#xff09;master 主节点 完全备份&#xff08; mysqldump &#xff09;master 主节点 创建复制用户并授权master 主节点 将完全备份文件拷贝至从节点修改 slave 从节点 的配置&#xff08; server-id rea…

gorm day9(结)

gorm day9 实体关联gorm会话 实体关联 自动创建、更新 在创建、更新数据时&#xff0c;GORM会通过Upsert自动保存关联及其引用记录。 user : User{Name: "jinzhu",BillingAddress: Address{Address1: "Billing Address - Address 1"},Ship…

[数学建模] 计算差分方程的收敛点

[数学建模] 计算差分方程的收敛点 差分方程&#xff1a;差分方程描述的是在离散时间下系统状态之间的关系。与微分方程不同&#xff0c;差分方程处理的是在不同时间点上系统状态的变化。通常用来模拟动态系统&#xff0c;如在离散时间点上更新状态并预测未来状态。 收敛点&…

git stash 正确用法

目录 一、背景 二、使用 2.1 使用之前&#xff0c;先简单了解下 git stash 干了什么&#xff1a; 2.2 git stash 相关命令 2.3 使用流程 1. 执行 git stash 2. 查看刚才保存的工作进度 git stash list 3. 这时候在看分支已经是干净无修改的(改动都有暂存到 stash) 4. 现在…

NLP快速入门

NLP入门 课程链接&#xff1a;https://www.bilibili.com/video/BV17K4y1W7yb/?p1&vd_source3f265bbf5a1f54aab2155d9cc1250219 参考文档链接1&#xff1a;NLP知识点&#xff1a;Tokenizer分词器 - 掘金 (juejin.cn) 一、分词 分词是什么&#xff1f; 每个字母都有对应…

数据分析案例-基于亚马逊智能产品评论的探索性数据分析

&#x1f935;‍♂️ 个人主页&#xff1a;艾派森的个人主页 ✍&#x1f3fb;作者简介&#xff1a;Python学习者 &#x1f40b; 希望大家多多支持&#xff0c;我们一起进步&#xff01;&#x1f604; 如果文章对你有帮助的话&#xff0c; 欢迎评论 &#x1f4ac;点赞&#x1f4…

URL编码算法:解决特殊字符在URL中的烦恼

引言&#xff1a; URL编码算法是一种将URL中的特殊字符转换为特定格式的编码方式。它在网络传输中起到了保护数据安全与完整性的重要作用。本文将深入探讨URL编码算法的优点与缺点&#xff0c;并介绍它在Web开发、网络安全等方面的应用。 URL编码解码 | 一个覆盖广泛主题工具…

JavaWeb学习|i18n

学习材料声明 所有知识点都来自互联网&#xff0c;进行总结和梳理&#xff0c;侵权必删。 引用来源&#xff1a;尚硅谷最新版JavaWeb全套教程,java web零基础入门完整版 i18n 国际化&#xff08;Internationalization&#xff09;指的是同一个网站可以支持多种不同的语言&…

Ubuntu 22 部署Zabbix 6.4

一、安装及配置postgresql sudo apt-get update sudo apt-get install postgresql postgresql-client 修改配置文件&#xff0c;配置远程访问&#xff1a;&#xff08;PostgreSQL安装路径下的data&#xff0c;也是安装时data的默认路径&#xff09;data目录下的 pg_hba.conf …

BN介绍:卷积神经网络中的BatchNorm

一、BN介绍 1.原理 在机器学习中让输入的数据之间相关性越少越好&#xff0c;最好输入的每个样本都是均值为0方差为1。在输入神经网络之前可以对数据进行处理让数据消除共线性&#xff0c;但是这样的话输入层的激活层看到的是一个分布良好的数据&#xff0c;但是较深的激活层…

.NET命令行(CLI)常用命令

本文用于记录了.NET软件开发全生命周期各阶段常用的一些CLI命令&#xff0c;用于开发速查。 .NET命令行&#xff08;CLI&#xff09;常用命令 项目创建&#xff08;1&#xff09;查看本机SDK&#xff08;2&#xff09;查看本机可以使用的.NET版本&#xff08;3&#xff09;生成…

C语言--------数据在内存中的存储

1.整数在内存中的存储 整数在内存是以补码的形式存在的&#xff1b; 整型家族包括char,int ,long long,short类型&#xff1b; 因为char类型是以ASCII值形式存在&#xff0c;所以也是整形家族&#xff1b; 这四种都包括signed,unsigned两种&#xff0c;即有符号和无符号&am…

Python Matplotlib 的学习笔记

Python Matplotlib 的学习笔记 0. Python Matplotlib 简介1. 为什么要用 Matplotlib&#xff1f;2. Matplotlib 基础类详解2-1. Line&#xff08;线&#xff09;2-2. Marker&#xff08;标记&#xff09;2-3. Text&#xff08;文本&#xff09;2-4. Legend&#xff08;图例&…

Python面向对象学习小记

python中的类可以分为经典类和新式类。 类的定义方法&#xff1a; class 类名&#xff1a; pass 类名后面没有小括号&#xff01;&#xff01;&#xff01; 【注意和函数的定义做区分。】 函数的定义&#xff1a; def 函数名(): pass

【Linux】并发解决(上)-中断屏蔽,原子操作

&#x1f525;博客主页&#xff1a;PannLZ &#x1f38b;系列专栏&#xff1a;《Linux系统之路》 &#x1f618;欢迎关注&#xff1a;&#x1f44d;点赞&#x1f64c;收藏✍️留言 文章目录 并发解决1.中断屏蔽2.原子操作2.1整形原子操作2.2位原子操作原子变量使用例子 并发解决…

(力扣)1314.矩阵区域和

给你一个 m x n 的矩阵 mat 和一个整数 k &#xff0c;请你返回一个矩阵 answer &#xff0c;其中每个 answer[i][j] 是所有满足下述条件的元素 mat[r][c] 的和&#xff1a; i - k < r < i k, j - k < c < j k 且(r, c) 在矩阵内。 示例 1&#xff1a; 输入&a…

【运维测试】移动测试自动化知识总结第1篇:移动端测试介绍(md文档已分享)

本系列文章md笔记&#xff08;已分享&#xff09;主要讨论移动测试相关知识。主要知识点包括&#xff1a;移动测试分类及android环境搭建&#xff0c;adb常用命令&#xff0c;appium环境搭建及使用&#xff0c;pytest框架学习&#xff0c;PO模式&#xff0c;数据驱动&#xff0…

随机过程及应用学习笔记(三)几种重要的随机过程

介绍独立过程和独立增量过程。重点介绍两种独立增量过程-—维纳过程和泊松过程。 目录 前言 一、独立过程和独立增量过程 1、独立过程&#xff08;Independent Process&#xff09; 2、独立增量过程&#xff08;Independent Increment Process&#xff09; 二、正态过程&am…