Spring Ioc和Aop,Aop的原理和实现案例,JoinPoint,@Aspect,@Before,@AfterReturning

news2025/5/23 19:40:07

DAY25.2 Java核心基础

Spring两大核心:Ioc和Aop

IOC

Ioc容器:装载bean的容器,自动创建bean

三种方式:

1、基于xml配置:通过在xml里面配置bean,然后通过反射机制创建bean,存入进Ioc容器中

2、基于注解的方式:通过注解标记类,Ioc读取有相关注解的类,然后通过反射创建bean对象存入Ioc容器中

3、基于配置类的方式:写一个java文件来替代xml,通过@Bean注解标记需要创建的对象,通过反射创建存入Ioc容器中

AOP

AOP:Aspect Oriented Programming,面向切面编程

面向对象编程 OOP (Object Oriented Programming):将程序中所有参与模块都抽象成对象,通过对象之间的相互调用关系来完成业务需求。

AOP:指的是把切面抽象为对象,在程序运行的时候动态的将非业务代码(比如打印日志)切入到业务代码中,从而实现代码的解耦合,将非业务代码抽象为一个对象

AOP优点:

  • 实现代码的解耦合
  • 提高代码的复用性
  • 提高代码的可维护性
  • 集中式管理横切逻辑
  • 提升开发效率
  • 业务代码不受非业务代码的影响,逻辑更加清晰
应用场景说明
日志记录自动打印请求参数、响应、耗时等
权限验证判断用户是否有权限执行操作
事务管理保证一组数据库操作的原子性
性能监控记录方法执行时间、内存等
异常处理统一捕获、记录、响应异常信息
缓存控制方法调用前先查缓存,结果缓存

总结一句话:AOP 本质上是“增强”代码的能力,不修改原代码,也能插入额外逻辑,让系统更模块化、更灵活、更清晰。

案例示例:

创建一个计算的接口

CalService:

public interface CalService {
    int add(int a, int b);
    int sub(int a, int b);
    int mul(int a, int b);
    int div(int a, int b);
}

实现类CalServiceImpl

@Component("calService")
public class CalServiceImpl implements CalService{
    @Override
    public int add(int num1, int num2) {
        int result = num1 + num2;
        return result;
    }

    @Override
    public int sub(int num1, int num2) {
        int result = num1 - num2;
        return result;
    }

    @Override
    public int mul(int num1, int num2) {
        int result = num1 * num2;
        return result;
    }

    @Override
    public int div(int num1, int num2) {
        int result = num1 / num2;
        return result;
    }
}

测试方法

public static void main(String[] args) {
    AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext("org.nanfengspringboot01.aop");
    CalService calService = (CalService) annotationConfigApplicationContext.getBean("calService");
    System.out.println(calService.add(4, 2));
    System.out.println(calService.sub(4, 2));
    System.out.println(calService.mul(4, 2));
    System.out.println(calService.div(4, 2));
}

输出:

image-20250522145926561

如果我们需要记录打印日志的话,是不是要更改实现类文件的实现

@Component("calService")
public class CalServiceImpl implements CalService{
    @Override
    public int add(int num1, int num2) {
        System.out.println("执行了加法运算");
        int result = num1 + num2;
        System.out.println("结果是:" + result);
        return result;
    }

    @Override
    public int sub(int num1, int num2) {
        System.out.println("执行了减法运算");
        int result = num1 - num2;
        System.out.println("结果是:" + result);
        return result;
    }

    @Override
    public int mul(int num1, int num2) {
        System.out.println("执行了乘法运算");
        int result = num1 * num2;
        System.out.println("结果是:" + result);
        return result;
    }

    @Override
    public int div(int num1, int num2) {
        System.out.println("执行了除法运算");
        int result = num1 / num2;
        System.out.println("结果是:" + result);
        return result;
    }
}

但是这样写的代码耦合程度太高了

咱可以用AOP来实现切面编程,将打印日志作为一个切面类抽象出来

