Spring Boot 3.x Migration: 关键特性与约束

Spring Boot 3.0(2022 年底发布)底层依赖 Spring Framework 6.x。本文汇总从 2.x 升级到 3.x 时最常见的破坏性变更与约束。框架总览见 Spring Boot。 Spring Boot 与 Spring Framework 版本对应 Spring Boot Spring Framework 3.0.x 6.0.x 3.2.x 6.1.x 3.3.x / 3.4.x 6.1.x / 6.2.x 3.5.x 6.2.x 1. Java 版本要求 Spring Boot 3.x 最低要求 Java 17。 2. javax → jakarta 命名空间迁移(最大变更) Java EE 已捐赠给 Eclipse 基金会,品牌更名为 Jakarta EE,所有包名从 javax.* 改为 jakarta.*。这是代码层面影响最广的变更,几乎所有用到 Servlet、JPA、Bean Validation 的代码都要修改: 旧包名(javax) 新包名(jakarta) javax.servlet.* jakarta.servlet.* javax.persistence.* jakarta.persistence.* javax.validation.* jakarta.validation.* javax.transaction.* jakarta.transaction.* javax.annotation.* jakarta.annotation.* import jakarta.servlet.http.HttpServletRequest; import jakarta.persistence.Entity; 3. Spring Security 6.x:WebSecurityConfigurerAdapter 彻底移除 WebSecurityConfigurerAdapter 已彻底移除,必须改为注册 SecurityFilterChain Bean,详见 Spring Security。 ...

Created 26266-06-26 · Updated 26266-06-26 · 2 min · 214 words · wiloon

Java Virtual Threads: 虚拟线程与高并发

Java 21(2023)正式引入虚拟线程(Project Loom)。对多数业务系统,Spring MVC + 虚拟线程是比 Spring WebFlux 更低成本的并发方案。Boot 里一行配置即可开启,见下文。 什么是虚拟线程 虚拟线程由 JVM 管理,数量可达百万级。阻塞时 JVM 自动挂起虚拟线程、释放底层 OS 线程去处理其他任务,数据返回后再恢复执行——对应用代码完全透明。 这与 Go 语言的协程(goroutine)是同一思想:用户态轻量级并发,阻塞时不占用 OS 线程。Go 从 2009 年就原生支持,Java 晚了约 14 年。 Java 虚拟线程 Go 协程(goroutine) 出现时间 2023(Java 21) 2009(Go 1.0) 调度器 JVM 内置 Go runtime 初始栈内存 约 1KB 约 2KB 与现有代码兼容 ✅ 完全兼容,API 不变 — 对应用层完全透明 虚拟线程的复杂性封装在 JVM 内部,应用层代码写法与传统线程一模一样: // platform thread pool ExecutorService executor = Executors.newFixedThreadPool(200); // virtual threads: same API, one-line change ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor(); executor.submit(() -> { User user = db.findById(id); // looks blocking; JVM parks the virtual thread return user; }); Spring Boot 3.2 开启虚拟线程只需一行配置,业务代码不用改: ...

Created 26266-06-26 · Updated 26266-06-26 · 1 min · 162 words · wiloon

Spring Boot Container Packaging: Fat JAR、分层 JAR 与 Buildpacks

背景 Spring Boot REST API 打成 jar 之后,放进容器常见有三层递进:先有一个能跑的 fat jar,再用分层 JAR 优化 Docker 缓存,最后用 Cloud Native Buildpacks 一键出镜像;若还要缩小运行时,可在 Buildpack 上显式开启 jlink 裁剪 JRE。fat jar 布局与 JarLauncher 见专文 Spring Boot Executable JAR。 Spring Framework 本身几乎不讲容器镜像;相关说明集中在 Spring Boot Reference 的 Packaging → Container Images。本文把分层 JAR、bootBuildImage、Paketo jlink 串成一条阅读路径,并附上官方文档索引。GraalVM Native Image 是另一条路线,见 GraalVM Native Image 简介。 三条路径总览 flowchart TB subgraph build [构建] SRC[源码 mvn package / bootJar] FAT[Fat JAR 可执行 uber jar] LAY[分层 JAR 含 layers.idx] end subgraph deploy [容器化] D1[简单 DockerfileCOPY jar + java -jar] D2[分层 Dockerfilejarmode extract --layers] BP[bootBuildImage / build-imagePaketo Buildpacks] end subgraph runtime [运行时 JVM] JRE[完整 JRE] JLINK[jlink 精简 JREBP_JVM_JLINK_ENABLED] end SRC --> FAT FAT --> LAY FAT --> D1 LAY --> D2 LAY --> BP D1 --> JRE D2 --> JRE BP --> JRE BP -.->|可选| JLINK 路径 典型产物 主要收益 复杂度 Fat jar + 简单镜像 单层 app.jar + JRE 基础镜像 上手最快 低 分层 JAR + Dockerfile 多 COPY 层 + JRE 推送镜像时依赖层可缓存 中 Buildpack(bootBuildImage) OCI 镜像,自动检测 jar 零 Dockerfile、与 Paketo 生态一致 低~中 Buildpack + jlink 同上,运行时 JRE 更小 缩小镜像体积 中(需调 env) 分层 JAR 分层 JAR 在 fat jar 布局不变的前提下,额外写入 BOOT-INF/layers.idx,声明哪些路径属于哪一层、层的写入顺序。Spring Boot 2.3 起默认开启;Maven repackage / Gradle bootJar 的 layered 无需额外配置即可得到。 ...

