---
title: "Solon Rpc 开发定制"
---


默认配置能跑通后，再按场景选择 Builder、`NamiConfiguration` 和 `Filter`。优先局部配置，避免一个全局配置器悄悄改变所有客户端。

### 1、 Builder：手动创建一个代理

`Nami.builder()` 返回 `NamiBuilder`，当前源码支持：`url`、`name`、`path`、`group`、`upstream`、`channel`、`encoder`、`decoder`、`timeout`、`heartbeat`、`headerSet`、`filterAdd` 和 `create`。

```java
UserService service = Nami.builder()
    .url("http://localhost:9001/rpc/v1/user")
    .headerSet("X-App", "demo-consumer")
    .timeout(10)
    .decoder(Snack4Decoder.instance)
    .encoder(Snack4Encoder.instance)
    .create(UserService.class);
```

`create` 要求传入接口；它创建的是 JDK 动态代理。若传入普通 class，源码会抛出 `NamiException`。

动态上游适合每次调用前选择地址：

```java
UserService service = Nami.builder()
    .path("/rpc/v1/user")
    .upstream(() -> "http://localhost:9001")
    .create(UserService.class);
```

### 2、 配置器：统一配置客户端

Nami 的 `NamiConfiguration` 方法签名是：

```java
void config(NamiClient client, NamiBuilder builder);
```

在 Solon 中可注册一个组件：

```java
import org.noear.nami.NamiBuilder;
import org.noear.nami.NamiConfiguration;
import org.noear.nami.annotation.NamiClient;
import org.noear.nami.coder.snack4.Snack4Decoder;
import org.noear.nami.coder.snack4.Snack4Encoder;
import org.noear.solon.annotation.Component;

@Component
public class DemoNamiConfiguration implements NamiConfiguration {
    @Override
    public void config(NamiClient client, NamiBuilder builder) {
        builder.decoder(Snack4Decoder.instance)
               .encoder(Snack4Encoder.instance)
               .timeout(10);
    }
}
```

当前 Solon 集成会发现 `NamiConfiguration` 并参与客户端创建。配置器会影响匹配到的客户端；如果 HTTP JSON 和二进制客户端并存，应通过不同配置器或显式 Builder 分开。

不要直接照搬旧资料中的 `SnackTypeEncoder` 等类名，当前仓库 snack4 模块实际提供的是 `Snack4Encoder`、`Snack4Decoder`。

### 3、 过滤器：在调用链上做横切处理

`Filter` 的唯一方法是：

```java
Result doFilter(Invocation inv) throws Throwable;
```

最小过滤器必须继续调用 `inv.invoke()`，否则请求不会真正发出：

```java
Filter logging = inv -> {
    long start = System.currentTimeMillis();
    try {
        return inv.invoke();
    } finally {
        long cost = System.currentTimeMillis() - start;
        System.out.println("rpc cost=" + cost + "ms, url=" + inv.url);
    }
};

UserService service = Nami.builder()
    .url("http://localhost:9001/rpc/v1/user")
    .filterAdd(logging)
    .create(UserService.class);
```

生产环境建议使用日志组件而不是 `System.out`，并脱敏 URL 参数、Token 和个人数据。

### 4、 选择建议

| 需求 | 方式 |
|---|---|
| Solon Bean 注入、统一默认值 | `@NamiClient` + `NamiConfiguration` |
| 独立 Java 程序或单个特殊客户端 | `Nami.builder()` |
| trace、鉴权头、耗时统计 | `Filter` |
| 服务地址发现 | `name/path` + Discovery/LoadBalance |
| 一次调用链临时携带头 | `NamiAttach` |