创建切面类CalAop

@Aspect
@Component
public class CalAop {
    @Before("execution(public int org.nanfengspringboot01.aop.CalService.*(..))")
    public void before(JoinPoint joinPoint) {
        System.out.println("Aop切面进入@before");
        System.out.println("方法名:" + joinPoint.getSignature().getName());
        Object[] args = joinPoint.getArgs();
        String string = Arrays.toString(args);
        System.out.println("方法参数:"+string);
    }
    @AfterReturning(value = "execution(public int org.nanfengspringboot01.aop.CalService.*(..))", returning = "result")
    public void after(JoinPoint joinPoint,Object result) {
        System.out.println("Aop切面进入@AfterReturning");
        String methodName = joinPoint.getSignature().getName();
        System.out.println(methodName+"方法结果是:"+result);
        System.out.println("Aop切面结束");
        System.out.println("----------------------------------");
    }
}

@Aspect:标记这个类为切面类

@Component:标记这个类需要注入到Ioc容器中

@Before:定义切面的位置,在方法执行之前执行

@AfterReturning/@After:定义切面的位置,在方法执行之后执行

JoinPoint 是 Spring AOP(面向切面编程)中的一个核心接口,它代表了在程序执行过程中可以插入横切关注点(如日志、事务、安全等)的一个具体“连接点”(比如方法调用或异常抛出)。

获取当前连接点的信息

  • 可以获取正在被拦截的方法、参数、目标对象等信息。

  • 常见用途:记录日志、权限校验、参数处理等。

支持在切面中访问原始方法的上下文

  • 例如方法名、参数值、注解等,便于做统一处理。

配合 @Around, @Before, @AfterReturning 等注解使用

  • 在定义切面方法时,作为参数传入,用于操作目标方法或获取其执行上下文。
AOP 为什么要使用接口,不直接使用类

AOP 底层实现用的是jdk动态代理,动态创建一个类,创建对象,关于动态代理可以查看我之前的动态代理文章

怎么动态创建类?依据:接口

AOP 是基于 IoC 容器的

使用 IoC 容器创建所有的 bean,再进行整合

有了切面类实现类就不需要打印那么多的日志了

@Component("calService")
public class CalServiceImpl implements CalService{
    @Override
    public int add(int num1, int num2) {
        int result = num1 + num2;
        return result;
    }

    @Override
    public int sub(int num1, int num2) {
        int result = num1 - num2;
        return result;
    }

    @Override
    public int mul(int num1, int num2) {
        int result = num1 * num2;
        return result;
    }

    @Override
    public int div(int num1, int num2) {
        int result = num1 / num2;
        return result;
    }
}

测试启动类:

@SpringBootApplication
//@EnableAspectJAutoProxy
@MapperScan("org.nanfengspringboot01.mapper")
public class Nanfengspringboot01Application {

    public static void main(String[] args) {
        ConfigurableApplicationContext ioc = SpringApplication.run(Nanfengspringboot01Application.class, args);
        CalService calService = (CalService) ioc.getBean("calService");
        calService.add(4,2);
        calService.sub(4,2);
        calService.mul(4,2);
        calService.div(4,2);
    }

}

SpringApplication.run(Nanfengspringboot01Application.class, args)的结果就是上下文的ioc容器,可以根据这个获取到所有的bean信息,也可以获取到对应的bean对象

@EnableAspectJAutoProxy注解在新版本是不用加的,springboot会自动整合

输出:

image-20250522151847199

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

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

相关文章

[解决conda创建新的虚拟环境没用python的问题]

问题复现 使用conda create -n env的时候,在对应的虚拟环境的文件里面找不到对应的python文件 为什么 首先,我们来看一下创建环境时的触发链路: 这表明当前环境中找不到Python可执行文件。 解决方法 所以很明显,我们需要指定…

【C++】控制台小游戏

