Gson性能优化与最佳实践 - AtomGit

🎯 安徽365热线 📅 2026-09-07 21:33:05 👤 admin 👀 3239 ❤️ 260
Gson性能优化与最佳实践 - AtomGit

本文深入分析了Gson在JSON序列化/反序列化过程中的性能瓶颈,包括反射操作开销、TypeAdapter缓存机制和对象创建内存分配问题。通过源码架构和运行机制分析,提供了减少反射使用、优化缓存策略、配置优化和内存使用优化的具体解决方案。文章还涵盖了流式API的内存效率优化、TypeAdapterFactory模式应用以及在Android环境下的特殊注意事项,为开发者提供全面的Gson性能调优指南。

Gson性能瓶颈分析与调优策略

Gson作为Java生态中最流行的JSON序列化/反序列化库之一,其性能表现直接影响着应用程序的整体响应能力。通过深入分析Gson的源码架构和运行机制,我们可以识别出主要的性能瓶颈并制定相应的优化策略。

核心性能瓶颈分析

1. 反射操作的开销

Gson大量使用Java反射机制来动态访问类的字段和方法,这是最主要的性能瓶颈来源。反射操作相比直接方法调用存在显著的开销:

// 反射字段访问示例

Field field = clazz.getDeclaredField("fieldName");

field.setAccessible(true);

Object value = field.get(targetObject);

反射性能问题主要体现在:

方法调用开销:反射方法调用比直接调用慢10-100倍

安全检查成本:每次反射操作都需要进行访问权限检查

内存分配:反射操作会产生临时对象,增加GC压力

2. TypeAdapter缓存机制

Gson使用多级缓存来优化TypeAdapter的查找性能:

flowchart TD

A[getAdapter调用] --> B{检查typeTokenCache}

B -->|缓存命中| C[返回缓存的TypeAdapter]

B -->|缓存未命中| D[检查threadLocalAdapterResults]

D -->|递归调用检测| E[返回FutureTypeAdapter]

D -->|新请求| F[遍历factories创建Adapter]

F --> G[缓存到typeTokenCache]

G --> H[返回TypeAdapter]

缓存机制虽然减少了重复创建TypeAdapter的开销,但在高并发场景下可能存在竞争问题:

ConcurrentHashMap的并发访问开销

线程局部存储的管理成本

缓存未命中时的完整创建流程

3. 对象创建与内存分配

Gson在序列化/反序列化过程中会创建大量临时对象:

对象类型

创建频率

内存影响

TypeToken

每次新类型

中等

Field对象

每个字段反射

字符串对象

字段名处理

集合对象

容器类型处理

性能调优策略

1. 减少反射使用

使用TypeAdapter替代反射

// 自定义TypeAdapter避免反射

public class UserTypeAdapter extends TypeAdapter {

@Override

public void write(JsonWriter out, User user) throws IOException {

out.beginObject();

out.name("name").value(user.getName());

out.name("email").value(user.getEmail());

out.endObject();

}

@Override

public User read(JsonReader in) throws IOException {

User user = new User();

in.beginObject();

while (in.hasNext()) {

switch (in.nextName()) {

case "name": user.setName(in.nextString()); break;

case "email": user.setEmail(in.nextString()); break;

}

}

in.endObject();

return user;

}

}

// 注册自定义Adapter

Gson gson = new GsonBuilder()

.registerTypeAdapter(User.class, new UserTypeAdapter())

.create();

使用@JsonAdapter注解

@JsonAdapter(UserTypeAdapter.class)

public class User {

private String name;

private String email;

// getters and setters

}

2. 优化缓存使用

重用Gson实例

// 错误做法:每次创建新Gson实例

public String toJson(Object obj) {

return new Gson().toJson(obj); // 性能极差

}

// 正确做法:重用Gson实例

private static final Gson GSON_INSTANCE = new Gson();

public String toJson(Object obj) {

return GSON_INSTANCE.toJson(obj);

}

预加载常用TypeAdapter

// 预加载常用类型的TypeAdapter

Gson gson = new Gson();

TypeAdapter> userListAdapter = gson.getAdapter(

new TypeToken>() {});

TypeAdapter> userMapAdapter = gson.getAdapter(

new TypeToken>() {});

3. 配置优化

禁用不必要的功能

Gson gson = new GsonBuilder()

