gRPC连接没关干净导致的资源泄漏:从日志到修复的复盘
线上遇到“Channel was garbage collected without being shut down”的错误,梳理了ManagedChannel关闭机制和常见踩坑点,给出实际可用的修复方式。
支持通配符SSL证书、多域名证书、IP证书。适配ACME接口, 支持Zerossl、Let's Encrypt和Google等渠道。登录已有账号
2026-10-03 10:15:44 Hutool Java JSON JSONObject 实战
做Java开发的基本绕不开JSON。接口返回的、消息队列里消费到的、前端post上来的,到处都是一堆JSON要往Java对象里塞。
Hutool的JSONUtil.toBean()算是我用得比较顺的一招,今天把这套流程从头到尾拆开,依赖、实体、工具封装、能直接跑的示例都有,中间那些容易翻车的点也一并记下来。
先看依赖。pom里加上Hutool和Lombok就行,版本挑个稳定的,真有需要再往上升,不用追新。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>hutool-json-demo</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.25</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.30</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>3.1.0</version>
<configuration>
<mainClass>com.example.Main</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</project>
实体类用@Data,getter/setter不用手写,省不少事。
User里嵌了一个Address,就是典型的嵌套JSON。这种结构在真实项目里太常见了,用户下面挂地址、订单下面挂商品信息,都是这么分层挂的。
package com.example;
import lombok.Data;
@Data
public class User {
private String username;
private Integer age;
private String gender;
private Address address;
}
@Data
class Address {
private String city;
private String street;
}
这里有个坑必须先说清楚。实体类必须保留无参构造函数。
我最早以为@Data就够用了,结果嵌套对象转出来直接是null,排查了半天才发现是被自己重载的构造器坑了。JSONUtil转嵌套对象时是new一个空对象再往里面set,没有无参构造器它会静默跳过,不报错,特别隐蔽,线上多半是弹出来的。
工具类我习惯单独抽一个JsonUtils,把JSON字符串和JSONObject两种入口都包一遍,业务代码里调着干净,以后别的地方也能复用,不用每次裸调toBean。
package com.example;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
public class JsonUtils {
public static <T> T jsonToObject(String jsonStr, Class<T> clazz) {
return JSONUtil.toBean(jsonStr, clazz);
}
public static <T> T jsonObjectToObject(JSONObject jsonObj, Class<T> clazz) {
return JSONUtil.toBean(jsonObj, clazz);
}
}
演示就两条路。一种直接拿JSON字符串转对象,另一种先构造JSONObject再转,跑出来的都是User,address也会跟着带出来。
package com.example;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
public class Main {
public static void main(String[] args) {
String jsonStr = "{\"username\":\"张三\",\"age\":25,\"gender\":\"男\",\"address\":{\"city\":\"北京\",\"street\":\"中关村\"}}";
User user1 = JsonUtils.jsonToObject(jsonStr, User.class);
System.out.println("JSON字符串转对象结果:");
System.out.println(user1);
JSONObject jsonObj = JSONUtil.createObj()
.set("username", "李四")
.set("age", 30)
.set("gender", "女")
.set("address", JSONUtil.createObj()
.set("city", "上海")
.set("street", "陆家嘴"));
User user2 = JsonUtils.jsonObjectToObject(jsonObj, User.class);
System.out.println("\nJSONObject转对象结果:");
System.out.println(user2);
}
}
说真的,用多了最烦的还是字段对不上。JSON里的键和目标类属性名必须一模一样,大小写都不能差。我在线上踩过一次,上游把userId悄悄改成了user_id,本地样例没测出来,一上线接口全是null字段,排查起来相当费劲。
这种字段改动的约定,最好是文档里先同步过再动代码。
字段类型也别忽略。JSON里是"25"这种字符串数字,要转Integer就可能出问题,Hutool内部有类型校验,报错还算友好。真碰上脏数据,先去源头把JSON改干净,比在转换这层硬兜要省心。
这套东西基本能覆盖日常八成场景了。要是服务要长期跑HTTPS把传输链路加密起来,顺便提一嘴,现在有lcjmSSL这类免费申请SSL证书的平台,支持多域名、泛域名和IP证书,申请、验证、部署都能自动跑,还提供API可以接进自己的发布流程,全自动续期基本不用人管,底层走的是Let's Encrypt、Google Trust Services这些可信CA。对Java服务组件的HTTPS发布来说,挺省心的一步到位。
线上遇到“Channel was garbage collected without being shut down”的错误,梳理了ManagedChannel关闭机制和常见踩坑点,给出实际可用的修复方式。
从异常信息到排查思路,梳理 Java 数组越界的常见原因和处理方式,附带一段边界检查的写法。
用正则去匹配 JSON 嵌套结构很容易踩坑,JS 自带的 JSON.parse 加 try catch 才是稳妥方案。
记录 datetime 字段定义、插入、格式化查询以及 Java 端类型映射、时区等问题,避免线上踩坑。
拥抱Java 8及更高版本带来的日期处理革新!本文聚焦于yyyy-MM-dd格式化,详细对比传统SimpleDateFormat与现代DateTimeFormatter。深入探讨DateTimeFormatter为何成为未来主流,其不可变性、线程安全等核心优势如何助你构建更健壮、高效的应用。是时候升级你的日期格式化方式了!