ASP.NET Core - 配置系統之配置提供程式

来源:https://www.cnblogs.com/wewant/archive/2023/03/10/17110754.html
-Advertisement-
Play Games

3. 配置提供程式 上面提到,通過 IConfigurationBuilder 的實現類對象,我們可以自由地往配置系統中添加不同的配置提供程式,從而獲取不同來源的配置信息。.NET Core 中,微軟提供了以下這些內置的配置提供程式: 文件配置提供程式 環境變數配置提供程式 命令行配置提供程式 Az ...


3. 配置提供程式

上面提到,通過 IConfigurationBuilder 的實現類對象,我們可以自由地往配置系統中添加不同的配置提供程式,從而獲取不同來源的配置信息。.NET Core 中,微軟提供了以下這些內置的配置提供程式:

  • 文件配置提供程式
  • 環境變數配置提供程式
  • 命令行配置提供程式
  • Azure應用配置提供程式
  • Azure Key Vault 配置提供程式
  • Key-per-file配置提供程式
  • 記憶體配置提供程式
  • 應用機密(機密管理器)
  • 自定義配置提供程式

這裡稍微介紹一下常用的幾個。

3.1 文件配置提供程式

顧名思義,這個就是我們熟悉的配置載入方式,從配置文件中載入配置信息。配置文件多種多樣,.NET Core框架內置支持Json、xml、ini三種格式的文件提供程式:

  • JSON配置提供程式(JsonConfigurationProvider)
  • XML配置提供程式(XmlConfigurationProvider)
  • INI配置提供程式(IniConfigurationProvider)

以上這些配置提供程式,均繼承於抽象基類 FileConfigurationProvider,當一個提供程式中發現重覆的鍵時,提供程式會引發 FormatException,所有類型的文件提供程式都是這樣的機制。

另外,所有文件配置提供程式都支持提供兩個配置參數:

  • optional:bool類型,指示該文件是否是可選的。如果該參數為false,但是指定的文件又不存在,則會報錯。
  • reloadOnChange:bool類型,指示該文件發生更改時,是否要重新載入配置。

3.1.1 JSON配置提供程式

JSON配置提供程式被封裝在 Microsoft.Extensions.Configuration.Json Nuget包中,若通過 ConfigurationBuilder 自行構建配置系統需要先安裝該依賴包。它通過 JsonConfigurationProvider 在運行時從 Json 文件中載入配置。

使用方式非常簡單,通過 IConfigurationBuilder 的實現類對象調用 AddJsonFile 擴展方法指定Json配置文件的路徑即可。以下代碼可用於控制台程式中創建主機並設置配置系統:

using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

using var host = Host.CreateDefaultBuilder(args)
    .ConfigureAppConfiguration((context, config) =>
    {
        // 清除原有的配置提供程式
        config.Sources.Clear();

        var env = context.HostingEnvironment;
        // 添加 json 配置文件
        config.AddJsonFile("appsettings.json",true, true)
            .AddJsonFile($"appsetting.{env.EnvironmentName}.json", true, true);
    })
    .Build();

var configuration = host.Services.GetService<IConfiguration>();

Console.WriteLine($"Settings:Provider: {configuration.GetValue<string>("Settings:Provider")}");

host.Run();

appsetting.json 配置文件中的內容如下:

{
  "Settings": {
    "Provider": "JsonProvider",
    "version": {
      "subKey1": "value",
      "subKey2": 1
    },
    "items": [ "item1", "item2", "item3" ]
  }
}

控制台程式運行之後輸出如下:

image

這樣有一點要註意的是,對於我們手動添加的配置文件需要設置一下文件屬性,讓其在項目生成的時候能夠正常生成到運行目錄,確保應用可以正常獲取到該文件:

image

3.1.2 XML配置提供程式

XML配置提供程式被封裝在 Microsoft.Extensions.Configuration.Xml Nuget包中,通過 XmlConfigurationProvider 類在運行時從 XML 文件載入配置。

使用方式也很簡單,與 JSON 配置提供程式類似,通過 AddXmlFile 擴展方法指定配置文件路徑。

using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

using var host = Host.CreateDefaultBuilder(args)
    .ConfigureAppConfiguration((context, config) =>
    {
        // 清除原有的配置提供程式
        config.Sources.Clear();

        var env = context.HostingEnvironment;
        //// 添加 json 配置文件
        //config.AddJsonFile("appsettings.json",true, true)
        //    .AddJsonFile($"appsetting.{env.EnvironmentName}.json", true, true);

        config.AddXmlFile("appsettings.xml", true, true);
    })
    .Build();