移动&#xff1a;W向上&#xff0c;S上下&#xff0c;A向左&#xff0c;D向右 程序代码&#xff1a; #include <iostream> #include <conio.h> #include <windows.h> using namespace std;bool gameOver; const int width 20; const int height 17; int …

配合本专栏前端文章对应的后端文章——从模拟到展示:一步步搭建传感器数据交互系统

对应文章&#xff1a;进一步完善前端框架搭建及vue-konva依赖的使用&#xff08;Vscode&#xff09;-CSDN博客 目录 一、后端开发 1.模拟传感器数据 2.前端页面呈现数据后端互通 2.1更新模拟传感器数据程序&#xff08;多次请求&#xff09; 2.2&#x1f9e9; 功能目标 …

springboot IOC

springboot IOC IoC Inversion of Control Inversion 反转 依赖注入 DI &#xff08;dependency injection &#xff09; dependency 依赖 injection 注入 Qualifier 预选赛 一文带你快速理解JavaWeb中分层解耦的思想及其实现&#xff0c;理解 IOC和 DI https://zhuanlan.…

Ajax01-基础

一、AJAX 1.AJAX概念 使浏览器的XMLHttpRequest对象与服务器通信 浏览器网页中&#xff0c;使用 AJAX技术&#xff08;XHR对象&#xff09;发起获取省份列表数据的请求&#xff0c;服务器代码响应准备好的省份列表数据给前端&#xff0c;前端拿到数据数组以后&#xff0c;展…

生成树协议(STP)配置详解:避免网络环路的最佳实践

生成树协议&#xff08;STP&#xff09;配置详解&#xff1a;避免网络环路的最佳实践 生成树协议&#xff08;STP&#xff09;配置详解&#xff1a;避免网络环路的最佳实践一、STP基本原理二、STP 配置示例&#xff08;华为交换机&#xff09;1. 启用生成树协议2. 配置根桥3. 查…

面向 C 语言项目的系统化重构实战指南

摘要: 在实际开发中,C 语言项目往往随着功能演进逐渐变得混乱:目录不清、宏滥用、冗余代码、耦合高、测试少……面对这样的“技术债积累”,盲目大刀阔斧只会带来更多混乱。本文结合 C 语言的特点,从项目评估、目录规划、宏与内联、接口封装、冗余剔除、测试与 CI、迭代重构…

Python Pandas库简介及常见用法

Python Pandas库简介及常见用法 一、 Pandas简介1. 简介2. 主要特点&#xff08;一&#xff09;强大的数据结构&#xff08;二&#xff09;灵活的数据操作&#xff08;三&#xff09;时间序列分析支持&#xff08;四&#xff09;与其他库的兼容性 3.应用场景&#xff08;一&…

第十六届蓝桥杯复盘

文章目录 1.数位倍数2.IPv63.变换数组4.最大数字5.小说6.01串7.甘蔗8.原料采购 省赛过去一段时间了&#xff0c;现在复盘下&#xff0c;省赛报完名后一直没准备所以没打算参赛&#xff0c;直到比赛前两天才决定参加&#xff0c;赛前两天匆匆忙忙下载安装了比赛要用的编译器ecli…

【已解决】HBuilder X编辑器在外接显示器或者4K显示器怎么界面变的好小问题

触发方式&#xff1a;主要涉及DPI缩放问题&#xff0c;可能在电脑息屏有概率触发 修复方式&#xff1a; 1.先关掉软件直接更改屏幕缩放&#xff0c;然后打开软件&#xff0c;再关掉软件恢复原来的缩放&#xff0c;再打开软件就好了 2.(不推荐&#xff09;右键HBuilder在属性里…

直线型绝对值位移传感器:精准测量的科技利刃

在科技飞速发展的今天&#xff0c;精确测量成为了众多领域不可或缺的关键环节。无论是工业自动化生产线上的精细操作&#xff0c;还是航空航天领域中对零部件位移的严苛把控&#xff0c;亦或是科研实验中对微小位移变化的精准捕捉&#xff0c;都离不开一款高性能的测量设备——…