Created 21216-06-21 · Updated 24246-06-24 · 5 min · 1027 words · -

Java Annotation(注解)

Annotation 是 Java 5 引入的语言特性,中文一般叫注解。它提供了一种类似注释的机制,用来将元数据(metadata)与程序元素(类、方法、成员变量等)关联起来。 更通俗地说,注解为程序元素加上与业务逻辑无关的说明信息,供框架或工具在编译期、类加载期或运行期读取和处理。注解本身不会改变程序的执行逻辑;JVM 执行字节码时会忽略注解,只有通过反射或注解处理器才能访问其中的信息。 框架中的注解(以 Spring 为例) JDK 5 提供的是 语言机制(@interface、@Retention、反射 API);框架上的 @Autowired、@Controller 等是 框架用 @interface 自定义的注解,不是 JDK 内置。容器在启动时扫描类路径、读取注解元数据,再决定注册哪些 Bean、如何注入、如何映射 URL。 时期 典型配置方式 Spring 1.x(2004 起) 几乎全 XML(<bean>、<property>);不要求 JDK 5 Spring 2.5(2007) XML 骨架 + @Autowired、@Component / @Service、@Controller、@RequestMapping 等 Spring 3.0(2009) @Configuration + @Bean(Java Config),技术上可零 XML,但需手写各基础设施 Spring Boot(2014) 自动配置 + application.yml,常见场景几乎不用 XML 或大量 @Configuration 时间上有先后:JDK 5 GA(2004-09) 早于 Spring 大规模注解化(2006–2007);Spring 1.0(2004-03)发布时 JDK 5 尚未 GA,1.x 自然以 XML 为主。整体脉络见 Spring §与 JDK 5 注解的关系。 ...

Created 26266-12-26 · Updated 24246-06-24 · 5 min · 896 words · -

Java version history, jdk history

Java 由 Sun Microsystems 于 1995 年发布,2010 年起由 Oracle 维护。讨论「版本」时容易混用 J2SE 1.4、Java 5、Java SE 8、JDK 17 等说法——它们分属平台品牌、对外版本号、运行时版本字符串、class 文件格式等不同层次。下文先列发布简史与各版本文档链接,再分节说明命名如何演变。 发布简史 时间 版本 备注 1995-05 Java 1.0 语言与平台首次发布 → JDK 1.0 1997-02 Java 1.1 内部类、JAR、RMI 等 → JDK 1.1 1998-12 Java 1.2 Java 2 Platform;Swing、集合框架 1999-04 HotSpot 首次发布 独立 JVM 产品,可配 JDK 1.2 → HotSpot 1999-06 J2SE / J2EE / J2ME 三版平台划分 2000-05 Java 1.3 HotSpot 成为 JDK 默认 VM(Classic 仍可选) 2002-02 J2SE 1.4 assert、NIO、regex、JUL;Classic VM 移除 → JDK 1.4 2004-02 J2SE 1.5 Beta Tiger 公开 Beta(泛型、注解等);早于 GA 2004-09 Java 5 泛型、enum、for-each、注解、JUC → JDK 5 2005-06 Java SE 6 公布 J2SE 更名为 Java SE 2006-12 Java SE 6 GA 脚本引擎、Web Service 增强 2011-07 Java SE 7 GA NIO.2、ForkJoin → JDK 7 2014-03 Java SE 8 GA Lambda、Stream → JDK 8;后被 Oracle 追溯认定为 LTS 2017-09 Java SE 9 GA 模块系统、半年发布模型 → JDK 9 2018-03 Java SE 10 短期版本 2018-09 Java SE 11 新发布策略下首个 LTS 2019~2021 Java 12~16 短期版本 2021-09 Java SE 17 LTS 间隔改为每 2 年 → JDK 17 2022~2023 Java 18~20 短期版本 2023-09 Java SE 21 → JDK 21 相对 JDK 17 的变化 2024~2025 Java 22~24 短期版本 2025-09 Java SE 25 → JDK 25 相对 JDK 21 的变化 2026-03 Java SE 26 → JDK 26 相对 JDK 25 的变化 2027-09 Java SE 29(计划) 下一 LTS 2010 年 Oracle 收购 Sun;2017 年起 OpenJDK 成为参考实现。发行版选型见 OpenJDK;企业版演变见 Java EE。 ...

Created 20206-06-20 · Updated 24246-06-24 · 3 min · 636 words · -

JDK 5