var configuration = host.Services.GetService<IConfiguration>();

Console.WriteLine($"Settings:Provider: {configuration.GetValue<string>("Settings:Provider")}");
Console.WriteLine($"Settings:items[1]: {configuration.GetValue<string>("Settings:items:1")}");

host.Run();

xml配置文件內容如下:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
	<Settings>
		<Provider>XmlProvider</Provider>
		<version>
			<subKey1>value</subKey1>
			<subKey2>1</subKey2>
		</version>
		<items>item1</items>
		<items>item2</items>
		<items>item3</items>
	</Settings>
</configuration>

運行程式控制台輸出如下:

image

這裡有一個和版本有關的點,對Xml文件中使用同一元素名稱的重覆元素,一般也就是數組,.NET 6及之後的xml配置提供程式會自動為其編製索引,不再需要顯式指定name屬性。如果是 .NET 6 以下的版本則需要這樣了:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
	<Settings>
		<Provider>XmlProvider</Provider>
		<version>
			<subKey1>value</subKey1>
			<subKey2>1</subKey2>
		</version>
		<items name="itemkey1">item1</items>
		<items name="itemkey2">item2</items>
		<items name="itemkey3">item3</items>
	</Settings>
</configuration>
Console.WriteLine($"Settings:items[1]: {configuration.GetValue<string>("Settings:items:itemkey2")}");

另外xml文件中的屬性也可用於提供值:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <key attribute="value" />
  <section>
    <key attribute="value" />
  </section>
</configuration>

獲取屬性的值可用以下配置鍵:

key:attribute
section:key:attribute

3.1.3 INI配置提供程式

INI 配置提供程式被封裝在 Microsoft.Extensions.Configuration.Ini Nuget包,通過 IniConfigurationProvider 類在運行時從 INI 文件載入配置。使用方式如下:

using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

using var host = Host.CreateDefaultBuilder(args)
    .ConfigureAppConfiguration((context, config) =>
    {
        // 清除原有的配置提供程式
        config.Sources.Clear();

        var env = context.HostingEnvironment;
        //// 添加 json 配置文件
        //config.AddJsonFile("appsettings.json",true, true)
        //    .AddJsonFile($"appsetting.{env.EnvironmentName}.json", true, true);

        //config.AddXmlFile("appsettings.xml", true, true);

        config.AddIniFile("appsettings.ini", true, true);
    })
    .Build();

var configuration = host.Services.GetService<IConfiguration>();

Console.WriteLine($"Settings:Provider: {configuration.GetValue<string>("Settings:Provider")}");
Console.WriteLine($"Settings:items[1]: {configuration.GetValue<string>("Settings:items:1")}");

host.Run();

ini配置文件內容如下:

[Settings]
Provider="IniProvider"
version:subKey1="value"
version:subKey2=1
items:0="item1"
items:1="item2"
items:3="item3"

運行應用,控制台輸出如下:
image

3.2 環境變數配置提供程式

環境變數配置提供程式被封裝在 Microsoft.Extensions.Configuration.EnvironmentVariables, 通過 EnvironmentVariablesConfigurationProvider 在運行時從環境變數中以鍵值對的方式載入配置。

環境變數一般情況下是配置在機器上的,而不同的操作系統對環境變數的設置要求有所不同,當環境變數存在多層的時候,層級之間的分隔有些支持通過 : 號進行分隔,有些不支持,雙下劃線()是全平臺支持的,所以設置環境變數的時候要使用雙下劃線()來代替冒號(:)。

各種不同的平臺下怎麼去添加環境變數這裡就不細說了,Windows 下大家最起碼都應該知道可以通過 我的電腦 -> 屬性 -> 高級系統設置 去可視化的添加,命令行的方式可閱讀下官方文章: ASP.NET Core 中的配置 | Microsoft Learn,Linux 平臺下可以通過 export 命令臨時添加,或者修改相應的配置文件 ~/.bashrc 或 /etc/profile,大家仔細查一下資料就行了。

處理在機器上直接設置環境變數外,我們開發測試的過程中也可以通過 ASP.NET Core框架下的 launchSettings.json 配置文件設置用於調試的臨時環境變數。在應用啟動調試時,該文件中的環境變數會替代系統的中的環境變數。

