Spring学习笔记——3

Spring学习笔记——3

  • 一、AOP简介
    • 1.1、AOP概述
    • 1.2、AOP思想的实现方案
    • 1.3、模拟AOP的基础代码
    • 1.4、AOP的相关概念
  • 二、基于XML配置的AOP
    • 2.1、XML方式AOP快速入门
    • 2.2、XML方式AOP配置详解
    • 2.3、XML方式AOP原理剖析
  • 三、基于注解配置AOP
    • 3.1、注解方式AOP基本使用
    • 3.2、注解方式AOP配置详解
    • 3.3、注解方式AOP原理解析

一、AOP简介

1.1、AOP概述

AOP,Aspect Oriented Programming,面向切面编程,是对面向对象编程OOP的升华。OOP是纵向对一个事物的抽象,一个对象包括静态的属性信息,包括动态的方法信息等。而AOP是横向的对不同事物的抽象,属性与属性、方法与方法、对象与对象都可以组成一个切面,而用这种思维去设计编程的方式叫做面向切面编程

在这里插入图片描述

1.2、AOP思想的实现方案

代理技术
动态代理技术,在运行期间,对目标对象的方法进行增强,代理对象同名方法内可以执行原有逻辑的同时嵌入执行其他增强逻辑或其他对象的方法

在这里插入图片描述

1.3、模拟AOP的基础代码

其实在之前学习BeanPostProcessor时,在BeanPostProcessor的after方法中使用动态代理对Bean进行了增强,实际存储到单例池singleObjects中的不是当前目标对象本身,而是当前目标对象的代理对象Proxy,这样在调用目标对象方法时,实际调用的是代理对象Proxy的同名方法,起到了目标方法前后都进行增强的功能,对该方式进行一下优化,将增强的方法提取出去到一个增强类中,且只对com.itheima.service.impl包下的任何类的任何方法进行增强

//自定义增强类
pubiic class MyAdvice{public void beforeAdvice(){system.out.println("beforeAdvice...");)public void afterAdvice() {System.out.println("afterAdvice...");}
}
public class MockAopBeanPostProcessor implements BeanPostProcessor , ApplicationContextAware {private ApplicationContext applicationContext;@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {//目的:对UserServiceImpl中的Show1和Show2方法进行增强,增强方法存在于Myadvice//问题:筛选 service.impl包下的所有类的所有方法都可以进行增强 解决方案:if-else//问题:Myadvice怎么获取 解决方案:从Spring容器中获取Myadivceif (bean.getClass().getPackage().getName().equals("com.Smulll.service.Impl")){//生成Bean的Proxy对象Object beanProxy = Proxy.newProxyInstance(bean.getClass().getClassLoader(),bean.getClass().getInterfaces(),(Object proxy, Method method, Object[] args) -> {Myadvice myadvice = applicationContext.getBean(Myadvice.class);//执行增强对象的before方法myadvice.before();//执行目标对象的指定方法Object invoke = method.invoke(bean, args);//执行增强对象的after方法myadvice.after();return invoke;});return beanProxy;}return null;}@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {this.applicationContext = applicationContext;}
}

1.4、AOP的相关概念

概念单词解释
目标对象Target被增强的方法所在的对象
代理对象Proxy对目标对象进行增强后的对象,客户端实际调用的对象
连接点Joinpoint目标对象中可以被增强的方法
切入点Pointcut目标对象中实际被增强的方法
通知\增强Advice增强部分的代码逻辑
切面Aspect增强和切入点的组合
织入Weaving将通知和切入点组合动态组合的过程

在这里插入图片描述

二、基于XML配置的AOP

2.1、XML方式AOP快速入门

前面我们自己编写的AOP基础代码还是存在一些问题的,主要如下

  • 被增强的包名在代码写死了
  • 通知对象的方法在代码中写死了
if (bean.getClass().getPackage().getName().equals("com.Smulll.service.Impl")){//生成Bean的Proxy对象Object beanProxy = Proxy.newProxyInstance(bean.getClass().getClassLoader(),bean.getClass().getInterfaces(),(Object proxy, Method method, Object[] args) -> {Myadvice myadvice = applicationContext.getBean(Myadvice.class);//执行增强对象的before方法myadvice.before();//执行目标对象的指定方法Object invoke = method.invoke(bean, args);//执行增强对象的after方法myadvice.after();return invoke;});return beanProxy;
}

通过配置文件的方式去解决上述问题

