Fastjson2 是阿里巴巴开源的一个高性能、功能丰富的 JSON 解析和生成库,是原有 Fastjson 的升级版。相比于 Fastjson1,Fastjson2 在性能、安全性、可扩展性等方面进行了全面优化和改进,以满足现代 Java 应用对高效数据处理的需求。
核心优势 ------ fast
天下武功,唯快不破,Fastjson2 正如其名称暗示的,在序列化、反序列化时候相对其它库有明显性能优势。在最常用的将 JSON 格式字符串反序列化为 Java 对象场景 Fastjson2 的性能差不多是jackson/gson 的 3~4 倍
- fastjson1 只相当于只相当于 Fastjson2 的 54.2%
- jackson 则只相当于Fastjson2 的 26.74%
- gson 是 Fastjson2 的 27.09%
plain
// aliyun.c8i.large jdk-11.0.19
fastjson2 > fastjson1 > jackson > gson
jdk8 100% 69.63% 34.43% 31.42%
jdk11 100% 54.20% 26.74% 27.09%
jdk17 100% 66.08% 25.64% 25.66%
详细测试数据:github.com/alibaba/fas...
在项目中使用 Fastjson2
添加 maven 依赖
xml
<dependency>
<groupId></groupId>
<artifactId>fastjson2</artifactId>
<version>2.0.51</version>
</dependency>
定义一个 Java Bean
java
public class User {
private Long id;
private String name;
private String email;
// 构造函数
public User() {}
public User(Long id, String name, String email) {
this.id = id;
this.name = name;
this.email = email;
}
// Getter 和 Setter
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
// toString 方法
@Override
public String toString() {
return "User{id=" + id + ", name='" + name + "', email='" + email + "'}";
}
}
序列化 Java 对象为 JSON
java
import com.alibaba.fastjson2.JSON;
public class SerializeExample {
public static void main(String[] args) {
User user = new User(1L, "Alice", "alice@example.com");
String jsonString = JSON.toJSONString(user);
System.out.println("Serialized JSON:");
System.out.println(jsonString);
}
}
输出
plain
Serialized JSON:
{"id":1,"name":"Alice","email":"alice@example.com"}
反序列化 JSON 为 Java 对象
java
import com.alibaba.fastjson2.JSON;
public class DeserializeExample {
public static void main(String[] args) {
String jsonString = "{"id":1,"name":"Alice","email":"alice@example.com"}";
User user = JSON.parseObject(jsonString, User.class);
System.out.println("Deserialized Object:");
System.out.println(user);
}
}
输出
plain
Deserialized Object:
User{id=1, name='Alice', email='alice@example.com'}
高级用法
Fastjson2 提供了多种高级功能
自定义序列化和反序列化
通过实现 ObjectWriter
和 ObjectReader
接口,可以自定义序列化和反序列化逻辑
java
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.writer.ObjectWriter;
import com.alibaba.fastjson2.writer.ObjectWriterCreator;
import com.alibaba.fastjson2.writer.ObjectWriterFactory;
import com.alibaba.fastjson2.writer.WriterFeature;
public class CustomSerializeExample {
public static void main(String[] args) {
User user = new User(2L, "Bob", "bob@example.com");
ObjectWriter<User> objectWriter = JSON.writerFor(User.class);
String jsonString = JSON.toJSONString(user, objectWriter, WriterFeature.PrettyFormat);
System.out.println("Custom Serialized JSON:");
System.out.println(jsonString);
}
}
输出
plain
Custom Serialized JSON:
{
"id": 2,
"name": "Bob",
"email": "bob@example.com"
}
使用注解控制序列化行为
Fastjson2 支持通过注解来控制序列化和反序列化的行为,例如 @JSONField
注解。
java
import com.alibaba.fastjson2.annotation.JSONField;
public class User {
private Long id;
@JSONField(name = "username")
private String name;
private String email;
// 构造函数、Getter、Setter和toString方法同上
}
序列化后的 JSON:
plain
{"id":3,"username":"Charlie","email":"charlie@example.com"}
处理集合和泛型
Fastjson2 可以高效地处理集合类型和带有泛型的类
java
import com.alibaba.fastjson2.JSON;
import java.util.List;
import java.util.ArrayList;
public class CollectionExample {
public static void main(String[] args) {
List<User> users = new ArrayList<>();
users.add(new User(1L, "Alice", "alice@example.com"));
users.add(new User(2L, "Bob", "bob@example.com"));
String jsonString = JSON.toJSONString(users);
System.out.println("Serialized List:");
System.out.println(jsonString);
List<User> deserializedUsers = JSON.parseArray(jsonString, User.class);
System.out.println("Deserialized List:");
deserializedUsers.forEach(System.out::println);
}
}
输出:
plain
Serialized List:
[{"id":1,"name":"Alice","email":"alice@example.com"},{"id":2,"name":"Bob","email":"bob@example.com"}]
Deserialized List:
User{id=1, name='Alice', email='alice@example.com'}
User{id=2, name='Bob', email='bob@example.com'}
使用流式 API 进行大数据处理
Fastjson2 支持流式 API,可以高效地处理大规模 JSON 数据,减少内存消耗。
java
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONReader;
import java.io.FileReader;
import java.io.IOException;
public class StreamingExample {
public static void main(String[] args) throws IOException {
try (JSONReader reader = JSON.createReader(new FileReader("users_large.json"))) {
reader.startArray();
while (reader.hasNext()) {
User user = reader.readObject(User.class);
// 处理每个用户对象
System.out.println(user);
}
reader.endArray();
}
}
}
JSONB 支持
JSONB(Binary JSON)是一种二进制格式的 JSON 数据表示方式。与传统的文本格式 JSON 相比,JSONB 格式有几个优势:
- 更高的解析速度:二进制格式减少了解析过程中的字符转换,提高了解析效率。
- 更小的数据体积:通过压缩和优化存储结构,JSONB 通常比同等的文本 JSON 更小。
- 更高的查询效率:适用于需要频繁查询和处理大规模 JSON 数据的场景。
JSON 插入速度快、查询速度慢,是因为处理函数必须在每次执行时重新解析该数据。JSONB 插入速度慢、查询速度快,原因是 JSONB 数据被存储在一种分解好的二进制格式中,因为需要做附加的转换,它在输入时要稍慢一些。但因为不需要重新解析,JSONB 在查询数据时快很多
java
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONB;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
public class SerializeToJSONBExample {
public static void main(String[] args) throws IOException {
User user = new User(1L, "Alice", "alice@example.com");
// 将对象序列化为 JSONB 字节数组
byte[] jsonbBytes = JSONB.toBytes(user);
// 将 JSONB 写入文件
Files.write(Paths.get("user.jsonb"), jsonbBytes);
System.out.println("Serialized JSONB:");
for(byte b : jsonbBytes){
System.out.printf("0x%02X ", b);
}
}
}
输出:
plain
Serialized JSONB:
0x5B 0x00 0x00 0x00 0x02 0x00 0x00 0x00 0x01 0x02 0x00 0x00 0x00 0x05 0x69 0x64 0xFFFF 0x00 0x00 0x00 0x08 0x41 0x6C 0x69 0x63 0x65 0x00 0x00 0x13 0x61 0x6C 0x69 0x63 0x65 0x40 0x65 0x78 0x61 0x6D 0x70 0x6C 0x65 0x2E 0x63 0x6F 0x6D
反序列化 JSONB 为 Java 对象
java
import com.alibaba.fastjson2.JSONB;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
public class DeserializeFromJSONBExample {
public static void main(String[] args) throws IOException {
// 读取 JSONB 字节数组
byte[] jsonbBytes = Files.readAllBytes(Paths.get("user.jsonb"));
// 将 JSONB 字节数组反序列化为 User 对象
User user = JSONB.parseObject(jsonbBytes, User.class);
System.out.println("Deserialized User Object:");
System.out.println(user);
}
}
输出:
plain
Deserialized User Object:
User{id=1, name='Alice', email='alice@example.com'}
JSONPath 支持
JSONPath 是一种用于从 JSON 数据中提取数据的查询语言,类似于 XPath 用于 XML。通过 JSONPath 可以使用表达式来轻松访问和解析 JSON 文档中的数据,从而实现复杂的数据查询和过滤。
java
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONPath;
public class JSONPathExample {
public static void main(String[] args) {
String json = """
{
"store": {
"book": [
{ "category": "reference", "author": "Nigel Rees", "title": "Sayings of the Century", "price": 8.95 },
{ "category": "fiction", "author": "Evelyn Waugh", "title": "Sword of Honour", "price": 12.99 },
{ "category": "fiction", "author": "Herman Melville", "title": "Moby Dick", "price": 8.99 }
],
"bicycle": { "color": "red", "price": 19.95 }
}
}
""";
Object document = JSON.parse(json);
// 提取所有书籍的价格
Object prices = JSONPath.eval(document, "$.store.book[*].price");
System.out.println(prices); // 输出: [8.95, 12.99, 8.99]
}
}
Java 13 引入了文本块(Text Blocks)功能,这使得编写多行字符串变得更加简单。可以用三个双引号 """
来定义多行字符串,这样可以避免在每一行末尾添加 +
号,并且可以更好地维护和阅读长字符串。
安全控制
随着 Fastjson 的流行,暴露出一些安全性和扩展性的问题。Fastjson2 致力于在保持高性能的同时,通过多项措施增强了库的安全防护能力
- Fastjson 默认启用了自动类型解析,这导致了多个严重的安全漏洞。而 Fastjson2 默认关闭了自动类型解析,避免了潜在的安全风险。开发者需要显式地启用此功能并严格控制允许的类型。
- 在需要启用自动类型解析的情况下,Fastjson2 提供了白名单机制,仅允许指定的类进行反序列化。通过设置白名单,开发者可以限制反序列化过程中的可控类,防止恶意代码执行。
- Fastjson2 强化了对输入 JSON 数据的验证,避免恶意构造的数据导致反序列化漏洞。通过严格的语法检查和类型验证,减少了潜在的安全隐患。
- Fastjson2 提供了多种安全配置选项,允许开发者根据具体需求灵活调整库的行为
为了最大限度地利用 Fastjson2 的安全特性,开发者应遵循以下最佳实践:
1. 禁用自动类型解析,除非必要
默认情况下,Fastjson2 已禁用自动类型解析,开发者应保持这一配置,只有在确实需要反序列化特定类型时,才启用并严格控制允许的类型。
java
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.parser.ParserConfig;
public class Fastjson2SecurityConfig {
public static void main(String[] args) {
String jsonString = "{"id":1,"name":"Alice","email":"alice@example.com"}";
// 默认情况下,自动类型解析是关闭的
User user = JSON.parseObject(jsonString, User.class);
System.out.println(user);
}
}
2. 配置白名单机制
在需要启用自动类型解析的情况下,务必配置白名单,仅允许可信的类进行反序列化。
java
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.parser.ParserConfig;
public class Fastjson2WhitelistExample {
public static void main(String[] args) {
// 配置 ParserConfig 并设置白名单
ParserConfig parserConfig = ParserConfig.getGlobalInstance();
parserConfig.addAccept("com.example.model."); // 仅允许反序列化指定包下的类
String jsonString = "{"@type":"com.example.model.User","id":2,"name":"Bob","email":"bob@example.com"}";
User user = JSON.parseObject(jsonString, User.class, parserConfig);
System.out.println(user);
}
}
3. 严格输入数据的验证和清洗
在反序列化之前,对输入的 JSON 数据进行严格的验证和清洗,确保数据的合法性和安全性。
java
public boolean isValidJson(String json) {
try {
JSON.parse(json);
return true;
} catch (JSONException e) {
return false;
}
}
if (isValidJson(inputJson)) {
User user = JSON.parseObject(inputJson, User.class);
// 处理用户对象
} else {
// 处理无效的 JSON 数据
}
4. 限制反序列化的类和包
通过严格配置反序列化的类和包,防止未经授权的类被反序列化,降低安全风险。
java
ParserConfig parserConfig = new ParserConfig();
parserConfig.addAccept("com.company.project.model.");
String jsonString = "{"@type":"com.company.project.model.User","id":10,"name":"Jane","email":"jane@example.com"}";
User user = JSON.parseObject(jsonString, User.class, parserConfig);
System.out.println(user);
通过以上措施,可以在享受 Fastjson2 高性能和丰富功能的同时,确保应用程序的数据处理过程安全可靠,防范潜在的安全威胁和攻击。