深入解析:SpringBoot与反射

news/2025/9/25 19:09:32/文章来源:https://www.cnblogs.com/yfceshi/p/19111811

反射机制是 Spring Boot 框架实现核心功能的底层基础,Spring Boot 的依赖注入(DI)、控制反转(IOC)、AOP(面向切面编程)、注解解析等核心特性都大量依赖反射。以下从 Spring Boot 的核心功能出发,详解反射的具体应用:

一、反射在 Spring Boot 核心功能中的应用

1. 控制反转(IOC)与依赖注入(DI)

Spring Boot 的 IOC 容器(如 ApplicationContext)的核心是动态管理对象的生命周期,而这完全依赖反射:

  • 对象创建:Spring 扫描配置类(如 @Component@Service 标注的类)后,通过反射获取这些类的 Class 对象,再调用其构造方法(通常是无参构造)动态创建实例,无需手动 new 对象。

// 伪代码:Spring 创建对象的过程
Class clazz = Class.forName("com.example.UserService"); // 获取类信息
Constructor constructor = clazz.getConstructor(); // 获取构造方法
Object instance = constructor.newInstance(); // 反射创建实例
  • 依赖注入:当类中存在 @Autowired 标注的字段或方法时,Spring 通过反射:

    • 调用 Field.setAccessible(true) 访问私有字段,直接注入依赖对象;
    • 或调用 Method.invoke() 执行 setter 方法,完成依赖注入。
2. 注解解析

Spring Boot 大量使用注解(如 @Controller@RequestMapping@Value 等),注解的解析完全依赖反射:

  • 扫描注解:Spring 启动时会扫描指定包下的类,通过 Class.getAnnotations() 或 Class.getDeclaredAnnotations() 反射获取类、方法、字段上的注解。

// 伪代码:解析 @Controller 注解
Class clazz = Class.forName("com.example.UserController");
if (clazz.isAnnotationPresent(Controller.class)) {
// 处理控制器类
}

  • 处理注解逻辑:例如解析 @RequestMapping("/user") 时,Spring 通过反射获取方法上的注解属性,将 URL 与方法绑定,实现请求映射。又如 @Value("${app.name}") 注解,Spring 通过反射访问字段并设置配置文件中的值。

3. AOP(面向切面编程)

AOP 的核心是动态增强方法功能(如事务、日志、权限校验),其底层依赖反射和动态代理,而动态代理的实现离不开反射:

  • 代理对象创建:Spring 会为目标类创建代理对象(JDK 动态代理或 CGLIB),代理对象在调用目标方法时,通过反射 Method.invoke() 执行原方法,并在前后插入增强逻辑(如事务的开启和提交)。
// 伪代码:AOP 增强方法
Method targetMethod = targetClass.getMethod("save"); // 反射获取目标方法
Object result = targetMethod.invoke(targetObject); // 执行原方法
4. 配置文件绑定(@ConfigurationProperties)

Spring Boot 的 @ConfigurationProperties 注解可将配置文件(如 application.yml)中的属性自动绑定到 Java 对象,其底层通过反射设置字段值:

  • 反射获取类的所有字段(包括私有字段);
  • 根据字段名匹配配置文件中的属性键;
  • 通过 Field.set() 反射设置字段值。

二、Spring Boot 中反射的典型场景示例

场景 1:自定义注解解析

假设我们定义一个 @Log 注解,用于记录方法调用日志,Spring Boot 可通过反射解析该注解并执行日志逻辑:

// 自定义注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME) // 必须为 RUNTIME,否则反射无法获取
public @interface Log {
String value() default "";
}
// 业务类
@Service
public class UserService {
@Log("查询用户")
public User getUser(Long id) {
return new User(id, "张三");
}
}
// 注解解析器(Spring 会自动扫描并处理)
@Component
public class LogAnnotationProcessor implements BeanPostProcessor {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
Class clazz = bean.getClass();
// 反射获取所有方法
for (Method method : clazz.getDeclaredMethods()) {
// 检查方法是否有 @Log 注解
if (method.isAnnotationPresent(Log.class)) {
Log logAnnotation = method.getAnnotation(Log.class);
System.out.println("日志:" + logAnnotation.value()); // 输出注解信息
// 此处可通过动态代理增强方法,实现日志记录逻辑
}
}
return bean;
}
}
场景 2:通过反射获取 Spring 容器中的 Bean

