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.hqwc.cn/news/100666.html

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

相关文章

react 基础知识(一)

1、 安装1 &#xff08;版本 react 18&#xff09; // 安装全局脚手架&#xff08;create-react-app基于webpackes6&#xff09; npm install -g create-react-app //使用脚手架搭建项目 create-react-app my-app // 打开目录 cd my-app // 运行项目 npm start2、初体验 impo…

【C#】泛型

【C#】泛型 泛型是什么 泛型是将类型作为参数传递给类、结构、接口和方法&#xff0c;这些参数相当于类型占位符。当我们定义类或方法时使用占位符代替变量类型&#xff0c;真正使用时再具体指定数据类型&#xff0c;以此来达到代码重用目的。 泛型特点 提高代码重用性一定…

1.初识爬虫

爬虫是批量模拟网络请求的程序&#xff0c;想百度谷歌这种搜索类网站本质上就是爬虫 使用爬虫的时候不应该对别人的网站有严重的影响&#xff0c;比如你爬的频率太高了&#xff0c;让人家的网站崩溃了。不应该爬取网页上显示不到的内容&#xff0c;比如有一个直播的网站&#…

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

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

MySQL误删数据 回滚

前言 生产环境数据库不允许删除表&#xff0c;可以将表修改成 XXX_to_delete 如果误删简单数据&#xff0c;可以考虑使用binlog恢复 一、查看命令 1.查看binlog是否开启 show variables like log_bin;切换到MySQL安装目录,查看mysqlbinlog日志文件 2.查看所有 binlog 日志…

MySQL之MHA高可用配置及故障切换

目录 一、什么是MHA 二、MHA的组成 1、MHA Node&#xff08;数据节点&#xff09; 2、MHA Manager&#xff08;管理节点&#xff09; 三、MHA的特点 四、MHA工作原理总结 五、MHA实验演示 一、什么是MHA MHA&#xff08;MasterHigh Availability&#xff09;是一套优秀的…

正方实践系统打卡

Use HTTP (已完成) &#x1f4dc; 使用指南 &#x1f6d6; 项目结构 log 日志文件 use 使用情况 (待) data.py 数据 log.py 日志 main.py 主函数 只需要修改data.py文件内容即可&#xff1a; header ——> 头文件 User-AgentCookieAccept user ——> 用户信息 ZFT…

GRU门控循环单元

GRU 视频链接 https://www.bilibili.com/video/BV1Pk4y177Xg?p23&spm_id_frompageDriver&vd_source3b42b36e44d271f58e90f86679d77db7Zt—更新门 Rt—重置门 控制保存之前一层信息多&#xff0c;还是保留当前神经元得到的隐藏层的信息多。 Bi-GRU GRU比LSTM参数少 …

手写Spring:第13章-把AOP扩展到Bean的生命周期

文章目录 一、目标&#xff1a;把AOP扩展到Bean的生命周期二、设计&#xff1a;把AOP扩展到Bean的生命周期三、实现&#xff1a;把AOP扩展到Bean的生命周期3.1 工程结构3.2 AOP动态代理融入Bean的生命周期类图3.3 定义Advice拦截器链3.3.1 定义拦截器链接口3.3.2 方法拦截器链接…

Python综合案例(动态柱状图)

一、基础柱状图 基本代码&#xff1a; """ 演示基础柱状图的开发 """ from pyecharts.charts import Bar from pyecharts.options import LabelOpts # 使用Bar构建基础柱状图 bar Bar() # 添加x轴的数据 bar.add_xaxis(["中国", &q…

js如何实现数组去重的常用方法

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 使用 Set&#xff08;ES6&#xff09;⭐ 使用 filter 和 indexOf⭐ 使用 reduce⭐ 使用对象属性⭐ 使用 includes 方法&#xff08;ES6&#xff09;⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 记得点击上方…

前端开发从 0 到 1 掌握 docker

文章目录 前端从 0 到 1 掌握 docker一、docker 的一些基础概念概念定义question&#xff1a;什么是docker&#xff1f; 为什么要使用docker&#xff1f; 二、实战操作 (墙裂建议读者实操一遍)Part1 - Linux CentOS 服务安装 DockerPart2 - 启动、使用、查看等命令Part3 - 示例…