分類: 3C資訊

  • 程序員需要了解的硬核知識之操作系統和應用

    程序員需要了解的硬核知識之操作系統和應用

    利用計算機運行程序大部分都是為了提高處理效率。例如,Microsoft Word 這樣的文字處理軟件,是用來提高文本文件處理效率的程序,Microsoft Excel 等表格計算軟件,是用來提高賬本處理效率的程序。這種為了提高特定處理效率的程序統稱為 應用

    程序員的工作就是編寫各種各樣的應用來提高工作效率,程序員一般不編寫操作系統,但是程序員編寫的應用離不開操作系統,此篇文章我們就針對 Windows 操作系統來說明一下操作系統和應用之間的關係。

    操作系統功能的歷史

    操作系統其實也是一種軟件,任何新事物的出現肯定都有它的歷史背景,那麼操作系統也不是憑空出現的,肯定有它的歷史背景。

    在計算機尚不存在操作系統的年代,完全沒有任何程序,人們通過各種按鈕來控制計算機,這一過程非常麻煩。於是,有人開發出了僅具有加載和運行功能的監控程序,這就是操作系統的原型。通過事先啟動監控程序,程序員可以根據需要將各種程序加載到內存中運行。雖然仍舊比較麻煩,但比起在沒有任何程序的狀態下進行開發,工作量得到了很大的緩解。

    隨着時代的發展,人們在利用監控程序編寫程序的過程中發現很多程序都有公共的部分。例如,通過鍵盤進行文字輸入,显示器進行數據展示等,如果每編寫一個新的應用程序都需要相同的處理的話,那真是太浪費時間了。因此,基本的輸入輸出部分的程序就被追加到了監控程序中。初期的操作系統就是這樣誕生了。

    類似的想法可以共用,人們又發現有更多的應用程序可以追加到監控程序中,比如硬件控製程序編程語言處理器(彙編、編譯、解析)以及各種應用程序等,結果就形成了和現在差異不大的操作系統,也就是說,其實操作系統是多個程序的集合體。

    我在 這篇文章中提到了彙編語言,這裏簡單再提一下。

    彙編語言是一種低級語言,也被稱為符號語言。彙編語言是第二代計算機語言,在彙編語言中,用助記符代替機器指令的操作碼,用地址符號或標號代替指令或操作數的地址。用一些容易理解和記憶的字母,單詞來代替一個特定的指令,比如:用ADD代表数字邏輯上的加減,MOV代表數據傳遞等等,通過這種方法,人們很容易去閱讀已經完成的程序或者理解程序正在執行的功能,對現有程序的bug修復以及運營維護都變得更加簡單方便

    可以說共用思想真是人類前進的一大步,對於解放生產力而言簡直是太重要了

    要把操作系統放在第一位

    對於程序員來說,程序員創造的不是硬件,而是各種應用程序,但是如果程序員只做應用不懂硬件層面的知識的話,是無法成為硬核程序員的。現在培訓機構培養出了一批怎麼用的人才,卻沒有培訓出為什麼這麼做的人才,畢竟為什麼不是培訓機構教的,而是學校教的,我很相信耗子叔說的話:學習沒有速成這回事。言歸正題。

    在操作系統誕生之後,程序員不需要在硬件層面考慮問題,所以程序員的數量就增加了。哪怕自稱對硬件一竅不通的人也可能製作出一個有模有樣的程序。不過,要想成為一個全面的程序員,有一點需要清楚的就是,掌握硬件的基本知識,並藉助操作系統進行抽象化,可以大大提高編程效率。

    下面就看一下操作系統是如何給開發人員帶來便利的,在 Windows 操作系統下,用 C 語言製作一個具有表示當前時間功能的應用。time() 是用來取得當前日期和時間的函數,printf() 是把結果打印到显示器上的函數,如下:

    #include <stdio.h>
    #include <time.h>
    
    void main(){
      // 保存當前日期和時間信息
      time_t tm;
      
      // 取得當前的日期和時間
      time(&tm);
      
      // 在显示器上显示日期和時間
      printf("%s\n", ctime(&tm));
    }

    讀者可以自行運行程序查看結果,我們主要關注硬件在這段代碼中做了什麼事情

    • 通過 time_t tm,為 time_t 類型的變量申請分配內存空間;
    • 通過 time(&tm) ,將當前的日期和時間數據保存到變量的內存空間中
    • 通過 printf(“%s\n”,ctime(&tm)), 把變量內存空間的內容輸出到显示器上。

    應用的可執行文件指的是,計算機的 CPU 可以直接解釋並運行的本地代碼,不過這些代碼是無法直接控制硬件的,事實上,這些代碼是通過操作系統來間接控制硬件的。變量中涉及到的內存分配情況,以及 time() 和 printf() 這些函數的運行結果,都不是面向硬件而是面向操作系統的。操作系統收到應用發出的指令后,首先會對該指令進行解釋,然後會對 時鐘IC 和显示器用的 I/O 進行控制。

    計算機中都安裝有保存日期和時間的實時時鐘(Real-time clock),上面提到的時鐘IC 就是值該實時時鐘。

    系統調用和編程語言的移植性

    操作系統控制硬件的功能,都是通過一些小的函數集合體的形式來提供的。這些函數以及調用函數的行為稱為系統調用,也就是通過應用進而調用操作系統的意思。在前面的程序中用到了 time() 以及 printf() 函數,這些函數內部也封裝了系統調用。

    C 語言等高級編程語言並不依存於特定的操作系統,這是因為人們希望不管是Windows 操作系統還是 Linux 操作系統都能夠使用相同的源代碼。因此,高級編程語言的機制就是,使用獨自的函數名,然後在編譯的時候將其轉換為系統調用的方式(也有可能是多個系統調用的組合)。也就是說,高級語言編寫的應用在編譯后,就轉換成了利用系統調用的本地代碼

    不過,在高級語言中也存在直接調用系統調用的編程語言,不過,利用這種方式做成應用,移植性並不友好。

    移植性:移植性指的是同樣的程序在不同操作系統下運行時所花費的時間,時間越少證明移植性越好。

    操作系統和高級編程語言使硬件抽象化

    通過使用操作系統提供的系統調用,程序員不必直接編寫控制硬件的程序,而且,通過使用高級編程語言,有時也無需考慮系統調用的存在,系統調用往往是自動觸發的,操作系統和高級編程語言能夠使硬件抽象化,這很了不起。

    下面讓我們看一個硬件抽象化的具體實例

    #include <stdio.h>
    
    void main(){
      
      // 打開文件
      FILE *fp = fopen("MyFile.txt","w");
      
      // 寫入文件
      fputs("你好", fp);
      
      // 關閉文件
      fclose(fp);
    }

    上述代碼使用 C 編寫的程序,fputs() 是用來往文件中寫入字符串的函數,fclose() 是用來關閉文件的函數。

    上述應用在編譯運行后,會向文件中寫入 “你好” 字符串。文件是操作系統對磁盤空間的抽象化,就如同我們在 這篇文章提到的一樣,磁盤就如同樹的年輪,磁盤的讀寫是以扇區為單位的,通過磁道來尋址,如果直接對硬件讀寫的話,那麼就會變為通過向磁盤用的 I/O 指定扇區位置來對數據進行讀寫了。

    但是,在上面代碼中,扇區壓根就沒有出現過傳遞給 fopen() 函數的參數,是文件名 MyFile.txt 和指定文件寫入的 w。傳遞給 fputs() 的參數,是往文件中寫入的字符串”你好” 和 fp,傳遞給 fclose() 的參數,也僅僅是 fp,也就是說磁盤通過打開文件這個操作,把磁盤抽象化了,打開文件這個操作就可以說是操作硬件的指令。

    下面讓我們來看一下代碼清單中 fp 的功能,變量 fp 中被賦予的是 fopen() 函數的返回值,該值被稱為文件指針。應用打開文件后,操作系統就會自動申請分配用來管理文件讀寫的內存空間。內存地址可以通過 fopen() 函數的返回值獲得。用 fopen() 打開文件后,接下來就是通過制定的文件指針進行操作,正因為如此,fputs() 和 fclose() 以及 fclose() 參數中都制定了文件指針。

    由此我們可以得出一個結論,應用程序是通過系統調用,磁盤抽象來實現對硬盤的控制的。

    Windows 操作系統的特徵

    Windows 操作系統是世界上用戶數量最龐大的群體,作為 Windows 操作系統的資深用戶,你都知道 Windows 操作系統有哪些特徵嗎?下面列舉了一些 Windows 操作系統的特性

    • Windows 操作系統有兩個版本:32位和64位
    • 通過 API 函數集成來提供系統調用
    • 提供了採用圖形用戶界面的用戶界面
    • 通過 WYSIWYG 實現打印輸出,WYSIWYG 其實就是 What You See Is What You Get ,值得是显示器上显示的圖形和文本都是可以原樣輸出到打印機打印的。
    • 提供多任務功能,即能夠同時開啟多個任務
    • 提供網絡功能和數據庫功能
    • 通過即插即用實現設備驅動的自設定

    這些是對程序員來講比較有意義的一些特徵,下面針對這些特徵來進行分別的介紹

    32位操作系統

    這裏表示的32位操作系統表示的是處理效率最高的數據大小。Windows 處理數據的基本單位是 32 位。這與最一開始在 MS-DOS 等16位操作系統不同,因為在16位操作系統中處理32位數據需要兩次,而32位操作系統只需要一次就能夠處理32位的數據,所以一般在 windows 上的應用,它們的最高能夠處理的數據都是 32 位的。

    比如,用 C 語言來處理整數數據時,有8位的 char 類型,16位的short類型,以及32位的long類型三個選項,使用位數較大的 long 類型進行處理的話,增加的只是內存以及磁盤的開銷,對性能影響不大。

    現在市面上大部分都是64位操作系統了,64位操作系統也是如此。

    通過 API 函數集來提供系統調用

    Windows 是通過名為 API 的函數集來提供系統調用的。API是聯繫應用程序和操作系統之間的接口,全稱叫做 Application Programming Interface,應用程序接口。

    當前主流的32位版 Windows API 也稱為 Win32 API,之所以這樣命名,是需要和不同的操作系統進行區分,比如最一開始的 16 位版的 Win16 API,和後來流行的 Win64 API

    API 通過多個 DLL 文件來提供,各個 API 的實體都是用 C 語言編寫的函數。所以,在 C 語言環境下,使用 API 更加容易,比如 API 所用到的 MessageBox() 函數,就被保存在了 Windows 提供的 user32.dll 這個 DLL 文件中。

    提供採用了 GUI 的用戶界面

    GUI(Graphical User Interface) 指得就是圖形用戶界面,通過點擊显示器中的窗口以及圖標等可視化的用戶界面,舉個例子:Linux 操作系統就有兩個版本,一種是簡潔版,直接通過命令行控制硬件,還有一種是可視化版,通過光標點擊圖形界面來控制硬件。

    通過 WYSIWYG 實現打印輸出

    WYSIWYG 指的是显示器上輸出的內容可以直接通過打印機打印輸出。在 Windows 中,显示器和打印機被認作同等的圖形輸出設備處理的,該功能也為 WYSIWYG 提供了條件。

    藉助 WYSIWYG 功能,程序員可以輕鬆不少。最初,為了是現在显示器中显示和在打印機中打印,就必須分別編寫各自的程序,而在 Windows 中,可以藉助 WYSIWYG 基本上在一個程序中就可以做到显示和打印這兩個功能了。

    提供多任務功能

    多任務指的就是同時能夠運行多個應用程序的功能,Windows 是通過時鐘分割技術來實現多任務功能的。時鐘分割指的是短時間間隔內,多個程序切換運行的方式。在用戶看來,就好像是多個程序在同時運行,其底層是 CPU 時間切片,這也是多線程多任務的核心。

    提供網絡功能和數據庫功能

    Windows 中,網絡功能是作為標準功能提供的。數據庫(數據庫服務器)功能有時也會在後面追加。網絡功能和數據庫功能雖然並不是操作系統不可或缺的,但因為它們和操作系統很接近,所以被統稱為中間件而不是應用。意思是處於操作系統和應用的中間層,操作系統和中間件組合在一起,稱為系統軟件。應用不僅可以利用操作系統,也可以利用中間件的功能。

    相對於操作系統一旦安裝就不能輕易更換,中間件可以根據需要進行更換,不過,對於大部分應用來說,更換中間件的話,會造成應用也隨之更換,從這個角度來說,更換中間件也不是那麼容易。

    通過即插即用實現設備驅動的自動設定

    即插即用(Plug-and-Play)指的是新的設備連接(plug) 后就可以直接使用的機制,新設備連接計算機后,計算機就會自動安裝和設定用來控制該設備的驅動程序

    設備驅動是操作系統的一部分,提供了同硬件進行基本的輸入輸出的功能。鍵盤、鼠標、显示器、磁盤裝置等,這些計算機中必備的硬件的設備驅動,一般都是隨操作系統一起安裝的。

    有時 DLL 文件也會同設備驅動文件一起安裝。這些 DLL 文件中存儲着用來利用該新追加的硬件API,通過 API ,可以製作出運行該硬件的心應用。

    文章參考:

    《程序是怎樣跑起來的》第九章

    關注公眾號後台回復 191106 即可獲得《程序是怎樣跑起來的》电子書

    本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理
    【其他文章推薦】

    台北網頁設計公司這麼多,該如何挑選?? 網頁設計報價省錢懶人包”嚨底家”

    網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

    ※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

    小三通海運與一般國際貿易有何不同?

    小三通快遞通關作業有哪些?

  • 【原創】使用批處理腳本自動生成並上傳NuGet包

    【原創】使用批處理腳本自動生成並上傳NuGet包

      Hello 大家好,我是TANZAME,我們又見面了。

      NuGet 是什麼這裏就不再重複啰嗦,園子里一搜一大把。今天要跟大家分享的是,在日常開發過程中如何統一管理我們的包,如何通過批處理腳本生成包並自動上傳到 NuGet。在實際項目開發過程中我們要上傳自己的包,一般的步驟都是:nuget spec => nuget pack => nuget push,一個包都要至少重複三個動作,如果有 N 個包那就要重複 N*3 次,想想都不能忍,所以便有了今天的分享主題。

    • 生成目錄

      既然是統一管理,生成的包自然是放在同一個文件夾,而不是分散在各個 .proj 目錄里。這裏我們在解決方案所在目錄新建一個目錄,這樣做的目的是方便 bat 腳本找到解決方案下面的子項目。比如我這裏新建的是 .nuget 這個目錄,需要注意的是如果目錄名稱有特殊字符的話不能直接右鍵新建,需要用命令提示符,直接在解決方案所在目錄使用快捷鍵 SHIFT + 右鍵 就能直接打開命令提示符,這樣可以省去一大堆 cd 的操作。

     

    • 下載 NuGet

      到 NuGet 官網下載命令行接口(CLI)。nuget.exe提供了完整的 nuget 功能, 可用於安裝、創建、發布和管理包, 而無需對項目文件進行任何更改。

    1. 請訪問 ,並選擇 NuGet 3.3 或更高版本(2.8.6 與 Mono 不兼容)。 始終建議使用最新版。若要將包發布到 nuget.org,版本至少必須是 4.1.0。
    2. 每次下載都直接下載 nuget.exe 文件。 讓瀏覽器將文件保存到選定文件夾。 此文件不 是安裝程序;如果直接在瀏覽器中運行,就不會看到任何內容。
    3. 將文件夾添加到 nuget.exe 中放置 PATH 環境變量的位置,這樣就可以從任意位置使用 CLI 工具。這裏我們把它放在上一步新建的 .nuget 文件夾下面,並設置 PATH 環境變量。

     

    • 生成清單

      是包含包元數據的 XML 清單, 此清單同時用於生成包以及為使用者提供信息。這個清單文件我們只需要生成一次,以後都不需要再重新生成。 .net Core 和使用sdk 特性.NET Standard 項目不需要 .nuspec 文件,如果是.net Core 和使用sdk 特性.NET Standard 項目則忽略此步驟。轉到項目所在目錄,SHIFT + 右鍵 調出命令提示符,輸入 nuget spec 命令即可生成我們所需要的包元數據清單。

     

      將這個清單文件剪切到第一步新建的 .nuget 文件夾,剪切過去後項目下面就不會憑空多出一個文件,看着清爽多了。然後做一下調整填入我們自己項目的相關信息, 比如像下面這樣:

    <?xml version="1.0" encoding="utf-8"?>
    <package xmlns="http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd">
      <metadata>
        <id>TZM.XFramework</id>
        <version>$version$</version>
        <title>$title$</title>
        <authors>$author$</authors>
        <owners>$author$</owners>
        <license type="expression">Apache-2.0</license>
        <projectUrl>https://github.com/TANZAME/TZM.XFramework</projectUrl>
        <iconUrl>http://go.microsoft.com/fwlink/?LinkID=386613</iconUrl>
        <description>TZM.XFramework is a lightweight and high performance object-relational mapper for .NET use the original Entity Framework api.</description>
        <copyright>Copyright 2019</copyright>
        <tags>.NET SqlServer MSSQL Database Data O/RM ADO.NET</tags>
        <repository type="git" url="https://github.com/TANZAME/TZM.XFramework" />
        <dependencies />
        <frameworkAssemblies>
          <frameworkAssembly assemblyName="System.Data"/>
          <frameworkAssembly assemblyName="System.ComponentModel.DataAnnotations"/>
          <frameworkAssembly assemblyName="System.Net.Http"/>
        </frameworkAssemblies>
      </metadata>
    </package>

     

    • 編寫腳本

      在第一步新建的文件夾里新建一個 bat 文件,重命名為 package.bat,接下來編寫我們的自動腳本。完整 bat 腳本,直接上代碼片段。

    1. 這裏我設置 nuget pack 包屬性為Release,並且不自動生成,所以需要先在 Release 模式下編譯完成再運行腳本。加上 -Build 參數的話輸出的信息太多看得賊難受,這裏把它去掉,我們自己手動編譯。
    2. 填充api_key。去 nuget 官網 登錄自己的帳號並創建一個 key,複製粘貼到 api_key 變量。
    3. 注意 .net framework 項目(fx)和 .net core 項目使用的命令不一樣
    4. 至此我們所有的準備步驟都已完成,雙擊 package.bat 運行腳本,解放雙手。
    @echo off
    set api_key=xxxxxxlef2j57rw4q26qcrvycvznyvcurgfxbzxxxxxxxx
    set source_api_uri=https://api.nuget.org/v3/index.json
    set startup_dir=%~dp0
    cd ..\
    set startup_dir=%cd%
    cd .nuget
    
    :: 打包 TZM.XFramework -Build
    echo pack TZM.XFramework
    copy TZM.XFramework.nuspec %startup_dir%\net45\TZM.XFramework
    nuget pack %startup_dir%\net45\TZM.XFramework\TZM.XFramework.csproj -Properties Configuration=Release
    del %startup_dir%\net45\TZM.XFramework\TZM.XFramework.nuspec
    echo=
    
    :: 打包 TZM.XFrameworkCore
    echo pack TZM.XFrameworkCore
    dotnet pack --no-build --configuration Release --output %startup_dir%\.nuget\ %startup_dir%\netcore\TZM.XFrameworkCore\TZM.XFrameworkCore.csproj
    
    :: 批量推送包
    for /R %cd% %%f in (*.nupkg) do ( 
    echo=
    dotnet nuget push %%f -k %api_key% -s %source_api_uri%
    )
    
    echo=
    pause

      最後貼一張最終運行的效果圖:

    • 總結

       通過這個腳本,我們可以在一個文件夾里統一管理我們的包,做到一鍵生成、上傳同時保持項目文件的清爽,嗯簡直不要太方便 ~..~

       參考資料:

       技術交流群:816425449

    本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※帶您來了解什麼是 USB CONNECTOR  ?

    ※自行創業 缺乏曝光? 下一步”網站設計“幫您第一時間規劃公司的門面形象

    ※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!!

    ※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

    ※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益

    ※試算大陸海運運費!

  • Spring Cloud gateway 七 Sentinel 註解方式使用

    Spring Cloud gateway 七 Sentinel 註解方式使用

    Sentinel 註解支持

    @SentinelResource 用於定義資源,並提供可選的異常處理和 fallback 配置項。 @SentinelResource 註解包含以下屬性:

    • value:資源名稱,必需項(不能為空)
    • entryType:entry 類型,可選項(默認為 EntryType.OUT)
    • blockHandler / blockHandlerClass: blockHandler 對應處理 BlockException 的函數名稱,可選項。blockHandler 函數訪問範圍需要是 public,返回類型需要與原方法相匹配,參數類型需要和原方法相匹配並且最後加一個額外的參數,類型為 BlockException。blockHandler 函數默認需要和原方法在同一個類中。若希望使用其他類的函數,則可以指定 blockHandlerClass 為對應的類的 Class 對象,注意對應的函數必需為 static 函數,否則無法解析。
    • fallback:fallback 函數名稱,可選項,用於在拋出異常的時候提供 fallback 處理邏輯。fallback 函數可以針對所有類型的異常(除了 – exceptionsToIgnore 裏面排除掉的異常類型)進行處理。fallback 函數簽名和位置要求:
      • 返回值類型必須與原函數返回值類型一致;
      • 方法參數列表需要和原函數一致,或者可以額外多一個 Throwable 類型的參數用於接收對應的異常。
      • fallback 函數默認需要和原方法在同一個類中。若希望使用其他類的函數,則可以指定 fallbackClass 為對應的類的 Class 對象,注意對應的函數必需為 static 函數,否則無法解析。
    • defaultFallback(since 1.6.0):默認的 fallback 函數名稱,可選項,通常用於通用的 fallback 邏輯(即可以用於很多服務或方法)。默認 fallback 函數可以針對所有類型的異常(除了 exceptionsToIgnore 裏面排除掉的異常類型)進行處理。若同時配置了 fallback 和 defaultFallback,則只有 fallback 會生效。defaultFallback 函數簽名要求:
      • 返回值類型必須與原函數返回值類型一致;
      • 方法參數列表需要為空,或者可以額外多一個 Throwable 類型的參數用於接收對應的異常。
      • defaultFallback 函數默認需要和原方法在同一個類中。若希望使用其他類的函數,則可以指定 fallbackClass 為對應的類的 Class 對象,注意對應的函數必需為 static 函數,否則無法解析。
    • exceptionsToIgnore(since 1.6.0):用於指定哪些異常被排除掉,不會計入異常統計中,也不會進入 fallback 邏輯中,而是會原樣拋出。

    注:1.6.0 之前的版本 fallback 函數只針對降級異常(DegradeException)進行處理,不能針對業務異常進行處理。

    特別地,若 blockHandler 和 fallback 都進行了配置,則被限流降級而拋出 BlockException 時只會進入 blockHandler 處理邏輯。若未配置 blockHandler、fallback 和 defaultFallback,則被限流降級時會將 BlockException 直接拋出。

    使用注意點采坑日記

    @SentinelResource 註解不單單用於controller的接口流控。同時也可以用於方法上面。如果看過實現方式代碼。可以知道他底層是基於cglib動態代理實現的。進行切面處理。注意點:

    • 不能修飾在接口上面。只能修飾在實現類的方法上
    • 不能修飾在靜態的方法上面。
    • 同一個bean方法A調用方法B,假設方法A和B都進行了註解。B方法註解失效,請參考@Transactional 失效。
      • @Transactional 加於private方法, 無效
      • @Transactional 加於未加入接口的public方法, 再通過普通接口方法調用, 無效
      • @Transactional 加於接口方法, 無論下面調用的是private或public方法, 都有效
      • @Transactional 加於接口方法后, 被本類普通接口方法直接調用, 無效
      • @Transactional 加於接口方法后, 被本類普通接口方法通過接口調用, 有效
      • @Transactional 加於接口方法后, 被它類的接口方法調用, 有效
      • @Transactional 加於接口方法后, 被它類的私有方法調用后, 有效

    blockHandler 和 blockHandlerClass 的使用

    blockHandler 是可選的。如果使用blockHandlerClass,必須搭配blockHandler使用, blockHandler指定blockHandlerClass類中對應的方法名稱。方法名稱、參數、返回值、static 必須按照上述文檔描述一樣。官方文檔沒有強調要必須要搭配使用。

    同理 fallback 和 fallbackClass也是上面講述的注意點。

    改造client 服務

            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
            </dependency>

    bootstrap.yml 配置文件

    spring:
        cloud:
            sentinel:
                    filter:
                        # sentienl 默認生效,本地調試false
                        enabled: true
                    transport:
                        dashboard: localhost:8890
                        port: 8719
                    # 飢餓加載
                    eager: true
                    datasource:
                        # Sentinel基於nacos存儲獲取配置信息
                        na:
                            nacos:
                                server-addr: 47.99.209.72:8848
                                groupId: DEFAULT_GROUP
                                dataId: ${spring.application.name}-${spring.profiles.active}-sentinel
                                # 類型
        #            FLOW("flow", FlowRule.class),
        #            DEGRADE("degrade", DegradeRule.class),
        #            PARAM_FLOW("param-flow", ParamFlowRule.class),
        #            SYSTEM("system", SystemRule.class),
        #            AUTHORITY("authority", AuthorityRule.class),
        #            GW_FLOW("gw-flow", "com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayFlowRule"),
        #            GW_API_GROUP("gw-api-group", "com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiDefinition");
                                rule-type: flow

    nacos 創建 cloud-discovery-client-dev-sentinel 配置文件

    [
        {
            "resource": "client:log:save",
            "limitApp": "default",
            "grade": 1,
            "count": 1,
            "strategy": 0,
            "controlBehavior": 0,
            "clusterMode": false
        },
        {
            "resource": "client:fegin:test",
            "limitApp": "default",
            "grade": 1,
            "count": 1,
            "strategy": 0,
            "controlBehavior": 0,
            "clusterMode": false
        },
         {
            "resource": "user:service:saveTx",
            "limitApp": "default",
            "grade": 1,
            "count": 1,
            "strategy": 0,
            "controlBehavior": 0,
            "clusterMode": false
        },
        {
            "resource": "user:service:save:test",
            "limitApp": "default",
            "grade": 1,
            "count": 1,
            "strategy": 0,
            "controlBehavior": 0,
            "clusterMode": false
        }
    ]

    創建 BackHandlerClass DiscoveryClientControllerBackHandler

    package com.xian.cloud.common.handler;
    
    import com.alibaba.csp.sentinel.slots.block.BlockException;
    import com.xian.cloud.entity.UserEntity;
    import lombok.extern.slf4j.Slf4j;
    
    /**
     *  對應處理 BlockException 的函數名稱 服務限流
     * @Author: xlr
     * @Date: Created in 9:08 PM 2019/11/16
     */
    @Slf4j
    public class DiscoveryClientControllerBackHandler {
    
        public static String defaultMessage(BlockException e){
            
            log.warn( "DiscoveryClientControllerBackHandler  defaultMessage BlockException : {}",e );
            return "defaultMessage 服務限流,請稍後嘗試";
        }
    
        public static String saveTx(UserEntity entity,BlockException e) {
    
            log.warn( "DiscoveryClientControllerBackHandler  saveTx BlockException : {}",e );
            return "saveTx 服務限流,請稍後嘗試";
        }
    }
    

    創建 FallBackHandlerClass

    package com.xian.cloud.common.handler;
    
    import com.xian.cloud.entity.UserEntity;
    import lombok.extern.slf4j.Slf4j;
    
    /**
     * 僅針對降級功能生效(DegradeException)
     * @Author: xlr
     * @Date: Created in 9:13 PM 2019/11/16
     */
    @Slf4j
    public class DiscoveryClientControllerFallBackHandler {
    
        public static String defaultMessage(Throwable t){
            
            log.warn( "DiscoveryClientControllerFallBackHandler defaultMessage Throwable : {}",t );
            return "defaultMessage 服務降級,請稍後嘗試";
        }
    
        public static String saveTx(UserEntity entity,Throwable t) {
    
            log.warn( "DiscoveryClientControllerFallBackHandler saveTx Throwable : {}",t );
            return "saveTx 服務降級,請稍後嘗試";
        }
    }

    對外接口DiscoveryClientController 添加接口

    
    @SentinelResource(
                value = "client:fegin:test",
                blockHandler = "defaultMessage",
                fallback = "defaultMessage",
                blockHandlerClass = DiscoveryClientControllerBackHandler.class,
                fallbackClass = DiscoveryClientControllerFallBackHandler.class
        )
        @RequestMapping(value = "fegin/test",method = RequestMethod.GET)
        public String feginTest() {
            String result = serverService.hello( "fegin" );
            return  " 返回 : " + result;
        }
            
            
     @GetMapping("/log/save")
        @SentinelResource(
                value = "client/log/save",
                blockHandler = "defaultMessage",
                fallback = "defaultMessage",
                blockHandlerClass = DiscoveryClientControllerBackHandler.class,
                fallbackClass = DiscoveryClientControllerFallBackHandler.class
        )
        public String save(){
            UserEntity entity = new UserEntity();
            entity.setUsername("tom");
            entity.setPassWord("1232131");
            entity.setEmail("222@qq.com");
            userService.saveTx(entity);
            return "success";
        }
            
        @GetMapping("user/service/save")
        public String userServiceSaveTx(){
            UserEntity entity = new UserEntity();
            String result = userService.saveTx( entity );
            return result;
        }
    

    UserServiceImpl 方法

      @Override
        @Transactional
        @SentinelResource(
                value = "user:service:saveTx",
                blockHandler = "saveTx",
                fallback = "saveTx",
                blockHandlerClass = DiscoveryClientControllerBackHandler.class,
                fallbackClass = DiscoveryClientControllerFallBackHandler.class
        )
        public String saveTx(UserEntity entity) {
    
            return "success";
        }

    以上就配置完畢。然後進行測試在頁面瘋狂刷新

    http://localhost:9011/client/user/service/save

    http://localhost:9011/client/fegin/test

    停止 server服務 再次調用 fegin、test

    服務降級和服務限流來回切換提示在前端頁面。blockHandlerClass、fallbackClass。

    如何喜歡可以關注分享本公眾號。

    版權聲明:本文為博主原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接和本聲明。轉載請附帶公眾號二維碼

    本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理
    【其他文章推薦】

    ※為什麼 USB CONNECTOR 是電子產業重要的元件?

    網頁設計一頭霧水??該從何著手呢? 找到專業技術的網頁設計公司,幫您輕鬆架站!

    ※想要讓你的商品成為最夯、最多人討論的話題?網頁設計公司讓你強力曝光

    ※想知道最厲害的台北網頁設計公司推薦台中網頁設計公司推薦專業設計師”嚨底家”!!

    ※專營大陸快遞台灣服務

    台灣快遞大陸的貨運公司有哪些呢?

  • 微信 AES 解密報錯 Illegal key size 三種解決辦法

    微信 AES 解密報錯 Illegal key size

    Java 環境

    java version "1.8.0_151"
    Java(TM) SE Runtime Environment (build 1.8.0_151-b12)
    Java HotSpot(TM) 64-Bit Server VM (build 25.151-b12, mixed mode)

    問題

    問題日誌
    最近在遷移的服務器,在遷移完之後, 一個有關微信小程序的日誌打印下面的報錯信息。

    c.t.b.a.c.weixin.aes.WXBizMsgCrypt - 小程序解密異常
    java.security.InvalidKeyException: Illegal key size

    解密失敗,看了下解密的密鑰是正確的,沒有任何問題。 這個在 經典 下是可以運行的,在 VPC 下運行不了。 (因為最近在進行阿里雲網絡遷移)

    問題原因

    微信在進行數據傳輸的時候,會進行加密,微信使用的 AES 加密使用的是 256位,Java 默認使用的解密包是 local_policy.jarUS_export_policy.jar,但是這個默認的只支持 128位的解密(java 版本在 1.8.0_161之後就沒有這個問題了,默認是支持)。我們的版本是 1.8.0_151 正好默認是只支持 128位的解密(其實不是不支持,只是默認配置的不支持)。

    解決辦法

    在前面我們沒有提及一個東西,就是在/usr/local/java/jdk1.8.0_151/jre/lib/security/policy/下有兩個目錄。

    [root@djx-117106 policy]# pwd
    /usr/local/java/jdk1.8.0_151/jre/lib/security/policy/
    [root@djx-117106 policy]# ls -l
    total 8
    drwxr-xr-x 2 root root 4096 Nov  2 10:47 limited
    drwxr-xr-x 2 root root 4096 Nov  2 10:47 unlimited
    [root@djx-117106 policy]# ls -l ./limited/
    total 8
    -rw-r--r-- 1 root root 3405 Jul  4 19:41 local_policy.jar
    -rw-r--r-- 1 root root 2920 Jul  4 19:41 US_export_policy.jar
    [root@djx-117106 policy]# ls -l ./unlimited/
    total 8
    -rw-r--r-- 1 root root 2929 Jul  4 19:41 local_policy.jar
    -rw-r--r-- 1 root root 2917 Jul  4 19:41 US_export_policy.jar
    

    有一個 limited 目錄(也就是對解密有限制的包,只支持 128位),也有一個 ulimited 目錄(也就是沒有限制的目錄)。

    更改 源碼

    我們在 /usr/local/java/jdk1.8.0_151/jre/lib/security/ 下的 java.security文件中看到。

    # To support older JDK Update releases, the crypto.policy property
    # is not defined by default. When the property is not defined, an
    # update release binary aware of the new property will use the following
    # logic to decide what crypto policy files get used :
    #
    # * If the US_export_policy.jar and local_policy.jar files are located
    # in the (legacy) <java-home>/lib/security directory, then the rules
    # embedded in those jar files will be used. This helps preserve compatibility
    # for users upgrading from an older installation.
    #
    # * If crypto.policy is not defined and no such jar files are present in
    # the legacy locations, then the JDK will use the limited settings
    # (equivalent to crypto.policy=limited)
    #
    # Please see the JCA documentation for additional information on these
    # files and formats.
    #crypto.policy=unlimited

    注意下文中的 (equivalent to crypto.policy=limited) 說明默認是使用的 limited.
    我們只需要加 crypto.policy=unlimited. 讓默認使用的不限制的。

    替換Jar包

    替換 /usr/local/java/jdk1.8.0_151/jre/lib/security/policy/limited的路徑的包。其實我們可以直接用 /usr/local/java/jdk1.8.0_151/jre/lib/security/policy/unlimited下面的包直接替換 /usr/local/java/jdk1.8.0_151/jre/lib/security/policy/limited/ 下面的兩個包。也就是讓默認使用不限制的jar包。

    升級 Java 版本

    https://www.oracle.com/technetwork/java/javase/8u161-relnotes-4021379.html
    在官方文檔寫到,

    security-libs/javax.crypto
     Unlimited cryptography enabled by default
    The JDK uses the Java Cryptography Extension (JCE) Jurisdiction Policy files to configure cryptographic algorithm restrictions. Previously, the Policy files in the JDK placed limits on various algorithms. This release ships with both the limited and unlimited jurisdiction policy files, with unlimited being the default. The behavior can be controlled via the new 'crypto.policy' Security property found in the /lib/java.security file. Please refer to that file for more information on this property.
    

    也就是從 1.8.0_161-b12 版本后,默認將採用無限制的加密算法,也就是使用 unlimited 下的jar包。我們也可以通過 設置 java.security 文件的 crypto.policy的值來改變這個默認的值。

    本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理
    【其他文章推薦】

    USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

    ※評比前十大台北網頁設計台北網站設計公司知名案例作品心得分享

    ※智慧手機時代的來臨,RWD網頁設計已成為網頁設計推薦首選

    台灣海運大陸貨務運送流程

    兩岸物流進出口一站式服務

  • CSS(7)— 清除浮動(float)

    CSS(7)— 清除浮動(float)

    CSS(7)— 通俗講解清除浮動

    上一篇講了CSS浮動 博客地址:

    一、理解清除浮動

    1、為什麼要清除浮動

    我們前面說過,浮動本質是用來做一些文字混排效果的,但是被我們拿來做布局用,則會有很多的問題出現。

    由於浮動元素不再佔用原文檔流的位置,所以它會對後面的元素排版產生影響,為了解決這些問題,此時就需要在該元素中清除浮動。

    準確地說,並不是清除浮動,而是清除浮動后造成的影響

    2、清除浮動本質

    清除浮動的本質: 主要為了解決父級元素因為子級浮動引起內部高度為0 的問題。

    我們來詳細解釋下這句話

    再解釋下就是在標準流下面一個父div沒有設置高度屬性,那麼它的高度就會被子元素的高度撐開。但是如果這個父div中的子元素是浮動的話,如果父div下面再有

    一個兄弟div,那麼這個兄弟div就會遮擋這個父元素。這個現象也叫浮動溢出

    示例

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Document</title>
        <style>
        .father {
            height: 200px;
            border: 1px solid red;
            width: 300px
    
        }
        .big {
            width: 100px;
            height: 100px;
            background-color: purple;
            float: left;
        }
        .small {
            width: 80px;
            height: 80px;
            background-color: blue;
            float: left;
        }
        .footer {
            width: 400px;
            height: 100px;
            background-color: pink;
        }
        </style>
    </head>
    <body>
        <div class="father"> 父div
            <div class="big">子div</div>
            <div class="small">子div</div>
        </div>
        <div class="footer">兄弟div</div>
    </body>
    </html>

    運行結果

    很明顯這裏,div1和div2已經上浮,而兄弟div就往上移動。這裏因為父div有文字所以佔了點高度,不然兄弟div會完全覆蓋父div。

    當然我們可以通過設置父div的高度,來使它不被兄弟div所覆蓋。比如這裏設置 height: 200px;

    在刷新下頁面

    當父div設置高度后,被覆蓋的問題卻是解決了,但在很多時候我們是不會去設置父div的高度,因為很多時候我們都不知道父div的高度要設置多少。

    所以這個時候需要思考解決這個問題。

    二、清除浮動的方法

    清除浮動的方法本質: 就是把父盒子里浮動的盒子圈到裏面,讓父盒子閉合出口和入口不讓他們出來影響其他元素。

    在CSS中,clear屬性用於清除浮動。

    基本語法格式

    選擇器 {clear:屬性值;}

    屬性值

    1、額外標籤法

    通過在浮動元素末尾添加一個空的標籤,例如

     <div style="clear:both"></div>

    我們在上面的代碼添加

    <body>
        <div class="father"> 父div
            <div class="big">子div</div>
            <div class="small">子div</div>
            <div style="clear:both"></div>  <!--  只需在父盒子里最後面添加這個空標籤添加clear:both屬性就可以清除浮動 -->
        </div>
        <div class="footer">兄弟div</div>
    </body>

    運行結果

    完美解決了。

    優點 通俗易懂,書寫方便。

    缺點 添加無意義的標籤,結構化較差。

    2、父級添加overflow屬性方法

    可以通過觸發BFC的方式,可以實現清除浮動效果。(BFC後面會講)

    可以給父級元素添加: overflow為 hidden|auto|scroll  都可以實現。

    我們將上面代碼修改為

    <body>
        <div class="father" style="overflow: hidden;"> 父div  <!-- 父元素添加 overflow: hidden --> 
            <div class="big">子div</div>
            <div class="small">子div</div>
        </div>
        <div class="footer">兄弟div</div>
    </body>

    也是能實現去除浮動的效果。

    優點 代碼簡潔

    缺點 內容增多時候容易造成不會自動換行導致內容被隱藏掉,無法显示需要溢出的元素。

    3、使用after偽元素清除浮動

    :after 方式為空元素的升級版,好處是不用單獨加標籤了** 

    示例

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>使用after偽元素清除浮動</title>
        <style>
        .clearfix:after {  /*正常瀏覽器 清除浮動*/
            content:"";
            display: block;
            height: 0;
            clear: both;
            visibility: hidden;
        }
        .clearfix {
            *zoom: 1;  /*zoom 1 就是ie6 清除浮動方式  *  ie7一下的版本所識別*/
        }
        .father {
            border: 1px solid red;
            width: 300px;
    
        }
        .big {
            width: 100px;
            height: 100px;
            background-color: purple;
            float: left;
        }
        .small {
            width: 80px;
            height: 80px;
            background-color: blue;
            float: left;
        }
        .footer {
            width: 400px;
            height: 100px;
            background-color: pink;
        }
        </style>
    </head>
    <body>
        <div class="father clearfix">
            <div class="big"></div>
            <div class="small"></div>
        </div>
        <div class="footer"></div>
    </body>
    </html>

    優點 符合閉合浮動思想 結構語義化正確

    缺點 由於IE6-7不支持:after,使用 zoom:1觸發 hasLayout。

    注意: content:”.” 裏面盡量跟一個小點,或者其他,盡量不要為空,否則再firefox 7.0前的版本會有生成空格。

    4、使用before和after雙偽元素清除浮動

    使用方法 將上面的clearfix樣式替換成如下

        .clearfix:before, .clearfix:after {
            content: "";
            display: table;
        }
        .clearfix:after {
            clear: both;
        }
    
        .clearfix {
            *zoom: 1;
        }

    優點 代碼更簡潔

    缺點 由於IE6-7不支持:after,使用 zoom:1觸發 hasLayout。

    5、總結

    1、在網頁主要布局時使用:after偽元素方法並作為主要清理浮動方式.文檔結構更加清晰;
    2、在小模塊如ul里推薦使用overflow:hidden;(同時留意可能產生的隱藏溢出元素問題);

    你如果願意有所作為,就必須有始有終。(9)

    本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理
    【其他文章推薦】

    台北網頁設計公司這麼多,該如何挑選?? 網頁設計報價省錢懶人包”嚨底家”

    網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

    ※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

    小三通海運與一般國際貿易有何不同?

    小三通快遞通關作業有哪些?

  • Go語言Hello world(GOPATH和Go Module版)

    Go語言Hello world(GOPATH和Go Module版)

    本文是「vangoleo的Go語言學習筆記」系列文章之一。
    官網:

    往期回顧:

    上一篇文章中,我們在Golang Playground中體驗了Go語言,編寫並運行了一個簡單的Hello World,相信大家對Go語言的語法有了一些了解。

    學習一種編程語言,除了基本的語法,更重要的是要了解如何在實際的工程中使用它。本文中,我會和大家一起,從零開始,安裝Go語言,配置環境,安裝IDE,開發一個Hello World程序。這個Hello World版我會編寫兩個版本:GOPATH和Go Module版本。

    Q:
    本教程為什麼會編寫兩個版本?
    A:
    網上大部分Go語言Hello World都只簡單地介紹了GOPATH版本。但是從Go的1.11版本之後,已不再推薦使用GOPATH來構建應用了。也就是說GOPATH被認為是廢棄的,錯誤的做法。
    正確的做法是使用Go Module。所以,有必要在教程中將這個信息告訴初學者,引導大家使用推薦的最佳實踐方式Go Module。
    或許這也是本Hello World教程和網上大部分教程的區別吧。會從開發者的實際使用出發。介紹Go語言的發展歷史和最佳實踐。

    安裝Go

    使用Go語言開發,第一步肯定是安裝Go啦。

    第一步:進入Go語言的官網https://golang.org。點擊“Download Go”。是的,就是那個傻傻的土撥鼠^_^

    第二步:根據操作系統下載對應的軟件包進行安裝。
    Golang對主流的操作系統都有支持,比如Windows,MacOS和Linux等。
    本系列教程中,我會使用MacOS操作系統,所以選擇下載“Apple macOS”。大家要根據自己的操作系統進行下載。

    第三步:安裝Go。
    在MacOS下安裝Go很簡單,就是標準的DMG文件安裝,直接“下一步”就可以了。
    第四步:確認Go是否安裝成功。
    運行命令“go version”,會輸出類似於“go version go1.12.9 darwin/amd64”的內容。請確保包沒有任何錯誤發生。

    配置環境

    和其他開發語言類似,安裝了Go之後,還需要對開發環境進行相應的配置。比如在Java中,需要配置JAVA_HOME,MAVEN等。
    Go開發相關的環境變量如下:

    • GOROOT:GOROOT就是Go的安裝目錄。
    • GOPATH:GOPATH保存go項目代碼。

    GOROOT

    GOROOT是Go的安裝路徑。Mac中安裝Go會自動配置好GOROOT,路徑為/usr/local/go。GOROOT在絕大多數情況下都不需要修改。以下是GOROOT目錄的內容(已省略了一些無關信息):

    tree -L 2 /usr/local/go
    
    ./
    ├── bin
    │   ├── go
    │   └── gofmt
    ├── doc
    │   ├── articles
    │   └── docs.html
    ├── src
    │   ├── errors
    │   ├── fmt
    │   ├── log
    │   └── os

    可以看到GOROOT下有bin,doc和src目錄。bin目錄下有我們熟悉的go和gofmt工具。可以認為GOOROOT和Java里的JDK目錄類似。

    GOPATH

    GOPATH是開發時的工作目錄。用於:

    • 保存編譯后的二進制文件。
    • go getgo install命令會下載go代碼到GOPATH。
    • import包時的搜索路徑。

    關於GOPATH需要特別注意。在GO的1.11版本之前,GOPATH是必需的,且所有的Go項目代碼都要保存在GOPATH目錄下。Go的1.11版本之後,GO官方引入了Go Module。使用Go Module管理的項目可以放在GOPATH目錄外面。

    使用GOPATH時,GO會在以下目錄中搜索包:

    1. GOROOT/src:該目錄保存了Go標準庫代碼。
    2. GOPATH/src:該目錄保存了應用自身的代碼和第三方依賴的代碼。

    假設程序中引入了如下的包:

    import "github.com/tom/hello-go/foo/bar"

    第一步:Go會先去GOROOT的scr目錄中查找,很顯然它不是標準庫的包,沒找到。
    第二步:繼續在GOPATH的src目錄去找,準確說是GOPATH/src/github.com/tom/hello-go/foo/bar這個目錄。如果該目錄不存在,會報錯找不到package。在使用GOPATH管理項目時,需要按照GO尋找package的規範來合理地保存和組織Go代碼。

    Go的這個“將所有代碼都放置在GOPATH中”的設計,的確是和其他主流語言很不一樣。不管Go官方是出於什麼考慮,這個設計在實際使用中,的確給開發者造成了很大的不便和理解上的困難。甚至直接勸退了很多Go的初學者。
    萬幸的是,Go Module正式發布了。Go Module的發布解決了困擾Go語言長達十年的代碼組織,依賴管理問題。

    說明:關於GOPATH和Go Module的歷史淵源,詳細使用,會在另一篇進行說明。本文還是聚焦在Hello World入門。

    另外,由於某些原因,Go的某些託管在Google倉庫中的代碼在國內是無法訪問的。如果使用Go Module,我們可以設置GOPROXY,讓Go從GOPROXY下載Go代碼,速度更快。國內用戶可以設置GOPROXY為,使用如下命令來設置GOPROXY:

    export GOPROXY=https://goproxy.cn

    關於環境配置,總結下來就是:

    • 如果使用Go Module(推薦的),設置export GOPROXY=。
    • 如果使用GOPATH(遺留的,被廢棄的),需要設置GOPATH到本地的某個目錄。

    安裝IDE

    目前比較常用的IDE有:

    • Visual Studio Code
    • GoLand

    Visual Studio Code是微軟開發的一款開源的,輕量級的文本編輯器。通過安裝Go插件,可以用於Go語言的開發。GoLand是JetBrains公司開發的,專業的Go語言開發IDE。

    推薦使用GoLand。很多人都說Visual Studio Code更輕量級,但作為一款每天都要重度使用的,需要靠它吃飯的工具,我們需要的是功能全面。尤其是當你需要完備的調試,需要強大的IDE智能輔助功能時,相信你會選擇更專業的GoLand。

    GoLand的官方主頁為https://www.jetbrains.com/go/,點擊“Download”即可下載

    注意
    GoLand使用的是和IntelliJ IDEA一樣的框架,是用Java語言開發的。你需要安裝Java環境才可以運行GoLand哦。

    GoLand是收費軟件,只有30天的試用期。試用期結束后,需要購買授權。當然在天朝,我們都習慣不花錢用軟件。大家可以自行百度或google搜索一下。

    Hello World(GOPATH版)

    第一步:設置GOPATH
    首先設置GOPATH,假設GOPATH設置為$HOME/worspace/go
    第二步:創建子目錄
    進入$HOME/workspace/go目錄。新建子目錄src。然後再src中新建子目錄hello。在hello目錄,新建一個hello-world.go文件:
    目錄結構應該如下所示:

    $HOME
      workspace
        go
          src
            hello
              hello-world.go

    第三步:創建hello-world.go文件:

    package main
    import "fmt"
    func main() {
        fmt.Println("hello world")
    }

    第四步:執行go build
    $HOME/workspace/go目錄執行命令:

    go build

    會生成一個可執行二進制文件:hello。如果是Windows系統,會生成hello.exe文件。
    第五步:運行hello文件:

    ./hello
    
    hello world

    輸出“hello world”。

    Hello World(GO Module版)

    第一步:創建項目的根目錄
    任意創建一個目錄(可以不在GOPATH中),假設是$HOME/tmp/hello。
    第二步:初始化Go模塊
    執行命令:

    go mod init github.com/vangoleo/hello

    該命令會將hello目錄初始化為一個Go module,並生成一個$HOME/tmp/hello/go.mod文件。內容如下:

    module github.com/vangoleo/hello
    
    go 1.12

    第三步:編寫hello.go文件
    編寫文件$HOME/tmp/hello/hello.go:

    package main
    
    import (
        "fmt"
        "rsc.io/quote"
    )
    
    func main() {
        fmt.Println(quote.Hello())
    }

    第四步:編輯go.mod文件:
    在實際項目中,都會使用到第三方庫。可以在Go Module中添加項目的依賴。本例中,我們會添加一個quote依賴,該依賴會打印當前語言的“Hello World”,比如,如果是中文環境,會打印“你好,世界”。
    編輯go.mod文件,添加quote依賴:

    module github.com/vangoleo/hello
    
    go 1.12
    
    require rsc.io/quote v1.5.2

    第五步:執行go build
    執行go build,會生成可執行文件$HOME/tmp/hello/hello
    第六步:執行hello文件
    執行hello文件,輸出“你好,世界”。

    最後

    本文中,我們從下載安裝,配置Go環境開始,並完成了GOPATH和Go Module兩個版本的Hello World應用。如果你跟着我一步一步完成了這些步驟,恭喜你!!!已經完成了第一個真正的Go應用,並且使用了正確的Go Module來管理Go程序。

    接下來,我們可以開始學習Go語言的語法部分(基本數據類型,判斷,循環等)了。咋們下期見。

    本文由 發布

    本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理
    【其他文章推薦】

    ※想知道網站建置網站改版該如何進行嗎?將由專業工程師為您規劃客製化網頁設計後台網頁設計

    ※不管是台北網頁設計公司台中網頁設計公司,全省皆有專員為您服務

    ※Google地圖已可更新顯示潭子電動車充電站設置地點!!

    ※帶您來看台北網站建置台北網頁設計,各種案例分享

    小三通物流營運型態?

    ※快速運回,大陸空運推薦?

  • 設計模式(Java語言)-單例模式

    設計模式(Java語言)-單例模式

      單例模式,簡而言之就是在整個應用程序裏面有且僅有一個實例,在程序的任何時候,任何地方獲取到的該對象都是同一個對象。單例模式解決了一個全局的類被頻繁創建和銷毀的,或者每次創建或銷毀都需要消耗大量cpu資源的對象的問題。單例模式總的可以分為懶漢模式和餓漢模式,顧名思義,懶漢模式是一個非常懶的漢子,只要你沒有使用到它,它就永遠不會實例化。餓漢模式的意思就是,漢子非常饑渴,只要在程序的編譯階段就給你分配內存,創建好對象。

      將懶漢模式和餓漢模式細分,又可以分為:

      1、懶漢模式

      2、餓漢模式

      3、雙檢模式

      4、靜態內部類模式

      5、枚舉模式

      不管是用哪一種方式實現的單例模式,其創建流程基本都是一直的:首先將構造方法聲明為private的,這樣就防止直接new出一個新的對象。第二,聲明一個私有的成員變量,即單例對象。第三步,聲明一個public的靜態方法,用於獲取或創建單例對象,外部想要獲取該對象必須通過這個方法獲取。

      一、懶漢模式1–線程安全

    /**
     * 餓漢模式1
     */
    public class HungrySingleton1 {
    
        private static HungrySingleton1 singleton = new HungrySingleton1();
    
        private HungrySingleton1(){}
    
        public static HungrySingleton1 getInstance() {
            return singleton;
        }
    
    
    }
    

      這種懶漢模式的優點是實現非常簡單。缺點是並起到懶加載的效果,如果項目沒有使用到這個對象的就會造成資源的浪費。

     

      二、餓漢模式1–線程不安全

    /**
     * 懶漢模式1
     */
    public class LazySingleton1 {
    
        private static LazySingleton1 singleton;
    
        private LazySingleton1(){}
    
        public static LazySingleton1 getInstance() {
            if (singleton == null) {
                singleton = new LazySingleton1();
            }
            return singleton;
        }
    
    
    }
    

      這種寫法雖然實現了懶加載的效果,但是嚴格意義上並不是單例模式,因為在多線程的環境下有可能會創建出多個不同的對象,至於為什麼,不懂的可以看一下我之間寫的關於Java內存模型的文章。這種寫法只能應用於單線程的環境下,局限性很大。實際中強烈不建議使用這種方法。

     

      三、懶漢模式2–線程安全

      

    /**
     * 懶漢模式2
     */
    public class LazySingleton2 {
    
        private static LazySingleton2 singleton;
    
        private LazySingleton2(){}
    
        public static synchronized LazySingleton2 getInstance() {
            if (singleton == null) {
                singleton = new LazySingleton2();
            }
            return singleton;
        }
    
    
    }
    

      這種寫法咋看跟上面的方法一樣,這種寫法在方法上添加了 synchronized  關鍵字,這樣就保證了每次只能有一個線程進入方法體中,解決了懶漢模式1中出現的問題。這種寫法的優點是實現了懶加載的效果,缺點是效率非常低,當多個線程同時獲取實例時,有可能會造成線程阻塞的情況。不推薦使用。

     

      懶漢模式3–線程不安全

    /**
     * 懶漢模式3
     */
    public class LazySingleton3 {
    
        private static LazySingleton3 singleton;
    
        private LazySingleton3(){}
    
        public static LazySingleton3 getInstance() {
            if (singleton == null) {
                synchronized (LazySingleton3.class) {
                    if (singleton == null) {
                        singleton = new LazySingleton3();
                    }
                }
            }
            return singleton;
        }
    }
    

      這種寫法進行了兩次 singleton == null 的判斷,在實際的應用中當我們調用這個方法時,其實99%的幾率是實例就已經創建好了,因此第一個 singleton == null 能過濾掉99%的調用,不用將方法鎖起來,從而提高了效率。這種方法的優點是實現懶加載的效果,效率和很高。缺點是代碼設計仍然後缺陷,jvm在為對象分配內存和賦值並不是一個原子操作,即 singleton = new LazySingleton3() 這段代碼在jvm中是由三個步驟實現的,首先jvm會在堆中為對象分配一定的內存空間,然後完成對象的初始化工作,然後將內存地址指向到對象中。但是,我們知道,jvm在編譯的時候並不總是根據我們編寫的代碼的順序來執行了,而是根據jvm覺得最優的順序執行(這個過程就叫做指令重排序),所以有可能在執行了步驟1后就執行了步驟3,這時候第二個線程進來的發現singleton並不為空,因此就直接返回了該對象,因此造成空指針異常。

     

      四、雙重檢查鎖模式—線程安全

    /**
     * 懶漢模式4
     */
    public class LazySingleton4 {
    
        private volatile static LazySingleton4 singleton;
    
        private LazySingleton4(){}
    
        public static LazySingleton4 getInstance() {
            if (singleton == null) {
                synchronized (LazySingleton4.class) {
                    if (singleton == null) {
                        singleton = new LazySingleton4();
                    }
                }
            }
            return singleton;
        }
    }
    

      相較於上面的方式,這種方式只是在成員變量中添加了 volatile  關鍵字,解決了指令重排序的問題,同時確保當前線程修改了這個變量時,其他的線程能夠及時讀到最新的值。這種方法缺點是寫起來比較複雜,要求程序員對jvm比較理解。優點是既保證了線程安全,同時也能夠保證了比較高的效率。

     

      五、靜態內部類模式–線程安全

    /**
     * 懶漢模式5
     */
    public class LazySingleton5 {
    
        private LazySingleton5(){}
    
        private static class Holder {
            private static final LazySingleton5 INSTANCE = new LazySingleton5();
        }
    
        public static LazySingleton5 getInstance() {
            return Holder.INSTANCE;
        }
    
    }
    

      這種寫法實現比較簡單,即實現了懶加載的效果,同時也保證的多線程環境下的線程安全問題。推薦使用這種方式。

     

      六、枚舉模式 — 線程安全

      

    /**
     * 懶漢模式6
     */
    public enum  LazySingleton6 {
    
       INSTANCE
    
    }

    //使用方法
    public class Test {

    public static void main(String[] args) {
    LazySingleton6 instance = LazySingleton6.INSTANCE;
    LazySingleton6 instance1 = LazySingleton6.INSTANCE;
    System.out.println(instance == instance1);

    }

    }

      推薦寫法,簡單高效。充分利用枚舉類的特性,只定義了一個實例,且枚舉類是天然支持多線程的。

      喜歡我寫的博客的同學可以關注訂閱號【Java解憂雜貨鋪】,裏面不定期發布一些技術幹活,也可以免費獲取大量最新最流行的技術教學視頻

      

     

     

     

     

     

    本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

    ※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益

    ※自行創業 缺乏曝光? 下一步"網站設計"幫您第一時間規劃公司的門面形象

    台灣寄大陸海運貨物規則及重量限制?

    大陸寄台灣海運費用試算一覽表

    南投搬家前需注意的眉眉角角,別等搬了再說!

  • 3. 彤哥說netty系列之Java BIO NIO AIO進化史

    3. 彤哥說netty系列之Java BIO NIO AIO進化史

    你好,我是彤哥,本篇是netty系列的第三篇。

    簡介

    上一章我們介紹了IO的五種模型,實際上Java只支持其中的三種,即BIO/NIO/AIO。

    本文將介紹Java中這三種IO的進化史,並從使用的角度剖析它們背後的故事。

    Java BIO

    BIO概念解析

    BIO,Blocking IO,阻塞IO,它是Java的上古產品,自出生就有的東西(JDK 1.0)。

    使用BIO則數據準備和數據從內核空間拷貝到用戶空間兩個階段都是阻塞的。

    BIO使用案例

    public class EchoServer {
        public static void main(String[] args) throws IOException {
            ServerSocket serverSocket = new ServerSocket(8080);
            while (true) {
                System.out.println("start accept");
                Socket socket = serverSocket.accept();
                System.out.println("new conn: " + socket.getRemoteSocketAddress());
    
                new Thread(()->{
                    try {
                        BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                        String msg;
                                            // 讀取消息,本文來源公從號彤哥讀源碼
                        while ((msg = reader.readLine()) != null) {
                            if (msg.equalsIgnoreCase("quit")) {
                                reader.close();
                                socket.close();
                                break;
                            } else {
                                System.out.println("receive msg: " + msg);
                            }
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }).start();
            }
        }
    }

    客戶端可以使用telnet來測試,而且你可以使用多個telnet來測試:

    [c:\~]$ telnet 127.0.0.1 8080
    
    
    Connecting to 127.0.0.1:8080...
    Connection established.
    To escape to local shell, press 'Ctrl+Alt+]'.
    hello world
    我是人才
    quit
    Connection closed by foreign host.

    BIO的使用方式非常簡單,服務端接收到一個連接就啟動一個線程來處理這個連接的所有請求。

    所以,BIO最大的缺點就是浪費資源,只能處理少量的連接,線程數隨着連接數線性增加,連接越多線程越多,直到抗不住。

    Java NIO

    NIO概念解析

    NIO,New IO,JDK1.4開始支持,內部是基於多路復用的IO模型。

    這裡有個歧義,很多人認為Java的NIO是Non-Blocking IO的縮寫,其實並不是。

    使用NIO則多條連接的數據準備階段會阻塞在select上,數據從內核空間拷貝到用戶空間依然是阻塞的。

    因為第一階段並不是連接本身處於阻塞階段,所以通常來說NIO也可以看作是同步非阻塞IO。

    NIO使用案例

    public class EchoServer {
        public static void main(String[] args) throws IOException {
            Selector selector = Selector.open();
            ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
            serverSocketChannel.bind(new InetSocketAddress(8080));
            serverSocketChannel.configureBlocking(false);
            // 將accept事件綁定到selector上
            serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
    
            while (true) {
                // 阻塞在select上
                selector.select();
                Set<SelectionKey> selectionKeys = selector.selectedKeys();
                // 遍歷selectKeys
                Iterator<SelectionKey> iterator = selectionKeys.iterator();
                while (iterator.hasNext()) {
                    SelectionKey selectionKey = iterator.next();
                    // 如果是accept事件
                    if (selectionKey.isAcceptable()) {
                        ServerSocketChannel ssc = (ServerSocketChannel) selectionKey.channel();
                        SocketChannel socketChannel = ssc.accept();
                        System.out.println("accept new conn: " + socketChannel.getRemoteAddress());
                        socketChannel.configureBlocking(false);
                        socketChannel.register(selector, SelectionKey.OP_READ);
                    } else if (selectionKey.isReadable()) {
                        // 如果是讀取事件,本文來源公從號彤哥讀源碼
                        SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
                        ByteBuffer buffer = ByteBuffer.allocate(1024);
                        // 將數據讀入到buffer中
                        int length = socketChannel.read(buffer);
                        if (length > 0) {
                            buffer.flip();
                            byte[] bytes = new byte[buffer.remaining()];
                            // 將數據讀入到byte數組中
                            buffer.get(bytes);
    
                            // 換行符會跟着消息一起傳過來
                            String content = new String(bytes, "UTF-8").replace("\r\n", "");
                            if (content.equalsIgnoreCase("quit")) {
                                selectionKey.cancel();
                                socketChannel.close();
                            } else {
                                System.out.println("receive msg: " + content);
                            }
                        }
                    }
                    iterator.remove();
                }
            }
        }
    }

    這裏同樣使用telnet測試,而且你可以使用多個telnet來測試:

    [c:\~]$ telnet 127.0.0.1 8080
    
    
    Connecting to 127.0.0.1:8080...
    Connection established.
    To escape to local shell, press 'Ctrl+Alt+]'.
    hello world
    我是人才
    quit
    Connection closed by foreign host.
    

    NIO的使用方式就有點複雜了,但是一個線程就可以處理很多連接。

    首先,需要註冊一個ServerSocketChannel並把它註冊到selector上並監聽accept事件,然後accept到連接後會獲取到SocketChannel,同樣把SocketChannel也註冊到selector上,但是監聽的是read事件。

    NIO最大的優點,就是一個線程就可以處理大量的連接,缺點是不適合處理阻塞性任務,因為阻塞性任務會把這個線程佔有着,其它連接的請求將得不到及時處理。

    Java AIO

    AIO概念介紹

    AIO,Asynchronous IO,異步IO,JDK1.7開始支持,算是一種比較完美的IO,Windows下比較成熟,但Linux下還不太成熟。

    使用異步IO則會在請求時立即返回,並在數據已準備且已拷貝到用戶空間後進行回調處理,兩個階段都不會阻塞。

    AIO使用案例

    public class EchoServer {
        public static void main(String[] args) throws IOException {
            AsynchronousServerSocketChannel serverSocketChannel = AsynchronousServerSocketChannel.open();
            serverSocketChannel.bind(new InetSocketAddress(8080));
            // 監聽accept事件,本文來源公從號彤哥讀源碼
            serverSocketChannel.accept(null, new CompletionHandler<AsynchronousSocketChannel, Object>() {
                @Override
                public void completed(AsynchronousSocketChannel socketChannel, Object attachment) {
                    try {
                        System.out.println("accept new conn: " + socketChannel.getRemoteAddress());
                        // 再次監聽accept事件
                        serverSocketChannel.accept(null, this);
    
                        // 消息的處理
                        while (true) {
                            ByteBuffer buffer = ByteBuffer.allocate(1024);
                            // 將數據讀入到buffer中
                            Future<Integer> future = socketChannel.read(buffer);
                            if (future.get() > 0) {
                                buffer.flip();
                                byte[] bytes = new byte[buffer.remaining()];
                                // 將數據讀入到byte數組中
                                buffer.get(bytes);
    
                                String content = new String(bytes, "UTF-8");
                                // 換行符會當成另一條消息傳過來
                                if (content.equals("\r\n")) {
                                    continue;
                                }
                                if (content.equalsIgnoreCase("quit")) {
                                    socketChannel.close();
                                    break;
                                } else {
                                    System.out.println("receive msg: " + content);
                                }
                            }
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
    
                @Override
                public void failed(Throwable exc, Object attachment) {
                    System.out.println("failed");
                }
            });
    
            // 阻塞住主線程
            System.in.read();
        }
    }

    這裏同樣使用telnet測試,而且你可以使用多個telnet來測試:

    [c:\~]$ telnet 127.0.0.1 8080
    
    
    Connecting to 127.0.0.1:8080...
    Connection established.
    To escape to local shell, press 'Ctrl+Alt+]'.
    hello world
    我是人才
    quit
    Connection closed by foreign host.
    

    AIO的使用方式不算太複雜,默認會啟一組線程來處理用戶的請求,而且如果在處理阻塞性任務,還會自動增加新的線程來處理其它連接的任務。

    首先,創建一個AsynchronousServerSocketChannel並調用其accept方法,這一步相當於監聽了accept事件,在收到accept事件後會獲取到AsynchronousSocketChannel,然後就可以在回調方法completed()裏面讀取數據了,當然也要繼續監聽accept事件。

    AIO最大的優點,就是少量的線程就可以處理大量的連接,而且可以處理阻塞性任務,但不能大量阻塞,否則線程數量會膨脹。

    槽點

    (1)三種IO的實現方式中對於換行符的處理竟然都不一樣,BIO中不會把換行符帶過來(其實是帶過來了,因為用了readLine()方法,所以換行符沒了),NIO中會把換行符加在消息末尾,AIO中會把換行符當成一條新的消息傳過來,很神奇,為啥不統一處理呢,也很疑惑。

    (2)JDK自帶的ByteBuffer是一個難用的東西。

    總結

    本文我們從概念和使用兩個角度分別介紹了BIO/NIO/AIO三種IO模型。

    問題

    看起來JDK的實現似乎很完美啊,為什麼還會有Netty呢?

    最後,也歡迎來我的公從號彤哥讀源碼系統地學習源碼&架構的知識。

    本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!!

    網頁設計一頭霧水??該從何著手呢? 找到專業技術的網頁設計公司,幫您輕鬆架站!

    ※想知道最厲害的台北網頁設計公司推薦台中網頁設計公司推薦專業設計師”嚨底家”!!

    大陸寄台灣空運注意事項

    大陸海運台灣交貨時間多久?

  • 大學生活這樣過,校招 offer 飛來找

    大學生活這樣過,校招 offer 飛來找

    01、開門見山

    由於比較喜歡分享的原因,認識了不少大學生。其中有不少佼佼者,比如說一年讀 50 本書的璐璐,校招斬獲一線大廠 Offer 的曉峰,通過運營公眾號實現經濟獨立的帥土。

    當然也有一些不知所措的,對未來。他們有些在文章底部留言,有些通過微信諮詢,還有一些在星球提問。每次我都認真地回答,他們也對我的熱情表示感謝。

    我想着,不如把自己的心得經驗通過文章的形式分享出來,這樣就能夠給更多的大學生提供參照。如果你讀完這篇文章后,有所收穫,就把它分享給更多的人。

    02、往事不可追

    蘇聯作家尼古拉·奧斯特洛夫斯基的小說《鋼鐵是怎樣煉成的》裏面有這樣一句至理名言——人生最寶貴的是生命,生命屬於人只有一次。一個人的生命應當這樣度過:當他回憶往事的時候,他不致因虛度年華而悔恨,也不致因碌碌無為而羞愧

    說來慚愧,回憶起我的大學時光,湧上心頭的是滿滿的悔恨和羞愧。

    我參加過兩次高考。第一次的成績真實地反映出了我平常的水準,我自己心裏也像明鏡一樣。沒有努力就不會有超水平的發揮。這也恰好給了我復讀的勇氣:只要努把力,沒準就會有驚喜。

    於是我從洛寧縣的一個二流高中輾轉去了平頂山市一高,下了很大的決心。結果呢,第二次的成績又真實地反映出了我平常的水準——意料之外卻也是情理之中,差二本線的分數和第一年完全一樣。

    當時我幾乎放棄了上大學的打算,還去搬了一個月的磚。詳情可以查看之前寫的文章《》

    後來實在是迫於無奈(身板不夠結實,搬不了幾塊磚),就聽從了同學的建議,志願上填了鄭州的一所大專。幸好專業服從了調劑,否則大專也上不了。我們學校錄取的分數當時蠻高的,最高分比一本線要高出一大截。大家之所以擠破頭想去,是因為學校最好的專業畢業后可以直接到國家電網上班,大多數人夢寐以求的工作。

    而我呢,比最低分只高出了零分。可想而知,我調劑后的專業「計算機網絡」在學校是多麼的不受待見。專業課的老師們秉持着和我們一起共同成長的理念,而我們秉持着和老師們一起沉淪的信心。

    上課的時候我帶着筆記本電腦在教室打遊戲,下課的時候我帶着筆記本電腦在宿舍打遊戲。除了周末去鄭州大學找女朋友散散心,我的大學生活過得是一塌糊塗,要多糟糕有多糟糕。

    可以這麼說,和璐璐、曉峰、帥土比起來,我是一個不折不扣的反面教材。可正因為如此,我接下來給出的建議那可就十足的寶貴了。多麼痛的領悟!

    03、積累項目經驗

    不少大學生以為,大學期間就應該深入學習理論知識,實戰經驗並不重要,等到工作以後再實踐也不晚。但這真的是一個錯誤的認知啊,理論知識確實非常重要,但要記住一點:學以致用。

    如果學到的理論知識不能夠應用於實戰當中,就好像我們手裡有一把南瓜子,卻沒有灑向肥沃的土壤。這樣的話,這些南瓜子就永遠只能是南瓜子,無法生根發芽,結出新的南瓜。更殘忍的是,這些南瓜子還會被我們吃進肚子里。

    我隨手查閱了一些企業的校招要求,裏面明確要求要有一定的項目經驗。這就意味着如果沒有項目經驗,就無法找到工作;找不到工作,就不會有項目經驗。好像是一個死結唉。

    也許這些校招要求過於苛刻了。說實話,我也應付不來。但我們應該知道,“人外有人,天外有天”,優秀的大學生多着呢,我們應付不來,他們一定能夠勝任。

    那有些同學可能會抱怨道,我就是一名普通的大學生,我沒他們那麼優秀,我該怎麼辦?況且,誰會樂意把項目交給我來說呢?

    別恐慌,別著急給自己設限。我之前認識一個同學,叫小曾。他說他們學校有一個群,裏面會不定期發布一些項目(企業網站、小商城等等),費用一般在 7K 左右。他缺錢的時候就找幾個宿友一起做。兩三年下來,自己主導的項目就有 3 個,還不帶輔助參与的。

    雖然是廉價勞動力,但總比無所事事強得多。畢業的時候他就感覺像旅歐回來的足球運動員,成長特別大。也成功斬獲了網易的一個 Offer。

    項目經驗嘛,沒必要非得是多麼大的項目,只要了解了項目的流程,有過思考和總結,有過入坑和爬坑,就是不可多得的項目經驗。

    再多說一句,小曾有時候會把一些搞不定的項目外包出去,賺取一些差價。你一定會覺得我在胡侃,但我想表達的是,這就是我們認識的方式。人與人之間的差距,和年齡無關,只和認知有關

    我只上過兩年大學,還一心撲在遊戲上,我的榮譽勳章上只有一個——掛科了三次,每次和同學們吹牛逼,我都要炫耀一番自己當年有多二。和同年齡段的小曾相比,我當時實在是弱爆了。我希望你以我為戒。

    04、真正的實習

    在知乎上看到一個神奇的問題:“想做一個程序員,一定要走培訓嗎?”這個問題的神奇之處就好像在問一個醫生:“我感冒了,一定要做個手術才能好嗎?”

    我大三的時候就因為這樣的無知,被騙進了一家軟件培訓機構。現在回想起來,胸口不免隱隱作痛。我大學兩年,學的是 Java 編程語言,雖然說荒唐度日,但好歹做過仿 QQ 聊天工具的,多多少少有點底子的。

    如果肯去一些招聘網站上尋找機會的話,也不會一無所獲。畢竟那時候的 Java 工程師也蠻吃香的。只是老師們沒有告訴我方法,我也沒有找到知心的大佬諮詢建議。於是連招聘網站都沒有上過,愚昧啊。

    但不管怎麼說,。而實習是一個提高自己、接觸社會的絕佳機會。

    首先,實習是有工資的。這一點特別重要,它讓我們擺脫了向父母伸手要錢的日子,有一種“翅膀長硬了”的感覺。儘管這份工資沒多少,但它證明我們對公司是有價值的。假如某個公司提倡“零工資”實習,那簡直是不要臉,不是真正的實習。

    其次,實習是有實際工作的。這一點也特別重要,它能夠讓我們茁壯地成長,有一種必須要變強的感覺。儘管每一個任務的工作量都很小,但它證明公司是重視我們的。假如公司把實習生放在一個角落沒人管,那簡直是浪費生命,不是真正的實習。

    最後,實習是有師父帶的。這一點千萬別忽視,它能夠讓我們更少犯錯、更快提高、更有收穫。儘管指導我們不是師父應盡的義務,但它證明公司是盡職盡責的。假如我們遇到的師父是負責任的,那麼謝天謝地謝師父吧。

    我在實習期的表現還不錯,順利的拿到了公司的正式邀請。畢業后一直在這家公司干,直到三年半后回到洛陽。這段工作的記憶至今依然非常美好。

    那除了培訓,還有什麼方法可以找到實習工作嗎?

    當然有,有很多!

    1)學校官網

    千萬不要忽視這一點啊!儘管學校官網的主頁一般做得稀耙爛,迎面撲來一種濃厚的“閏土”氣息,但上面的信息還是挺有價值的。

    下圖是我在鄭州大學的招生就業欄目中找到的招聘信息,更新日期為上一個工作日,蠻及時的。

    一定要未雨綢繆,不要等畢業的時候再去關注,那恐怕就有點晚了。最好從大一就開始持續關注。為什麼呢?

    如果一家企業從大一到畢業那年都在招聘,那就可以間接地說明這家企業運作的還不錯:要麼規模在擴大,要麼人員在流動,很良性,值得信賴。

    2)網上渠道

    我就不再推薦網站了,免得我有打廣告的嫌疑。只要你在搜索引擎里輸入“校園招聘”就會找到答案。去關注一些自己感興趣的公司,尤其是一些大廠,遇到心儀的就及時跟進。

    3)朋友介紹

    無論是實習找工作,還是正式找工作,朋友介紹永遠是最值得我們信賴的。這裏的“朋友”可不是躺在微信好友或者 QQ 好友列表裡的那些“占坑”朋友,而是經常有技術上的交流,生活中的交流的朋友。

    怎麼去認識這些朋友呢?教你一招,想盡一切辦法聯繫上各大知識分享社區上的大佬,那些排名比較靠前的,手頭都會有一些內推的機會。

    當然,前提是你有證明你很優秀的資本。

    05、new 一個對象

    好吧,我承認,我大學做的最正確的一件事就是——找了一個女朋友。是她,是她,就是她,讓我乏味的大學生活不再空虛寂寞冷。

    ,沒有對象就容易出現 NullPointerException。有了的話要注意安全,噓。

    這個話題我不打算談得太多,畢竟我不是情感博主。唯一給同學們的建議就是:如果遇到合適的人,認真談一場戀愛吧

    06、最後的建議

    開復老師:就要畢業了。

    回頭看自己所謂的大學生活,

    我想哭,不是因為離別,而是因為什麼都沒學到。

    我不知,簡歷該怎麼寫,若是以往我會讓它空白。

    最大的收穫也許是……對什麼都沒有的忍耐和適應……

    上面這段內容是一位同學寫給李開復老師的一封信,看完后我的眼淚一直在眼眶里打轉,因為他說出了我大二結束后的心聲。

    李開復老師給出的回復是:讀大學時,你應當掌握這七項,學好自修之道、基礎知識、實踐貫通、興趣培養、积極主動、掌控時間、為人處事。

    在我看來,這更像是對整個人生的建議。如果你來問我的話,我的回答就是以上你看到的這些內容。

    謝謝大家的閱讀,原創不易,喜歡就隨手點個贊,這將是我最強的寫作動力。如果你覺得文章對你有所幫助,也蠻有趣的,就關注一下我的微信公眾號「沉默王二」,拜謝。

    本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※專營大陸空運台灣貨物推薦

    台灣空運大陸一條龍服務

    ※評比南投搬家公司費用收費行情懶人包大公開

    南投搬家費用,距離,噸數怎麼算?達人教你簡易估價知識!

  • 防野火再度釀災 澳洲科學家開發預測衛星

    摘錄自2020年3月4日中央通訊社報導

    澳洲國立大學(Australian National University)今天(4日)表示,校內研究團隊正在開發一枚「鞋盒大小」的衛星,運用紅外線偵測器來測量森林覆蓋面積和空氣濕度,盼獲得的資料能協助判斷很可能爆發野火的地點,及野火可能難以控制的地點。不過,距離正式啟用大概還要5年時間。

    澳洲國立大學在聲明中說,這項科技將「專門用來偵測澳洲植被和林區的變化,例如針對易燃的尤加利樹」。

    遙測專家耶夫拉(Marta Yebra)表示,新衛星收集到的資料將提供給消防人員。:「這項紅外線科技和首次能夠取得的資料,將有助控制特定起火點,進而降低野火發生的頻率、嚴重程度,及對澳洲民眾、經濟和環境帶來的長遠影響。」

    研究人員指出,全球暖化正造成澳洲夏天時期更長,且爆發野火的危險越來越高。原因是冬天縮短,使得預防野火的工作更難執行。

    本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※帶您來了解什麼是 USB CONNECTOR  ?

    ※自行創業 缺乏曝光? 下一步”網站設計“幫您第一時間規劃公司的門面形象

    ※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!!

    ※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

    ※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益

    ※試算大陸海運運費!