Java-Spring入门指南(十一)代理模式与Spring AOP实战

作者:珹洺日期:2025/10/2

Java-Spring入门指南(十一)代理模式与Spring AOP实战

  • 前言
  • 一、代理模式
    • 1.1 静态代理
      • 步骤1:定义租房接口(抽象行为)
        • 步骤2:实现房东类(真实对象)
        • 步骤3:编写中介类(代理对象)
        • 步骤4:测试静态代理
        • 静态代理的优缺点
    • 1.2 动态代理
  • 二、AOP是什么?
    • 2.1 AOP是什么?
    • 2.2 AOP有什么用?
    • 2.3 AOP的使用场景是什么?
    • 2.4 AOP的核心特点是什么?
  • 三、AOP在Spring中的应用
    • 3.1 准备依赖
    • 3.2 配置Spring的AOP命名空间
    • 3.3 定义业务接口与实现类
      • 学生服务接口(StudentService.java)
        • 学生服务实现类(StudentServiceImpl.java)
    • 3.4 定义“切面”类(增强逻辑)
    • 3.5 配置AOP:指定切入点与通知
  • 四、测试Spring AOP

前言

在前一篇博客中,我们掌握了Spring纯Java类配置的技巧,彻底摆脱了XML的束缚。

  • 而Spring中另一项核心技术——面向切面编程(AOP),能让我们在不修改原有业务代码的前提下,为方法添加额外功能(如日志、事务、权限校验等)。

我的个人主页,欢迎来阅读我的其他文章
https://blog.csdn.net/2402%5F83322742?spm=1011.2415.3001.5343
我的Java-Spring入门指南知识文章专栏
欢迎来阅读指出不足
https://blog.csdn.net/2402%5F83322742/category%5F13040333.html?spm=1001.2014.3001.5482

在这里插入图片描述


Spring的官方AOP讲解网站
https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html#aop

一、代理模式

代理模式的核心是:通过“代理对象”代替“真实对象”,在不修改真实对象的前提下,为其添加额外功能

我们用房东中介租客的例子来列举一下

  • 房东(真实对象):有房子要租,但不想直接和租客打交道,还想在租房前后做额外操作(如签合同、收押金)。
  • 中介(代理对象):代替房东与租客交互,能在“租客租房”的前后添加自己的操作(如带看、收中介费)。
  • 租客(调用者):只需和中介交互,就能完成租房,无需关心房东的细节。

1.1 静态代理

静态代理需要手动为每个真实对象编写对应的代理类,步骤如下:

步骤1:定义租房接口(抽象行为)

1// 租房接口:定义租房的核心行为
2public interface Rent {
3    void rentHouse(); // 租房方法
4}
5

步骤2:实现房东类(真实对象)

1// 房东:真实对象,实现租房接口
2public class Landlord implements Rent {
3    @Override
4    public void rentHouse() {
5        System.out.println("房东:我的房子成功租出去了");
6    }
7}
8

步骤3:编写中介类(代理对象)

1// 中介:代理对象,也实现租房接口
2public class Mediator implements Rent {
3    private Landlord landlord; // 持有真实对象(房东)的引用
4
5    public Mediator(Landlord landlord) {
6        this.landlord = landlord;
7    }
8
9    @Override
10    public void rentHouse() {
11        // 租房前:中介的额外操作
12        System.out.println("中介:带租客看房,收取中介费");
13        // 调用真实对象的核心方法
14        landlord.rentHouse();
15        // 租房后:中介的额外操作
16        System.out.println("中介:协助签合同,收取押金");
17    }
18}
19

步骤4:测试静态代理

1
2public class ProxyTest {
3    public static void main(String[] args) {
4        // 1. 创建真实对象(房东)
5        Landlord landlord = new Landlord();
6        // 2. 创建代理对象(中介),并传入房东
7        Mediator mediator = new Mediator(landlord);
8        // 3. 通过中介租房(调用代理对象的方法)
9        mediator.rentHouse();
10    }
11}
12

运行结果:
在这里插入图片描述

静态代理的优缺点

  • 优点:逻辑直观,能在不修改真实对象的前提下,为其添加额外功能。
  • 缺点:代理类与真实对象绑定,若有100个真实对象,就得写100个代理类,代码冗余且维护成本高。

1.2 动态代理

动态代理无需手动编写代理类,而是运行时自动生成代理对象(常见的有JDK动态代理——基于接口、CGLIB动态代理——基于子类)。

但动态代理的底层代码较为复杂,而Spring AOP帮我们封装了这些细节,让我们能更简单地使用AOP。


二、AOP是什么?

