1. 程式人生 > >springboot mongodb配置解析

springboot mongodb配置解析

官網配置

前言

由於以前使用mongo都是簡單的本地裸奔,根本沒有設定過使用者密碼,昨天收到運維同事反饋說伺服器被挖礦木馬攻擊了,嚇得趕緊在docker裡面開啟認證,但是設定完後問題來了,開發同事又說不能用配置檔案如下

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

看起來很ok但是在啟動boot的時候在會連線兩次(別問我為什麼是兩次,boot原始碼還沒有看多少),第一次是失敗了,但是第二次成功了,但是讀取資料時候又用的是mongoTemplate

(第一次建立的)這個導致一直卡死,沒有辦法只能用uri方式配置了,下面介紹boot怎麼解析它

配置檔案(yml)

spring:
  data:
    mongodb:
      uri: mongodb://localhost:27017/file

對應的java程式碼是

@ConfigurationProperties(prefix = "spring.data.mongodb")
public class MongoProperties {
    public static final String DEFAULT_URI = "mongodb://localhost/test"
; // 預設uri= public String determineUri() { return (this.uri != null ? this.uri : DEFAULT_URI); } .... // 關鍵程式碼 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,然後進入MongoClientURI

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

    /**
     * Creates a MongoURI from the given string.
     * 從給定的字串建立一個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建立一個構建器,並且設定一些系統屬性
         */
        public Builder() {
    /*設定心跳頻率,在叢集中*/        heartbeatFrequency(Integer.parseInt(System.getProperty("com.mongodb.updaterIntervalMS", "10000")));
    /*最小心跳頻率*/ minHeartbeatFrequency(Integer.parseInt(System.getProperty("com.mongodb.updaterIntervalNoMasterMS", "500")));
    /*設定用於群集心跳的連線的連線超時*/        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裡面設定或者直接在boot啟動方法裡面設定。

看到這裡後發現使用了一個proxied(代理)繼續往下看

  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;
        //這裡可以看出支援兩種協議: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));
        }
        // 擷取協議頭,eg:sunny:[email protected]:27007/file?connectTimeoutMS=400000
        String unprocessedConnectionString;
        if (isMongoDBProtocol) {
            unprocessedConnectionString = connectionString.substring(MONGODB_PREFIX.length());
        } else {
            unprocessedConnectionString = connectionString.substring(MONGODB_SRV_PREFIX.length());
        }

        // 分割出使用者和主機資訊 eg:sunny:[email protected]: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:[email protected]: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是否包含@和:出現次數大於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;
        }

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

        // 解析引數
        String nsPart;
        idx = unprocessedConnectionString.indexOf("?");
        if (idx == -1) {
            nsPart = unprocessedConnectionString;
            unprocessedConnectionString = "";
        } else {
            // nsPart=file 獲取資料庫名稱
            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;
        }
        /*資料庫健康連結 mongodb+srv 協議才使用*/
        String txtRecordsQueryParameters = isSRVProtocol ? resolveAdditionalQueryParametersFromTxtRecords(unresolvedHosts.get(0)) : "";
        /*連結引數  connectTimeoutMS=400000*/
        String connectionStringQueryParamenters = unprocessedConnectionString;

        Map<String, List<String>> connectionStringOptionsMap = parseOptions(connectionStringQueryParamenters);
        Map<String, List<String>> txtRecordsOptionsMap = parseOptions(txtRecordsQueryParameters);
        //判斷是否設定 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);
    }
  }

完結

mongo這塊程式碼是臨時看的,可能沒有太認真,如果有誤請指出,還有就是mongodb+srv 協議沒有使用過,有使用經驗的歡迎留言交流,謝謝

相關推薦

springboot mongodb配置解析

官網配置 前言 由於以前使用mongo都是簡單的本地裸奔,根本沒有設定過使用者密碼,昨天收到運維同事反饋說伺服器被挖礦木馬攻擊了,嚇得趕緊在docker裡面開啟認證,但是設定完後問題來了,開發同事又說不能用配置檔案如下 spring: data:

Springboot +Mongodb配置

1. MongoDB在pom.xml檔案中的依賴 springboot 版本 2.0.7 <dependency> <groupId>org.springframework.boot</groupId> <artifactId&g

解析SpringBoot配置檔案(.yml/.yaml)

解析SpringBoot中配置檔案(.yml/.yaml) springBoot配置檔案的載入有先後順序為: 1.application.yml 2.application.yaml 3.application.properoties 後加載的會把先載入的給覆蓋掉 #普通資料的配置

SpringBoot應用配置常用相關檢視解析