JDK 5(Java SE 5)于 2004 年 9 月正式发布,是 JDK 1.4 之后的一次重大更新。第一个对外以「Java 5」而非「Java 1.5」命名的版本;平台品牌 J2SE → Java SE 的过渡亦在此前后。详见 Java 版本历史。 Tiger 语言特性(含注解)自 2002 年起在 JCP 并行规划(JSR 175 等于 JDK 1.4 发布后不久立项);2003 年 12 月有 Early Access 构建,2004 年 2 月公开 Beta——均早于上述正式版。 发布历程 「2004 年 9 月」指 GA(正式版);Tiger 在 JCP 与 Sun 产品线上的里程碑更早: 阶段 大约时间 说明 JDK 1.4 GA 2002-02 1.4 落地后,Tiger 语言特性(含 JSR 175 注解)即在 JCP 并行推进 JSR 175 立项 2002-03~04 JCP 评审通过,专家组成立 JSR 175 公开评审 2003-11 注解规范草案公开 Tiger Early Access 2003-12 预发布 JDK(含注解等语言特性),面向早期测试 Tiger 公开 Beta 2004-02 可在 java.sun.com/j2se/1.5 下载试用 JDK 5 Final 2004-09-30 对外称 Java 5 / J2SE 5.0;java.version 仍为 1.5.0_xxx 同一 Tiger 版本还打包了泛型(JSR 14)、枚举与增强 for(JSR 201)、JUC(JSR 166)等;整体由 JSR 176(J2SE 5.0 Release Contents)归集交付。 ...

Created 28286-03-28 · Updated 24246-06-24 · 3 min · 560 words · -

JLS: Java Language Specification

什么是 JLS JLS(Java Language Specification,Java 语言规范)是 Oracle 官方发布的权威文档,完整定义了 Java 编程语言的语法、语义和行为。 可以把它理解为 Java 语言的"宪法"——编译器、JVM 实现者以及语言特性设计者,都必须以 JLS 为准。 官方地址:Java SE 规范 JLS 的主要内容 JLS 按章节组织,每章覆盖语言的一个核心方面: 章节 主题 第 2 章 词法结构(关键字、字面量、标识符) 第 3 章 类型、值与变量 第 6 章 名称(作用域、遮蔽、访问控制) 第 8 章 类声明 第 9 章 接口声明(含注解类型) 第 14 章 语句 第 15 章 表达式 第 17 章 线程与锁(Java 内存模型) 为什么要了解 JLS 大多数开发者日常不需要阅读 JLS,但以下场景中它非常有用: 理解边界行为:遇到语言"奇怪"行为时(如整数溢出、字符串 == 比较、自动装箱陷阱),JLS 给出权威解释。 注解与反射:JLS 第 9 章详细定义注解类型声明(@interface)的语法和语义,是理解注解底层的基础。 Java 内存模型:JLS 第 17 章定义了可见性、有序性保证,是理解 volatile、synchronized、happens-before 的权威来源。 框架/工具开发:编写编译器插件、注解处理器(APT)、字节码工具时,需要精确理解语言规范。 JLS 与 JVM 规范的区别 JLS 和 JVMS(Java Virtual Machine Specification,Java 虚拟机规范)经常被混淆: ...

Created 23236-06-23 · Updated 23236-06-23 · 1 min · 139 words · -

2026 W25

本周一(6 月 16 日)补写了 2026 W24 周记。下面记 W25 自己的事。 投递邀请与简历准备 6 月 15 日收到一份投递简历的邀请。这周主要修改简历和可能的面试准备,homelab 改造、公司刻章之类都先往后放。 写简历时沿用平时写代码、写 blog 用的 SDD 思路:先和 AI 写一份 spec,对照旧简历与新职位描述列出差异;再按差异到个人 profile 里挖过往项目的故事;回到 spec 标注每条差异可以引用哪些素材;最后让 AI 根据 spec 生成新一版简历。因为此前投过类似方向的岗位,很多段落可以复用,这个流程既有结构又省时间。6 月 17 日跟前同事聊 AI 用法时,才突然意识到 SDD 不只适用于代码和文章——简历同样适用。 挖素材的过程中,我把一些早年做过但没在简历里展开的项目重新整理成文,例如 车联网平台第三方数据推送集成。有些事只是做过、学过,和跟别人讲过一次之后,大脑里留下的关联是不一样的;输出过一遍,需要的时候更容易想起来。 PDF 导出是另一条线。以前用 VS Code / Cursor 的 Preview 在浏览器里打开再打印 PDF,软件更新后这条路走不通了。跟 AI 聊了几轮,第一次正经用排版工具链:Markdown 经 Pandoc + XeLaTeX 出 PDF,定制了 LaTeX 模板和一键脚本。流程稳定后另写了一篇技术记录:Markdown to PDF: Pandoc + XeLaTeX 简历导出实践。 看职位描述时还记下一个概念 Speed over Perfection,顺手写进了 agile 笔记。 梳理 Java 文档 简历主体定稿后,重心转到 blog 里攒了很久的 Java 笔记。这次投的是 Java 方向,正好借机把零散文章理顺:拆大篇、补版本脉络、把 JVM 和 HotSpot 分开写。日历上这几天和简历收尾有重叠,但主线已经换成「整理文档」。 ...

