springboot mongodb配置解析

官網(wǎng)配置

前言

由于以前使用mongo都是簡單的本地裸奔揩晴,根本沒有設(shè)置過用戶密碼,昨天收到運(yùn)維同事反饋說服務(wù)器被挖礦木馬攻擊了贪磺,嚇得趕緊在docker里面開啟認(rèn)證硫兰,但是設(shè)置完后問題來了,開發(fā)同事又說不能用配置文件如下

spring:
  data:
    mongodb:
      host: 127.0.0.1
      port: 27017
      username: sunny
      password: 123456
      database: admin

看起來很ok但是在啟動boot的時候在會連接兩次(別問我為什么是兩次寒锚,boot源碼還沒有看多少)劫映,第一次是失敗了,但是第二次成功了刹前,但是讀取數(shù)據(jù)時候又用的是mongoTemplate(第一次創(chuàng)建的)這個導(dǎo)致一直卡死泳赋,沒有辦法只能用uri方式配置了,下面介紹boot怎么解析它

配置文件(yml)

spring:
  data:
    mongodb:
      uri: mongodb://sunny:123456@127.0.0.1:27017/file

對應(yīng)的java代碼是

@ConfigurationProperties(prefix = "spring.data.mongodb")
public class MongoProperties {
    public static final String DEFAULT_URI = "mongodb://localhost/test";
    // 默認(rèn)uri=
    public String determineUri() {
        return (this.uri != null ? this.uri : DEFAULT_URI);
    }
    ....
    // 關(guān)鍵代碼 idea ctrl+g 169 就可以看到
    public String getMongoClientDatabase() {
        if (this.database != null) {
            return this.database;
        }
        return new MongoClientURI(determineUri()).getDatabase();
    }
}
// 讀取yml文件前綴為(spring.data.mongodb)

由源碼可以看出這里如果uri=null則使用DEFAULT_URI喇喉,然后進(jìn)入MongoClientURI

public class MongoClientURI {
    private final ConnectionString proxied;
    private final MongoClientOptions.Builder builder;

    /**
     * Creates a MongoURI from the given string.
     * 從給定的字符串創(chuàng)建一個MongoURI
     * @param uri the URI
     */
    public MongoClientURI(final String uri) {
        this(uri, new MongoClientOptions.Builder());
    }
     /**
     * Mongo database URI. Cannot be set with host, port and credentials.
     */
    public MongoClientURI(final String uri, final MongoClientOptions.Builder builder) {
        this.builder = notNull("builder", builder);
        proxied = new ConnectionString(uri);
    }
}

到這里了就先看new MongoClientOptions.Builder() 方法

@Immutable
public class MongoClientOptions {
        /**
         * Creates a Builder for MongoClientOptions, getting the appropriate system properties            *for initialization.
         *  這里MongoClientOptions創(chuàng)建一個構(gòu)建器祖今,并且設(shè)置一些系統(tǒng)屬性
         */
        public Builder() {
    /*設(shè)置心跳頻率,在集群中*/        heartbeatFrequency(Integer.parseInt(System.getProperty("com.mongodb.updaterIntervalMS", "10000")));
    /*最小心跳頻率*/ minHeartbeatFrequency(Integer.parseInt(System.getProperty("com.mongodb.updaterIntervalNoMasterMS", "500")));
    /*設(shè)置用于群集心跳的連接的連接超時*/        heartbeatConnectTimeout(Integer.parseInt(System.getProperty("com.mongodb.updaterConnectTimeoutMS", "20000")));
    /*socket 鏈接超時*/        heartbeatSocketTimeout(Integer.parseInt(System.getProperty("com.mongodb.updaterSocketTimeoutMS", "20000")));
    /*可接受的延遲差 15秒*/        localThreshold(Integer.parseInt(System.getProperty("com.mongodb.slaveAcceptableLatencyMS", "15")));
        }
}

System.getProperty(xxxx)可以在jvm里面設(shè)置或者直接在boot啟動方法里面設(shè)置拣技。

