Springboot 輕量替代框架 Solon 1.3.10 釋出

劉之西東 發表於 2021-03-08

Solon 是一個微型的Java開發框架。專案從2018年啟動以來,參考過大量前人作品;歷時兩年,4000多次的commit;核心保持0.1m的身材,超高的跑分,良好的使用體驗。支援:RPC、REST API、MVC、WebSocket、Socket 等多種開發模式。

Solon 強調:剋制 + 簡潔 + 開放的原則;力求:更小、更快、更自由的體驗。

替代?那有什麼差別!

Solon 特性簡集,相較於 Springboot 有什麼區別?

所謂更小:

核心0.1m,最小開發單位0.2m(相比Dubbo、Springboot專案包,小到可以乎略不計)

所謂更快:

本機helloworld測試,Qps可達12萬之多。可參考:《helloworld_wrk_test

所謂更自由:(程式碼操控自由)

// 除了註解模式之外,還可以按需手動
//
//手動獲取配置(Props 為 Properties 增強版)
Props db = Solon.cfg().getProp("db");

//手動獲取容器裡的Bean
UserService userService = Aop.get(UserService.class);

//手動監聽http post請求
Solon.global().post("/user/update", x-> userService.updateById(x.paramMap()));

//手動新增個RPC服務
Solon.global().add("/rpc/", HelloService.class, true);

//手動獲取一個RPC服務消費端
HelloService helloService = Nami.builder().create(HelloService.class);

本次版本重大變更:

1、增加過濾器(Filter),之前由觸發器替代

所謂觸發器,例:

//::在"/demo/"處理之前觸發
app.before("/demo/", c-> System.out.println("我是請求之前觸發的..."+ctx.path()) );

//::在"/demo/"處理之後觸發
app.after("/demo/", c-> System.out.println("我是請求之後觸發的..."+ctx.path()) );

“觸發器”聽起來像是資料庫的東西,在Solon裡的特性與資料庫的觸發特性確實也沒什麼區別。。。算是借用了。

Solon 之前的設計中僅有觸發器和攔截器兩種概念,也覺很夠用。但某些場景下,過濾器會更合適。相對於觸發器,過濾器的好處是把後續的處理完整的包圍起來,擁有更強的控制性(比如,融斷或併發限制)。

來看下Solon的過濾器,註解模式:

//通過註解,申明一個過濾器
@Component
public class FilterDemo implements Filter {
    @Override
    public void doFilter(Context ctx, FilterChain chain) throws Throwable {
        System.out.println("我是好人過濾器!!!path="+ctx.path());
        chain.doFilter(ctx);
    }
}

純手寫模式

//通過手動為應用新增一個過濾器
app.filter((ctx, chain)->{
    System.out.println("我是過濾器!!!path="+ctx.path());
    chain.doFilter(ctx);
});

//Solon.global() 即為全域性app物件...

用法上,與Servlet的過濾器幾首一樣。。。(注:Solon 不是 Servlet 框架。它可以適配各種不同的Http容器)

2、強化自帶閘道器的通用性、組裝性

同一份介面實現,不同的協議輸出:

簡單版輸出輸入:

@Mapping("/api/v1/**")
@Controller
public class ApiGateway1x extends ApiGatewayBase {
    @Override
    protected void register() {
        before(new StartInterceptor()); //開始

        after(new OutputBuildInterceptor()); //輸出構建
        after(new OutputInterceptor()); //輸出
        after(new LogInterceptor()); //日誌
        after(new EndInterceptor("v1")); //結束

        //載入bean,做為介面
        addBeans(bw -> "api".equals(bw.tag()));
    }
}

複雜版輸入輸出:

@Mapping("/api/v3/**")
@Component
public class ApiGateway3x extends ApiGatewayBase {
    @Override
    protected void register() {
    
        filter(new SentryFilter()); //新增融斷過濾器

        before(new StartTrigger()); //開始
        before(new ParamsParseTrigger()); //引數解析
        before(new ParamsSignCheckTrigger(new Md5Encoder())); //引數簽名較驗,用MD5編碼簽名
        before(new ParamsRebuildTrigger(new AesDecoder())); //引數重構

        after(new OutputBuildTrigger(new AesEncoder())); //輸出構建,用AES編碼載入輸出內容
        after(new OutputSignTrigger(new Md5Encoder())); //輸出簽名,用MD5編碼簽名
        after(new OutputTrigger()); //輸出
        after(new LogTrigger()); //日誌
        after(new EndTrigger("v3")); //結束

        //載入bean,做為介面
        addBeans(bw -> "api".equals(bw.tag()));
    }
}

附:入門示例