Created 21216-06-21 · Updated 23236-06-23 · 1 min · 149 words · -

OpenJDK JDK 发行版:Temurin、Corretto、Dragonwell

OpenJDK 与「发行版」 OpenJDK 是 Java 平台的开源参考实现(源码项目)。日常 java -version 看到的并不是「裸 OpenJDK 源码」,而是各厂商/社区基于该源码(或与之同步的分支)构建、测试、打包后的 JDK 发行版(distribution)。 多数发行版默认捆绑 HotSpot 虚拟机,因此 Temurin、Corretto、Dragonwell 之间换的是供应商、构建渠道与支持策略,不是换一套 JVM 实现。JVM 实现层选型见 Java 虚拟机。 OpenJDK 源码(openjdk/jdk) │ ├── 各发行版构建 + TCK / 内部 QA │ ▼ Temurin / Corretto / Dragonwell / Oracle JDK … │ └── 默认内含 HotSpot(Semeru 等除外,见下文) 常见发行版对照 发行版 维护方 许可 / 费用 典型特点 Eclipse Temurin Eclipse Adoptium 免费(GPLv2 + Classpath) AdoptOpenJDK 继任;通过 Java SE TCK;无特殊理由时的默认推荐 Amazon Corretto Amazon 免费 AWS 生态常用;长期支持声明;Corretto 补丁分支 Dragonwell(含 Alibaba Dragonwell) 阿里云 免费 面向国内与大促场景优化;部分版本含 Wisp 协程、增强 GC 等 Alibaba 扩展 Oracle JDK Oracle 免费(个人/开发等,见 Oracle 许可 FAQ)/ 商业订阅 Oracle 官方构建;与 OpenJDK 功能同步策略见 Oracle 文档 Microsoft Build of OpenJDK Microsoft 免费 Azure / Windows / GitHub Actions 场景常见 Red Hat Build of OpenJDK Red Hat 免费 / 随 RHEL 订阅支持 OpenShift、RHEL 企业环境 Azul Platform Core(Zulu 等) Azul 免费构建 + 商业支持 多版本、多平台;企业 SLA IBM Semeru IBM 免费 / 商业 OpenJ9 虚拟机,不是 HotSpot;见 jvm.md Linux 发行版自带的 openjdk-*-jdk(Debian/Ubuntu/Arch 包)也是基于 OpenJDK 源码的构建,可视为「 distro 维护的发行版」,更新节奏跟随各发行版仓库。 ...

Created 21216-06-21 · Updated 21216-06-21 · 2 min · 346 words · -

GraalVM

是什么 GraalVM 是 Oracle 主导的 高性能 JDK 发行版与工具链,基于 OpenJDK,但不止「又一个 Temurin」:它在同一产品里组合了 Java 运行时、Graal JIT 编译器、Native Image AOT、Truffle 多语言运行时 等能力。 日常讨论里常把 GraalVM 缩略成「Native Image 用的那个 JDK」,实际上 Native Image 只是其组件之一;完整图景见下文与 Java 虚拟机 生态对照。 发行版 版本 说明 Community Edition (CE) 开源(GPLv2 + Classpath exception),GitHub 发布 Enterprise Edition (EE) 商业支持,额外性能与工具(需 Oracle 许可) 安装后通常提供 java、javac、native-image、gu(GraalVM Updater,用于安装/管理组件)等命令。具体组件集因版本与安装方式而异。 三种常见使用方式 GraalVM 发行版 │ ┌─────────────────────┼─────────────────────┐ ▼ ▼ ▼ JVM 模式(java) Native Image Truffle / Polyglot HotSpot + Graal JIT AOT 本地二进制 JS/Python/Ruby 等同 JVM 上互操作 │ │ │ └── 见专文 └── 仍跑 .class,可替代默认 C2 路径(视版本与 -XX 开关) 1. JVM 模式:Graal 作 JIT 用 GraalVM 自带的 java 跑字节码,底层仍是 HotSpot VM,但可用 Graal 编译器 作为 JIT 替代或补充传统 C1/C2(取决于 JDK 版本与 JVM 参数;OpenJDK 曾实验性集成 Graal JIT,JDK 17+ 默认路径以 C2 为主,Graal JIT 需显式启用或视发行版而定)。 ...

Created 21216-06-21 · Updated 21216-06-21 · 2 min · 341 words · -

Java 模块系统:JPMS 与 Jigsaw