静态代理的“一对一”绑定方式,在复杂业务中会变得非常繁琐。而AOP(Aspect Oriented Programming,面向切面编程) 正是为解决这个问题而生:它能通过“切面”,对多个类的多个方法 统一添加增强功能,完全无需手动编写代理类。

2.1 AOP是什么?

AOP是一种编程思想,核心逻辑是:将与核心业务无关,但又分散在多个业务中的通用功能(如日志、事务、权限),抽取成“切面(Aspect)”,在合适的时机(如方法执行前/后),动态“织入”到业务方法中

在这里插入图片描述

简单来说:业务代码只关注核心逻辑,通用功能交给AOP统一处理

2.2 AOP有什么用?

AOP专为解决“横切关注点”问题而生:

  • 横切关注点:与业务逻辑无关,但需在多个业务方法中重复出现的逻辑(如日志打印、事务控制、异常处理、权限校验等)。
  • AOP的价值:让横切关注点与业务逻辑解耦,只需写一次,就能作用于多个方法,既减少代码冗余,又便于统一维护。

2.3 AOP的使用场景是什么?

AOP的典型应用场景包括:

  • 日志记录:方法执行前/后自动记录日志。
  • 事务管理:方法执行前开启事务,执行后提交/回滚事务。
  • 权限校验:方法执行前校验用户权限。
  • 性能监控:统计方法的执行时间。
  • 异常处理:统一捕获和处理方法中的异常。

2.4 AOP的核心特点是什么?

  • 切面(Aspect):横切关注点的封装(如“日志切面类”),包含“何时增强”“增强哪些方法”“做什么增强”。
  • 通知(Advice):切面中的具体增强逻辑(如“方法执行前打印日志”),分为前置通知(before)、后置通知(after)、环绕通知(around)等。
  • 连接点(Join Point):程序中可以被增强的点(Spring AOP中主要指方法调用)。
  • 切入点(Pointcut)具体要增强的连接点,通过表达式指定(如“增强com.niit包下所有Service的方法”)。
  • 织入(Weaving):将切面的通知“织入”到目标方法的过程(Spring在运行时完成织入)。

三、AOP在Spring中的应用

Spring对AOP提供了完善的支持,我们可以通过XML配置或注解实现AOP。下面结合代码,用XML配置方式实战Spring AOP。

3.1 准备依赖

使用Spring AOP需添加aspectjweaver依赖:

1<!-- AspectJ织入依赖:支持AOP功能的核心依赖 -->
2<dependency>
3    <groupId>org.aspectj</groupId>
4    <artifactId>aspectjweaver</artifactId>
5    <version>1.9.9.1</version>
6</dependency>
7

在这里插入图片描述

3.2 配置Spring的AOP命名空间

applicationContext.xml中,添加AOP的命名空间和约束:

1<?xml version="1.0" encoding="UTF-8"?>
2<beans xmlns="http://www.springframework.org/schema/beans"
3       xmlns:context="http://www.springframework.org/schema/context"
4       xmlns:aop="http://www.springframework.org/schema/aop"
5        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
6        xsi:schemaLocation="http://www.springframework.org/schema/beans
7        http://www.springframework.org/schema/beans/spring-beans.xsd
8        http://www.springframework.org/schema/context
9        http://www.springframework.org/schema/context/spring-context.xsd
10        http://www.springframework.org/schema/aop
11        http://www.springframework.org/schema/aop/spring-aop.xsd">
12
13        <!-- 组件扫描:让Spring管理带@Service/@Component等注解的类 -->
14       <context:component-scan base-package="org.example.aop1"/>
15</beans>
16

3.3 定义业务接口与实现类

定义接口和实现类:

学生服务接口(StudentService.java)

1public interface StudentService {
2    void add();   // 添加学生
3    void del();   // 删除学生
4    void update();// 修改学生
5    void query(); // 查询学生
6}
7

学生服务实现类(StudentServiceImpl.java)

1
2import org.springframework.stereotype.Component;
3
4// 注册为Spring的Bean,id为"ssi"
5@Component("ssi")
6public class StudentServiceImpl implements StudentService {
7    @Override
8    public void add() {
9        System.out.println("【核心业务】添加学生");
10    }
11
12    @Override
13    public void del() {
14        System.out.println("【核心业务】删除学生");
15    }
16
17    @Override
18    public void update() {
19        System.out.println("【核心业务】修改学生");
20    }
21
22    @Override
23    public void query() {
24        System.out.println("【核心业务】查询学生");
25    }
26}
27

在这里插入图片描述

3.4 定义“切面”类(增强逻辑)

创建“日志切面”,在方法执行前打印增强信息:

