当前位置: 首页 > news >正文

Spring之AOP实现

1. AOP的实现方式

  1. 使用AspectJ的编译器来改动class类文件实现增强(使用不广泛) ----- 编译阶段

    这种对class类文件增强的, 也可以增强static静态方法, 而通过代理方式就无法实现静态方法的增强

    可通过查看编译后class文件反编译后的java代码验证

  2. agent增强(使用不广泛) ----- 类加载阶段

这种方式的增强也会使得代理类在内部自己调用自己的方法也获得增强, 原因是这种方式是通过类加载阶段进行的增强, 在通过this.xxFunc()调用自己本类的方法也是触发代理类的方法。

可通过arthas等工具查看jvm内存中增强后的类的反编译后的java代码验证

  1. Proxy代理方式实现AOP(绝大多数的选择)
  • JDK 代理 (只能代理实现了接口的类, 而且也只能代理那些接口方法, 代理类与目标类同级关系)
  • CGLIB 代理 (能代理类和接口, 但该类或代理的方法不能使用final修饰, 因为是基于继承进行增强的, 代理类与目标类是父 / 子 关系)

代理创建的两个时机:

  1. 初始化之后
  2. 实例创建之后, 依赖注入之前(有循环依赖时), 并暂存于二级缓存 earlySingletonObjects

JDK实现的代理:

public class JdkProxyDemo {interface Foo{void foo();}// 将被用作jdk代理的实例类static class Target implements Foo{@Overridepublic void foo() {System.out.println("target foo");}// 这个方法无法被代理,因为不是来自接口的方法public void test(){System.out.println("test");}}// jdk代理 只能针对接口代理// cglib代理public static void main(String[] args) {// 目标对象Target target = new Target();ClassLoader classLoader = JdkProxyDemo.class.getClassLoader();//用来加载在运行期间动态生成的字节码Foo proxyInstance = (Foo) Proxy.newProxyInstance(classLoader, new Class[]{Foo.class}, new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("before...");// 目标.方法(参数)// method.invoke(proxy, args); 错误写法, 这里的proxy代表代理类自身, 传入proxy会陷入无限循环Object result = method.invoke(target, args);System.out.println("after...");return result;}});proxyInstance.foo();}
}

Cglib实现的代理:

注意: 在MethodInterceptor实现的intercept()方法中,传入了一个参数methodProxy, 通过该对象调用methodProxy.invoke(target, args)也能执行目标对象, 但其内部不是通过反射的方式。