Java 9 之前的版本 .class 文件是 JVM 看到的最小可执行文件,而一个大型程序需要编写很多 Class,并生成一堆 .class 文件,不便于管理,所以,jar 文件就是 class 文件的容器。 在 Java 9 之前,一个大型 Java 程序会生成自己的 jar 文件,同时引用依赖的第三方 jar 文件,而 JVM 自带的 Java 标准库,实际上也是以 jar 文件形式存放的,这个文件叫 rt.jar,一共有 60 多 M。 如果是自己开发的程序,除了一个自己的 app.jar 以外,还需要一堆第三方的 jar 包,运行一个 Java 程序,一般来说,命令行写这样: java -cp app.jar:a.jar:b.jar:c.jar com.liaoxuefeng.sample.Main jar 只是用于存放 class 的容器,它并不关心 class 之间的依赖。 从 Java 9 开始,原有的 Java 标准库已经由一个单一巨大的 rt.jar 分拆成了几十个模块,这些模块以 .jmod 扩展名标识,可以在 $JAVA_HOME/jmods 目录下找到它们: java.base.jmod java.compiler.jmod java.datatransfer.jmod java.desktop.jmod ... 这些 .jmod 文件每一个都是一个 JDK 模块,模块名就是文件名去掉 .jmod 后缀(例如 java.base.jmod → 模块 java.base)。 ...

Created 8086-03-08 · Updated 21216-06-21 · 5 min · 1003 words · -

java 反射, reflect

java 反射, reflect http://www.iteye.com/topic/137944 什么是反射 反射的概念是由 Smith 在 1982 年首次提出的,主要是指程序可以访问、检测和修改它本身状态或行为的一种能力。这一概念的提出很快引发了计算机科学领域关于应用反射性的研究。它首先被程序语言的设计领域所采用, 并在 Lisp 和面向对象方面取得了成绩。其中 LEAD/LEAD++ 、OpenC++ 、MetaXa 和 OpenJava 等就是基于反射机制的语言。最近,反射机制也被应用到了视窗系统、操作系统和文件系统中。 反射本身并不是一个新概念,尽管计算机科学赋予了反射概念新的含义。在计算机科学领域,反射是指一类应用,它们能够自描述和自控制。也就是说,这类应用通过采用某种机制来实现对自己行为的描述 (self-representation) 和监测 (examination) ,并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义。 什么是Java中的类反射 Reflection 是 Java 程序开发语言的特征之一,它允许运行中的 Java 程序对自身进行检查,或者说"自审",并能直接操作程序的内部属性和方法。Java 的这一能力在实际应用中用得不是很多,但是在其它的程序设计语言中根本就不存在这一特性。例如,Pascal、C 或者 C++ 中就没有办法在程序中获得函数定义相关的信息。 Reflection 是 Java 被视为动态 (或准动态) 语言的关键,允许程序于执行期 Reflection APIs 取得任何已知名称之 class 的內部信息,包括 package、type parameters、superclass、implemented interfaces、inner classes, outer class, fields、constructors、methods、modifiers,並可于执行期生成instances、变更 fields 內容或唤起 methods。 Java类反射中所必须的类 Java的类反射所需要的类并不多,它们分别是: Field、Constructor、Method、Class、Object,下面我将对这些类做一个简单的说明。 Field类: 提供有关类或接口的属性的信息,以及对它的动态访问权限。反射的字段可能是一个类 (静态) 属性或实例属性,简单的理解可以把它看成一个封装反射类的属性的类。 Constructor类: 提供关于类的单个构造方法的信息以及对它的访问权限。这个类和Field类不同,Field类封装了反射类的属性,而Constructor类则封装了反射类的构造方法。 Method类: 提供关于类或接口上单独某个方法的信息。所反映的方法可能是类方法或实例方法 (包括抽象方法) 。 这个类不难理解,它是用来封装反射类方法的一个类。 ...

Created 9096-09-09 · Updated 21216-06-21 · 5 min · 947 words · -

通过java反射机制获取该类的所有属性类型、值、

