溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Springboot中如何進(jìn)行Serverless的訂單應(yīng)用

發(fā)布時(shí)間:2021-09-29 16:12:54 來源:億速云 閱讀:187 作者:柒染 欄目:云計(jì)算

本篇文章為大家展示了Springboot中如何進(jìn)行Serverless的訂單應(yīng)用,內(nèi)容簡明扼要并且容易理解,絕對(duì)能使你眼前一亮,通過這篇文章的詳細(xì)介紹希望你能有所收獲。

前言

這是一個(gè) JAVA 開發(fā)的訂單后臺(tái)應(yīng)用(沒錯(cuò)!就是那個(gè)讓無數(shù)大學(xué)生痛不欲生的訂單后臺(tái)系統(tǒng)),結(jié)合 Serverless 這一無服務(wù)器思想,嘗試通過云函數(shù) + API 網(wǎng)關(guān) + 云數(shù)據(jù)庫的組合來部署 Springboot 的成功之作。

本文作者:Freeeeeedom

該應(yīng)用提供了完整的用戶登錄驗(yàn)證、接口數(shù)據(jù)驗(yàn)證、訂單流 (CRUD) 等強(qiáng)大的功能,而且在本地開發(fā)調(diào)試時(shí)也能模擬 API 網(wǎng)關(guān)調(diào)用云函數(shù)(本地 Java 開發(fā)云端部署不是問題),還兼容了云消息隊(duì)列 CMQ 的調(diào)用,以便后續(xù)開發(fā)引入云中間件。

同時(shí),這種部署方式也能讓其他的 Springboot 很快地轉(zhuǎn)換為云函數(shù)部署。

為響應(yīng)國家「十四五計(jì)劃」的環(huán)保計(jì)劃,特地的研究了一下傳說中的 Serverless 方案(省服務(wù)器 ????),于是便有了這次嘗試。

語言和框架

  • JAVA 天下第一**,當(dāng)然 c/c++/c#/node/python/go/php/vb 這些也不錯(cuò)

  • JAVA 的單體應(yīng)用還能選什么呢?只能是 Springboot 啊

部署準(zhǔn)備

  1. 注冊(cè)個(gè)騰訊云賬號(hào)

  2. 開通以下產(chǎn)品權(quán)限(云函數(shù)、API 網(wǎng)關(guān)、對(duì)象存儲(chǔ))

  3. 財(cái)力允許的話還可以購買數(shù)據(jù)庫服務(wù)(因?yàn)槟晟佥p狂打折時(shí)我購買了這倆很長很長時(shí)間)

  • mysql數(shù)據(jù)庫

  • redis數(shù)據(jù)庫

Springboot中如何進(jìn)行Serverless的訂單應(yīng)用

部署方案

訂單應(yīng)用來說的話,必然是提供 restful 的接口,所以在統(tǒng)一 VPC 內(nèi)采用了云函數(shù) + API 網(wǎng)關(guān)的模式提供接口,于是就有了以下方案:

  1. 應(yīng)用主體部署在云函數(shù)

  2. 使用 API 網(wǎng)關(guān)作為函數(shù)入口

  3. 頁面則是使用了對(duì)象存儲(chǔ)部署

  4. 數(shù)據(jù)庫方面則使用了同一 vpc 下的云數(shù)據(jù)庫(財(cái)力有限只嘗試了 mysql、redis,理論上其他應(yīng)該都可行)

嘗試部署

要讓 JAVA 工程部署到云函數(shù)上,首先了解什么是云函數(shù)(以下摘自微信開放文檔)

云函數(shù)即在云端(服務(wù)器端)運(yùn)行的函數(shù)。在物理設(shè)計(jì)上,一個(gè)云函數(shù)可由多個(gè)文件組成,占用一定量的 CPU 內(nèi)存等計(jì)算資源;各云函數(shù)完全獨(dú)立;可分別部署在不同的地區(qū)。開發(fā)者無需購買、搭建服務(wù)器,只需編寫函數(shù)代碼并部署到云端即可在小程序端調(diào)用,同時(shí)云函數(shù)之間也可互相調(diào)用。