SpringBoot的自動裝配裝配了檢視解析器了嗎? SpringBoot使用JSP SpringBoot中使用Thymeleaf SpringBoot中使用Freemark SpringBoot的自動裝配裝配了檢視解析器了嗎? 我們可以看到SpringBoot自動裝配的WebMvcAutoConf

SpringBoot自動配置註解原理解析

1. SpringBoot啟動主程式類: 1 @SpringBootApplication 2 public class DemoApplication { 3 public static void main(String[] args) { 4 5 SpringApp

springboot原始碼解析:自己實現一個springboot自動配置

上兩篇將到了springboot自動配置和條件註解是如何實現,這篇在前兩篇的基礎上自己實現一個springboot的自動配置,用到條件註解。 需求:加入自己手寫的jar。直接就可以使用StringRedisTemplate。 1.新建一個maven專案,pom.xml如下:

SpringBoot-自動配置原始碼解析

接著上一篇部落格《 SpringBoot-快速搭建WEB工程》提出的需要分析的三個方面:我們來深入的探究SpringBoot是如何在沒有一個配置檔案的情況下為我們啟動好一個完整的WEB工程的,首先我們從@SpringBootApplication 開始這裡的分析

解析springboot裏的pom文件和對應配置解析(一)

driver font xmlns 配置解析 ng- idata rod 4.0 sna 利用Idea的默認設置創建springboot項目,pom文件的結構如下 <?xml version="1.0" encoding="UTF-8"?> <pr

案例解析springboot自動配置未生效問題定位(條件斷點)

  Spring Boot在為開發人員提供更高層次的封裝,進而提高開發效率的同時,也為出現問題時如何進行定位帶來了一定複雜性與難度。但Spring Boot同時又提供了一些診斷工具來輔助開發與分析,如spring-boot-starter-actuator。本文分享一個基於actuator與IDE

springboot自動配置原始碼解析

springboot版本:2.1.6.RELEASE      SpringBoot 自動配置主要通過 @EnableAutoConfiguration, @Conditional, @EnableConfigurationProperties&nb

我是如何做到springboot自動配置原理解析

一前言 springboot 2.0.0版本分析,整體的自動配置流程如下: 具體配置參考官方文件:springboot-doc 二 @SpringBootApplication 核心註解@SpringBootConfiguration其實就是@Configuration註解,表示是個配置類;@Enable

【轉】MongoDB配置文件說明

details 5.0 key 第一個 pen log data 端口 this 啟動MongoDB有2種方式,一是直接指定配置參數,二是指定配置文件。這裏先介紹配置文件,啟動方式如下: mongod --config /etc/mongodb.conf 配置如下:ve

nginx+gridfs+mongodb 配置訪問png圖片顯示無法加載問題

nginx配置文件 做了 nginx配置 副本 server port 問題 模塊 bject 上傳文件後,瀏覽器中請求:http://&lt;nginx server ip>:<port>/gfs/<my file> 瀏覽器出現“無法

mongodb配置和基本操作

特性 服務 win done service 基本 添加 close english MongoDB3.0新特性WiredTigerMMAPv1可插拔引擎API基於web的可視化管理工具 查看版本號mongod --version啟動數據庫 mongod --dbpath

nginx 1.12 配置解析php

alt 配置解析 cgi fast file lan try_files 技術 cati server { listen 80; server_name foo.com; root /path; index index.html index

附4 springboot源碼解析-run

chang tee fsmc lang hfs mcc beijing isa dma %E5%85%B3%E4%BA%8E%E7%BA%BF%E6%80%A7%E6%A8%A1%E5%9E%8B%E4%BD%A0%E5%8F%AF%E8%83%BD%E8%BF%98%E4

SSM整理筆記3——配置解析

repos gen bject sep scope resource att 2.x 處理 github:https://github.com/lakeslove/SSM 項目的目錄結構如下 首先,配置web.xml <?xml version="1.0" enc

第十二章 springboot + mongodb(復雜查詢)

參考 參數 iter extends lec con display itl dad 簡單查詢:使用自定義的XxxRepository接口即可。(見 第十一章 springboot + mongodb(簡單查詢)) 復雜查詢:使用MongoTemplate以及一些查詢

第十一章 springboot + mongodb(簡單查詢)

req all bool pan 可能 set 如果 創建 使用 1、mongodb在mac上的安裝 下載mongodb,https://www.mongodb.org/ 解壓縮到一個指定文件夾,如:/Users/enniu1/Desktop/zjg/mongodb

springboot RabbitMQ 配置

接收 handle mes 客戶端 fin ng- 技術 msg framework 引用自 http://www.cnblogs.com/ityouknow/p/6120544.html 自己留一份 記錄一下   RabbitMQ 即一個消息隊列,主要是用來實現應