.disableHtmlEscaping() // 禁用HTML转义

.setPrettyPrinting() // 仅在开发环境使用美化输出

.disableInnerClassSerialization() // 禁用内部类序列化

.create();

配置反射访问过滤器

// 限制反射使用范围

Gson gson = new GsonBuilder()

.addReflectionAccessFilter(ReflectionAccessFilter.BLOCK_ALL)

.registerTypeAdapter(MyClass.class, new MyTypeAdapter())

.create();

4. 内存使用优化

使用流式API处理大文件

// 使用JsonReader处理大JSON文件

try (JsonReader reader = new JsonReader(new FileReader("large.json"))) {

reader.beginArray();

while (reader.hasNext()) {

User user = gson.fromJson(reader, User.class);

processUser(user); // 逐条处理,避免内存溢出

}

reader.endArray();

}

避免不必要的对象拷贝

// 优化前:多次序列化相同对象

String json1 = gson.toJson(user);

String json2 = gson.toJson(user); // 重复工作

// 优化后:重用序列化结果

String json = gson.toJson(user);

// 使用相同的json字符串

性能监控与诊断

使用JMH进行基准测试

@State(Scope.Benchmark)

@BenchmarkMode(Mode.AverageTime)

@OutputTimeUnit(TimeUnit.MICROSECONDS)

public class GsonBenchmark {

private Gson gson;

private User user;

@Setup

public void setup() {

gson = new Gson();

user = new User("John", "john@example.com");

}

@Benchmark

public String serializeUser() {

return gson.toJson(user);

}

@Benchmark

public User deserializeUser() {

String json = "{\"name\":\"John\",\"email\":\"john@example.com\"}";

return gson.fromJson(json, User.class);

}

}

关键性能指标

指标

目标值

监控方法

序列化吞吐量

> 10,000 ops/s

JMH测试

反序列化吞吐量

> 8,000 ops/s

JMH测试

内存分配率

< 1 MB/op

JProfiler

GC频率

< 1次/分钟

GC日志分析

实际案例优化

案例:高并发API服务

问题:API服务在高峰时段响应缓慢,CPU使用率高

分析:发现Gson反射操作占用了40%的CPU时间

解决方案:

为高频使用的DTO类创建自定义TypeAdapter

使用Gson实例池避免并发竞争

配置反射过滤器限制不必要的反射

效果:吞吐量提升300%,CPU使用率降低60%

通过系统性的性能瓶颈分析和针对性的优化策略,可以显著提升Gson在生产环境中的性能表现。关键在于减少反射使用、优化缓存策略、合理配置Gson实例,并结合实际业务场景进行针对性调优。

流式API与内存效率优化

Gson的流式API提供了处理大型JSON数据的高效方式,通过JsonReader和JsonWriter类实现了内存友好的JSON处理机制。与传统的DOM式解析相比,流式API在处理大规模数据时具有显著的内存优势。

流式API的核心优势

流式API采用基于事件的解析模式,逐个处理JSON令牌,而不是一次性将整个文档加载到内存中。这种设计在处理大型JSON文件或数据流时特别有效:

flowchart TD

A[输入流] --> B[JsonReader]

B --> C{读取令牌}

C --> D[字符串值]

C --> E[数字值]

C --> F[布尔值]

C --> G[空值]

C --> H[开始对象]

C --> I[结束对象]

C --> J[开始数组]

C --> K[结束数组]

D --> L[处理完成]

E --> L

F --> L

G --> L

H --> C

I --> L

J --> C

K --> L

内存缓冲机制

Gson的流式API采用了智能的内存缓冲策略,通过固定大小的字符缓冲区来最小化内存占用:

// JsonReader内部的缓冲区配置

static final int BUFFER_SIZE = 1024;

private final char[] buffer = new char[BUFFER_SIZE];

private int pos = 0;

private int limit = 0;

这种设计使得无论输入数据多大,JsonReader都只使用固定大小的内存缓冲区。缓冲区大小经过优化,足以处理最长的数字字面量,同时保持较小的内存占用。

性能对比分析

下表展示了流式API与传统DOM解析在内存使用方面的对比:

特性

流式API (JsonReader)

传统DOM解析

内存占用

固定 (~1KB缓冲区)

与文档大小成正比

启动时间

立即开始处理