Ansible模块——管理100台Linux的最佳实践

使用 Ansible 管理 100 台 Linux 服务器时&#xff0c;推荐遵循以下 最佳实践&#xff0c;以提升可维护性、可扩展性和安全性。以下内容结合实战经验进行总结&#xff0c;适用于中大型环境&#xff08;如 100 台服务器&#xff09;&#xff1a; 一、基础架构设计 1. 分组与分层…

从0开始学习大模型--Day09--langchain初步使用实战

众所周知&#xff0c;一味地学习知识&#xff0c;所学的东西和概念都是空中楼阁&#xff0c;大部分情况下&#xff0c;实战都是很有必要的&#xff0c;今天就通过微调langchain来更深刻地理解它。 中间如何进入到langchain界面请参考结尾视频链接。 首先&#xff0c;进入界面…

C++中的菱形继承问题

假设有一个问题&#xff0c;类似于鸭子这样的动物有很多种&#xff0c;如企鹅和鱿鱼&#xff0c;它们也可能会有一些共同的特性。例如&#xff0c;我们可以有一个叫做 AquaticBird &#xff08;涉禽&#xff0c;水鸟的一类&#xff09;的类&#xff0c;它又继承自 Animal 和 Sw…

网络-MOXA设备基本操作

修改本机IP和网络设备同网段&#xff0c;输入设备IP地址进入登录界面&#xff0c;交换机没有密码&#xff0c;路由器密码为moxa 修改设备IP地址 交换机 路由器 环网 启用Turbo Ring协议&#xff1a;在设备的网络管理界面中&#xff0c;找到环网配置选项&#xff0c;启用Turb…

飞桨paddle import fluid报错【已解决】

跟着飞桨的安装指南安装了paddle之后 pip install paddlepaddle有一个验证&#xff1a; import paddle.fluid as fluid fluid.install check.run check()报错情况如下&#xff0c;但是我在pip list中&#xff0c;确实看到了paddle安装上了 我import paddle别的包&#xff0c…

测试工程师要如何开展单元测试

单元测试是软件开发过程中至关重要的环节&#xff0c;它通过验证代码的最小可测试单元(如函数、方法或类)是否按预期工作&#xff0c;帮助开发团队在早期发现和修复缺陷&#xff0c;提升代码质量和可维护性。以下是测试工程师开展单元测试的详细步骤和方法&#xff1a; 一、理…

IPv4 地址嵌入 IPv6 的前缀转换方式详解

1. 概述 在 IPv4 和 IPv6 网络共存的过渡期&#xff0c;NAT64&#xff08;Network Address Translation 64&#xff09;是一种关键技术&#xff0c;用于实现 IPv6-only 网络与 IPv4-only 网络的互操作。NAT64 前缀转换通过将 IPv4 地址嵌入到 IPv6 地址中&#xff0c;允许 IPv…

野火鲁班猫(arrch64架构debian)从零实现用MobileFaceNet算法进行实时人脸识别(三)用yolov5-face算法实现人脸检测

环境直接使用第一篇中安装好的环境即可 先clone yolov5-face项目 git clone https://github.com/deepcam-cn/yolov5-face.git 并下载预训练权重文件yolov5n-face.pt 网盘链接: https://pan.baidu.com/s/1xsYns6cyB84aPDgXB7sNDQ 提取码: lw9j &#xff08;野火官方提供&am…

【图像生成大模型】HunyuanVideo:大规模视频生成模型的系统性框架

HunyuanVideo&#xff1a;大规模视频生成模型的系统性框架 引言HunyuanVideo 项目概述核心技术1. 统一的图像和视频生成架构2. 多模态大语言模型&#xff08;MLLM&#xff09;文本编码器3. 3D VAE4. 提示重写&#xff08;Prompt Rewrite&#xff09; 项目运行方式与执行步骤1. …