  • 配置哪些包、哪些类、哪些方法需要被增强
  • 配置目标方法要被哪些通知方法所增强,在目标方法执行之前还是之后执行增强

配置方式的设计、配置文件(注解)的解析工作,Spring已经帮我们封装好了

xml方式配置AOP的步骤:

  1. 导入AOP相关坐标;
<dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.9.6</version>
</dependency>
  1. 准备目标类、准备通知类,并配置给Spring管理;
  2. 配置切点表达式(哪些方法被增强);
  3. 配置织入(切点被哪些通知方法增强,是前置增强还是后置增强)。
<?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 id="userService" class="com.Smulll.service.Impl.UserServiceImpl"></bean><!--配置增强类--><bean id="myadvice" class="com.Smulll.advice.Myadvice"></bean><!--配置aop--><aop:config><!--配置切点表达式 目的:指定哪些方法被增强--><aop:pointcut id="mtPointcut" expression="execution(void com.Smulll.service.Impl.UserServiceImpl.show1())"/><!--配置织入 目的:指定哪些切点与哪些通知结合--><aop:aspect ref="myadvice"><aop:before method="before" pointcut-ref="mtPointcut"></aop:before><aop:after method="after" pointcut-ref="mtPointcut"></aop:after></aop:aspect></aop:config>
</beans>

2.2、XML方式AOP配置详解

xml配置AOP的方式还是比较简单的,下面看一下AOP详细配置的细节:

  • 切点表达式的配置方式
    • 可以配置多个切点
    <!--配置aop-->
    <aop:config><!--配置切点表达式 目的:指定哪些方法被增强--><aop:pointcut id="mtPointcut" expression="execution(void com.Smulll.service.Impl.UserServiceImpl.show1())"/><aop:pointcut id="mtPointcut2" expression="execution(void com.Smulll.service.Impl.UserServiceImpl.show2())"/>
    </aop:config>
    
    • pointcut属性可以再后面直接写上要结合的切点
    <!--配置aop-->
    <aop:config><!--配置切点表达式 目的:指定哪些方法被增强--><aop:pointcut id="mtPointcut" expression="execution(void com.Smulll.service.Impl.UserServiceImpl.show1())"/><!--配置织入 目的:指定哪些切点与哪些通知结合--><aop:aspect ref="myadvice"><aop:before method="before" pointcut-ref="mtPointcut"></aop:before><aop:after method="after" pointcut="execution(void com.Smulll.service.Impl.UserServiceImpl.show1())"></aop:after></aop:aspect>
    </aop:config>
    
  • 切点表达式的配置语法
    execution([访问修饰符]返回值类型 包名.类名.方法名(参数))
    