需要完整解析

适用场景

大型文件、流数据

小型到中型文档

内存峰值

恒定低内存

可能很高

处理方式

基于事件

基于树结构

高效的内存管理技巧

1. 对象池和重用

对于需要频繁创建的对象,建议使用对象池模式:

// 对象重用示例

private static final ThreadLocal READER_POOL =

ThreadLocal.withInitial(() -> new JsonReader(new StringReader("")));

public JsonReader getReusableReader(Reader source) {

JsonReader reader = READER_POOL.get();

try {

// 重置reader状态并设置新源

Method resetMethod = JsonReader.class.getDeclaredMethod("reset", Reader.class);

resetMethod.setAccessible(true);

resetMethod.invoke(reader, source);

} catch (Exception e) {

// 备用方案:创建新实例

reader = new JsonReader(source);

}

return reader;

}

2. 字符串处理优化

Gson在处理字符串时采用了延迟解析策略,只有在需要时才创建字符串对象:

// JsonReader中的字符串处理逻辑

private String nextString(boolean quoted) throws IOException {

// 直接从缓冲区读取,避免创建中间StringBuilder

// 只有在确定需要字符串时才创建String对象

}

3. 数字解析优化

对于数字值,Gson提供了多种解析方法以避免不必要的对象创建:

// 高效的数字处理示例

try (JsonReader reader = new JsonReader(new StringReader(json))) {

reader.beginArray();

while (reader.hasNext()) {

// 直接读取原始类型,避免装箱

int value = reader.nextInt();

long bigValue = reader.nextLong();

double decimal = reader.nextDouble();

// 或者使用nextString()获取原始字符串表示

String numberStr = reader.nextString();

}

reader.endArray();

}

流式处理模式

1. 增量处理大型数组

public void processLargeArray(JsonReader reader) throws IOException {

reader.beginArray();

while (reader.hasNext()) {

processSingleItem(reader);

// 及时清理处理过的数据

System.gc(); // 在适当的时候调用GC

}

reader.endArray();

}

private void processSingleItem(JsonReader reader) throws IOException {

reader.beginObject();

while (reader.hasNext()) {

String name = reader.nextName();

switch (name) {

case "id":

long id = reader.nextLong();

processId(id);

break;

case "data":

String data = reader.nextString();

processData(data);

break;

default:

reader.skipValue(); // 跳过不需要的字段

}

}

reader.endObject();

}

2. 内存敏感的批处理

// 分批处理大量数据

private static final int BATCH_SIZE = 1000;

public void processInBatches(JsonReader reader) throws IOException {

List batch = new ArrayList<>(BATCH_SIZE);

reader.beginArray();

while (reader.hasNext()) {

DataItem item = parseItem(reader);

batch.add(item);

if (batch.size() >= BATCH_SIZE) {

processBatch(batch);

batch.clear(); // 释放当前批次内存

}

}

// 处理剩余项目

if (!batch.isEmpty()) {

processBatch(batch);

}

reader.endArray();

}

避免常见的内存陷阱

1. 字符串累积

// 错误做法:累积大量字符串

List allData = new ArrayList<>();

try (JsonReader reader = new JsonReader(input)) {

reader.beginArray();

while (reader.hasNext()) {

allData.add(reader.nextString()); // 内存爆炸!

}

reader.endArray();

}

// 正确做法:流式处理

try (JsonReader reader = new JsonReader(input)) {

reader.beginArray();

while (reader.hasNext()) {

String data = reader.nextString();

processImmediately(data); // 立即处理并释放

}

reader.endArray();

}

2. 不必要的对象创建

// 优化对象创建模式

public class DataProcessor {

private final ReusableDataContainer container = new ReusableDataContainer();

public void processStream(JsonReader reader) throws IOException {

reader.beginArray();

while (reader.hasNext()) {

fillContainer(reader, container);

process(container);

container.reset(); // 重用对象

}

reader.endArray();

}

}

性能监控和调优

内存使用监控

// 监控内存使用情况

public class MemoryAwareProcessor {

private static final long MEMORY_THRESHOLD = 100 * 1024 * 1024; // 100MB

public void processWithMemoryCheck(JsonReader reader) throws IOException {

Runtime runtime = Runtime.getRuntime();

reader.beginArray();

while (reader.hasNext()) {

long usedMemory = runtime.totalMemory() - runtime.freeMemory();

if (usedMemory > MEMORY_THRESHOLD) {

// 内存使用过高,采取应对措施

handleMemoryPressure();

}

processItem(reader);

}

reader.endArray();

}

}