通过反射遍历对象字段的示例。object.getClass() 返回该实例类型的 Class 对象;反射 API 总览见 Java 反射机制。 通过java反射机制获取该类的所有属性类型、值 http://blog.csdn.net/sd4000784/article/details/7448221 方法使用了这俩个包下的 field 和method import Java.lang.reflect.Field; import java.lang.reflect.Method; public static void getObjectValue(Object object) throws Exception { //我们项目的所有实体类都继承BaseDomain (所有实体基类: 该类只是串行化一下) //不需要的自己去掉即可 if (object != null && object instanceof BaseDomain) {//if (object!=null ) --begin // 拿到该类 Class<?> clz = object.getClass(); // 获取实体类的所有属性,返回Field数组 Field[] fields = clz.getDeclaredFields(); for (Field field : fields) {// -for() begin System.out.println(field.getGenericType());//打印该类的所有属性类型 // 如果类型是String if (field.getGenericType().toString().equals( "class java.lang.String")) { // 如果type是类类型,则前面包含"class ",后面跟类名 // 拿到该属性的gettet方法 /** * 这里需要说明一下: 他是根据拼凑的字符来找你写的getter方法的 * 在Boolean值的时候是isXXX (默认使用ide生成getter的都是isXXX) * 如果出现NoSuchMethod异常 就说明它找不到那个gettet方法 需要做个规范 */ Method m = (Method) object.getClass().getMethod( "get" + getMethodName(field.getName())); String val = (String) m.invoke(object);// 调用getter方法获取属性值 if (val != null) { System.out.println("String type:" + val); } } // 如果类型是Integer if (field.getGenericType().toString().equals( "class java.lang.Integer")) { Method m = (Method) object.getClass().getMethod( "get" + getMethodName(field.getName())); Integer val = (Integer) m.invoke(object); if (val != null) { System.out.println("Integer type:" + val); } } // 如果类型是Double if (field.getGenericType().toString().equals( "class java.lang.Double")) { Method m = (Method) object.getClass().getMethod( "get" + getMethodName(field.getName())); Double val = (Double) m.invoke(object); if (val != null) { System.out.println("Double type:" + val); } } // 如果类型是Boolean 是封装类 if (field.getGenericType().toString().equals( "class java.lang.Boolean")) { Method m = (Method) object.getClass().getMethod( field.getName()); Boolean val = (Boolean) m.invoke(object); if (val != null) { System.out.println("Boolean type:" + val); } } // 如果类型是boolean 基本数据类型不一样 这里有点说名如果定义名是 isXXX的 那就全都是isXXX的 // 反射找不到getter的具体名 if (field.getGenericType().toString().equals("boolean")) { Method m = (Method) object.getClass().getMethod( field.getName()); Boolean val = (Boolean) m.invoke(object); if (val != null) { System.out.println("boolean type:" + val); } } // 如果类型是Date if (field.getGenericType().toString().equals( "class java.util.Date")) { Method m = (Method) object.getClass().getMethod( "get" + getMethodName(field.getName())); Date val = (Date) m.invoke(object); if (val != null) { System.out.println("Date type:" + val); } } // 如果类型是Short if (field.getGenericType().toString().equals( "class java.lang.Short")) { Method m = (Method) object.getClass().getMethod( "get" + getMethodName(field.getName())); Short val = (Short) m.invoke(object); if (val != null) { System.out.println("Short type:" + val); } } // 如果还需要其他的类型请自己做扩展 }//for() -end }//if (object!=null ) --end } // 把一个字符串的第一个字母大写、效率是最高的、 private static String getMethodName(String fildeName) throws Exception{ byte[] items = fildeName.getBytes(); items[0] = (byte) ((char) items[0] - 'a' + 'A'); return new String(items); }

Created 17176-09-17 · Updated 21216-06-21 · 2 min · 333 words · -

java.lang.Class类

说明 java.lang.Class 的说明已整理至专文:java.lang.Class。 本文保留 url java-class-object 以兼容旧链接。 维护记录 时间 修改内容 原因 2026-06-21 正文删去,改为指向 lang-class.md 与 Class 专文去重

Created 2026-01-02 · Updated 21216-06-21 · 1 min · 17 words · -

Java反射机制

Java反射机制 通过反射取对象的属性值 import java.lang.reflect.Field; import java.util.HashMap; import java.util.Map; public class ReflectTest { public static void main(String[] args) { Foo foo = new Foo(); foo.setBar("xxx"); Map map = new HashMap(); map.put("foo", "bar"); foo.setTags(map); Class fooClass = foo.getClass(); System.out.println("name:" + fooClass.getName()); try { Field[] fields = fooClass.getDeclaredFields(); for (Field field : fields) { field.setAccessible(true); System.out.println("field: " + field.getName()); Object obj = field.get(foo); System.out.println(obj); } Field field0 = fooClass.getDeclaredField("bar"); System.out.println(field0); } catch (Exception e) { e.printStackTrace(); } } } class Foo { private String bar; private Map<String, String> tags; public void setBar(String bar) { this.bar = bar; } public void setTags(Map tags) { this.tags = tags; } } Reflection 是Java被视为动态 (或准动态) 语言的一个关键性质。这个机制允许程序在运行时透过Reflection APIs取得任何一个已知名称的class的内部信息,包括其modifiers (诸如public, static 等等) 、superclass (例如Object) 、实现之interfaces (例如Cloneable) ,也包括fields和methods的所有信息,并可于运行时改变fields内容或唤起methods。本文借由实例,大面积示范Reflection APIs。 ...

Created 2026-01-02 · Updated 21216-06-21 · 5 min · 1008 words · -

Class.forName

