spring注解驱动系列--AOP探究一

一、AOP--动态代理

指在程序运行期间动态的将某段代码切入到指定方法指定位置进行运行的编程方式

二、使用栗子

一、导入aop模块

       <dependency><groupId>org.springframework</groupId><artifactId>spring-aspects</artifactId><version>4.3.12.RELEASE</version></dependency>

二、定义一个业务逻辑类

在业务逻辑运行的时候将日志进行打印(方法之前、方法运行结束、方法出现异常,xxx)


public class MathCalculator {public int div(int i,int j){System.out.println("MathCalculator...div...");return i/j;	}}

三、定义一个日志切面类

切面类里面的方法需要动态感知MathCalculator.div运行到哪里然后执行;


/*** 切面类** @Aspect: 告诉Spring当前类是一个切面类**/
@Aspect
public class LogAspects {//抽取公共的切入点表达式//1、本类引用//2、其他的切面引用@Pointcut("execution(public int com.spring.annotate.aop.MathCalculator.*(..))")public void pointCut(){};//@Before在目标方法之前切入;切入点表达式(指定在哪个方法切入)@Before("pointCut()")public void logStart(JoinPoint joinPoint){Object[] args = joinPoint.getArgs();System.out.println(""+joinPoint.getSignature().getName()+"运行。。。@Before:参数列表是:{"+Arrays.asList(args)+"}");}@After("com.spring.annotate.aop.LogAspects.pointCut()")public void logEnd(JoinPoint joinPoint){System.out.println(""+joinPoint.getSignature().getName()+"结束。。。@After");}//JoinPoint一定要出现在参数表的第一位@AfterReturning(value="pointCut()",returning="result")public void logReturn(JoinPoint joinPoint,Object result){System.out.println(""+joinPoint.getSignature().getName()+"正常返回。。。@AfterReturning:运行结果:{"+result+"}");}@AfterThrowing(value="pointCut()",throwing="exception")public void logException(JoinPoint joinPoint,Exception exception){System.out.println(""+joinPoint.getSignature().getName()+"异常。。。异常信息:{"+exception+"}");}}

四、给切面类的目标方法标注何时何地运行(通知注解)

一、通知方法:
              前置通知(@Before):logStart:在目标方法(div)运行之前运行
              后置通知(@After):logEnd:在目标方法(div)运行结束之后运行(无论方法正常结束还是异常结束)
              返回通知(@AfterReturning):logReturn:在目标方法(div)正常返回之后运行
              异常通知(@AfterThrowing):logException:在目标方法(div)出现异常以后运行
              环绕通知(@Around):动态代理,手动推进目标方法运行(joinPoint.procced())

五、将切面类和业务逻辑类(目标方法所在类)都加入到容器中

@EnableAspectJAutoProxy
@Configuration
public class MainConfigOfAOP {//业务逻辑类加入容器中@Beanpublic MathCalculator calculator(){return new MathCalculator();}//切面类加入到容器中@Beanpublic LogAspects logAspects(){return new LogAspects();}
}

六、必须告诉Spring哪个类是切面类(给切面类上加一个注解:@Aspect) 

七、给配置类中加 @EnableAspectJAutoProxy 【开启基于注解的aop模式】

三、AOP原理

一、@EnableAspectJAutoProxy注解

一、@EnableAspectJAutoProxy详情

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({AspectJAutoProxyRegistrar.class})
public @interface EnableAspectJAutoProxy {boolean proxyTargetClass() default false;boolean exposeProxy() default false;
}