public class CglibProxyDemo {static class Target{public void foo(){System.out.println("target foo");}}public static void main(String[] args){Target target = new Target();Target proxyInstance = (Target) Enhancer.create(Target.class, new MethodInterceptor() {@Overridepublic Object intercept(Object proxy, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {System.out.println("before...");Object result = method.invoke(target, args); //Spring使用的方式//Object result = methodProxy.invoke(target, args); 非反射方式调用, 而且可以不用目标就调用System.out.println("after...");return result;}});proxyInstance.foo();}
}

2.Spring中的两种切面

@Aspect: 高级切面, 可以包含多组通知和切面

Advisor: 低级切面, 适合框架内部使用, 只有一个通知和一个切面

Spring在处理这两个切面时, @Aspect切面最终还是转为Advisor

两种方式使用示例:

public class AspectDemo {public static void main(String[] args) {GenericApplicationContext context = new GenericApplicationContext();context.registerBean("aspect1", Aspect1.class);context.registerBean("config", Config.class);context.registerBean(ConfigurationClassPostProcessor.class);context.refresh();for (String beanDefinitionName : context.getBeanDefinitionNames()) {System.out.println(beanDefinitionName);}}static class Target1{public void foo(){System.out.println("target1 foo");}}static class Target2{public void bar(){System.out.println("target bar");}}//高级切面,Aspect@Aspectstatic class Aspect1{@Before("execution(* foo())")public void before(){System.out.println("aspect1 before...");}@After("execution(* foo())")public void after(){System.out.println("aspect1 after...");}}//低级切面, 由一个切点(AspectJExpressionPointcut)和一个通知(MethodInterceptor)组成@Configurationstatic class Config{@Beanpublic Advisor advisor3(MethodInterceptor advice3){AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();pointcut.setExpression("execution(* foo())");return new DefaultPointcutAdvisor(pointcut , advice3);}@Beanpublic MethodInterceptor advice3(){return new MethodInterceptor() {@Overridepublic Object invoke(MethodInvocation methodInvocation) throws Throwable {System.out.println("advice3 before...");Object result = methodInvocation.proceed();System.out.println("advice3 after...");return result;}};}}
}

相关文章:

Spring之AOP实现

1. AOP的实现方式 使用AspectJ的编译器来改动class类文件实现增强(使用不广泛) ----- 编译阶段 这种对class类文件增强的, 也可以增强static静态方法, 而通过代理方式就无法实现静态方法的增强 可通过查看编译后class文件反编译后的java代码验证 agent增强(使用不广泛) ----- 类…...

Spring之基于xml的自动装配、基于Autowired注解的自动装配

文章目录基于xml的自动装配①注解②扫描③新建Maven Module④创建Spring配置文件⑤标识组件的常用注解⑥创建组件⑦扫描组件⑧测试⑨组件所对应的bean的id基于注解的自动装配①场景模拟②Autowired注解③Autowired注解其他细节④Autowired工作流程Autowire 注解的原理Qualifier…...

【案例】--(非分布式)轻量级任务调度平台

目录 一、前言说明二、背景2.1、完成任务,顺便搭建了一个任务调度平台三、具体实现解析3.1、技术栈等选型3.2、完成具体功能解析(1)、支持基本任务功能(2)、支持日志收集功能(3)、支持用户异常,选择性关闭调度功能(4)、实时监控正在执行和任务队列的任务情况(5)、实时监控任务…...

key的作用原理与列表的遍历、追加、搜索、排序

目录 一、key的作用原理 二、实现列表遍历并对在列表最前方进行追加元素 三、实现列表过滤搜索 1、用computed计算属性来实现 2、用watch监听输入值的变化来实现 四、按年龄排序输出列表 一、key的作用原理 1. 虚拟DOM中key的作用: key是虚拟DOM对象的标识&a…...

SQL性能优化的47个小技巧,你了解多少?

收录于热门专栏Java基础教程系列(进阶篇) 1、先了解MySQL的执行过程 了解了MySQL的执行过程,我们才知道如何进行sql优化。 客户端发送一条查询语句到服务器;服务器先查询缓存,如果命中缓存,则立即返回存…...

DPDK — 数据加速方案的核心思想

目录 文章目录 目录DPDK 数据加速方案1、使用用户态协议栈来代替内核协议栈Linux UIO FrameworkDPDK UIO Framework2、使用轮训来代替中断Kernelspace igb_uio DriverUserspace PMD3、使用多核编程代替多线程无锁环队列:CPU 核间无锁通信DPDK 数据加速方案...

[python入门㊽] - 自定义异常 raise 关键字

目录 ❤ 自定义抛出异常关键字 - raise ❤ 使用raise主动引发异常 ❤ raise 关键字的用法 ❤ 触发异常 ❤ 自定义异常类 在前面我们学过异常三个关键字分别是try、except 以及 finally 在编程过程中合理的使用异常可以使得程序正常的执行。有直接抛出异常的形式&…...

DDOS攻击

注:本博客只是为了自己的学习,记录自己的学习,请勿用于其他途径、1、winR-->cmd2、ping 网站3、替换IP1 import java.io.BufferedInputStream;2 import java.io.IOException;3 import java.net.MalformedURLException;4 import java.net.U…...

网络编程套接字

文章目录1. socket编程接口1-1 socket 常见API1-2 sockaddr结构2. 简单的UDP网络程序2-1 日志(固定用法:标准部分自定义部分)2-2 服务器代码实现1. 框架2. 初始化服务器3. 服务器运行4. 调用服务器封装函数(UdpServer)…...

海量数据相似数据查询方法

1、海量文本常见 海量文本场景,如何寻找一个doc的topn相似doc,一般存在2个问题, 1)、两两对比时间o(n^2) 2)、高维向量比较比较耗时。 文本集可以看成(doc,word)稀疏矩阵,一般常见的方法是构建到排索引,然后进行归并…...

Codeforces Round #822 (Div. 2)

A(签到) - Select Three Sticks 题意: 给你一个长度为 n 的正整数序列,你可以操作任意次,每一次操作可以选择任意一个元素,把它 1 或者 - 1,问最少多少次操作可以使得序列中存在三个相同的数字以构成一个等边三角形.…...

华为OD机试 - 最短木板长度(JS)

最短木板长度 题目 小明有 n n n块木板,第 i i i(1≤ i i </...

java设计模式——观察者模式

概述 定义:又被称为发布-订阅(Publish/Subscribe)模式&#xff0c;它定义了一种一对多的依赖关系&#xff0c;让多个观察者对象同时监听某一个主题对象。这个主题对象在状态变化时&#xff0c;会通知所有的观察者对象&#xff0c;使他们能够自动更新自己。 结构 在观察者模式…...

linux高级命令之线程的注意点

线程的注意点学习目标能够说出线程的注意点1. 线程的注意点介绍线程之间执行是无序的主线程会等待所有的子线程执行结束再结束线程之间共享全局变量线程之间共享全局变量数据出现错误问题2. 线程之间执行是无序的import threading import timedeftask():time.sleep(1)print(&qu…...

MyBatisPlus ---- 多数据源

MyBatisPlus ---- 多数据源1. 创建数据库及表2. 引入依赖3. 配置多数据源4. 创建用户service5. 创建商品service6. 测试适用于多种场景&#xff1a;纯粹多库、读写分离、一主多从、混合模式等 目前我们就来模拟一个纯粹多库的一个场景&#xff0c;其他场景类似 场景说明&#x…...

Java多线程

目录1 多线程1.1 进程1.2 线程1.3 多线程的实现方式1.3.1 方式1&#xff1a;继承Tread类1.3.2 方式2&#xff1a;实现Runnable接口1.3.3 方式3&#xff1a;实现Callable接口1.4 设置和获取线程名称1.5 线程调度1.6 线程控制1.7 线程生命周期1.8 数据安全问题之案例&#xff1a;…...

linux高级命令之线程执行带有参数的任务

线程执行带有参数的任务学习目标能够写出线程执行带有参数的任务1. 线程执行带有参数的任务的介绍前面我们使用线程执行的任务是没有参数的&#xff0c;假如我们使用线程执行的任务带有参数&#xff0c;如何给函数传参呢?Thread类执行任务并给任务传参数有两种方式:args 表示以…...

管理会计报告和财务报告的区别

财务会计报告是给投资人看的&#xff0c;可以反映公司总体的盈利能力。不过&#xff0c;我们回顾一下前面“第一天”里面提到的问题。如果你是公司的产品经理&#xff0c;目前有三个产品在你的管辖范围内。上级给你一笔新的资金&#xff0c;这笔资金应该投到哪个产品上&#xf…...

华为OD机试 - 最左侧冗余覆盖子串(Python) | 机试题算法思路 【2023】

最近更新的博客 华为OD机试 - 自动曝光(Python) | 机试题算法思路 【2023】 华为OD机试 - 双十一(Python) | 机试题算法思路 【2023】 华为OD机试 - 删除最少字符(Python) | 机试题算法思路 【2023-02】 华为OD机试 - Excel 单元格数值统计(Python) | 机试题算法思路 …...

【Opencv 系列】第1章 图像基础

通过本套课程,可以学到: 1.opencv的基本操作 2.两个案例,目标追踪&人脸识别 对重点内容,我会提示,包括我再准备这套课程过程中遇到的坑点! 最后代码我会放到git上,章节顺序一致:https://github.com/justinge/opencv_tutorial.git 系列文章目录 第1章 Opencv 图像基础 和 …...

在软件开发中正确使用MySQL日期时间类型的深度解析

在日常软件开发场景中&#xff0c;时间信息的存储是底层且核心的需求。从金融交易的精确记账时间、用户操作的行为日志&#xff0c;到供应链系统的物流节点时间戳&#xff0c;时间数据的准确性直接决定业务逻辑的可靠性。MySQL作为主流关系型数据库&#xff0c;其日期时间类型的…...

Spark 之 入门讲解详细版(1)

1、简介 1.1 Spark简介 Spark是加州大学伯克利分校AMP实验室&#xff08;Algorithms, Machines, and People Lab&#xff09;开发通用内存并行计算框架。Spark在2013年6月进入Apache成为孵化项目&#xff0c;8个月后成为Apache顶级项目&#xff0c;速度之快足见过人之处&…...

Psychopy音频的使用

Psychopy音频的使用 本文主要解决以下问题&#xff1a; 指定音频引擎与设备&#xff1b;播放音频文件 本文所使用的环境&#xff1a; Python3.10 numpy2.2.6 psychopy2025.1.1 psychtoolbox3.0.19.14 一、音频配置 Psychopy文档链接为Sound - for audio playback — Psy…...

从零实现STL哈希容器:unordered_map/unordered_set封装详解

本篇文章是对C学习的STL哈希容器自主实现部分的学习分享 希望也能为你带来些帮助~ 那咱们废话不多说&#xff0c;直接开始吧&#xff01; 一、源码结构分析 1. SGISTL30实现剖析 // hash_set核心结构 template <class Value, class HashFcn, ...> class hash_set {ty…...

C++使用 new 来创建动态数组

问题&#xff1a; 不能使用变量定义数组大小 原因&#xff1a; 这是因为数组在内存中是连续存储的&#xff0c;编译器需要在编译阶段就确定数组的大小&#xff0c;以便正确地分配内存空间。如果允许使用变量来定义数组的大小&#xff0c;那么编译器就无法在编译时确定数组的大…...

保姆级教程:在无网络无显卡的Windows电脑的vscode本地部署deepseek

文章目录 1 前言2 部署流程2.1 准备工作2.2 Ollama2.2.1 使用有网络的电脑下载Ollama2.2.2 安装Ollama&#xff08;有网络的电脑&#xff09;2.2.3 安装Ollama&#xff08;无网络的电脑&#xff09;2.2.4 安装验证2.2.5 修改大模型安装位置2.2.6 下载Deepseek模型 2.3 将deepse…...

iOS性能调优实战:借助克魔(KeyMob)与常用工具深度洞察App瓶颈

在日常iOS开发过程中&#xff0c;性能问题往往是最令人头疼的一类Bug。尤其是在App上线前的压测阶段或是处理用户反馈的高发期&#xff0c;开发者往往需要面对卡顿、崩溃、能耗异常、日志混乱等一系列问题。这些问题表面上看似偶发&#xff0c;但背后往往隐藏着系统资源调度不当…...

面向无人机海岸带生态系统监测的语义分割基准数据集

描述&#xff1a;海岸带生态系统的监测是维护生态平衡和可持续发展的重要任务。语义分割技术在遥感影像中的应用为海岸带生态系统的精准监测提供了有效手段。然而&#xff0c;目前该领域仍面临一个挑战&#xff0c;即缺乏公开的专门面向海岸带生态系统的语义分割基准数据集。受…...

省略号和可变参数模板

本文主要介绍如何展开可变参数的参数包 1.C语言的va_list展开可变参数 #include <iostream> #include <cstdarg>void printNumbers(int count, ...) {// 声明va_list类型的变量va_list args;// 使用va_start将可变参数写入变量argsva_start(args, count);for (in…...

MyBatis中关于缓存的理解

MyBatis缓存 MyBatis系统当中默认定义两级缓存&#xff1a;一级缓存、二级缓存 默认情况下&#xff0c;只有一级缓存开启&#xff08;sqlSession级别的缓存&#xff09;二级缓存需要手动开启配置&#xff0c;需要局域namespace级别的缓存 一级缓存&#xff08;本地缓存&#…...