Class.forName 是获取 java.lang.Class 对象的一种方式:用字符串形式的完全限定类名在运行时查找并加载类。类名来自配置、用户输入或 JDBC 驱动名等场景时,通常走这条路径。 API 形式 // 等价于 forName(name, true, 当前 ClassLoader) Class<?> clazz = Class.forName("com.example.Foo"); // 显式控制是否初始化、使用哪个 ClassLoader Class<?> clazz = Class.forName("com.example.Foo", false, classLoader); 第二个参数 initialize: true:加载后执行类初始化(静态代码块、静态字段赋值等) false:只加载并链接,暂不初始化 单参数 Class.forName(name) 相当于 initialize = true。 与 .class、getClass() 的区别 方式 类名来源 默认是否初始化 Foo.class 编译期写死 否 obj.getClass() 已有实例 否 Class.forName("Foo") 运行期字符串 是 Class 对象本身的含义、唯一性等见专文 java.lang.Class。 典型用途 JDBC 驱动加载(历史写法) 早期 JDBC 常用 Class.forName 触发驱动类静态块,向 DriverManager 注册: Class.forName("com.mysql.cj.jdbc.Driver"); Connection conn = DriverManager.getConnection(url, user, password); 驱动类静态块执行即可完成注册,一般不必再 newInstance()。现代 JDBC 4+ 驱动多通过 SPI 自动加载,此写法已较少见,但有助于理解 forName 与类初始化的关系。 ...

Created 21216-12-21 · Updated 21216-06-21 · 1 min · 127 words · -

java.lang.Class

java.lang.Class 是 JVM 为每一种 Java 类型在运行时维护的元信息对象。它不代表某个业务实例,而是代表类型本身——类、接口、枚举、注解类型、数组、基本类型乃至 void 都有对应的 Class 实例。 反射、注解 读取、框架扫描等能力,都依赖先拿到正确的 Class 对象。 Class 与实例的区别 实例对象 Class 对象 含义 某个类的具体对象 描述类型本身的元数据 示例 new SampleSubject() SampleSubject.class 数量 可创建多个实例 每种类型在 JVM 中唯一 SampleSubject a = new SampleSubject(); SampleSubject b = new SampleSubject(); a.getClass() == SampleSubject.class; // true a.getClass() == b.getClass(); // true:同一类型的 Class 只有一个 a == b; // false:实例不同 何时创建、由谁创建 Class 没有 public 构造方法,不能 new Class()。对象在类加载过程中由 JVM 通过类加载器的 defineClass 等机制创建。加载流程见 java classloader。 ...

Created 21216-06-21 · Updated 21216-06-21 · 2 min · 264 words · -

Forward 与 Redirect

forward vs redirect forward(请求转发):服务器收到请求后,在服务器内部把请求转交给另一个资源处理,再把结果返回客户端;浏览器地址栏不变,客户端不知道发生了转发。 redirect(重定向):服务器返回 3xx 状态码,浏览器再次发起新请求访问目标 URL,地址栏变为新地址;因此有两次往返,通常比 forward 开销大。 数据与作用域 forward:同一 HttpServletRequest 继续传递,request 属性、request 参数可带到目标资源;常用 request.getAttribute() 读取上一环节放入的数据。 redirect:浏览器发的是新请求,上一请求的 request 属性不会保留;URL 查询参数会随新请求带上。HttpSession 仍可通过 cookie 关联(session 级数据一般可用),但不要把「上一 request 的 attribute」误当成 redirect 后还能直接读。 效率:forward 仅在服务端处理,对客户端透明;redirect 多一次客户端往返,通常更慢。 范围:因 request.setAttribute() 的生命周期限于当前 request,redirect 会导致 attribute 丢失;需要跨 redirect 传值时,常用 session、URL 参数或 flash 等机制。 前后端分离下的表现 典型架构为 React 前端 + Spring Boot REST API。页面路由与组件组合由前端负责,后端主要返回 JSON;因此早年 JSP 时代「forward 到另一个 JSP 拼页面」的用法在业务层已基本消失,但两种机制仍以不同形式存在。 redirect:仍然常见 redirect 是 HTTP 层行为,与是否使用 JSP 无关。前后端分离项目中常见场景: OAuth / 第三方登录:授权服务器回调后,后端或网关返回 302 跳转到前端路由(如 /auth/callback) PRG(Post-Redirect-Get):表单或写操作后 return "redirect:/...",避免刷新重复提交(多见于仍保留 @Controller 的服务端表单) 文件下载、外链跳转:API 或网关返回 302 指向实际资源地址 网关 / 反向代理:未登录时重定向到登录页(也可由前端根据 401 自行跳转) 前端日常路由切换由 React Router 完成,不经过 Servlet redirect;但跨域认证、登录回调、下载等仍会碰到 HTTP 重定向。 ...

Created 21216-09-21 · Updated 21216-06-21 · 1 min · 206 words · -

Servlet 生命周期