{
  "$schema": "https://json.schemastore.org/launchsettings.json",
  "profiles": {
    "ConfigurationSample": {
      "commandName": "Project",
      "dotnetRunMessages": true,
      "launchBrowser": true,
      "launchUrl": "swagger",
      "applicationUrl": "http://localhost:5004",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development",
        "Custom_settings__Provider": "EnvironmentVariablesProvider",
        "Custom_settings__version__subKey1": "value",
        "Custom_settings__items__0": "item1",
        "Custom_settings__items__1": "item2",
        "Custom_settings__items__2": "item3"
      }
    }
  }
}

環境變數配置提供程式使用也很簡單,註意以下示例為了使用 launchSettings.json 中的環境變數是在 ASP.NET Core項目中測試的。

var builder = WebApplication.CreateBuilder(args);

builder.Host.ConfigureAppConfiguration(builder =>
{
    builder.Sources.Clear();
    // 篩選前置為 Custom_ 的環境變數,將其載入為應用配置,其他的不載入
    builder.AddEnvironmentVariables("Custom_");
});

var app = builder.Build();

Console.WriteLine($"Settings:Provider: {app.Configuration.GetValue<string>("Settings:Provider")}");
Console.WriteLine($"Settings:items[1]: {app.Configuration.GetValue<string>("Settings:items:1")}");

app.Run();

在添加環境變數時,通過指定參數 prefix,只讀取限定首碼的環境變數。不過在讀取環境變數時,會將首碼刪除。如果不指定參數 prefix,那麼會讀取所有環境變數。

當創建預設通用主機(Host)時,預設就已經添加了首碼為 DOTNET_ 的環境變數,如果是在 ASP.NET Core 中,配置了 Web主機時,預設添加了首碼為 ASPNETCORE_ 的環境變數,而後主機載入應用配置時,再根據策略添加了其他的環境變數,如果沒有傳遞 prefix 參數則是所有環境變數。這一塊的載入機制,下麵再細講。

運行應用,控制台輸出如下:
image

除此之外,環境變數提供程式還有一些隱藏的功能點,當沒有向 AddEnvironmentVariables 傳入首碼時,預設也會針對含有以下首碼的環境變數進行特殊處理:

image

這個功能點比較少用到,但是大家看到這個大概都會有點疑惑,具體的形式是怎麼樣的,下麵稍微測試一下

首先在 launchSettings.json 文件中添加多一個環境變數:

"MYSQLCONNSTR_Default": "Server=myServerAddress;Database=myDataBase;Uid=myUsername;Pwd=myPassword;"

之後在應用中列印如下兩個配置:

Console.WriteLine($"ConnectionStrings:Default: { app.Configuration.GetValue<string>("ConnectionStrings:Default") }");
Console.WriteLine($"ConnectionStrings:Default_Provider: { app.Configuration.GetValue<string>("ConnectionStrings:Default_ProviderName") }");

輸出結果如下:
image

也就是說,這種形式的環境變數會被自動轉換為兩個。

3.3 命令行配置提供程式

命令行配置提供程式被封裝在 Microsoft.Extensions.Configuration.CommandLine 包中,通過CommandLineConfigurationProvider在運行時從命令行參數鍵值對中載入配置。

當我們通過 dotnet 命令啟動一個 .NET Core 應用時,我們可以在命令後面追加一些參數,這些參數將在入口文件中被 args 變數接收到。命令行配置提供程式使用如下:

using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

using var host = Host.CreateDefaultBuilder(args)
    .ConfigureAppConfiguration((context, config) =>
    {
        // 清除原有的配置提供程式
        config.Sources.Clear();
        config.AddCommandLine(args);
    })
    .Build();

var configuration = host.Services.GetService<IConfiguration>();

Console.WriteLine($"Settings:Provider: {configuration.GetValue<string>("Settings:Provider")}");
Console.WriteLine($"Settings:items[1]: {configuration.GetValue<string>("Settings:items:1")}");

host.Run();

之後通過命令行程式啟動應用,並傳入相應的參數:

dotnet ConfigurationSampleConsole.dll Settings:Provider=CommandLineProvider Settings:items:1=item1

image

命令行參數的設置有三種方式:

(1) 使用 = 號連接鍵值:

dotnet ConfigurationSampleConsole.dll Settings:Provider=CommandLineProvider Settings:items:0=item1 Settings:items:1=item2