 这个注解主要是导入了@Import({AspectJAutoProxyRegistrar.class}),AspectJAutoProxyRegistrar这个类,也就是说具体功能就是在这个类中。

二、 AspectJAutoProxyRegistrar.class详解

1、AspectJAutoProxyRegistrar源码

class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {AspectJAutoProxyRegistrar() {}public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {// 注册一个AnnotationAwareAspectJAutoProxyCreator
对象,名字是internalAutoProxyCreatorAopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);AnnotationAttributes enableAspectJAutoProxy = AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);if (enableAspectJAutoProxy != null) {if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);}if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);}}}
}

 2、AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);源码

 private static BeanDefinition registerOrEscalateApcAsRequired(Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {Assert.notNull(registry, "BeanDefinitionRegistry must not be null");if (registry.containsBeanDefinition("org.springframework.aop.config.internalAutoProxyCreator")) {BeanDefinition apcDefinition = registry.getBeanDefinition("org.springframework.aop.config.internalAutoProxyCreator");if (!cls.getName().equals(apcDefinition.getBeanClassName())) {int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());int requiredPriority = findPriorityForClass(cls);if (currentPriority < requiredPriority) {apcDefinition.setBeanClassName(cls.getName());}}return null;} else {RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);beanDefinition.setSource(source);beanDefinition.getPropertyValues().add("order", Integer.MIN_VALUE);beanDefinition.setRole(2);registry.registerBeanDefinition("org.springframework.aop.config.internalAutoProxyCreator", beanDefinition);return beanDefinition;}}

这里主要就是往容器中注册参数Class<?> cls对象,也就是AnnotationAwareAspectJAutoProxyCreator,名字为internalAutoProxyCreator。而AnnotationAwareAspectJAutoProxyCreator对象就是整个aop的核心。

三、AnnotationAwareAspectJAutoProxyCreator详解 

AnnotationAwareAspectJAutoProxyCreator层级关系

 AnnotationAwareAspectJAutoProxyCreator的父类
           ->AspectJAwareAdvisorAutoProxyCreator的父类
               ->AbstractAdvisorAutoProxyCreator的父类
                  ->AbstractAutoProxyCreator实现了
                        implements SmartInstantiationAwareBeanPostProcessor(后置处理器), BeanFactoryAware(bean工厂)
 主要关注后置处理器(在bean初始化完成前后做事情)、自动装配BeanFactory

二、AnnotationAwareAspectJAutoProxyCreator创建和注册流程

AnnotationAwareAspectJAutoProxyCreator其实就是后置处理器,他会在其他bean创建或者加载之前提前创建,那么当其他bean有使用aop功能时,会经历对象的生命周期,在生命周期中会执行后置处理器,那么AnnotationAwareAspectJAutoProxyCreator就会在bean创建的时候拦截到。

一、传入配置类,创建ioc容器

二、注册配置类,调用refresh()刷新容器;

三、 registerBeanPostProcessors(beanFactory);注册bean的后置处理器来方便拦截bean的创建;   

    一、先获取ioc容器已经定义了的需要创建对象的所有BeanPostProcessor(后置处理器)

其中一个对象就是org.springframework.aop.config.internalAutoProxyCreator

二、给容器中加别的BeanPostProcessor
 
三、优先注册实现了PriorityOrdered接口的BeanPostProcessor;  再给容器中注册实现了Ordered接口的BeanPostProcessor;最后注册没实现优先级接口的BeanPostProcessor;

注册BeanPostProcessor,实际上就是创建BeanPostProcessor对象,保存在容器中;里面调用了getBean方法,也就是创建bean的方法,进去就是spring bean的创建流程了

 进入常见bean方法,首先是获取单例bean,获取不到再进行bean的创建

 

创建internalAutoProxyCreator的BeanPostProcessor【AnnotationAwareAspectJAutoProxyCreator】
 

 

1、创建Bean的实例

2、populateBean;给bean的各种属性赋值

3、initializeBean:初始化bean 

  1、调用invokeAwareMethods():处理Aware接口的方法回调

    private void invokeAwareMethods(String beanName, Object bean) {if (bean instanceof Aware) {if (bean instanceof BeanNameAware) {((BeanNameAware)bean).setBeanName(beanName);}if (bean instanceof BeanClassLoaderAware) {ClassLoader bcl = this.getBeanClassLoader();if (bcl != null) {((BeanClassLoaderAware)bean).setBeanClassLoader(bcl);}}if (bean instanceof BeanFactoryAware) {((BeanFactoryAware)bean).setBeanFactory(this);}}}

2、applyBeanPostProcessorsBeforeInitialization():应用后置处理器的postProcessBeforeInitialization()

