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

【quarkus系列】解决native包反射问题之RegisterForReflection 注解

背景

在使用 Quarkus 等框架时,反射机制可能是我们剥离spring框架之后做native包需要的解决问题。
首先先了解讨论为什么原生包(native image)不支持传统的反射机制呢?扩展一下知识点,两者之间的区别。

反射机制:反射允许 Java 程序在运行时动态地发现和使用类、方法和字段。这种动态性带来了极大的灵活性,但也有一些缺点,如性能开销和安全问题。

原生包(native image):GraalVM 提供了一种将 Java 应用程序编译为原生可执行文件的能力,这种方式能够显著提高启动速度和减少内存占用。这是因为原生包在编译时进行了大量的优化和提前计算,而不是依赖运行时的动态特性。

综上,我们在编译期,即使使用了反射机制,也不会影响我们代码正常运行,换言之,只要我们不制作native镜像包,都不会影响我们的使用。

那我们解释一下为什么会不支持呢。

  • 原生包的构建依赖静态分析,分析应用程序的全部代码路径。这种方法需要知道所有可能的类、方法和字段引用。

  • 编译时,所有可能被使用的代码都必须是已知的。反射机制的动态性使得在编译时无法确定哪些类和成员会在运行时被访问。

  • 生成原生包时,GraalVM 会去除所有未使用的类和方法以减少包的大小。反射需要运行时的类型信息和元数据,而这些信息在编译期间可能被删除,导致运行时无法通过反射机制访问。

  • 反射机制需要大量的元数据来支持运行时动态查找,这会增加内存占用。而原生包的一个主要优势就是减少内存占用,因此这两者是矛盾的。

针对上面的扩展,相信大家应该会进一步了解了原生包的机制了吧!下面开启今天的主题RegisterForReflection

RegisterForReflection

为了在原生包中使用反射,GraalVM 提供了一些解决方案,主要是通过显式注册反射信息。
@RegisterForReflection注解用于显式声明哪些类需要在运行时使用反射。这些信息在编译时被收集并保存在配置文件中,以便在生成原生包时包含必要的元数据,确保在原生镜像中能够正确处理反射操作。

实践

语法示例

  • 方式一:使用 @RegisterForReflection 注解
import io.quarkus.runtime.annotations.RegisterForReflection;@RegisterForReflection
public class MyClass {private String name;private int age;// Constructors, Getters, and Setters
}
  • 方式二:配置文件注册反射信息
    除了使用注解,还可以通过配置文件注册反射信息。这在处理第三方库或无法修改源代码的情况下非常有用。

META-INF/native-image/reflect-config.json文件中添加如下配置:

[{"name": "com.example.MyClass","allDeclaredFields": true,"allDeclaredMethods": true}
]

构建native镜像

  • dockerfile.native
FROM quay.io/quarkus/ubi-quarkus-native-image:22.3-java11 AS buildWORKDIR /workspace
COPY . .RUN ./mvnw package -Pnative -Dquarkus.native.container-build=true# Stage 2: Create the minimal runtime image
FROM registry.access.redhat.com/ubi8/ubi-minimal:8.6WORKDIR /work/
RUN chown 1001 /work \&& chmod "g+rwX" /work \&& chown 1001:root /workCOPY --from=build /workspace/target/*-runner /work/applicationEXPOSE 8080
USER 1001CMD ["./application", "-Dquarkus.http.host=0.0.0.0"]
  • 构建命令docker build -f src/main/docker/Dockerfile.native -t quarkus/getting-started .
  • 运行命令docker run -i --rm -p 8080:8080 quarkus/getting-started

相关文章:

  • 【八股系列】谈谈关于对webpack热更新的原理?
  • Golang | Leetcode Golang题解之第114题二叉树展开为链表
  • 装机必备——360压缩安装教程
  • Kubernetes集群上的Etcd备份和恢复
  • 汇编原理()二进制 跳转指令
  • 蒲公英旁路组网:总部旁路,分部一级组网方案
  • 安卓六种页面加载优化方案对比总结
  • Linux安装PostgreSQL脚本
  • 装饰模式:鸡腿堡
  • 提高联盟营销收入的秘密武器
  • Nginx实战:https 配置SSL证书
  • 弱密码系统登录之后强制修改密码
  • Codeforces Round 916 (Div. 3) C. Quests (贪心 + 模拟)
  • 鸿蒙开发接口图形图像:【@ohos.display (屏幕属性)】
  • Qt子线程更新UI的一种新玩法
  • 2018以太坊智能合约编程语言solidity的最佳IDEs
  • canvas 五子棋游戏
  • DOM的那些事
  • gitlab-ci配置详解(一)
  • Hibernate最全面试题
  • iBatis和MyBatis在使用ResultMap对应关系时的区别
  • interface和setter,getter
  • JavaScript学习总结——原型
  • PV统计优化设计
  • Python 基础起步 (十) 什么叫函数?
  • 从零开始的无人驾驶 1
  • 当SetTimeout遇到了字符串
  • 回顾2016
  • 聚类分析——Kmeans
  • 详解NodeJs流之一
  • - 语言经验 - 《c++的高性能内存管理库tcmalloc和jemalloc》
  • 再次简单明了总结flex布局,一看就懂...
  • Python 之网络式编程
  • 阿里云API、SDK和CLI应用实践方案
  • 阿里云移动端播放器高级功能介绍
  • 交换综合实验一
  • ​DB-Engines 12月数据库排名: PostgreSQL有望获得「2020年度数据库」荣誉?
  • ​MPV,汽车产品里一个特殊品类的进化过程
  • ​香农与信息论三大定律
  • !!java web学习笔记(一到五)
  • # 服务治理中间件详解:Spring Cloud与Dubbo
  • (k8s)Kubernetes本地存储接入
  • (八)c52学习之旅-中断实验
  • (附源码)计算机毕业设计ssm基于B_S的汽车售后服务管理系统
  • (入门自用)--C++--抽象类--多态原理--虚表--1020
  • (实测可用)(3)Git的使用——RT Thread Stdio添加的软件包,github与gitee冲突造成无法上传文件到gitee
  • **Java有哪些悲观锁的实现_乐观锁、悲观锁、Redis分布式锁和Zookeeper分布式锁的实现以及流程原理...
  • .babyk勒索病毒解析:恶意更新如何威胁您的数据安全
  • .NET 8 编写 LiteDB vs SQLite 数据库 CRUD 接口性能测试(准备篇)
  • .net获取当前url各种属性(文件名、参数、域名 等)的方法
  • .NET精简框架的“无法找到资源程序集”异常释疑
  • .NET开源项目介绍及资源推荐:数据持久层
  • @Tag和@Operation标签失效问题。SpringDoc 2.2.0(OpenApi 3)和Spring Boot 3.1.1集成
  • [ C++ ] STL priority_queue(优先级队列)使用及其底层模拟实现,容器适配器,deque(双端队列)原理了解
  • [ vulhub漏洞复现篇 ] Grafana任意文件读取漏洞CVE-2021-43798