    其中
    • 访问修饰符可以省略不写;
    • 返回值类型、某一级包名、类名、方法名可以使用*表示任意;
    • 包名与类名之间使用单点.表示该包下的类,使用双点..表示该包及其子包下的类;
    • 参数列表可以使用两个点..表示任意参数。
//表示访问修饰符为public、无返回值、在com.itheima . aop包下的TargetImpl类的无参方法show
execution(public void com.itheima.aop.TargetImpl.show())
//表述com.itheima.aop包下的TargetImpl类的任意方法
execution(* com.itheima.aop.TargetImpl.*(..))
//表示com.itheima.aop包下的任意类的任意方法
execution(* com.itheima.aop.*.*(..))
//表示com.itheima. aop包及其子包下的任意类的任意方法
execution(* com.itheima.aop..*.*(..))
//表示任意包中的任意类的任意方法
execution(* *..*.*(..) )
  • 通知的类型
通知名称配置方式执行时机
前置通知<aop:before >目标方法执行之前执行
后置通知<aop:after-returning >目标方法执行之后执行,目标方法异常时,不在执行
环绕通知<aop:around >目标方法执行前后执行,目标方法异常时,环绕后方法不在执行
异常通知<aop:after-throwing >目标方法抛出异常时执行
最终通知<aop:after >不管目标方法是否有异常,最终都会执行

通知方法再被调用时,Spring可以为其传递一些必要的参数

参数类型作用
JoinPoint连接点对象,任何通知都可使用,可以获得当前目标对象、目标方法参数等信息
ProceedingJoinPointJoinPoint子类对象,主要是在环绕通知中执行proceed(),进而执行目标方法
Throwable异常对象,使用在异常通知中,需要在配置文件中指出异常对象名称
public void 通知方法名称(JoinPoint joinPoint){//获得目标方法的参数system.out.println(joinPoint.getArgs()) ;//获得目标对象system.out.println(joinPoint.getTarget());//获得精确的切点表达式信息System.out.println(joinPoint.getstaticPart());
}

Throwable对象

public void afterThrowing (JoinPoint joinPoint, Throwable th) {
//获得异常信息System.out.println("异常对象是:"+th+"异常信息是:"+th.getMessage());
}
<aop:after-throwing method="afterThrowing" pointcut-ref="myPointcut" throwing="th"/>
  • AOP的配置的两种方式
    • 使用<advisor>配置切面
    • 使用<aspect>配置切面

spring定义了一个Advice接口,实现了该接口的类都可以作为通知类出现

public interface Advice{
}

2.3、XML方式AOP原理剖析

动态代理的实现的选择,在调用getProxy()方法时,我们可选用的AopProxy接口有两个实现类,如上图,这两种都是动态生成代理对象的方式,一种就是基于JDK的,一种是基于Cglib的

代理技术使用条件配置方式
JDK动态代理技术目标类有接口,是基于接口动态生成实现类的代理对象目标类有接口的情况下,默认方式
Cglib 动态代理技术目标类无接口且不能使用final修饰,是基于被代理对象动态生成子对象为代理对象目标类无接口时,默认使用该方式;目标类有接口时,手动配置<aop:config proxy-target-class="true”>强制使用Cglib方式

在这里插入图片描述

Target target = new Target() ;//目标对象
Advices advices = new Advices();//通知对象
Enhancer enhancer = new Enhancer();//增强器对象
enhancer.setSuperclass(Target.class);//增强器设置父类
//增强器设置回调
enhancer.setCallback((MethodInterceptor) (o,method,objects,methodProxy)->{advices.before ( ) ;object result = method.invoke(target,objects);advices.afterReturning();return result;
});
//创建代理对象
Target tagetProxy = (Target) enhancer.create();
//测试
String result = targetProxy.show("haohao");

三、基于注解配置AOP

3.1、注解方式AOP基本使用

Spring的AOP也提供了注解方式配置,使用相应的注解替代之前的xml配置,xml配置AOP时,我们主要配置了三部分:目标类被Sprina容器管理、通知类被Spring管理、通知与切点的织入(切面),如下:

<!--配置目标-->
<bean id="target" class="com.itheima.aop.TargetImpl"></bean>
<!--配置通知-->
<bean id="advices" class="com.itheima.aop.Advices"></bean>
<!--配置aop-->
<aop:config proxy-target-class="true"><aop:aspect ref="advices"><aop:around method="around" pointeut="execution(* com.itheima.aop.*.*(..))"/></aop:aspect>
</aop:config>

配置aop,其实配置aop主要就是配置通知类中的哪个方法(通知类型)对应的切点表达式是什么
在这里插入图片描述
注解@Aspect@Around需要被Spring解析,所以在Spring核心配置文件中需要配置aspectj的自动代理

<aop:aspectj-autoproxy>

3.2、注解方式AOP配置详解

各种注解方式通知类型

//前置通知
@Before("execution( *com. itheima.aop.*.*(..))")
public void before(JoinPoint joinPoint){}
//后置通知
@AfterReturning("execution(* com.itheima.aop.*.*(..))")
public void afterReturning(JoinPoint joinPoint){}
//环绕通知
@Around("execution (* com.itheima.aop.*.*(..))")
public void around(ProceedingJoinPoint joinPoint) throws Throwable{}
//异常通知
@AfterThrowing("execution(* com.itheima.aop.*.*(..))")
public void afterThrowing(JoinPoint joinPoint){}
//最终通知
@After("execution(* com.itheima.aop.*.*(..))")
public void after(JoinPoint joinPoint){}
@Component
@Aspect
public class MyAdvice {@Pointcut("execution(* com.Smulll.service.Impl.*.*(..))")public void pointcut(){};//@Before("execution(* com.Smulll.service.Impl.*.*(..))")@Before("MyAdvice.pointcut()")public void before(){System.out.println("前置增强");}//@AfterReturning("execution(* com.Smulll.service.Impl.*.*(..))")@AfterReturning("MyAdvice.pointcut()")public void afterreturning(){System.out.println("后置增强");}//@Around("execution(* com.Smulll.service.Impl.*.*(..))")@Around("MyAdvice.pointcut()")public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {System.out.println("环绕前增强。。。");Object proceed = proceedingJoinPoint.proceed();//执行目标方法JoinPoint.StaticPart staticPart = proceedingJoinPoint.getStaticPart();Object target = proceedingJoinPoint.getTarget();System.out.println("表达式:"+staticPart);System.out.println("当前目标对象为:"+target);System.out.println("环绕后增强。。。");return proceed;}//@AfterThrowing("execution(* com.Smulll.service.Impl.*.*(..))")@AfterThrowing("MyAdvice.pointcut()")public void afterThrowAdvice(){System.out.println("异常抛出通知。。。报异常时执行");}//@After("execution(* com.Smulll.service.Impl.*.*(..))")@After("MyAdvice.pointcut()")public void after(){System.out.println("最终增强");}
}

使用配置类进行spring的配置

@Configuration
@ComponentScan("com.Smulll")//<context:component-scan base-package="com.Smulll"/>
@EnableAspectJAutoProxy//<aop:aspectj-autoproxy/>
public class Springconfig {
}

3.3、注解方式AOP原理解析

之前在使用xml配置AOP时,是借助的Spring的外部命名空间的加载方式完成的,使用注解配置后,就抛弃了<aop.config>标签,而该标签最终加载了名为AspectJAwareAdvisorAutoProxyCreator的BeanPostProcessor ,最终,在该BeanPostProcessor中完成了代理对象的生成。

同样,从aspectj-autoproxy标签的解析器入手

this.registerBeanDefinitionParser("aspectj-autoproxy",new AspectJAutoProxyBeanDefinitionParser());

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

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

相关文章

手写Spring:第15章-通过注解注入属性信息

文章目录 一、目标&#xff1a;通过注解注入属性信息二、设计&#xff1a;通过注解注入属性信息三、实现&#xff1a;通过注解注入属性信息3.1 工程结构3.2 自动扫描注入占位符配置和对象类图3.3 读取属性并填充到容器中3.3.1 定义解析字符串接口3.3.2 配置Bean工厂添加解析器3…

基于Java+SpringBoot+Vue前后端分离农产品直卖平台设计和实现

博主介绍&#xff1a;✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专…

手写签名到背景上合为1张图

手写签名到背景上合为1张图 package.json中 "signature_pad": "3.0.0-beta.3"<template><div class"home"><canvas id"canvas" width"500" height"300"></canvas><button click"…

ELK高级搜索(三)

文章目录 11&#xff0e;索引Index入门11.1 索引管理11.2 定制分词器11.3 type底层结构11.4 定制dynamic mapping11.5 零停机重建索引 12&#xff0e;中文分词器 IK分词器12.1 Ik分词器安装使用12.2 ik配置文件12.3 使用mysql热更新 13&#xff0e;java api 实现索引管理14&…

026:vue中el-progress逆向倒计时方式显示

第026个 查看专栏目录: VUE ------ element UI 专栏目标 在vue和element UI联合技术栈的操控下&#xff0c;本专栏提供行之有效的源代码示例和信息点介绍&#xff0c;做到灵活运用。 &#xff08;1&#xff09;提供vue2的一些基本操作&#xff1a;安装、引用&#xff0c;模板使…

Redis多机数据库实现

Redis多机数据库实现 为《Redis设计与实现》笔记 复制 客户端可以使用SLAVEOF命令将指定服务器设置为该服务器的主服务器 127.0.0.1:12345> SLAVEOF 127.0.0.1 6379127.0.0.1:6379将被设置为127.0.0.1:123456的主服务器 旧版复制功能的实现 Redis的复制功能分为同步&a…

Linux之history、tab、alias、命令执行顺序、管道符以及exit

目录 Linux之history、tab、alias、命令执行顺序、管道符以及exit history历史命令 格式 参数 修改默认记录历史命令条数 案例 案例1 --- 显示history历史记录中出现次数最高的top10 案例2 --- 增加history显示的时间信息 命令与文件名补全 --- tab 命令别名 格式 案…

MySQL事务管理

文章目录 MySQL事务管理0. MySQL的CURD不加控制&#xff0c;出现的问题1. 什么是事务2. 为什么会出现事务3. 事务的版本支持与提交方式3.1 版本支持3.2 提交方式 4. 事务的操作4.0 准备工作4.1 事务正常操作(1) 创建保存点后, rollback(2) 直接rollback(3) 正常提交 4.2 事务异…

学生免费申请IDEA使用流程

IntelliJ IDEA一般简称IDEA&#xff0c;是Java编程语言开发的集成环境&#xff0c;在业界被公认为最好的Java开发工具。 1 IDEA官网下载 1.1 官网地址 https://www.jetbrains.com/idea/ 1.2 IDEA下载 访问官网&#xff0c;单击download按钮&#xff0c;下载“IntelliJ IDE…

牛客练习赛115 A Mountain sequence

题目&#xff1a; 样例&#xff1a; 输入 3 5 1 2 3 4 5 3 3 3 3 3 1 2 1 输出 16 1 3 思路&#xff1a; 依据题意&#xff0c;再看数据范围&#xff0c;可以知道暴力肯定是不可能了&#xff0c;然后通过题目意思&#xff0c;我们可以排列模拟一下&#xff0c;这里排列所得结…

Vue+NodeJS上传图片到腾讯云Cos

一.前端Vue 1.选择图片 --HTML <input type"file" accept"image/*" change"handleFileChange"> <el-button size"large" click"changeAvatar">上传头像</el-button> //选择图片 function handleFileC…

ubuntu22.04 设置网卡开机自启

配置文件路径 在Ubuntu中&#xff0c;网络配置文件通常位于/etc/netplan/目录下&#xff0c;其文件名以.yaml为后缀。Netplan是Ubuntu 17.10及更高版本中默认的网络配置工具&#xff0c;用于配置网络接口、IP地址、网关、DNS服务器等。 我们可以看到配置文件为 01-network-ma…

48、springboot 的国际化之让用户在程序界面上弄个下拉框,进行动态选择语言

上一篇是直接改浏览器的支持语言。 在浏览器上面直接改国际化语言 这次要实现的功能是直接在程序界面动态选择语言。 Locale 代表语言、国家。 ★ 在界面上动态改变语言 应用之所以能动态呈现不同的语言界面&#xff0c;其实关键在于如何确定客户端的Locale&#xff08;代…

Hugging News #0904: 登陆 AWS Marketplace

每一周&#xff0c;我们的同事都会向社区的成员们发布一些关于 Hugging Face 相关的更新&#xff0c;包括我们的产品和平台更新、社区活动、学习资源和内容更新、开源库和模型更新等&#xff0c;我们将其称之为「Hugging News」。本期 Hugging News 有哪些有趣的消息&#xff0…

Python库-coverage测试覆盖率

Coverage.py 是用于测量Python程序代码覆盖率的工具。它 监视程序&#xff0c;注意代码的哪些部分已执行&#xff0c;然后 分析源以识别可以执行但未执行的代码。 覆盖率测量通常用于衡量测试的有效性。它 可以显示测试正在执行代码的哪些部分&#xff0c;以及哪些部分是 不。…

掌握API数据检索:过滤和排序的综合指南

API可以返回大量的数据&#xff0c;这使得开发人员很难只检索他们需要的信息。这就是API的过滤和排序功能的用武之地。 过滤和排序是API设计的两个基本功能&#xff0c;它们允许开发人员有效地从API检索特定的数据。过滤使开发人员能够通过指定返回的数据必须满足的标准来缩小A…

javaee spring 测试aop 切面

切面类 package com.test.advice;import org.aspectj.lang.ProceedingJoinPoint;//增强类 public class MyAdvice {//将这个增强方法切入到service层的add方法前public void before(){System.out.println("添加用户之前");}}目标类 package com.test.service;publi…

[Vue3 博物馆管理系统] 使用Vue3、Element-plus tabs组件构建选项卡功能

系列文章目录 第一章 定制上中下&#xff08;顶部菜单、底部区域、中间主区域显示&#xff09;三层结构首页 第二章 使用Vue3、Element-plus菜单组件构建菜单 第三章 使用Vue3、Element-plus走马灯组件构建轮播图 第四章 使用Vue3、Element-plus tabs组件构建选项卡功能 [第五…

探索 Wall-E 的寻路算法

几年前,Yandex 组织了一场名为“机器人快递员”的竞赛,并提供了诱人的奖品:一张参加专业人士封闭式自动驾驶会议的门票。该竞赛类似于一场游戏,参与者的任务是在地图上找到最佳路线并使用机器人快递员优化送货。 当我深入研究这个主题时,我发现尽管路线查找问题已经解决,…

【MongoDB】Ubuntu22.04 下安装 MongoDB | 用户权限认证 | skynet.db.mongo 模块使用

文章目录 Ubuntu 22.04 安装 MongoDB后台启动 MongoDBshell 连入 MongoDB 服务 MongoDB 用户权限认证创建 root 用户开启认证重启 MongoDB 服务创建其他用户查看用户信息验证用户权限删除用户 skynet.db.mongo 模块使用authensureIndexfind、findOneinsert、safe_insertdelete、…