在 Spring Boot 中,可通过 ApplicationContext 的反射能力获取容器中的 Bean:

@SpringBootApplication
public class MyApp implements CommandLineRunner {
@Autowired
private ApplicationContext context;
public static void main(String[] args) {
SpringApplication.run(MyApp.class, args);
}
@Override
public void run(String... args) throws Exception {
// 获取 UserService 类的 Bean(底层通过反射创建和管理)
UserService userService = context.getBean(UserService.class);
User user = userService.getUser(1L);
System.out.println(user);
}
}

三、反射在 Spring Boot 中的优缺点

优点
  1. 解耦:通过反射动态创建对象和注入依赖,避免了硬编码的 new 操作,降低了类之间的耦合。
  2. 灵活性:框架可通过反射适配任意标注了注解的类,无需提前知道类的具体实现。
  3. 简化开发:开发者无需手动管理对象依赖,只需通过注解声明,反射机制自动完成复杂的底层操作。
缺点
  1. 性能损耗:反射绕过了编译期检查,每次调用 Method.invoke() 或 Constructor.newInstance() 都有额外的性能开销(Spring 通过缓存反射对象缓解此问题)。
  2. 调试难度:反射调用的方法在栈跟踪中不易定位,增加了调试复杂度。
  3. 安全风险:反射可访问私有成员,可能破坏类的封装性(Spring 内部通过严格的权限控制规避此问题)。

四、Spring Boot 对反射性能的优化

Spring 为减少反射的性能损耗,做了以下优化:

  1. 缓存机制:将频繁使用的 ClassMethodConstructor 对象缓存到 ConcurrentHashMap 中,避免重复解析。
  2. 字节码增强:对于 AOP 等场景,优先使用 CGLIB 动态代理(直接生成字节码,而非反射调用),减少反射次数。
  3. 提前初始化:在容器启动时完成大部分反射操作(如扫描类、创建对象),避免运行时的性能开销。

总结

反射是 Spring Boot 框架的 “灵魂”,没有反射,就无法实现 IOC、DI、AOP 等核心功能。它让 Spring Boot 具备了动态性和灵活性,使开发者能专注于业务逻辑而非对象管理。尽管反射存在性能损耗,但 Spring 通过一系列优化手段将其影响降到最低,成为 Java 生态中最成功的框架之一。

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

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

相关文章

云栖小镇现场追踪!触摸AI 未来

原文: https://mp.weixin.qq.com/s/-jkeIywNb1alCajgZveSSw 9 月 24 日的杭州云栖小镇,人山人海 ——2025 云栖大会。作为每年必蹲的科技盛会,今年大会的主题 “云智一体・碳硅共生” 可不是空口号。走在 4 万平方米…

刚入手一手房怎么网上做网站Wordpress如何创建菜单

edge浏览器扩展插件中心10月发布 可直接安装Chrome扩展 Windows 10的全新浏览器Edge收获了不少好评,我们也知道它将在今年秋天迎来扩展程序的支持。 Mashable已经指出,微软将保证Edge上的扩展严控权限、卸载干净,保证不拖累整体性能&#x…

济南网站建设seo优化wordpress页面内

文章目录 python常用库之数据库orm框架之SQLAlchemy一、什么是SQLAlchemySQLAlchemy 使用场景 二、SQLAlchemy使用SQLAlchemy根据模型查询SQLAlchemy SQL 格式化的方式db_session.query和 db_session.execute区别实测demo 总结:让我们留意一下SQLAlchemy 的 lazy lo…

AT_arc154_d [ARC154D] A + B C ?

直接被这个题闪到了。 首先发现 \(1\) 是最小的,其有很多性质,因此可以花费 \(n - 1\) 次操作比较出来 \(1\) 的位置。 同理,\(2, 3, ..., n\) 都是可以这样比较出来的,但操作次数是 \(O(n^2)\) 级别的,题目只给了…

SQL注入-联合注入

一、SQL语句基础知识 首先打开PHP的数据库,如下图所示,再在终端中输入后连接到数据库点击查看代码 mysql -u root -p1.1 MySQL的基础语句 1.1.1 创造数据库 用来创建一个数据库的语句如下:点击查看代码 create data…