(2) 使用 / 號表示鍵,值跟在鍵後面,鍵值以空格分隔

dotnet ConfigurationSampleConsole.dll /Settings:Provider CommandLineProvider /Settings:items:0 item1 /Settings:items:1 item2

(3) 使用 -- 符號表示鍵,值跟在鍵後面,鍵值以空格分隔

dotnet ConfigurationSampleConsole.dll --Settings:Provider CommandLineProvider --Settings:items:0 item1 --Settings:items:1 item2

如果值之中本來就有空格的,可以使用 "" 號包括。

dotnet ConfigurationSampleConsole.dll --Settings:Provider CommandLineProvider --Settings:items:0 item1 --Settings:items:1 "test item2"

AddCommandLine 擴展方法提供了重載,允許額外傳入一個參數,該參數提供一個交換映射字典,針對命令行配置參數進行key映射。例如命令行傳入鍵是 name01 ,映射後的的鍵為 project:name。這裡有一些要註意的點:

  • 交換映射key必須以-或--開頭。當使用-開頭時,命令行參數書寫時也要以-開頭,當使用--開頭時,命令行參數書寫時可以以--或/開頭。
  • 交換映射字典中的key不區分大小寫,不能包含重覆 key。如不能同時出現-n和-N,但可以同時出現 -n 和 --n 。
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

using var host = Host.CreateDefaultBuilder(args)
    .ConfigureAppConfiguration((context, config) =>
    {
        // 清除原有的配置提供程式
        config.Sources.Clear();

        var switchMappings = new Dictionary<string, string>
        {
            ["--b1"] = "Settings:Provider",
            ["-b2"] = "Settings:items"
        };

        config.AddCommandLine(args, switchMappings);
    })
    .Build();

var configuration = host.Services.GetService<IConfiguration>();

Console.WriteLine($"Settings:Provider: {configuration.GetValue<string>("Settings:Provider")}");
Console.WriteLine($"Settings:items[1]: {configuration.GetValue<string>("Settings:items:1")}");

host.Run();

image

3.4 記憶體配置提供程式

記憶體配置提供程式就比較簡單了,它直接被包含在 Microsoft.Extensions.Configuration,通過MemoryConfigurationProvider在運行時從記憶體中的集合中載入配置。使用方式如下:

using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

using var host = Host.CreateDefaultBuilder(args)
    .ConfigureAppConfiguration((context, config) =>
    {
        // 清除原有的配置提供程式
        config.Sources.Clear();

        config.AddInMemoryCollection(new Dictionary<string, string> {
            { "Settings:Provider", "InMemoryProvider" },
            { "Settings:items:1", "MemoryItem" }
        });
    })
    .Build();

var configuration = host.Services.GetService<IConfiguration>();

Console.WriteLine($"Settings:Provider: {configuration.GetValue<string>("Settings:Provider")}");
Console.WriteLine($"Settings:items[1]: {configuration.GetValue<string>("Settings:items:1")}");

host.Run();![image]

image

3.5 配置載入順序

上面介紹了一些常用的配置提供程式,這些配置提供程式都是通過擴展方法添加到 ConfigurationBuilder 對象中的,而從上面 ConfigurationBuilder 的源碼可以看出,添加一個配置提供程式的時候其實應該是添加了一個對應的 IConfigurationSource 對象,而後在 ConfigurationBuilder 中被保存到集合中。

這就可以看出,配置系統是允許同時添加多種配置提供程式,支持多來源的配置信息同時存在的。那麼當多個配置處理程式都被添加到配置系統之中,那我們從配置系統中通過配置鍵獲取配置值的時候是怎麼進行的呢,當多個配置提供程式存在相同的配置鍵時,我們獲取到的配置值是哪個呢?

從 ConfigurationRoot 的源碼中可以可以看到,當我們用索引器 API 讀取配置值時,是調用了 GetConfiguration 方法

image

而 GetConfiguration 方法中的邏輯也很簡單,只是遍歷提供程式集合嘗試從提供程式去獲取值,需要關註的是遍歷的順序。

image

這裡的邏輯是這樣子的,倒敘進行遍歷,後添加的配置處理程式先被遍歷,一旦通過key從提供程式中獲取到值就返回結果,不再繼續遍歷。所以添加配置提供程式的順序決定相同配置鍵最終的值, 當多個配置處理程式存在相同鍵時,越後添加的配置提供程式優先順序越高,從最後的一個提供程式獲取到值之後就不再從其他處理程式獲取。