最佳实践总结

优先使用原始类型:使用nextInt(), nextLong(), nextDouble()等方法来避免装箱操作

及时跳过不需要的数据:使用skipValue()跳过不关心的JSON结构

重用对象实例:在处理循环中重用对象以减少GC压力

分批处理:对于大量数据,采用分批处理策略

监控内存使用:在关键点检查内存使用情况,防止内存溢出

使用合适的缓冲区大小:根据数据特征调整处理批次大小

通过合理运用Gson的流式API和上述优化技巧,可以在处理大型JSON数据时显著降低内存占用,提高应用程序的整体性能和稳定性。流式API特别适合处理网络流、大型文件和高并发场景下的JSON数据处理需求。

TypeAdapterFactory模式应用

TypeAdapterFactory是Gson中一个强大而灵活的设计模式,它允许开发者为一组相关类型创建类型适配器。这种模式特别适用于处理具有相似JSON结构的多个类型,能够显著提升代码的复用性和性能。

TypeAdapterFactory的核心机制

TypeAdapterFactory接口定义了一个简单但强大的方法:

public interface TypeAdapterFactory {

TypeAdapter create(Gson gson, TypeToken type);

}

该方法接收Gson实例和TypeToken参数,返回对应类型的TypeAdapter。如果工厂不支持该类型,则返回null。

内置TypeAdapterFactory实现分析

Gson内部提供了多个TypeAdapterFactory实现,展示了不同的应用场景:

1. CollectionTypeAdapterFactory

public final class CollectionTypeAdapterFactory implements TypeAdapterFactory {

private final ConstructorConstructor constructorConstructor;

@Override

public TypeAdapter create(Gson gson, TypeToken typeToken) {

Type type = typeToken.getType();

Class rawType = typeToken.getRawType();

if (!Collection.class.isAssignableFrom(rawType)) {

return null;

}

Type elementType = GsonTypes.getCollectionElementType(type, rawType);

TypeAdapter elementTypeAdapter = gson.getAdapter(TypeToken.get(elementType));

// ... 创建适配器实例

}

}

这个工厂处理所有Collection类型的序列化和反序列化,通过类型推断和委托模式实现泛型支持。

2. MapTypeAdapterFactory

MapTypeAdapterFactory采用类似的模式处理Map类型,支持复杂的键值对结构。

自定义TypeAdapterFactory实践

枚举类型小写转换工厂

public class LowercaseEnumTypeAdapterFactory implements TypeAdapterFactory {

public TypeAdapter create(Gson gson, TypeToken type) {

Class rawType = (Class) type.getRawType();

if (!rawType.isEnum()) {

return null;

}

final Map lowercaseToConstant = new HashMap<>();

for (T constant : rawType.getEnumConstants()) {

lowercaseToConstant.put(toLowercase(constant), constant);

}

return new TypeAdapter() {

public void write(JsonWriter out, T value) throws IOException {

if (value == null) {

out.nullValue();

} else {

out.value(toLowercase(value));

}

}

public T read(JsonReader reader) throws IOException {

if (reader.peek() == JsonToken.NULL) {

reader.nextNull();

return null;

} else {

return lowercaseToConstant.get(reader.nextString());

}

}

};

}

private String toLowercase(Object o) {

return o.toString().toLowerCase(Locale.US);

}

}

第三方库集成示例

public class MultisetTypeAdapterFactory implements TypeAdapterFactory {

public TypeAdapter create(Gson gson, TypeToken typeToken) {

Type type = typeToken.getType();

if (typeToken.getRawType() != Multiset.class

|| !(type instanceof ParameterizedType)) {

return null;

}

Type elementType = ((ParameterizedType) type).getActualTypeArguments()[0];

TypeAdapter elementAdapter = gson.getAdapter(TypeToken.get(elementType));

return (TypeAdapter) newMultisetAdapter(elementAdapter);

}

private TypeAdapter> newMultisetAdapter(

TypeAdapter elementAdapter) {

return new TypeAdapter>() {

public void write(JsonWriter out, Multiset value) throws IOException {

if (value == null) {

out.nullValue();

return;

}

out.beginArray();

for (Multiset.Entry entry : value.entrySet()) {

out.value(entry.getCount());

elementAdapter.write(out, entry.getElement());

}

out.endArray();

}

public Multiset read(JsonReader in) throws IOException {

if (in.peek() == JsonToken.NULL) {

in.nextNull();

return null;

}

Multiset result = LinkedHashMultiset.create();

in.beginArray();

while (in.hasNext()) {

int count = in.nextInt();

E element = elementAdapter.read(in);

result.add(element, count);

}

in.endArray();

return result;

}

};

}

}