实用指南:【JavaEE】多线程案例(一)

实用指南:【JavaEE】多线程案例(一)pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Mon…

网站开发和c语言反网站搭建一条龙

MySQL 5.5以上版本 与之前的版本安装出入有些区别: 下面是安装过程mysql5.6 下载地址:ftp://mirror.switch.ch/mirror/mysql/Downloads/MySQL-5.6/一:卸载旧版本使用下面的命令检查是否安装有MySQL Serverrpm -qa | grep mysql有的话通过下面…

架构架构设计师备考第32天——数据库交互NoSQL

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

交互:在终端中输入用户信息

交互:在终端中输入用户信息Python可以允许用户在终端中输入一些信息。 Input功能 接受输入字符串 # -*- coding: utf-8 -*- name = input("Please input your name:") print("Hello " + name + &…

传奇三端互通新开服网站百度非企推广开户

这个算法来自LINUX的源码,下面带有大神的解析,自己在RTC实验中也使用了,不用月份表,润平年的处理,几行就可得出结果,以下是程序和大神的解析Linux源码中的mktime算法解析我们知道,从CMOS中读出来…

php网站开发系统wordpress 引用网页

近日,紫光云技术有限公司在天津举行主题为“产业城市 擎领未来”的IMPACT2019紫光云峰会,深度阐释打造产业数字引擎的理念和实践,并为unI X云创中心揭牌,发布紫光云芯片产业数字引擎。 天津市人民政府副秘书长杨明远为大会致辞会上…

爱站网关键字挖掘wordpress 小组

Java中new一个对象时,JVM到底做了什么? 在Java编程中,new关键字是我们创建对象的最常用方式。但你是否想过,当你写下new MyClass()时,Java虚拟机(JVM)到底在背后做了哪些工作?今天&…

电脑迁移技巧:适用于 Windows 10/11 的免费磁盘克隆优秀的工具

电脑迁移技巧:适用于 Windows 10/11 的免费磁盘克隆优秀的工具pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Co…

详细介绍:Windows安装PostgreSQL入门操作手册

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

主播网站建立商务网站管理的主要内容数据管理

最近在微调 ChatGLM3-6b 时,训练好模型之后,调用inference_hf.py函数验证模型的时候报了如下错误,下面是解决方案。 我在训练时使用的是ptuning_v2.yaml配置文件,训练运行代码如下: CUDA_VISIBLE_DEVICES1 python fi…

东莞市公租房申请网站-建设网微信积分商城

Apache Doris 在查询优化方面通过结合 RBO 和 CBO,实现了对简单和复杂查询的高效优化。RBO 负责处理常量折叠、子查询改写和谓词下推等基础优化操作,而 CBO 则在 Join Reorder 等复杂场景中发挥作用。这种结合策略使得 Apache Doris 能够在面对各种查询场景时,既能保证优化过…

Java学习日记9.18

9.18 数据类型 整数扩展 进制 二进制: ob 十进制: 没有 八进制: 0 十六进制: 0x int i = 10 int i1 = 010 int i2 = 0x10输出结果将会是 10 8 16浮点数拓展 float 定义的小数必须在后边加一个f或F (因为小数默认的…

在PVE中实现宿主机与虚拟机同网段通信的配置方案

在PVE中实现宿主机与虚拟机同网段通信的配置方案本文内容由笔者根据遇到的问题口述,并通过ai整理而成供,遇到同样问题的同学参考。问题背景 在配置PVE服务器的过程中发现,当网络环境使用VLAN时,如果PVE宿主机的管理…

一种CDN动态加速首次访问加速方法

本文分享自天翼云开发者社区《一种CDN动态加速首次访问加速方法》.作者:蒋辉 具体方案如下: 1. 对于全站加速,节点内部的探测采用的非请求触发式探测(已实现),在首次访问时,使用配置的顶层父方案作为回源节点回源…

CF1716题解

CF1716A 不难发现,只保留一个1即可,其余的怎么变都可以,所以变成k个后,直接取max在序列中有1的情况下必然可以构造出来点击查看代码 #include<bits/stdc++.h> using namespace std; const int N=55; int t,n…