3.6 預設配置來源

上面也有提到通過主機運行和管理應用,在通過主機運行的項目中,主機在啟動的時候就已經預設添加了一些配置提供程式,所以我們創建了一個 ASP.NET Core 模板項目之後就可以獲取到 appsettings.json 等配置文件中的配置信息。下麵介紹一下預設添加的配置提供程式。

Host.CreateDefaultBuilder(String[]) 方法或者 WebApplication.CreateBuilder(args) 方法執行的時候,會按照以下順序添加應用的配置提供程式:

(1) 記憶體配置提供程式
(2) Chained 配置提供程式(添加現有的主機配置)
(3) JSON 配置提供程式 (添加 appsettings.json 配置文件)
(4) JSON 配置提供程式 (添加 appsettings.{Environment}.json 配置文件)
(5) 機密管理器(僅Windows)
(6) 環境變數配置提供程式 (未限定首碼)
(7) 命令行配置提供程式

配置分主機配置和應用配置,主機啟動時應用仍未啟動,主機啟動過程中的配置就是主機配置。上面第一個Chained 配置提供程式就是承接過來的主機配置。而主機配置是按照以下順序載入的:

(1) 環境變數配置提供程式(以 DOTNET_ 為首碼的環境變數)
(2) 命令行配置提供程式 (命令行參數)
(3) 環境變數配置提供程式(以 ASPNETCORE_ 為首碼的環境變數,如果是Web主機的話)

所以最終的應用配置載入順序應該是下麵這樣:

(1) 記憶體配置提供程式
(2) 環境變數配置提供程式(以 DOTNET_ 為首碼的環境變數)
(3) 命令行配置提供程式 (命令行參數)
(4) 環境變數配置提供程式(以 ASPNETCORE_ 為首碼的環境變數,如果是Web主機的話)
(5) JSON 配置提供程式 (添加 appsettings.json 配置文件)
(6) JSON 配置提供程式 (添加 appsettings.{Environment}.json 配置文件)
(7) 機密管理器(僅Windows)
(8) 環境變數配置提供程式 (未限定首碼)
(9) 命令行配置提供程式 (命令行參數)

按照越後面添加的提供程式優先的方式,最終應用配置會覆蓋主機配置,並且最優先是最後添加的命令行配置提供程式,我們可以通過以下方式列印配置系統中所有的配置提供程式,進行驗證:

var builder = WebApplication.CreateBuilder(args);

var app = builder.Build();

var configurationRoot = (IConfigurationRoot)app.Configuration;
foreach (var provider in configurationRoot.Providers.AsEnumerable())
{
    Console.WriteLine(provider.ToString());
}

app.Run();

最終控制台列印出來的結果如下:

最終控制台列印出來的結果如下:image

雖然應用配置優先,會覆蓋前面的主機配置,但是有一些變數會在初始化主機生成器的時候就提前進行鎖定,並且之後不會受應用配置的影響:

這裡提到環境名稱,其實也就是軟體運行的環境,最最基本的也會分為開發環境、生產環境兩種。軟體運行環境通過環境變數來設置,普通的.NET Core 應用環境變數key為NETCORE_ENVIRONMENT,Web應用環境變數key為ASPNETCORE_ENVIRONMENT,Web應用下如果兩者同時存在,後者會覆蓋前者。軟體應用根據不同的環境會有不同的行為邏輯,例如上面講到的 appsettings.{environment}.json 根據環境而不同的配置文件,例如之前的 入口文件 文章中講到的 Startup 文件根據不同環境的分離配置方式,而我們在代碼中有時也會根據環境處理不同的邏輯,這時候我們可以註入 IHostEnvironment 服務,通過它獲取當前應用的運行環境,入口文件中無論是 WebApplicationBuilder 對象還是 WebApplication 對象都包含該類型的屬性。

通過環境變數設置當前運行環境,其實環境變數的值只是一個字元串,我們可以設置成任意值,這是運行的,.NET Core 框架下 IHostEnvironment 也能夠正常載入到相應的環境名稱,但是.NET Core 預設只提供了對 Development、Production 和 Staging 三種環境的判別,以及相應的處理邏輯和擴展方法,如果是其他的自定義環境則需要開發人員自行進行相應的處理了。和 .NET Core 應用環境相關的知識點大家可以看一下官方文檔: 在 ASP.NET Core 中使用多個環境 | Microsoft Learn

