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.mzph.cn/news/683206.shtml

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

相关文章

控制论与科学方法论

《控制论与科学方法论》&#xff0c;真心不错。 书籍原文电子版PDF&#xff1a;https://pan.quark.cn/s/00aa929e4433&#xff08;分类在学习目录下&#xff09; 备用链接&#xff1a;https://pan.xunlei.com/s/VNgj2vjW-Hf_543R2K8kbaifA1?pwd2sap# 控制论是一种让系统按照我…

CTF-web 之 burp suite 使用

burp suite 使用 一般其是作为一个辅助工具&#xff0c;直接使用来解题的部分是少数&#xff0c;我们可以使用它来观察请 求和响应&#xff0c;并且可以反复的提交&#xff0c;关键的是他还带有很多其他的功能&#xff0c;在我们做题的过程中&#xff0c; 使用的关键点包括&…

MyBatis篇----第六篇

系列文章目录 文章目录 系列文章目录前言一、什么是 MyBatis 的接口绑定?有哪些实现方式?二、使用 MyBatis 的 mapper 接口调用时有哪些要求?三、Mapper 编写有哪几种方式?前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳…

OpenGL-ES 学习(1)---- AlphaBlend

AlphaBlend OpenGL-ES 混合本质上是将 2 个片元的颜色进行调和(一般是求和操作)&#xff0c;产生一个新的颜色 OpenGL ES 混合发生在片元通过各项测试之后&#xff0c;准备进入帧缓冲区的片元和原有的片元按照特定比例加权计算出最终片元的颜色值&#xff0c;不再是新&#xf…

书生浦语大模型实战营-课程笔记(2)

介绍了一下InternLm的总体情况。 InternLm是训练框架&#xff0c;Lagent是智能体框架。 这个预训练需要这么多算力&#xff0c;大模型确实花钱。 Lagent是智能体框架&#xff0c;相当于LLM的应用。 pip设置 开发机的配置 pip install transformers4.33.1 timm0.4.12 sente…

vue项目搭建测试

5&#xff0c;项目测试 导入elementplus以及样式 import ElementPlus from element-plus import element-plus/dist/index.csscreateApp(App).use(store).use(router).use(ElementPlus).mount(#app)<template><el-row class"mb-4"><el-button>De…

MATLAB|基于改进二进制粒子群算法的含需求响应机组组合问题研究(含文献和源码)

目录 主要内容 模型研究 1.改进二进制粒子群算法&#xff08;BPSO&#xff09; 2.模型分析 结果一览 下载链接 主要内容 该程序复现《A Modified Binary PSO to solve the Thermal Unit Commitment Problem》&#xff0c;主要做的是一个考虑需求响应的机组组合…

投资银行在网络安全生态中的作用

文章目录 一、投资银行的含义(一)并购买方。(二)并购卖方。(三)IPO辅助。(四)投资银行业务的另一方面是帮助这些交易融资。二、从投资银行角度看网络安全产业(一)行业的短期前景三、复杂的网络安全并购(一)行业知识对投资银行业务很重要(二)在网络安全领域,技术…

HDFS的超级用户

一. 解释原因 HDFS(Hadoop Distributed File System)和linux文件系统管理一样&#xff0c;也是存在权限控制的。 但是很不一样的是&#xff0c; 在Linux文件系统中&#xff0c;超级用户Superuser是root而在HDFS中&#xff0c;超级用户Superuser是启动了namenode的用户&#x…

neo4j下载安装最新教程 2024.02

文章目录 neo4j简介下载地址配置环境变量命令行启动验证安装结果 neo4j简介 Neo4j 是一个高性能的 NoSQL 图形数据库&#xff0c;它将结构化数据存储在网络&#xff08;从数学角度叫做图&#xff09;上而不是表中。Neo4j 也可以被看作是一个高性能的图引擎&#xff0c;该引擎具…

mathtype公式

Mathtype 手写板 Win11手写板按钮灰色问题解决&#xff1a;在C:\Program Files\Common Files\microsoft shared\ink目录下粘贴mip.exe&#xff0c;C:\Program Files\Common Files\microsoft shared\ink\en-US目录下添加mip.exe.mui提取码y04v 公式识别 配合免费图片公式识别…