看到這里后發(fā)現(xiàn)使用了一個proxied(代理)繼續(xù)往下看

  public class ConnectionString {  
  /**
     * Creates a ConnectionString from the given string.
     * 
     * @param connectionString     the connection string
     * @since 3.0
     */
    public ConnectionString(final String connectionString) {
        this.connectionString = connectionString;
        //這里可以看出支持兩種協(xié)議:mongodb://和mongodb+srv://
        boolean isMongoDBProtocol = connectionString.startsWith(MONGODB_PREFIX);
        boolean isSRVProtocol = connectionString.startsWith(MONGODB_SRV_PREFIX);
        if (!isMongoDBProtocol && !isSRVProtocol) {
            throw new IllegalArgumentException(format("The connection string is invalid. "
                    + "Connection strings must start with either '%s' or '%s", MONGODB_PREFIX, MONGODB_SRV_PREFIX));
        }
        // 截取協(xié)議頭千诬,eg:sunny:123456@127.0.0.1:27007/file?connectTimeoutMS=400000
        String unprocessedConnectionString;
        if (isMongoDBProtocol) {
            unprocessedConnectionString = connectionString.substring(MONGODB_PREFIX.length());
        } else {
            unprocessedConnectionString = connectionString.substring(MONGODB_SRV_PREFIX.length());
        }

        // 分割出用戶和主機(jī)信息 eg:sunny:123456@127.0.0.1:27007
        String userAndHostInformation;
        int idx = unprocessedConnectionString.lastIndexOf("/");
        if (idx == -1) {
            if (unprocessedConnectionString.contains("?")) {
                throw new IllegalArgumentException("The connection string contains options without trailing slash");
            }
            userAndHostInformation = unprocessedConnectionString;
            unprocessedConnectionString = "";
        } else {
            //userAndHostInformation=sunny:123456@127.0.0.1:27007
            userAndHostInformation = unprocessedConnectionString.substring(0, idx);
             // unprocessedConnectionString=file?connectTimeoutMS=400000
            unprocessedConnectionString = unprocessedConnectionString.substring(idx + 1);
        }

        // Split the user and host information
        String userInfo;
        String hostIdentifier;
        String userName = null;
        char[] password = null;
        idx = userAndHostInformation.lastIndexOf("@");
        if (idx > 0) {
            // userInfo=sunny:123456
            userInfo = userAndHostInformation.substring(0, idx);
            //  hostIdentifier=127.0.0.1:27007
            hostIdentifier = userAndHostInformation.substring(idx + 1);
            // 判斷userInfo是否包含@和:出現(xiàn)次數(shù)大于1
            int colonCount = countOccurrences(userInfo, ":");
            if (userInfo.contains("@") || colonCount > 1) {
                throw new IllegalArgumentException("The connection string contains invalid user information. "
                        + "If the username or password contains a colon (:) or an at-sign (@) then it must be urlencoded");
            }
            if (colonCount == 0) {
                userName = urldecode(userInfo);
            } else {
                // idx=5
                idx = userInfo.indexOf(":");
                // userName=sunny
                userName = urldecode(userInfo.substring(0, idx));
                //passpword=123456
                password = urldecode(userInfo.substring(idx + 1), true).toCharArray();
            }
        } else {
            hostIdentifier = userAndHostInformation;
        }

        // 驗(yàn)證host
        List<String> unresolvedHosts = unmodifiableList(parseHosts(asList(hostIdentifier.split(",")), isSRVProtocol));
        this.hosts = isSRVProtocol ? resolveHostFromSrvRecords(unresolvedHosts.get(0)) : unresolvedHosts;

        // 解析參數(shù)
        String nsPart;
        idx = unprocessedConnectionString.indexOf("?");
        if (idx == -1) {
            nsPart = unprocessedConnectionString;
            unprocessedConnectionString = "";
        } else {
            // nsPart=file 獲取數(shù)據(jù)庫名稱
            nsPart = unprocessedConnectionString.substring(0, idx);
            // unprocessedConnectionString=connectTimeoutMS=400000
            unprocessedConnectionString = unprocessedConnectionString.substring(idx + 1);
        }
        if (nsPart.length() > 0) {
            nsPart = urldecode(nsPart);
            idx = nsPart.indexOf(".");
            // 是否指定集合
            if (idx < 0) {
                database = nsPart;
                collection = null;
            } else {
                database = nsPart.substring(0, idx);
                collection = nsPart.substring(idx + 1);
            }
        } else {
            database = null;
            collection = null;
        }
        /*數(shù)據(jù)庫健康鏈接 mongodb+srv 協(xié)議才使用*/
        String txtRecordsQueryParameters = isSRVProtocol ? resolveAdditionalQueryParametersFromTxtRecords(unresolvedHosts.get(0)) : "";
        /*鏈接參數(shù)  connectTimeoutMS=400000*/
        String connectionStringQueryParamenters = unprocessedConnectionString;

        Map<String, List<String>> connectionStringOptionsMap = parseOptions(connectionStringQueryParamenters);
        Map<String, List<String>> txtRecordsOptionsMap = parseOptions(txtRecordsQueryParameters);
        //判斷是否設(shè)置 authsource、replicaset
        if (!ALLOWED_OPTIONS_IN_TXT_RECORD.containsAll(txtRecordsOptionsMap.keySet())) {
            throw new MongoConfigurationException(format("A TXT record is only permitted to contain the keys %s, but the TXT record for "
            + "'%s' contains the keys %s", ALLOWED_OPTIONS_IN_TXT_RECORD, unresolvedHosts.get(0), txtRecordsOptionsMap.keySet()));
        }
        Map<String, List<String>> combinedOptionsMaps = combineOptionsMaps(txtRecordsOptionsMap, connectionStringOptionsMap);
        if (isSRVProtocol && !combinedOptionsMaps.containsKey("ssl")) {
            combinedOptionsMaps.put("ssl", singletonList("true"));
        }
        translateOptions(combinedOptionsMaps);
        credential = createCredentials(combinedOptionsMaps, userName, password);
        warnOnUnsupportedOptions(combinedOptionsMaps);
    }
  }