除了上面講到的主機配置,其他還有一些主機配置,例如URLS,但這個是可以通過應用配置設置的,讀取相應的配置值時也應用從應用配置讀取。

URLS 配置Web應用啟動後的訪問地址,這個配置可以多個地方設置,其中命令行參數最優先,其他地方設置的應該被命令行參數覆蓋。但是如果通過Kestrel 終結點方式設置了Web應用的訪問地址,那Kestrel 終結點的配置將覆蓋其他所有的訪問地址的配置。

如在 appsettings.json 中添加以下配置:

"Kestrel": {
    "Endpoints": {
      "Https": {
        "Url": "https://localhost:9999"
      }
    }
  }

那麼以下幾種方式設置的 URLS 都會失效:

  • UseUrls
  • 命令行上的 --urls
  • 環境變數 ASPNETCORE__URLS

也就是說,就算我們用以下命令啟動應用,應用最終的訪問地址還是以Kestrel終結點配置的為準:

dotnet run --urls="https://localhost:7777"

Kestrel 配置與 URLS 配置不是一個參數,我們可以通過在命令行或者環境變數中設置 kestrel 中間點配置來覆蓋 appsettings.json 中的,這又回到配置提供程式的優先順序問題了。

set Kestrel__Endpoints__Https__Url=https://localhost:8888

dotnet run Kestrel__Endpoints__Https__Url=https://localhost:8888

在主機啟動的邏輯中Kestrel具備更高的最終優先順序,但是其實主機內部是先根據URLS創建了一個終結點,之後又替換為 Kestrel 配置的終結點的。通過應用啟動時的控制台輸出可以看出。

image

這種情況對於單機應用沒有什麼影響,但是對於使用自動服務發現的微服務架構而言就可能有問題了,可能導致註冊服務註冊中心的終結點是第一個,而後應用終結點又被改變,導致註冊中心記錄的服務終結點和實際的不一致。

這一篇的內容比較多,但是不大好拆分,整個知識點是一個整體,通過這一章的內容相信大家能夠對 .NET Core 框架配置系統內部的工作原理有一個詳細的瞭解。



參考文章:

ASP.NET Core 中的配置 | Microsoft Learn
配置 - .NET | Microsoft Learn
理解ASP.NET Core - 配置(Configuration)



ASP.NET Core 系列:
目錄:ASP.NET Core 系列總結
上一篇:ASP.NET Core - 配置系統之配置添加


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 2023Java面試題最經典的問題之一了,非常經典的Java基礎知識,一定要學會! 在Java中,String類被設計成final,這意味著它的值在創建後不可更改。這是因為字元串在Java中使用廣泛,作為文本處理、網路通信等方面的核心數據類型。如果String類是可變的,那麼在使用時可能會出現安全問 ...
  • 最近發現一個不錯的免費開源學習項目:30天學會Python 如果您最近有學習Python的打算,不妨看看這個是否適合你? 項目地址:https://github.com/Asabeneh/30-Days-Of-Python 博客地址:https://blog.didispace.com/tj-30- ...
  • 最新版 IDEA 2022.3.2 中配置熱載入工具 DevTools 在SpringBoot開發調試中,如果我每行代碼的修改都需要重啟再調試,可能比較費時間;SpringBoot團隊針對此問題提供了spring-boot-devtools(簡稱devtools)插件,用此插件提升開發調試的效率。 ...
  • 前言 之前寫過一篇基於ML.NET的手部關鍵點分類的博客,可以根據圖片進行手部的提取分類,於是我就將手勢分類和攝像頭數據結合,集成到了我開發的電子腦殼軟體里。 電子腦殼是一個為稚暉君開源的桌面機器人ElectronBot提供一些軟體功能的桌面程式項目。它是由綠蔭阿廣也就是我開發的,使用了微軟的WAS ...
  • 最近在使用 Blazor 開發管理後臺時遇到瞭如下的問題,我這裡後臺整體採用了 AntDesignBlazor 組件庫,在上線之後發現ReuseTabs組件在使用過程中,如果預設 / 沒有指定為項目的base href,打開標簽頁後,相互切換會導致url錯誤。 本地開發的時候項目是直接啟動運行的,所 ...
  • 在DNF中,角色貼圖以.ani文件的坐標為中心,NPK中png的坐標為繪製坐標(坐上)進行繪製,繪製的結果如圖所示: 原點坐標-232,-333 原點坐標-232,-333 皮膚坐標207,224 皮膚坐標207,224 太刀柄194,264 太刀柄194,264 太刀刃213,283 太刀刃213 ...
  • 概述 非同步這個概念在不同語境下有不同的解釋,比如在一個單核CPU里開啟兩個線程執行兩個函數,通常認為這種調用是非同步的,但對於CPU來說它是單核不可能同時運行兩個函數,不過是由系統調度在不同的時間分片中執行。一般來說,如果兩個工作能同時進行,就認為是非同步的。在編程中,它通常代表函數的調用可以在不執行完 ...
  • 1 - 文本控制項 我們熟悉的文本控制項不外乎TextBox,RichTextBox。在WPF中還有一個PasswordBox,不過區分於前者的區別就是PasswordBox是直接繼承於Control的比較特殊,前三者是繼承於TextBoxBase的。接下來我們就簡單介紹下這幾個控制項。 1.1 - 多行 ...