1
2import org.springframework.aop.MethodBeforeAdvice;
3import org.springframework.stereotype.Component;
4
5import java.lang.reflect.Method;
6
7// 注册为Spring的Bean
8@Component
9public class LogBefore implements MethodBeforeAdvice {
10    /**
11     * 方法执行前的增强逻辑
12     * @param method 被增强的方法
13     * @param args 方法参数
14     * @param target 被增强的目标对象
15     */
16    @Override
17    public void before(Method method, Object[] args, Object target) throws Throwable {
18        System.out.println("【AOP增强】" + 
19                           "类:" + target.getClass().getName() + 
20                           ",方法:" + method.getName() + 
21                           " 即将执行~");
22    }
23}
24

3.5 配置AOP:指定切入点与通知

applicationContext.xml中,配置“哪些方法”要被“哪个切面”增强:

1<!-- AOP配置:将增强逻辑织入目标方法 -->
2<aop:config>
3    <!-- 1. 定义切入点:通过表达式指定要增强的方法 -->
4    <!-- execution(* com.niit.aop1.*.*(..)) 含义:
5         - 第一个*:返回值类型任意
6         - com.niit.aop1.*:com.niit.aop1包下的任意类
7         - 第二个*:类中的任意方法
8         - (..):方法参数任意(个数、类型不限)
9    -->
10    <aop:pointcut id="myPointcut" expression="execution(* org.example.aop1(..))"/>
11    
12    <!-- 2. 配置通知:将LogBefore的增强逻辑,织入到myPointcut指定的方法中 -->
13    <aop:advisor advice-ref="logBefore" pointcut-ref="myPointcut"/>
14</aop:config>
15

在这里插入图片描述

配置说明:

  • aop:pointcut:通过expression表达式定义切入点(要增强的方法)。
  • aop:advisor:将通知advice-ref指定的LogBefore)与切入点pointcut-ref指定的myPointcut)关联,完成“织入”。

四、测试Spring AOP

编写测试类,获取StudentService的Bean并调用方法,观察AOP是否生效:

1
2
3import org.springframework.context.support.ClassPathXmlApplicationContext;
4
5public class MyTest {
6    public static void main(String[] args) {
7        // 加载Spring配置文件
8        ClassPathXmlApplicationContext context = 
9                new ClassPathXmlApplicationContext("applicationContext.xml");
10        // 获取StudentService的Bean(注意:此时获取的是Spring生成的代理对象)
11        StudentService studentService = (StudentService) context.getBean("ssi");
12        // 调用方法,触发AOP增强
13        studentService.add();
14        studentService.query();
15        // 关闭容器
16        context.close();
17    }
18}
19

运行结果:
在这里插入图片描述

可以看到:无需修改StudentServiceImpl的代码,方法执行前自动添加了日志增强逻辑——这就是AOP的“无侵入式增强”魅力。


我的个人主页,欢迎来阅读我的其他文章
https://blog.csdn.net/2402%5F83322742?spm=1011.2415.3001.5343
我的Java-Spring入门指南知识文章专栏
欢迎来阅读指出不足
https://blog.csdn.net/2402%5F83322742/category%5F13040333.html?spm=1001.2014.3001.5482

非常感谢您的阅读,喜欢的话记得三连哦

在这里插入图片描述


Java-Spring入门指南(十一)代理模式与Spring AOP实战》 是转载文章,点击查看原文


相关推荐


(14)ASP.NET Core2.2 中的日志记录
老葱头蒸鸡2025/10/2

1.前言 ASP.NET Core支持适用于各种内置和第三方日志记录提供应用程序的日志记录API。本文介绍了如何将日志记录API与内置提供应用程序一起使用。 2.添加日志提供程序 日志记录提供应用程序显示或存储日志。例如,控制台提供应用程序在控制台上显示日志,Azure Application Insights提供应用程序将这些日志存储在Azure Application Insights中。要添加提供应用程序,请在Program.cs中调用提供程序的Add{provider name}扩


Python 的内置函数 abs
IMPYLH2025/10/2

Python 内建函数列表 > Python 的内置函数 abs 无论是在数学计算、数据分析,还是日常编程中,我们经常需要获取一个数的绝对值。Python 提供的 abs() 函数,可以让我们轻松地计算数字的绝对值,而无需手动判断正负。 abs 函数的参数和返回值如下: def abs(x): ''' 计算参数的绝对值 :param x: 要计算的值 :return: x 的绝对值 ''' 示例 在线运行 print(abs(-50)) p


[论文阅读] 人工智能 + 软件工程 | 从“人工扒日志”到“AI自动诊断”:LogCoT框架的3大核心创新
张较瘦_10/1/2025

