手撸Spring系列8:Spring AOP(理论篇)
说在前头: 笔者本人为大三在读学生,书写文章的目的是为了对自己掌握的知识和技术进行一定的记录,同时乐于与大家一起分享,因本人资历尚浅,发布的文章难免存在一些错漏之处,还请阅读此文章的大牛们见谅与斧正。若在阅读时有任何的问题,也可通过评论提出,本人将根据自身能力对问题进行一定的解答。
手撸Spring系列是笔者本人首次尝试的、较为规范的系列博客,将会围绕Spring框架分为
IOC/DI 思想
、Spring MVC
、AOP 思想
、Spring JDBC
四个模块,并且每个模块都会分为理论篇
、源码篇
、实战篇
三个篇章进行讲解(大约12篇文章左右的篇幅)。从原理出发,深入浅出,一步步接触Spring源码并手把手带领大家一起写一个 迷你版的Spring框架 ,促进大家进一步了解Spring的本质!由于源码篇涉及到源码的阅读,可能有小伙伴没有成功构建好Spring源码的阅读环境,笔者强烈建议:想要真正了解Spring,一定要构建好源码的阅读环境再进行研究,具体构建过程可查看笔者此前的博客:《如何构建Spring5源码阅读环境》
前言
从今天的博客开始,我们将开始探究Spring AOP 的源码~!!
由于AOP的理论和概念理解起来会比较困难(当然,你是大佬除外),笔者刚接触时也在了AOP的理论知识中困了许久。但如果试着去完成了一个Spring AOP的小Demo
后,一般思路就会豁然开朗。因此,在此次的理论篇中,除了讲解Spring AOP的理论知识外,还会附带一个小的实操案例~~!!
一、什么是AOP
我们先来看看百度百科是如何解释AOP的
在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
AOP
为Aspect Oriented Programming
的缩写,直译为“面向切面编程”。在初学Java时我们开始接触了OOP
面向对象编程,而学习Spring IOC 后我们又学习了OOB
面向Bean编程。此时又多了一个AOP
面向切面编程,我们又该如何来理解所谓面向切面的编程呢?
首先希望大家要搞懂一个最重要的点,AOP是为了 增强
一个方法而存在的,它并不会左右方法具体的 业务逻辑 ,通过AOP的切点织入的代码都是处理 非业务逻辑 的任务。如 写日志
等操作是不参与具体的业务逻辑的,日志写或者是不写,并不会左右你的程序是否能够正常运行,只是出现异常时的排查工作会比较麻烦而已,像这种写日志操作就是非业务逻辑的代码。而像这种代码在每个方法中几乎都是重复的,复制黏贴式的代码会给程序的维护带来不便,此时AOP将这些业务需求和系统需求分开的优势就展现出来了!!
二、AOP重要的概念
AOP中有几个重要的概念,分别是:切面Aspect
、通知Advice
、切点Pointcut
、连接点(JoinPonit)
、目标对象(Target)
、织入
。
- 切点: 切点就是具体需要去
切
的地方(具体需要增强的方法) - 通知: 通知包含两要素:①通知的时间;②通知的信息(具体要做什么事情)
- 切面: = 切点 + 通知(去哪里?什么时候?去做些什么?)
- 连接点: 连接点是在应用执行过程中能够插入切面的一个点,这个点可以是调用方法时、抛出以异常时、甚至修改一个字段时
- 目标对象: 需要被代理的类,如IndexService
- 织入: 把一个切面应用到真实对象上面的过程,就叫做织入(知道时间、地点、任务后,最后就是执行啦)
其中通知还分为前置通知
、后置通知
、异常通知
、最终通知
、环绕通知
。
- 前置通知(Before Advice): 方法执行前执行
- 后置返回通知(After Return Advice): 方法返回之前执行,可以对方法的返回值进行修改,在此之前如果出现异常则不会执行
- 后置通知(After Advice): 方法返回之后执行,不可以对方法的返回值进行修改,即使出现异常也会执行
- 异常通知(After Throwing Advice): 方法执行异常后执行
- 环绕通知(Around Advice): 环绕通知可以看成是前四个通知的集合,通过它就可以完成前四个通知的任务,并且环绕通知会比前置通知先执行。
为了让大家能够进一步的理解这些概念,笔者将带领着各位读者朋友们来写一个小demo~!!
三、.写一个小Demo
ApplicationConfig
首先我们需要开启AOP功能,这里我们使用注解的方式,在配置类上使用注解@EnableAspectJAutoProxy
即可
@EnableAspectJAutoProxy
@Configuration
public class ApplicationConfig {}
LogAspect
接着写一个日志切面类,里面定义了切点以及前置通知、后置通知、异常通知、最终通知。其中,@Pointcut
的匹配规则,还不了解的读者朋友们可以通过这篇博客进行了解:Spring AOP 切点匹配规则
package com.example.demo.aspect;import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;/*** <p>日志AOP配置类</p>* @author Bosen* @date 2021/9/17 15:37*/
@Component
@Aspect
public class LogAspect {/*** <p>配置切面</p>*/@Pointcut("execution(public * com.example.demo.service.*.*(..))")public void logPointcut(){}/*** <p>前置通知</p>*/@Before("logPointcut()")public void logBefore() {System.out.println("This is LogAspect before");}/*** <p>后置返回通知</p>*/@AfterReturning("logPointcut()")public void logAfterReturning() {System.out.println("This is LogAspect AfterReturning");}/*** <p>异常通知</p>*/@AfterThrowing("logPointcut()")public void logAfterThrowing() {System.out.println("This is LogAspect AfterThrowing");}/*** <p>后置通知</p>*/@After("logPointcut()")public void logAfter() {System.out.println("This is LogAspect After");}
}
IndexService
最后编写一个可以用于调用的service层方法echo
public class IndexService {public void echo() {System.out.println("This is IndexService echo");}
}
调用echo方法
@SpringBootTest
class DemoApplicationTests {@AutowiredIndexService service;@Testvoid contextLoads() {service.echo();}
}
执行后的结果如下:
由于echo
方法并没有异常抛出,因此不会执行异常通知,但如果出现异常,则后置返回通知将不会执行,转而执行异常通知,但后置通知不会受影响。
体验过上面四个通知(前置通知、后置返回通知、异常通知、后置通知)后,我们再来看看环绕通知,我们可以将环绕通知看成是前四个通知的集合。
环绕通知Around Advice
我们修改一下日志切面类LogAsoect
@Component
@Aspect
public class LogAspect {/*** <p>配置切面</p>*/@Pointcut("execution(public * com.example.demo.service.*.*(..))")public void logPointcut(){}/*** <p>环绕通知</p>*/@Around("logPointcut()")public Object logAround(ProceedingJoinPoint joinPoint) {// 得到方法执行所需的参数Object[] args = joinPoint.getArgs();Object proceed = null;try {System.out.println("前置通知Before");// 明确调用业务层方法proceed = joinPoint.proceed(args);System.out.println("后置返回通知AfterReturning");}catch (Throwable throwable){System.out.println("异常通知AfterThrowing");throwable.printStackTrace();} finally {System.out.println("后置通知After");}return proceed;}
}
再次调用echo结果如下:
通过上面的调用,我们发现其实环绕通知就可以独自完成前置、后置返回、异常、后置通知。
到了这里,相信各位读者朋友们已经对切面、切点、通知之间的关系已经有了一个比较清晰的理解~!!有了基础后,讲起Spring AOP的执行流程将会变得特别容易了~!!
四、Spring AOP执行流程
转自:https://blog.csdn.net/yxh13521338301/article/details/105224144
@EnableAspectJAutoProxy
开启aop- 底层是将
AspectJAutoProxyRegistrar
注入spring容器 - AspectJAutoProxyRegistrar通过AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry)的底层
registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source)
将AnnotationAwareAspectJAutoProxyCreator
注入spring容器 - AnnotationAwareAspectJAutoProxyCreator是BeanPostProcessor的子类,也是AOP的入口
- AnnotationAwareAspectJAutoProxyCreator的上级中
AbstractAutoProxyCreator
为AOP的核心类 - AbstractAutoProxyCreator重新了后置处理方法
postProcessAfterInitialization
,其中通过wrapIfNecessary
创建代理 - Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean)); - 层层包装调用,进入到
DefaultAopProxyFactory
的createAopProxy
方法创建代理 - 创建代理时判断目标对象是否实现接口,是则使用
JDK
的动态代理,否则使用CGLIB
的动态代理(CGLIB可以适用于有接口或无接口的类,但JDK动态代理只可以用于实现了接口的类) - 在JDK的动态代理的类JdkDynamicAopProxy中,可看到其中invoke方法实现代理功能
- List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); 获取aop的所有通知
- 使用责任链模式执行所有通知,执行目标方法
- 当我们在调用
getBean
去实例化springbean时,安装springbean的生命周期,在执行完bean自定义的init方法后,进入后置处理
这时就会创建代理类,当bean执行方法时,进入代理类的invoke,执行所有通知,再执行目标方法,实现代理功能
手撸Spring系列8:Spring AOP(理论篇)相关推荐
- [Spring手撸专栏学习笔记]——把AOP动态代理,融入到Bean的生命周期
本文是学习<Spring 手撸专栏>第 10 章笔记,主要记录我的一些debug调试过程,方便后期复习.具体学习,大家可以去看一下这个专栏,强烈推荐. 方案 其实在有了AOP的核心功能实现 ...
- 彻底学会Spring的IOC和AOP——理论+实操
目录 1 IOC 1.1 概念 1.2 底层原理 1.3 IOC容器 1.4 Bean管理:基于xml配置文件实现 1.5 两种类型的Bean 1.6 Bean的作用域 1.7 Bean的生命周期 1 ...
- Spring系列之Spring框架和SpringAOP集成过程分析(十)
转载请注明出处:https://blog.csdn.net/zknxx/article/details/80724180 在开始这个系列之前大家先想一下我们是怎么在项目中使用SpringAOP的(这里 ...
- Spring系列 1.Spring概述及IOP
Spring概述 简介 Spring : 春天 ->给软件行业带来了春天 2002年,Rod Jahnson首次推出了Spring框架雏形interface21框架. 2004年3月24日,Sp ...
- 【Spring 系列】Spring知识地图
文章目录 Spring IOC 知道 会用 熟练 掌握 专家 Spring AOP 知道 会用 熟练 掌握 专家 Spring MVC 知道 会用 熟练 掌握 专家 Spring WebFlux 知道 ...
- Spring系列之Spring常用注解总结
参看博客:https://www.cnblogs.com/xiaoxi/p/5935009.html 传统的Spring做法是使用.xml文件来对bean进行注入或者是配置aop.事物,这么做有两个缺 ...
- Spring系列之Spring常用注解总结 原文:https://www.cnblogs.com/xiaoxi/p/5935009.html
传统的Spring做法是使用.xml文件来对bean进行注入或者是配置aop.事物,这么做有两个缺点: 1.如果所有的内容都配置在.xml文件中,那么.xml文件将会十分庞大:如果按需求分开.xml文 ...
- Spring系列之Spring Web MVC-20
目录 Spring Web MVC DispatcherServlet 上下文层次结构 特殊Bean Web MVC 配置 程序配置 工作原理 异常 视图解析 配置 重定向 转发 内容协商 过滤器 F ...
- Spring 系列:Spring AOP 中@Pointcut的用法(多个Pointcut)
格式: execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern ...
- Spring系列之一 Spring MVC
摘要: 最近在看Spring的书,之前一直跟着项目做,虽然项目用到了Spring的很多功能,但是我很少有机会在工作的项目中去配置Spring.感觉只有理论是不够的,虽然只是用Spring的配置让人感觉 ...
最新文章
- LeetCode-笔记-394. 字符串解码
- 模拟浏览器发送请求报文
- Ubuntu apt-get 更新/查看软件
- 基于 gRPC 和 .NET Core 的服务器流
- RocketMq学习笔记001---Kafka,ActiveMQ、RabbitMQ、RocketMQ消息中间件的对比
- 矩池云上缺少curand.h、cublas_v2.h、cusolverDn.h头文件解决方法
- 【OpenCV入门指南】第六篇 轮廓检测 下
- 论文的研究背景如何着笔
- 张家界航空工业职业学院计算机,张家界航空工业职业技术学院2021年招生代码...
- 当年我们一起追过的Java,Java SE 个人笔记
- 基于C#+SQL Server实现(Web)学生选课管理系统【100010309】
- 计算机科学期刊催稿,SOFT COMPUTING
- 机器人Scribit_Scribit墙壁绘图机器人:一款可以在墙上涂鸦和创作的机器人
- 计蒜客 幼儿园买玩具
- iso 2631 matlab,声学基础及其分析软件 - 声振论坛 - 振动,动力学,声学,信号处理,故障诊断 - Powered by Discuz!...
- Office-kms
- linux下oracle数据库升级,Linux下升级Oracle 10
- c语言中的字符变量用保留两位小数,字符数字转换保留2位小数
- 文本编辑器 Notepad
- Orange 学习3 - Evaluate模块简介-1
热门文章
- 荷露叮咚wp建站系列视频课程.3WordPress功能菜单介绍
- 【appium报错】Original error:Could not proxy command to remote server. Original error:socket hang up
- iftop相关参数及说明
- 网易WEB白帽子-WEB安全体系建设
- 根据前序遍历和中序遍历创建二叉树
- statusBar控件
- Visual Studio 2017正式版各版本比较:企业版最强大
- IPFS系列 - 默克有向无环图(Merkle DAG)
- java pgp 加密_java – 如何解密签名的pgp加密文件?
- 旅行商问题(TSP)简介