云函數(shù)其實(shí)就是將業(yè)務(wù)拆分成函數(shù)粒度部署在云上,那么就寫了個(gè)簡單的 demo 部署到云函數(shù)上,并且配上了 API 網(wǎng)關(guān)嘗試調(diào)用。

 /**
 * 純javascf快速開發(fā)部署(不走springboot)
 *
 * @author Freeeeeedom
 * @date 2020/10/24 10:31
 */
public class Scf {
    /**
     * log Object
     */
    private static Logger log = LoggerFactory.getLogger(Scf.class);
    private static DruidDataSource dataSource1 = new DruidDataSource();

    static {
        //此處加載或修改數(shù)據(jù)源 多數(shù)據(jù)源配置多個(gè)
        dataSource1.setUsername("Freeeeeedom");
        dataSource1.setUrl("jdbc:mysql://Freeeeeedom?autoReconnectForPools=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai");
        dataSource1.setPassword("Freeeeeedom");
        dataSource1.setMinIdle(1);
        dataSource1.setMaxActive(5);
        dataSource1.setMaxWait(10000);
        dataSource1.setValidationQuery("SELECT 1 from dual");
        log.info("數(shù)據(jù)源加載ok~");
    }

    /**
     * 純scf入口參數(shù)
     *
     * @param insertParam 入?yún)?
     * @return java.lang.Object 執(zhí)行結(jié)果
     * @author Freeeeeedom
     * @date 2020/10/24 10:31
     */
    public Object pure(Map<String, Object> insertParam) {
        log.info("param:{}", gson.toJson(insertParam);
        Gson gson = new GsonBuilder().disableHtmlEscaping().create();
        try {
            Class.forName("com.mysql.jdbc.Driver");
        } catch (ClassNotFoundException e) {
            log.error("內(nèi)部處理異常", e);
        }
        Map response = new HashMap();
        JdbcTemplate jdbcTemplate = new JdbcTemplate();
        jdbcTemplate.setDataSource(dataSource1);
        Map order = jdbcTemplate.queryForMap("select order_id,create_time from `order` limit 1");
        log.info(order.toString());
        return buildResponse(gson, gson.toJson(order), response);
    }

    private Object buildResponse(Gson gson, String json, Map response) {
        Map<String, String> headers = new HashMap(1);
        headers.put("Content-Type", "application/json");
        response.put("statusCode", HttpStatus.OK.value());
        response.put("headers", headers);
        response.put("body", json);
        return gson.toJson(response);
    }
}

只需要打包好代碼,然后將入口函數(shù)設(shè)置為 scf.Scf::pure 就實(shí)現(xiàn)了接收數(shù)據(jù),然后從數(shù)據(jù)庫查詢了第一個(gè)訂單的 id 和創(chuàng)建時(shí)間并且返回的能力:

Springboot中如何進(jìn)行Serverless的訂單應(yīng)用

每一次通過 API 網(wǎng)關(guān)觸發(fā)云函數(shù)都會(huì)觸發(fā) pure 這個(gè)方法(調(diào)用者 > 調(diào)用 API 網(wǎng)關(guān) > 云函數(shù) --> pure),但經(jīng)測(cè)試發(fā)現(xiàn) static 的數(shù)據(jù)源初始化并不會(huì)被重復(fù)加載,這也奠定了 springboot 可部署基礎(chǔ)。

其中通過 log 打印 API 網(wǎng)關(guān)帶來的參數(shù),直接將其復(fù)制為 json,然后通過 main 函數(shù)模擬調(diào)用,這樣就實(shí)現(xiàn)了本地模擬 serverless 部署后的調(diào)用。

log.info("param:{}", gson.toJson(insertParam);

有了這些基礎(chǔ),那么只需要有一個(gè)入口類模擬 springboot 啟動(dòng)的加載,然后再映射一下 API 網(wǎng)關(guān)過來入口參數(shù),即可實(shí)現(xiàn) springboot 在云函數(shù)上部署(其實(shí)就是上面 SCF 類的超級(jí) plus 版本)。

** API 網(wǎng)關(guān)配置**

這里的路徑參數(shù)對(duì)應(yīng) springboot 里的 mapping 路徑

Springboot中如何進(jìn)行Serverless的訂單應(yīng)用

Springboot中如何進(jìn)行Serverless的訂單應(yīng)用

本地調(diào)試

有了上面那些 demo 后,可得知我們模擬云端部署運(yùn)行已經(jīng)不是問題。那么怎么在本地調(diào)試呢?答案很簡單,直接啟動(dòng) springboot 然后調(diào)正常就完事了。

沒錯(cuò),就是直接用原生的 springboot 玩法即可。把 springboot 部署到云函數(shù)其實(shí)就是外掛了一個(gè) springboot 的啟動(dòng)類(設(shè)計(jì)模式上叫適配器模式?(+_+)?

功能

完整的 springboot,能用 springboot 做的都能實(shí)現(xiàn),我只是編寫了一些小功能驗(yàn)證這個(gè)應(yīng)用。

  • [x] 與本地服務(wù)器數(shù)據(jù)庫連接

  • [x] 云數(shù)據(jù)庫連接

  • [x] vpc數(shù)據(jù)庫連接

  • [x] 外部接口調(diào)用(發(fā)短信驗(yàn)證碼)

  • [x] 實(shí)現(xiàn)簡單的訂單流 (crud)

  • [x] 實(shí)現(xiàn)簡單的登錄能力

  • [x] 實(shí)現(xiàn)簡單的數(shù)據(jù)驗(yàn)證能力

整個(gè)項(xiàng)目功能簡單但代碼卻不少。

安全

首先 "serverless"、"騰訊"、"云服務(wù)" 這幾個(gè)詞就足以代表安全了,但為了功能完整性我還是嘗試加了點(diǎn)東西。

在這個(gè)系統(tǒng)中,我選擇了 header 中加簽名的方式驗(yàn)證數(shù)據(jù),原因是啥,操作簡單,有效唄。加密手段和方案暫且不說,就從流程上來看,是很方便的:

  1. 從 API 網(wǎng)關(guān)調(diào)用參數(shù)中獲取到 header,body

  2. 驗(yàn)證數(shù)據(jù)有效性

  3. 請(qǐng)求轉(zhuǎn)入業(yè)務(wù)模塊

  4. 驗(yàn)證數(shù)據(jù)有效性

  5. 參數(shù)進(jìn)入功能模塊

  6. 驗(yàn)證數(shù)據(jù)有效性

  7. ………………

其實(shí)只有 123 步驟是最有效的,后面的 45678 如果你想的話……更不用說 API 網(wǎng)關(guān)本身提供的鑒權(quán)功能了。

Springboot中如何進(jìn)行Serverless的訂單應(yīng)用

性能

內(nèi)存的話對(duì)于訂單系統(tǒng)來說單次請(qǐng)求加上 JVM 也才 300mb,而云函數(shù)單個(gè)函數(shù)執(zhí)行內(nèi)存能拉到 3GB,哪怕有點(diǎn)量的分布式計(jì)算應(yīng)該問題也不大。

Springboot中如何進(jìn)行Serverless的訂單應(yīng)用

并發(fā)的話云函數(shù)上的預(yù)置并發(fā)上限 200 個(gè),訂單系統(tǒng)嘛,QPS1000?10000?100000? ezpz了,再怎么也比自家機(jī)柜服務(wù)器強(qiáng)幾百幾千個(gè)量級(jí)了。

Springboot中如何進(jìn)行Serverless的訂單應(yīng)用

內(nèi)存算力不夠服務(wù)器擴(kuò)容?不存在的。

最后

生成個(gè) VUE 項(xiàng)目,改改鏈接調(diào)調(diào)頁面,然后上傳到存儲(chǔ)桶上,一鍵打開 CDN ~( ̄▽ ̄)~*完美!

察覺到了到了科技的進(jìn)步,時(shí)代的發(fā)展,Serverless 的強(qiáng)大。

上述內(nèi)容就是Springboot中如何進(jìn)行Serverless的訂單應(yīng)用,你們學(xué)到知識(shí)或技能了嗎?如果還想學(xué)到更多技能或者豐富自己的知識(shí)儲(chǔ)備,歡迎關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI