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

news2024/10/7 2:32:37

一、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 {

	//业务逻辑类加入容器中
	@Bean
	public MathCalculator calculator(){
		return new MathCalculator();
	}

	//切面类加入到容器中
	@Bean
	public 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
对象,名字是internalAutoProxyCreator
        AopConfigUtils.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.coloradmin.cn/o/1526449.html

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

相关文章

数据在内存的存储

整数在内存中的存储 我们来回顾一下&#xff0c;整数在计算机是以补码的形式进行存储的&#xff0c;整数分为正整数和负整数&#xff0c;正整数的原码、反码和补码是一样的&#xff0c;负整数的原码、反码和补码略有不同&#xff08;反码是原码除符号位&#xff0c;其他位按位取…

注册-前端部分

前提:后端jar环境、Vue3环境、Redis环境 搭建页面(html标签、css样式) → 绑定数据与事件(表单校验) → 调用后台接口(接口文档、src/api/xx.js封装、页面函数中调用) Login.vue文件: <script setup> import { User, Lock } from "@element-plus/icons-…

【Axure高保真原型】多色知识图谱

今天和大家分享中继器版多色知识图谱的原型模板&#xff0c;鼠标拖动节点&#xff0c;对应节点会跟随鼠标移动&#xff0c;和相关节点对应的连接线也会自动调整&#xff1b;节点圆是多色的&#xff0c;案例中包括红、黄、浅蓝、深蓝、绿、青、紫、灰色&#xff0c;后续可以根据…

Java代码基础算法练习-数制转换-2024.03.18

任务描述&#xff1a; 输入一个 10 进制正整数n(取值范围:0<n<1000)&#xff0c;然后输出它所对应的八进制(要求用模除取余&#xff0c;不得直接转换输出) 任务要求&#xff1a; 十进制数转八进制数的思想&#xff1a; 十进制数转八进制数的思想主要基于“除基取余”法&…

kingbase 服务器配置(参数修改)

引言&#xff1a; 人大金仓作为国产数据库的佼佼者(单机)&#xff0c;也是每位数据库从业者必须数据库之一 配置文件 kingbase 参数配置 主要由 kingbase.conf 和 kingbase.auto.conf 设置 kingbase.conf 该参数文件为主配置文件&#xff0c;一般情况下&#xff0c;需要 重启…

HarmonyOS(鸿蒙)快速入门

一:下载开发工具 鸿蒙的开发工具叫DevEco 下载点击 其他部分都一直next 就行,这个页面出现的install 建议都点击install 然后单独选择安装目录 可能存在的问题 就是之前安装nodejs&#xff08;比如自己开发web或者RN等情况&#xff09;版本低 等情况 所以建议你单独安装一次 …

Linux chapter1 常用命令 cp

note 1 : netstat、curl、ip、nmap、dig 这些都是常用的网络诊断工具&#xff0c;它们的全称如下&#xff1a; netstat&#xff1a;Network Statistics&#xff0c;网络统计&#xff0c;用于显示网络连接&#xff0c;路由表&#xff0c;网络接口统计等网络信息。curl&#xf…

Springboot 博客_001 环境准备(VS code版本)

本人喜欢用vs coder&#xff08;免费又好用&#xff09;, 所以以下拿vs coder配置开发 安装JDK17 下载JDK17 https://www.oracle.com/java/technologies/downloads/#jdk17-windows 安装JDK17 标题双击运行&#xff0c;一路默认 删除原本的环境变量 配置环境变量 查看是否安…

PTA L2-018 多项式A除以B

这仍然是一道关于A/B的题&#xff0c;只不过A和B都换成了多项式。你需要计算两个多项式相除的商Q和余R&#xff0c;其中R的阶数必须小于B的阶数。 输入格式&#xff1a; 输入分两行&#xff0c;每行给出一个非零多项式&#xff0c;先给出A&#xff0c;再给出B。每行的格式如下…

了解抖音小程序与抖音小店的区别

首先&#xff0c;从功能和定位上来看&#xff0c;抖音小店是抖音官方推出的一种功能&#xff0c;专为商家提供在抖音平台上销售商品的工具。而抖音小程序则是一种无需下载即可使用的应用&#xff0c;类似于微信小程序&#xff0c;但主要在抖音、头条、极速版头条等平台上运行。…

逻辑回归LogisticRegression quickstart

本文将用可视化思路理解逻辑回归 数学背景 比如我们认定一个的值只可能在[0, 1], 那当小于0.5&#xff0c;我们认为他就是a&#xff0c;当大于0.5&#xff0c;我们认为他就是b 数据集 使用鸢尾花数据集 4个特征值3个类别 二分类&#xff0c;单维度 只使用一个特征X ir…

Linux docker3--数据卷-nginx配置示例

一、因为docker部署服务都是以最小的代价部署&#xff0c;所以通常在容器内部很多依赖和命令无法执行。进入容器修改配置的操作也比较麻烦。本例介绍的数据卷作用就是将容器内的配置和宿主机文件打通&#xff0c;之后修改宿主机的配置文件就相当于修改了docker进程的配置文件&a…

“灯塔”——一个让人爱不释手的前端监测工具

引言 "灯塔"&#xff08;fee&#xff09;作为一个前端监控系统&#xff0c;通常具备捕获浏览器端错误、性能监控、用户行为跟踪等功能。它的主要目的是帮助开发者了解他们的网站或应用在用户端的表现&#xff0c;以及时发现并解决问题。下面是关于这种系统的一些关键…

【web开发网页制作】Html+Css+js网页制作轮播效果个人网页主题(4页面附代码)

个人网页制作目录 涉及知识写在前面一、网页主题二、网页效果Page1、我的首页Page2、文经风采&#xff08;学校&#xff09;Page3、美图分享Page4、热剧推送视频效果 三、网页架构与技术3.1 脑海构思3.2 整体布局3.3 技术说明书 四、网页源码HtmlCss 作者寄语 涉及知识 轮播效…

9. 编程常见错误归类

编程常见错误归类 9.1 编译型错误9.2 链接型错误9.3 运行时错误 9.1 编译型错误 编译型错误⼀般都是语法错误&#xff0c;这类错误⼀般看错误信息就能找到⼀些蛛丝马迹的&#xff0c;双击错误信息也能初步的跳转到代码错误的地方或者附近。编译错误&#xff0c;随着语言的熟练…

显隐特征融合的指静脉识别网络

文章目录 显隐特征融合的指静脉识别网络总结摘要介绍显隐式特征融合网络(EIFNet)掩膜生成模块(MGM)掩膜特征提取模块(MFEM)内容特征提取模块(CFEM)特征融合模块(FFM) THUFVS实验和结果数据集实现细节评估掩膜生成模型消融实验FFM模块门控层Batch Size损失函数超参数选择 论文 …

java 线上生产问题排查思路,jvm内存溢出实例重启原因排查生产实战

java jvm内存溢出实例重启排查生产实战&#xff08;使用VisualVM&#xff09; 背景 项目组线上生产环境不定期的发生内存爆满然后实例重启&#xff0c;实例发布上线后实例内存不断增长最后维持在百分之九十多&#xff0c;十分危险。因此我参与到了排查中&#xff0c;本篇博客将…

2258: 【搜索】【广度优先】最少转弯问题

题目描述 给出一张地图&#xff0c;这张地图被分为nm&#xff08;n,m<100&#xff09;个方块&#xff0c;任何一个方块不是平地就是高山。平地可以通过&#xff0c;高山则不能。现在你处在地图的&#xff08;x1,y1&#xff09;这块平地&#xff0c;问&#xff1a;你至少需要…

二、SQL基础学习(函数、约束、事务)

目录 1、函数1.1、字符串函数1.2、数值函数1.3、日期函数1.4 、流程函数 2、约束2.1、外键约束2.2、删除/更新行为 3、事务3.1、事务的四大特性3.2、并发事务问题3.2、事务的隔离级别 1、函数 1.1、字符串函数 # concat select concat(Hello, MySql);# lower select lower(He…

第六十回 吴用智赚玉麒麟 张顺夜闹金沙渡-飞桨科学计算套件PaddleScience

吴用说我到北京让卢俊义上山&#xff0c;小菜一碟&#xff0c;但是我需要一个粗心大胆的同伴一起去。黑旋风李逵自告奋勇&#xff0c;答应了吴用三件事才被允许去&#xff1a;一、 不喝酒 二、扮做道童听吩咐 三、不说话当哑巴。 两人拜做算命的道士和道童&#xff0c;来到北京…