随着软件服务系统日益庞大、复杂,基于日志的故障诊断对保证软件服务的可靠性至关重要。已有的日志故障诊断方法虽能确定故障类型,但无法为推理过程提供解释,导致难以在生产环境部署。为此,本文提出LogCoT框架,通过Auto-FSC算法利用超大规模闭源LLM提取日志语义,生成可解释根因分析报告;结合无类别标注指令优化与有类别标注参数微调,优化Mistral基座模型;再用LLMf-IPO算法纠正错误结果,对齐用户意图。在两大生产日志数据集上的实验表明,LogCoT在Accuracy、Macro-F1、Weighted


WPS文字如何合并多个文档:两种方法
揭老师高效办公9/30/2025

要合并多个Word文档,使用WPS文字有两种方法,一种是插入附件,引用附件中的文字,会把所有文档中的文字依次合并。第二种方式需要会员,使用WPS的“文档合并拆分”应用,每个文档都会从新的一页开始插入。


医院病人信息管理系统 Web 版开发实战(一)
FPGA+护理+人工智能2025/10/3

医院病人信息管理系统Web版开发实战 文章目录 医院病人信息管理系统Web版开发实战一、概述二、项目结构搭建2.1 Flask 项目结构原理2.2 创建项目文件夹2.3 初始化 Flask 应用 三、路由设计3.1 Flask 路由机制原理3.2 定义核心路由3.3 数据存储函数 四、模板开发4.1 Jinja2 模板引擎原理4.2 基础模板设计4.3 首页模板(index.html)4.4 添加病人模板(add.html)4.5 详情和编辑模板 未完待续


精选 4 款开源免费、美观实用的 MAUI UI 组件库,助力轻松构建美观且功能丰富的应用程序!
追逐时光者2025/10/5

前言 一套优秀的 UI 组件库不仅能大幅提升开发效率,还能显著增强应用的视觉体验与交互质感。今天大姚给大家分享 4 款开源免费、美观实用的 MAUI UI 组件库,助你轻松打造专业级的跨平台应用程序。 .NET MAUI介绍 .NET 多平台应用 UI (.NET MAUI) 是一个跨平台框架,用于使用 C# 和 XAML 创建本机移动和桌面应用。使用 .NET MAUI,可从单个共享代码库开发可在 Android、iOS、macOS 和 Windows 上运行的应用。 .NET开源免费的跨平


Android系统模块编译调试与Ninja使用指南
龙之叶2025/10/6

模块编译调试方法 (此处举例framework、installd、SystemUI等模块的编译调试,其他类似) 1. Framework模块编译 Android系统代码的framework目录内,一共有3个模块单独编译:framework、services、framework-res.apk。 注意:偶尔会有改了代码但没检测到,编译结束后产物并未更新的情况,所以可以考虑先剪切掉原先的产物或者检查产物更新时间确保已经重新编译。 步骤: 完成根目录下 source build/envsetup.sh


Webpack实战笔记:从自动构建到本地服务器搭建的完整流程
XiangCoder2025/10/7

作为前端开发者,Webpack 是绕不开的构建工具。最近系统学习了 Webpack 的自动构建和服务器搭建,整理了一套从基础到实战的操作笔记,包含具体案例和踩坑经验,适合新手跟着实操。 前言:为什么需要 Webpack 构建工具? 刚开始写前端项目时,我们习惯在 index.html 里手动引入各种 js、css 文件。但随着项目变大,会遇到两个核心问题: 资源越来越多,手动管理引入路径容易出错(尤其是加哈希值优化缓存时); 开发时需要频繁刷新页面看效果,效率太低。 Web


单机已达上限?PerfTest 分布式压测登场,轻松模拟百万用户洪峰
Go有引力2025/10/9

前言 在前一篇文章中,我们详细介绍了 perftest 的单机压测能力,展示了它如何通过极简的命令行实现对 HTTP/1.1、HTTP/2、HTTP/3 与 WebSocket 的高性能测试。然而,当业务系统庞大、服务部署分布式、网络链路复杂时,单机的压测能力显然无法满足真实生产环境的模拟需求。 幸运的是,perftest 不止于单机。它同样支持 分布式集群压测,通过 Collector + Agent 的架构,让你轻松在多台机器上同时发起测试,实现百万乃至千万级并发的性能评估。 为什么选择分


老题新解|十进制转二进制
程序员莫小特2025/10/10

《信息学奥赛一本通》第160题:十进制转二进制 题目描述 给定一个十进制整数 n n n,请将其转换为对应的二进制表示,并输出。 输入格式 输入包含一行,一个整数 n

首页编辑器站点地图

Copyright © 2025 聚合阅读

License: CC BY-SA 4.0