TypeAdapterFactory的性能优化策略

1. 延迟初始化与缓存

flowchart TD

A[TypeAdapterFactory.create调用] --> B{类型是否支持?}

B -->|否| C[返回null]

B -->|是| D{适配器是否已缓存?}

D -->|是| E[返回缓存适配器]

D -->|否| F[创建新适配器]

F --> G[缓存适配器]

G --> H[返回适配器]

2. 委托模式优化

通过Gson实例获取委托适配器,避免重复的类型适配器创建:

Type elementType = ((ParameterizedType) type).getActualTypeArguments()[0];

TypeAdapter elementAdapter = gson.getAdapter(TypeToken.get(elementType));

注册与优先级管理

TypeAdapterFactory的注册顺序影响匹配优先级:

GsonBuilder builder = new GsonBuilder();

builder.registerTypeAdapterFactory(new CustomFactory1()); // 高优先级

builder.registerTypeAdapterFactory(new CustomFactory2()); // 低优先级

Gson gson = builder.create();

最佳实践总结

实践要点

说明

示例

精确类型检查

在create方法中严格检查支持的类型

if (!rawType.isEnum()) return null;

委托模式

重用Gson已有的类型适配器

gson.getAdapter(TypeToken.get(elementType))

缓存机制

对昂贵的操作进行缓存

枚举常量映射缓存

null处理

正确处理null值场景

if (value == null) out.nullValue();

异常处理

妥善处理IO异常和解析错误

throws IOException声明

复杂类型处理流程图

sequenceDiagram

participant Client

participant Gson

participant TypeAdapterFactory

participant TypeAdapter

participant JsonReader/Writer

Client->>Gson: toJson() / fromJson()

Gson->>TypeAdapterFactory: create(TypeToken)

TypeAdapterFactory-->>Gson: TypeAdapter or null

Gson->>TypeAdapter: read() / write()

TypeAdapter->>JsonReader/Writer: 数据读写操作

JsonReader/Writer-->>TypeAdapter: 处理结果

TypeAdapter-->>Gson: 转换后的对象/JSON

Gson-->>Client: 最终结果

TypeAdapterFactory模式为Gson提供了极高的扩展性,使得开发者能够为特定类型或类型家族定制序列化行为,同时在性能优化方面提供了良好的基础架构支持。

Android环境下的Gson使用注意事项

在Android开发中使用Gson进行JSON序列化和反序列化时,开发者需要特别注意一些关键事项,以确保应用在发布版本中能够正常工作。由于Android平台的独特特性,特别是代码压缩和混淆工具(如ProGuard和R8)的存在,Gson的使用需要额外的配置和注意事项。

代码混淆与字段名保留

Android构建系统默认启用代码混淆和优化,这会导致Gson无法正确识别字段名称。以下是必须配置的ProGuard/R8规则:

# 保持Gson相关的类和注解

-keepattributes Signature, RuntimeVisibleAnnotations, AnnotationDefault

# 保持TypeToken类及其子类

-keep class com.google.gson.reflect.TypeToken

-keep class * extends com.google.gson.reflect.TypeToken

# 保持使用@JsonAdapter注解的类

-keep @com.google.gson.annotations.JsonAdapter class *

# 保持使用Gson注解的字段

-keepclassmembers class * {

@com.google.gson.annotations.* ;

}

# 保持自定义TypeAdapter的构造函数

-keepclassmembers class * extends com.google.gson.TypeAdapter {

();

}

使用@SerializedName注解

为了避免字段名被混淆,强烈建议对所有需要序列化的字段使用@SerializedName注解:

public class User {

@SerializedName("user_id")

private String userId;

@SerializedName("user_name")

private String userName;

@SerializedName("email_address")

private String email;

}

