Spring学习笔记——3

news2025/1/12 1:06:46

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;
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        //目的:对UserServiceImpl中的Show1和Show2方法进行增强,增强方法存在于Myadvice
        //问题:筛选 service.impl包下的所有类的所有方法都可以进行增强 解决方案:if-else
        //问题:Myadvice怎么获取 解决方案:从Spring容器中获取Myadivce
        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;
        }
        return null;
    }

    @Override
    public 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/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/aop
       http://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.coloradmin.cn/o/981488.html

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

相关文章

springMVC基础技术使用

目录 1.常用注解 1.1RequestMapping 1.2.RequestParam 1.3.RequestBody 1.4.PathVariable 2.参数传递 2.1 slf4j-----日志 2.2基础类型 2.3复杂类型 2.4RequestParam 2.5PathVariable 2.6RequestBody 2.7请求方法&#xff08;增删改查&#xff09; 3.返回值 3.1void …

rhcsa学习1基本命令(软硬链接,获取帮助等)

pwd 显示该shell的当前工作目录的完整路径名 ls 列出指定目录的目录内容 cd 更改shell的当前工作目录 没有什么特殊情况命令小写 ~所在位置&#xff1a;当前工作目录 #当前用户为管理员root $当前是普通用户 命令由三个基本部分组成&#xff1a; 命令、选项、参数 如下 -a --a…

Qt MinGW / MSVC

MinGW/MSVC的关系 MinGW / MSVC.dll / .lib / .a 的关系 MinGW / MSVC Qt 中有两种方式编译&#xff1a;一种是MinGW &#xff0c;另一种MSVC&#xff0c;是两种不同的编译器。 MinGW(Minimalist GNUfor Windows)&#xff0c;它是一个可自由使用和自由发布的Windows特定头文件…

2020年09月 C/C++(一级)真题解析#中国电子学会#全国青少年软件编程等级考试

C/C编程&#xff08;1~8级&#xff09;全部真题・点这里 第1题&#xff1a;输出整数 输入四个整数&#xff0c;把输入的第三、第四个整数输出。 时间限制&#xff1a;3000 内存限制&#xff1a;65536 输入 只有一行&#xff0c;共四个整数&#xff0c;整数之间由一个空格分隔。…

React中消息订阅与发布(PubSubJS)——两个组件之间通信

结合案例&#xff1a;github搜索案例 结果如下图 1.父容器代码 import React, { Component } from react import Search from ./components/Search import List from ./components/List export default class App extends Component {render() {return (<div className&…

QT Day5思维导图

聊天室代码&#xff1a; #include "cli.h" #include "ui_cli.h"Cli::Cli(QWidget *parent): QWidget(parent), ui(new Ui::Cli) {ui->setupUi(this);socket new QTcpSocket(this);connect(socket,&QTcpSocket::connected,this,&Cli::connect_…

Android Jetpack 中Hilt的使用

Hilt 是 Android 的依赖项注入库&#xff0c;可减少在项目中执行手动依赖项注入的样板代码。执行 手动依赖项注入 要求您手动构造每个类及其依赖项&#xff0c;并借助容器重复使用和管理依赖项。 Hilt 通过为项目中的每个 Android 类提供容器并自动管理其生命周期&#xff0c;…

图的学习,深度和广度遍历

一、什么是图 表示“多对多”的关系 包括&#xff1a; 一组顶点&#xff1a;通常用V&#xff08;Vertex&#xff09;表示顶点集合一组边&#xff1a;通常用E&#xff08;Edge&#xff09;表示边的集合 边是顶点对&#xff1a;(v, w)∈E&#xff0c;其中v,w∈V有向边<v, w&…

线性代数的学习和整理20,关于向量/矩阵和正交相关,相似矩阵等

目录 1 什么是正交 1.1 正交相关名词 1.2 正交的定义 1.3 正交向量 1.4 正交基 1.5 正交矩阵的特点 1.6 正交矩阵的用处 1 什么是正交 1.1 正交相关名词 orthogonal set 正交向量组正交变换orthogonal matrix 正交矩阵orthogonal basis 正交基orthogonal decompositio…

【微服务】五. Nacos服务注册