3、invokeInitMethods();执行自定义的初始化方法

4、applyBeanPostProcessorsAfterInitialization();执行后置处理器的postProcessAfterInitialization()

4、经过上面几步,BeanPostProcessor(AnnotationAwareAspectJAutoProxyCreator)创建成功;--》aspectJAdvisorsBuilder

四、把BeanPostProcessor注册到BeanFactory中;


 

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

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

相关文章

虚拟机开机字体变大,进入系统后字体模糊

问题 虚拟机开机字体变大&#xff0c;进入系统后字体模糊。 原因 虚拟机配置问题。 解决办法 修改配置为如下:

资深老鸟经验,性能测试-性能指标分析总结,一篇策底概全...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 性能测试指标 1、…

leetcode代码记录(不同路径

目录 1. 题目&#xff1a;2. 我的代码&#xff1a;小结&#xff1a; 1. 题目&#xff1a; 一个机器人位于一个 m x n 网格的左上角 &#xff08;起始点在下图中标记为 “Start” &#xff09;。 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角&#xff08;在…

Python实现24点游戏

24点游戏是一种数学益智游戏&#xff0c;它的目标是通过使用加法、减法、乘法和除法这四种基本算术运算&#xff0c;使得四个数字的结果等于24。这个游戏不仅能锻炼玩家的数学计算能力&#xff0c;还能提高逻辑思维和快速反应能力。 游戏规则非常简单&#xff1a; 游戏通常使…

如何使用ArcGIS Pro生成带计曲线等高线

等高线作为常见的地图要素经常会被使用到&#xff0c;一般情况下生成的等高线是不带计曲线的&#xff0c;在某些情况下我们需要带计曲线的等高线&#xff0c;这里为大家介绍一下ArcGIS Pro生成带计曲线等高线的方法&#xff0c;希望能对你有所帮助。 数据来源 教程所使用的数…

Node.js 文件夹遍历技巧:实现高效的文件管理

在 Node.js 开发中&#xff0c;经常需要对文件系统进行操作&#xff0c;包括遍历文件夹以获取文件列表。本文将讨论使用 Node.js 遍历文件夹的几种常用方法&#xff0c;并通过一个实际案例来演示如何实现。 基本概念 在开始之前&#xff0c;让我们了解一些基本的概念&#xff…

关 于 重 燃 学 习 的 热 情

3月1日是我回学校的第一天。经历了长达8个月在家的昏暗时刻&#xff0c;我这10天的感觉和在家的感觉发生了翻天覆地的变化&#xff0c;最明显的莫过于学习状态的改变。 倒不是说在家学的不好&#xff0c;而是说在学校&#xff0c;我对学习的整体感觉&#xff0c;以及专注程度&…

微信小程序Skyline模式自定义tab组件胶囊与原生胶囊平齐,安卓和ios均自适应

进入下面小程序可以体验效果&#xff1a; 至于原理的话&#xff0c;解释起来毕竟麻烦&#xff0c;各位可以看源码自己分析。其实很简单&#xff0c;就算计算布局。很多网上公布的布局&#xff0c;都不能正常自适应。在下这个是完美可以的 1、WXML <view class"weui…

Kubernetes operator系列:kubebuilder 实战演练 之 开发多版本CronJob

云原生学习路线导航页&#xff08;持续更新中&#xff09; 本文是 Kubernetes operator学习 系列文章&#xff0c;本节会在上一篇开发的Cronjob基础上&#xff0c;进行 多版本Operator 开发的实战 本文的所有代码&#xff0c;都存储于github代码库&#xff1a;https://github.c…

【全面了解自然语言处理三大特征提取器】RNN(LSTM)、transformer(注意力机制)、CNN

目录 一 、RNN1.RNN单个cell的结构2.RNN工作原理3.RNN优缺点 二、LSTM1.LSTM单个cell的结构2. LSTM工作原理 三、transformer1 Encoder&#xff08;1&#xff09;position encoding&#xff08;2&#xff09;multi-head-attention&#xff08;3&#xff09;add&norm 残差链…

【C语言】指针基础知识(一)

计算机上CPU&#xff08;中央处理器&#xff09;在处理数据的时候&#xff0c;需要的数据是在内存中读取的&#xff0c;处理后的数据也会放回内存中。 一,内存和地址 内存被分为一个个单元&#xff0c;一个内存单元的大小是一个字节。 内存单元的编号&#xff08;可以理解为门…

2024年值得创作者关注的十大AI动画创新平台

别提找大型工作室制作动画了。如今,AI平台让我们就可以轻松制作动画。从简单的文本生动画功能到复杂的角色动作,这些平台为各种类型的创作者提供了不同的功能。 AI已经有了长足的发展,现在它可以理解复杂的人类动作和艺术意图,将简单的输入转化成丰富而详细的动画。 下面…

【前端Vue】Vue3+Pinia小兔鲜电商项目第1篇:认识Vue3,1. Vue3组合式API体验【附代码文档】

全套笔记资料代码移步&#xff1a; 前往gitee仓库查看 感兴趣的小伙伴可以自取哦&#xff0c;欢迎大家点赞转发~ 全套教程部分目录&#xff1a; 部分文件图片&#xff1a; 认识Vue3 1. Vue3组合式API体验 通过 Counter 案例 体验Vue3新引入的组合式API vue <script> ex…

AJAX学习(四)

版权声明 本文章来源于B站上的某马课程&#xff0c;由本人整理&#xff0c;仅供学习交流使用。如涉及侵权问题&#xff0c;请立即与本人联系&#xff0c;本人将积极配合删除相关内容。感谢理解和支持&#xff0c;本人致力于维护原创作品的权益&#xff0c;共同营造一个尊重知识…

C++内存分布与动态内存管理

文章目录 :dizzy: C/C内存分布:dizzy:C语言中动态内存管理方式  :sparkles:malloc   :sparkles:calloc  :sparkles:reallocfree :dizzy:C语言中动态内存管理方式  :sparkles:new和delete操作内置类型  :sparkles:new和delete操作自定义类型 :dizzy:operator new与ope…

数星星 刷题笔记 (树状数组)

依题意 要求每个点 x, y 的左下方有多少个星星 又因为 是按照y从小到大 给出的 所以 我们在计算个数的时候是按照y一层层变大来遍历的 因此我们在处理每一个点的时候 只需要看一下 当前的点有多少个点的x值比当前点小即可 树状数组的 操作模板 P3374 【模板】树…

动态规划题目集一(代码 注解)

目录 介绍&#xff1a; 题目一: 题目二&#xff1a; 题目三&#xff1a; 题目四&#xff1a; 题目五&#xff1a; 题目六&#xff1a; 题目七&#xff1a; 题目八&#xff1a; 题目九&#xff1a; 介绍&#xff1a; 动态规划是一种算法设计技术&#xff0c;用于解决具有重叠…

水泵房远程监控物联网系统

随着物联网技术的快速发展&#xff0c;越来越多的行业开始利用物联网技术实现设备的远程监控与管理。水泵房作为城市供水系统的重要组成部分&#xff0c;其运行状态的监控与管理至关重要。HiWoo Cloud作为专业的物联网云服务平台&#xff0c;为水泵房远程监控提供了高效、稳定、…

Java访问数据库(重点:SpringBoot整合Mybatis)

目录 一、通过JDBC访问数据库1、思路2、示例3、思考 二、通过ORM框架访问数据库&#xff08;主要是Mybatis&#xff09;1、示例1.1 配置1.2 SQL写在xxxMapper.xml中&#xff1a;mapper/UserMapper.xml1.3 xxxMapper.xml对应的xxxMapper接口&#xff08;Application通过该接口访…

磁盘未格式化,数据恢复有妙招

一、初遇磁盘未格式化&#xff0c;惊慌失措 在日常生活和工作中&#xff0c;我们经常会使用各种存储设备来保存重要的文件和数据。然而&#xff0c;有时当我们尝试访问这些存储设备时&#xff0c;却会突然遇到一个令人头痛的问题——磁盘未格式化。这个突如其来的提示让我们措…