版本兼容性配置

不同版本的Gson对Android API级别有不同要求:

Gson版本

最低Android API级别

主要特性

2.11.0+

API 21 (Android 5.0)

现代Android支持

2.10.1-

API 19 (Android 4.4)

向后兼容

避免使用匿名和局部类

Gson无法正确处理匿名类和局部类的序列化,这些类会被序列化为null:

// 错误示例 - 匿名类

Gson gson = new Gson();

Object anonymousObj = new Object() {

String name = "test";

};

String json = gson.toJson(anonymousObj); // 结果为null

// 正确做法 - 使用静态嵌套类

public static class UserData {

String name = "test";

}

构造函数要求

确保数据类具有无参构造函数,否则Gson可能无法正确实例化对象:

public class Product {

private String name;

private double price;

// 必须有无参构造函数

public Product() {}

public Product(String name, double price) {

this.name = name;

this.price = price;

}

}

处理Android特定问题

1. 避免反射访问Android内部类

Gson默认使用反射访问字段,这可能与Android系统的内部类冲突:

// 自定义TypeAdapter避免反射问题

public class DateAdapter extends TypeAdapter {

@Override

public void write(JsonWriter out, Date value) throws IOException {

out.value(value.getTime());

}

@Override

public Date read(JsonReader in) throws IOException {

return new Date(in.nextLong());

}

}

// 注册自定义适配器

Gson gson = new GsonBuilder()

.registerTypeAdapter(Date.class, new DateAdapter())

.create();

2. 使用@Keep注解保护关键类

在Android项目中,可以使用@Keep注解来防止特定类被混淆:

@Keep

public class ImportantData {

private String criticalField;

// 构造函数和其他方法

}

性能优化建议

1. 重用Gson实例

Gson实例是线程安全的,应该重用而不是每次创建新实例:

// 应用级别单例

public class GsonProvider {

private static final Gson INSTANCE = new GsonBuilder().create();

public static Gson getGson() {

return INSTANCE;

}

}

2. 使用TypeToken处理泛型

正确使用TypeToken来处理泛型集合:

// 错误方式 - 会导致类型擦除问题

List users = gson.fromJson(json, List.class);

// 正确方式 - 使用TypeToken

Type userListType = new TypeToken>(){}.getType();

List users = gson.fromJson(json, userListType);

调试和故障排除

当应用在Debug模式工作正常但在Release模式失败时,检查以下方面:

字段名混淆:使用mapping文件解码混淆后的字段名

构造函数移除:确保无参构造函数没有被R8优化掉

类型信息丢失:验证泛型签名是否被正确保留

安全注意事项

避免序列化敏感数据,特别是包含密码、密钥或其他认证信息的对象。Gson的反射机制可能会意外暴露这些数据。

替代方案考虑

对于新项目,考虑使用专门为Android优化的JSON库,如Moshi或Kotlin Serialization,这些库使用代码生成而非反射,在Android环境下具有更好的性能和兼容性。

// Moshi依赖

implementation 'com.squareup.moshi:moshi:1.15.0'

implementation 'com.squareup.moshi:moshi-kotlin:1.15.0'

// Kotlin Serialization

implementation 'org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.0'

通过遵循这些最佳实践和注意事项,开发者可以确保Gson在Android环境中稳定可靠地工作,同时保持应用的性能和安全性。

Gson作为Java生态中流行的JSON处理库,其性能优化需要从多个维度综合考虑。通过减少反射使用、自定义TypeAdapter、优化缓存策略和合理配置Gson实例,可以显著提升性能。流式API特别适合处理大型JSON数据,能有效降低内存占用。TypeAdapterFactory模式提供了灵活的扩展机制。在Android环境下,需要特别注意代码混淆、字段名保留和版本兼容性问题。遵循这些最佳实践,结合具体的业务场景进行针对性优化,能够使Gson在生产环境中发挥出最佳性能表现。

🎯 相关推荐

倒数(邓紫棋)
🎯 日博365邮箱

倒数(邓紫棋)

📅 10-07 👀 8504
社区资源整合的4大攻略  |  社工课
🎯 安徽365热线

社区资源整合的4大攻略 | 社工课

📅 06-25 👀 4251

🎁 合作伙伴