【开源】在线办公系统 JAVA+Vue.js+SpringBoot+MySQL

目录 1 功能模块1.1 员工管理模块1.2 邮件管理模块1.3 人事档案模块1.4 公告管理模块 2 系统展示3 核心代码3.1 查询用户3.2 导入用户3.3 新增公告 4 免责声明 本文项目编号&#xff1a; T 001 。 \color{red}{本文项目编号&#xff1a;T001。} 本文项目编号&#xff1a;T001。…

磁盘database数据恢复: ddrescue,dd和Android 设备的数据拷贝

ddrescue和dd 区别&#xff1a; GNU ddrescue 不是 dd 的衍生物&#xff0c;也与 dd 没有任何关系 除了两者都可用于将数据从一台设备复制到另一台设备。 关键的区别在于 ddrescue 使用复杂的算法来复制 来自故障驱动器的数据&#xff0c;尽可能少地造成额外的损坏。ddrescue…

mysql8.0.36主从复制(读写分离)配置教程

1、关闭防火墙 使用命令行关闭防火墙 在Ubuntu系统中&#xff0c;可以使用以下命令关闭防火墙&#xff1a; sudo ufw disable执行该命令后&#xff0c;系统会提示是否要关闭防火墙&#xff0c;确认后即可关闭防火墙。 查看防火墙状态 使用以下命令可以查看防火墙当前的状…

Vegeta压测工具学习与使用

Vegeta压测工具学习与使用 目标&#xff1a; 能够在命令行下使用Vegeta对指定API进行测试了解如何导出结果&#xff0c;以及能获得什么样的结果(P99,P99.9,QPS)探索能否导出其他结果&#xff0c;是否能够执行复杂命令或简易脚本等 时间比较紧迫&#xff0c;预计两到三个小时内完…

详解tomcat中的jmx监控

目录 1.概述 2.如何开启tomcat的JMX 3.tomcat如何实现JMX的源码分析 1.概述 本文是博主JAVA监控技术系列文章的第二篇&#xff0c;前面一篇文章中我们介绍了JAVA监控技术的基石——jmx&#xff1a; 【JMX】JAVA监控的基石-CSDN博客 本文我们将从使用和源码实现两个方面聊…

BLDC驱动刹车电路、能量泄放电路

不同STM32的性能; APM2.8飞控整合资料&#xff1a; APM2.8飞控说明书 GitBook BLDC的制动首先要考虑MOS的泄放电阻的选择&#xff0c;参考前面博客。 刹车电阻制动&#xff1a; 如图所示就是一种通过功率电阻耗散电机制动过程中产生电能的电路。因为功率电阻在这个电路中起…

【AI视野·今日Robot 机器人论文速览 第七十八期】Wed, 17 Jan 2024

AI视野今日CS.Robotics 机器人学论文速览 Wed, 17 Jan 2024 Totally 49 papers &#x1f449;上期速览✈更多精彩请移步主页 Daily Robotics Papers Safe Mission-Level Path Planning for Exploration of Lunar Shadowed Regions by a Solar-Powered Rover Authors Olivier L…

【并发编程】ThreadPoolExecutor类

&#x1f4dd;个人主页&#xff1a;五敷有你 &#x1f525;系列专栏&#xff1a;并发编程⛺️稳重求进&#xff0c;晒太阳 ThreadPoolExecutor 1) 线程池状态 ThreadPoolExecutor 使用 int 的高 3 位来表示线程池状态&#xff0c;低 29 位表示线程数量 状态名 高三位 …

全闭环直播推流桌面分享远控系统

直播推流涉及多协议&#xff0c;多端技术栈和知识点&#xff0c;&#xff0c;想要做好并不容易&#xff0c;经过几年时间的迭代&#xff0c;终于小有成就&#xff0c;聚集了媒体服务器&#xff0c;实时会议sfu&#xff0c;远控kvm等功能。可以做一个音视频应用的瑞士小军刀。主…