一周排行
    -Advertisement-
    Play Games
  • 前言 在我們開發過程中基本上不可或缺的用到一些敏感機密數據,比如SQL伺服器的連接串或者是OAuth2的Secret等,這些敏感數據在代碼中是不太安全的,我們不應該在源代碼中存儲密碼和其他的敏感數據,一種推薦的方式是通過Asp.Net Core的機密管理器。 機密管理器 在 ASP.NET Core ...
  • 新改進提供的Taurus Rpc 功能,可以簡化微服務間的調用,同時可以不用再手動輸出模塊名稱,或調用路徑,包括負載均衡,這一切,由框架實現並提供了。新的Taurus Rpc 功能,將使得服務間的調用,更加輕鬆、簡約、高效。 ...
  • 順序棧的介面程式 目錄順序棧的介面程式頭文件創建順序棧入棧出棧利用棧將10進位轉16進位數驗證 頭文件 #include <stdio.h> #include <stdbool.h> #include <stdlib.h> 創建順序棧 // 指的是順序棧中的元素的數據類型,用戶可以根據需要進行修改 ...
  • 前言 整理這個官方翻譯的系列,原因是網上大部分的 tomcat 版本比較舊,此版本為 v11 最新的版本。 開源項目 從零手寫實現 tomcat minicat 別稱【嗅虎】心有猛虎,輕嗅薔薇。 系列文章 web server apache tomcat11-01-官方文檔入門介紹 web serv ...
  • C總結與剖析:關鍵字篇 -- <<C語言深度解剖>> 目錄C總結與剖析:關鍵字篇 -- <<C語言深度解剖>>程式的本質:二進位文件變數1.變數:記憶體上的某個位置開闢的空間2.變數的初始化3.為什麼要有變數4.局部變數與全局變數5.變數的大小由類型決定6.任何一個變數,記憶體賦值都是從低地址開始往高地 ...
  • 如果讓你來做一個有狀態流式應用的故障恢復,你會如何來做呢? 單機和多機會遇到什麼不同的問題? Flink Checkpoint 是做什麼用的?原理是什麼? ...
  • C++ 多級繼承 多級繼承是一種面向對象編程(OOP)特性,允許一個類從多個基類繼承屬性和方法。它使代碼更易於組織和維護,並促進代碼重用。 多級繼承的語法 在 C++ 中,使用 : 符號來指定繼承關係。多級繼承的語法如下: class DerivedClass : public BaseClass1 ...
  • 前言 什麼是SpringCloud? Spring Cloud 是一系列框架的有序集合,它利用 Spring Boot 的開發便利性簡化了分散式系統的開發,比如服務註冊、服務發現、網關、路由、鏈路追蹤等。Spring Cloud 並不是重覆造輪子,而是將市面上開發得比較好的模塊集成進去,進行封裝,從 ...
  • class_template 類模板和函數模板的定義和使用類似,我們已經進行了介紹。有時,有兩個或多個類,其功能是相同的,僅僅是數據類型不同。類模板用於實現類所需數據的類型參數化 template<class NameType, class AgeType> class Person { publi ...
  • 目錄system v IPC簡介共用記憶體需要用到的函數介面shmget函數--獲取對象IDshmat函數--獲得映射空間shmctl函數--釋放資源共用記憶體實現思路註意 system v IPC簡介 消息隊列、共用記憶體和信號量統稱為system v IPC(進程間通信機制),V是羅馬數字5,是UNI ...