Nacos服务注册 5.1 Nacos服务分级存储模型Nacos服务分级存储模型&#xff1a;服务集群属性&#xff1a;总结&#xff1a; 5.2 根据集群负载均衡总结 5.3 Nacos服务实例的权重设置总结&#xff1a; 5.6 环境隔离namespace总结 5.7 Nacos和Eureka的对比总结 5.1 Nacos服务分级存储…

2023年亲测有效----树莓派启动时自动邮件上报ip

2023年亲测 树莓派启动时自动邮件上报ip 首先开启qq邮箱smtp服务shell文件内容启动自动执行python文件注意事项 首先开启qq邮箱smtp服务 然后点击开启就会有授权码 shell文件内容 在自己的shell里&#xff0c;运行echo $PATH&#xff0c;把内容覆盖下面的path。 功能 作用就…

图解系列 图解Kafka之Producer

开局一张图&#xff0c;其他全靠吹 发送消息流程如下&#xff1a; 1.初始化流程 指定bootstrap.servers&#xff0c;地址的格式为 host:port。它会连接bootstrap.servers参数指定的所有Broker&#xff0c;Producer启动时会发起与这些Broker的连接。因此&#xff0c;如果你为这…

点云从入门到精通技术详解100篇-伪雷达点云预测

前言 近年来,“自动驾驶”已经成为一个耳熟能详的词语,它是一种通过车载计 算实现无人驾驶的智能汽车系统。自动驾驶汽车依靠人工智能、视觉计算、视觉 传感器、控制设备和定位系统协同合作,让系统可以在无人主动操作的情况下, 自动安全地操作机动车辆。其中视觉传感器作…

【继RNN之后的一项技术】Transfomer 学习笔记

谷歌团队在17年的神作&#xff0c;论文17年6月发布 https://arxiv.org/abs/1706.03762 被NIPS2017收录&#xff0c;目前引用量已经逼近3w。 以下内容参考李沐老师的课程《动⼿学深度学习(Pytorch版)》 简介 注意力 自主性&#xff1a;有目的的搜索某样东西&#xff08;键&…

Python小知识 - 如何使用Python进行机器学习

如何使用Python进行机器学习 Python是一种解释型、面向对象、动态数据类型的高级程序设计语言。 机器学习是人工智能的一个分支&#xff0c;是让计算机自动“学习”。学习的过程是从经验E中获得知识K。经验E可以是一个数据集&#xff0c;比如一个图像数据集。知识K可以是计算机…

Python爬虫-爬取文档内容,如何去掉文档中的表格,并保存正文内容

前言 本文是该专栏的第58篇,后面会持续分享python爬虫干货知识,记得关注。 做过爬虫项目的同学,可能或多或少爬取过文档数据,比如说“政务网站,新闻网站,小说网站”等平台的文档数据。爬取文档数据,笔者这里就不过多详述,而本文,笔者将主要介绍在爬取文档数据的过程中…

六安RapidSSL泛域名https能保护几个域名

RapidSSL是Geotrust旗下的子品牌&#xff0c;Geotrust是国际知名的CA认证机构&#xff0c;每年都要通过WebTrust年检&#xff0c;而Geotrust旗下的https证书已经应用于市场多年&#xff0c;Geotrust的子品牌RapidSSL证书经营的DV基础型泛域名https证书也受到市场的欢迎。今天就…

MFC新建内部消息

提示&#xff1a;记录一下MFC新建内部消息的成功过程 文章目录 前言一、pandas是什么&#xff1f;二、使用步骤 1.引入库2.读入数据总结 前言 先说一下基本情况&#xff0c;因为要在mapview上增加一个显示加载时间的功能。然后发现是要等加载完再显示时间&#xff0c;显示在主…

动手学深度学习d2l.Animator无法在PyCharm中显示动态图片的解决方案

from d2l import torch as d2l一、问题描述 运行d2l的训练函数&#xff0c;仅在控制台输出以下内容&#xff0c;无法显示动态图片&#xff08;训练监控&#xff09; <Figure size 350x250 with 1 Axes> <Figure size 350x250 with 1 Axes> <Figure size 350x2…

数据结构与算法之贪心动态规划

一&#xff1a;思考 1.某天早上公司领导找你解决一个问题&#xff0c;明天公司有N个同等级的会议需要使用同一个会议室&#xff0c;现在给你这个N个会议的开始和结束 时间&#xff0c;你怎么样安排才能使会议室最大利用&#xff1f;即安排最多场次的会议&#xff1f;电影的话 那…