完結(jié)

mongo這塊代碼是臨時看的膏斤,可能沒有太認(rèn)真徐绑,如果有誤請指出,還有就是mongodb+srv 協(xié)議沒有使用過莫辨,有使用經(jīng)驗(yàn)的歡迎留言傲茄,謝謝

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市沮榜,隨后出現(xiàn)的幾起案子烫幕,更是在濱河造成了極大的恐慌,老刑警劉巖敞映,帶你破解...
    沈念sama閱讀 217,185評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件较曼,死亡現(xiàn)場離奇詭異,居然都是意外死亡振愿,警方通過查閱死者的電腦和手機(jī)捷犹,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評論 3 393
  • 文/潘曉璐 我一進(jìn)店門弛饭,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人萍歉,你說我怎么就攤上這事侣颂。” “怎么了枪孩?”我有些...
    開封第一講書人閱讀 163,524評論 0 353
  • 文/不壞的土叔 我叫張陵憔晒,是天一觀的道長。 經(jīng)常有香客問我蔑舞,道長拒担,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,339評論 1 293
  • 正文 為了忘掉前任攻询,我火速辦了婚禮从撼,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘钧栖。我一直安慰自己低零,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,387評論 6 391
  • 文/花漫 我一把揭開白布拯杠。 她就那樣靜靜地躺著掏婶,像睡著了一般。 火紅的嫁衣襯著肌膚如雪潭陪。 梳的紋絲不亂的頭發(fā)上气堕,一...
    開封第一講書人閱讀 51,287評論 1 301
  • 那天,我揣著相機(jī)與錄音畔咧,去河邊找鬼茎芭。 笑死,一個胖子當(dāng)著我的面吹牛誓沸,可吹牛的內(nèi)容都是我干的梅桩。 我是一名探鬼主播,決...
    沈念sama閱讀 40,130評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼拜隧,長吁一口氣:“原來是場噩夢啊……” “哼宿百!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起洪添,我...
    開封第一講書人閱讀 38,985評論 0 275
  • 序言:老撾萬榮一對情侶失蹤垦页,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后干奢,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體痊焊,經(jīng)...
    沈念sama閱讀 45,420評論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,617評論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了薄啥。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片辕羽。...
    茶點(diǎn)故事閱讀 39,779評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖垄惧,靈堂內(nèi)的尸體忽然破棺而出刁愿,到底是詐尸還是另有隱情,我是刑警寧澤到逊,帶...
    沈念sama閱讀 35,477評論 5 345
  • 正文 年R本政府宣布铣口,位于F島的核電站,受9級特大地震影響觉壶,放射性物質(zhì)發(fā)生泄漏脑题。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,088評論 3 328
  • 文/蒙蒙 一掰曾、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧停团,春花似錦旷坦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,716評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至舌胶,卻和暖如春捆蜀,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背幔嫂。 一陣腳步聲響...
    開封第一講書人閱讀 32,857評論 1 269
  • 我被黑心中介騙來泰國打工辆它, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人履恩。 一個月前我還...
    沈念sama閱讀 47,876評論 2 370
  • 正文 我出身青樓锰茉,卻偏偏與公主長得像,于是被迫代替她去往敵國和親切心。 傳聞我的和親對象是個殘疾皇子飒筑,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,700評論 2 354

推薦閱讀更多精彩內(nèi)容

  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 46,808評論 6 342
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn)绽昏,斷路器协屡,智...
    卡卡羅2017閱讀 134,654評論 18 139
  • SpringMVC原理分析 Spring Boot學(xué)習(xí) 5、Hello World探究 1全谤、POM文件 1肤晓、父項(xiàng)目...
    jack_jerry閱讀 1,287評論 0 1
  • ¥開啟¥ 【iAPP實(shí)現(xiàn)進(jìn)入界面執(zhí)行逐一顯】 〖2017-08-25 15:22:14〗 《//首先開一個線程,因...
    小菜c閱讀 6,404評論 0 17
  • feisky云計(jì)算、虛擬化與Linux技術(shù)筆記posts - 1014, comments - 298, trac...
    不排版閱讀 3,847評論 0 5