Servlet 运行在 Servlet 容器中,生命周期由容器管理。规范通过 Servlet 接口的 init()、service()、destroy() 描述这一过程;Java EE 8 及以前包名为 javax.servlet.*,Spring Boot 3 起对应 Jakarta Servlet(jakarta.servlet.*),语义不变。 四个阶段 加载和实例化 Servlet 容器负责加载和实例化 Servlet。容器启动时,或在首次需要该 Servlet 处理请求时,创建实例。容器通过类加载器找到 Servlet 类,再用反射调用无参构造方法实例化,因此业务 Servlet 一般不应定义带参构造方法。 初始化 实例化后,容器调用 init() 做一次性初始化(如读取配置、建立连接)。每个 Servlet 实例的 init() 只执行一次。初始化期间可通过 ServletConfig 读取配置(传统项目多在 web.xml,Spring Boot 中常由框架代劳)。失败时可抛出 ServletException 或 UnavailableException 通知容器。 请求处理 请求到达后,容器调用 service();HttpServlet 会按 HTTP 方法分派到 doGet()、doPost() 等。service() 执行前 init() 必须已成功完成。处理中通过 ServletRequest / ServletResponse(或 HttpServletRequest / HttpServletResponse)读写请求与响应。若抛出表示永久不可用的 UnavailableException,容器会调用 destroy() 并返回 404;暂时不可用则返回 503。 服务终止 容器卸载 Servlet 或关闭时调用 destroy(),释放资源。之后实例被回收;若再次需要,容器会创建新实例。 ...

Created 30306-10-30 · Updated 21216-06-21 · 2 min · 227 words · -

Java Bean

Java Bean 一、 javabean 是什么? Bean的中文含义是"豆子",顾名思义,JavaBean是指一段特殊的Java类, 就是有默然构造方法,只有get,set的方法的java类的对象. 最初,JavaBean的目的是为了将可以重复使用的软件代码打包标准。特别是用与帮助厂家开发在IDE下使用的java软件部件。这些包括如Grid控件,用户可以将该部件拖放到开发环境中。从此,JavaBean就可以扩展为一个 java web 应用的标准部件。 专业点解释是: JavaBean定义了一组规则 JavaBean就是遵循此规则的平常的Java对象 满足这三个条件: 1.执行java.io.Serializable 接口 2.提供无参数的构造器 3.提供getter 和 setter方法访问它的属性. 简单地说,JavaBean是用Java语言描述的软件组件模型,其实际上是一个类。这些类遵循一个接口格式,以便于使函数命名、底层行为以及继承或实现的行为,可以把类看作标准的JavaBean组件进行构造和应用。 JavaBean一般分为可视化组件和非可视化组件两种。可视化组件可以是简单的GUI元素,如按钮或文本框,也可以是复杂的,如报表组件;非可视化组件没有GUI表现形式,用于封装业务逻辑、数据库操作等。其最大的优点在于可以实现代码的可重用性。JavaBean又同时具有以下特性。 易于维护、使用、编写。 可实现代码的重用性。 可移植性强,但仅限于Java工作平台。 便于传输,不限于本地还是网络。 可以以其他部件的模式进行工作。 对于有过其他语言编程经验的读者,可以将其看作类似微软的ActiveX的编程组件。但是区别在于JavaBean是跨平台的,而ActiveX组件则仅局限于Windows系统。总之,JavaBean比较适合于那些需要跨平台的、并具有可视化操作和定制特性的软件组件。 2 使用JavaBean的原因 程序中往往有重复使用的段落,JavaBean就是为了能够重复使用而设计的程序段落,而且这些段落并不只服务于某一个程序,而且每个JavaBean都具有特定功能,当需要这个功能的时候就可以调用相应的JavaBean。从这个意义上来讲,JavaBean大大简化了程序的设计过程,也方便了其他程序的重复使用。 JavaBean传统应用于可视化领域,如AWT (窗口工具集) 下的应用。而现在,JavaBean更多地应用于非可视化领域,同时,JavaBean在服务器端的应用也表现出强大的优势。非可视化的JavaBean可以很好地实现业务逻辑、控制逻辑和显示页面的分离,现在多用于后台处理,使得系统具有更好的健壮性和灵活性。JSP + JavaBean和JSP + JavaBean + Servlet成为当前开发Web应用的主流模式。 3 JavaBean的开发 在程序设计的过程中,JavaBean不是独立的。为了能够更好地封装事务逻辑、数据库操作而便于实现业务逻辑和前台程序的分离,操作的过程往往是先开发需要的JavaBean,再在适当的时候进行调用。但一个完整有效的JavaBean必然会包含一个属性,伴随若干个get/set (只读/只写) 函数的变量来设计和运行的。JavaBean作为一个特殊的类,具有自己独有的特性。应该注意以下3个方面。 JavaBean类必须有一个没有参数的构造函数。 JavaBean类所有的属性最好定义为私有的。 JavaBean类中定义函数setXxx() 和getXxx()来对属性进行操作。其中Xxx是首字母大写的私有变量名称。 维护记录 时间 修改内容 原因 2026-06-20 补充 EJB 与 JavaBean 面试速记 承接自 java-basic 移出的 JavaEE 段落 2026-06-20 删除 EJB 与 JavaBean 对比及相关段落 EJB 已边缘化,与 JavaBean 专题无关

Created 16166-10-16 · Updated 20206-06-20 · 1 min · 75 words · -