Spring Security 之 rememberMe 自動登錄

自動登錄是將用戶的登錄信息保存在用戶瀏覽器的cookie中,當用戶下次訪問時,自動實現校驗並建立登錄態的一種機制。
Spring Security提供了兩種非常好的令牌:

  • 散列算法加密用戶必要的登錄信息並生成令牌
  • 數據庫等持久性數據存儲機制用的持久化令牌

散列加密方案

在Spring Security中加入自動登錄的功能非常簡單:

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/api/user/**").hasRole("user")  //user 角色訪問/api/user/開頭的路由
                .antMatchers("/api/admin/**").hasRole("admin") //admin 角色訪問/api/admin/開頭的路由
                .antMatchers("/api/public/**").permitAll()                 //允許所有可以訪問/api/public/開頭的路由
                .and()
                .formLogin()
                .and()
                .rememberMe().userDetailsService(userDetailsService());      //記住密碼
    }


重啟服務后訪問受限 API,這次在表單登錄頁中多了一個可選框:

勾選“Remember me on this computer”可選框(簡寫為Remember-me),按照正常的流程登錄,並在開發者工具中查看瀏覽器cookie,可以看到除JSESSIONID外多了一個值:

這是Spring Security默認自動登錄的cookie字段。在不配置的情況下,過期時間是兩個星期:

Spring Security會在每次表單登錄成功之後更新此令牌,具體處理方式在源碼中:

RememberConfigurer:

持久化令牌方案

在持久化令牌方案中,最核心的是series和token兩個值,它們都是用MD5散列過的隨機字符串。不同的是,series僅在用戶使用密碼重新登錄時更新,而token會在每一個新的session中都重新生成。
解決了散列加密方案中一個令牌可以同時在多端登錄的問題。每個會話都會引發token的更
新,即每個token僅支持單實例登錄。
自動登錄不會導致series變更,而每次自動登錄都需要同時驗證series和token兩個值,當該
令牌還未使用過自動登錄就被盜取時,系統會在非法用戶驗證通過後刷新 token 值,此時在合法用戶
的瀏覽器中,該token值已經失效。當合法用戶使用自動登錄時,由於該series對應的 token 不同,系統
可以推斷該令牌可能已被盜用,從而做一些處理。例如,清理該用戶的所有自動登錄令牌,並通知該
用戶可能已被盜號等
Spring Security使用PersistentRememberMeToken來表明一個驗證實體:

public class PersistentRememberMeToken {
    private final String username;
    private final String series;
    private final String tokenValue;
    private final Date date;

    public PersistentRememberMeToken(String username, String series, String tokenValue, Date date) {
        this.username = username;
        this.series = series;
        this.tokenValue = tokenValue;
        this.date = date;
    }

    public String getUsername() {
        return this.username;
    }

    public String getSeries() {
        return this.series;
    }

    public String getTokenValue() {
        return this.tokenValue;
    }

    public Date getDate() {
        return this.date;
    }
}

需要使用持久化令牌方案,需要傳入PersistentTokenRepository的實例:

PersistentTokenRepository接口主要涉及token的增刪查改四個接口:

MyPersistentTokenRepositoryImpl使我們實現PersistentTokenRepository接口:

@Service
public class MyPersistentTokenRepositoryImpl implements PersistentTokenRepository {

    @Autowired
    private JPAPersistentTokenRepository  repository;

    @Override
    public void createNewToken(PersistentRememberMeToken persistentRememberMeToken) {
        MyPersistentToken myPersistentToken = new MyPersistentToken();
        myPersistentToken.setSeries(persistentRememberMeToken.getSeries());
        myPersistentToken.setUsername(persistentRememberMeToken.getUsername());
        myPersistentToken.setTokenValue(persistentRememberMeToken.getTokenValue());
        myPersistentToken.setUser_last(persistentRememberMeToken.getDate());
        repository.save(myPersistentToken);
    }

    @Override
    public void updateToken(String series, String tokenValue, Date lastUsed) {
        MyPersistentToken myPersistentToken = repository.findBySeries(series);
        myPersistentToken.setUser_last(lastUsed);
        myPersistentToken.setTokenValue(tokenValue);
        repository.save(myPersistentToken);
    }

    @Override
    public PersistentRememberMeToken getTokenForSeries(String series) {
        MyPersistentToken myPersistentToken = repository.findBySeries(series);
        PersistentRememberMeToken persistentRememberMeToken = new PersistentRememberMeToken(myPersistentToken.getUsername(), myPersistentToken.getSeries(), myPersistentToken.getTokenValue(), myPersistentToken.getUser_last());
        return persistentRememberMeToken;
    }

    @Override
    @Transactional
    public void removeUserTokens(String username) {
        repository.deleteByUsername(username);
    }
}
public interface JPAPersistentTokenRepository extends JpaRepository<MyPersistentToken,Long> {
    MyPersistentToken findBySeries(String series);
    void deleteByUsername(String username);
}
@Entity
@Table(name = "persistent_token")
public class MyPersistentToken {
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE)
    private Long id;
    private  String username;
    @Column(unique = true)
    private  String series;
    private  String tokenValue;
    private  Date user_last;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getSeries() {
        return series;
    }

    public void setSeries(String series) {
        this.series = series;
    }

    public String getTokenValue() {
        return tokenValue;
    }

    public void setTokenValue(String tokenValue) {
        this.tokenValue = tokenValue;
    }

    public Date getUser_last() {
        return user_last;
    }

    public void setUser_last(Date user_last) {
        this.user_last = user_last;
    }
}

當自動登錄認證時,Spring Security 通過series獲取用戶名、token以及上一次自動登錄時間三個信息,通過用戶名確認該令牌的身份,通過對比 token 獲知該令牌是否有效,通過上一次自動登錄時間獲知該令牌是否已過期,並在完整校驗通過之後生成新的token。

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

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

台北網頁設計公司這麼多該如何選擇?

※智慧手機時代的來臨,RWD網頁設計為架站首選

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

※幫你省時又省力,新北清潔一流服務好口碑

※回頭車貨運收費標準

人類的「故鄉」找到了! 20萬年前誕生於非洲波札那

摘錄自2019年10月29日中央社報導

科學家29日表示,人類祖先是在距今20萬年前誕生於非洲的波札那北部,當地現遍布沙漠和鹽地,但20萬年前卻是廣大的湖泊溼地,生機盎然。

科學期刊「自然」(Nature)刊出由澳洲雪梨大學(University of Sydney)和嘉文醫學研究所(Garvan Institute of Medical Research and University of Sydney)遺傳學家海斯(Vanessa Hayes)所率研究團隊做的這份研究。

法新社報導,現居南非與納米比亞的科伊桑人(Khoisan)是一支古老種族,他們體內有高比例的線粒體DNA支系L0,國際研究團隊從200名科伊桑人身上採集DNA樣本,和地理分布、考古、氣候變遷資料相比對。

在涵蓋現今波札那北部、納米比亞、辛巴威的地區,20萬年前有一個相當於目前維多利亞湖(Lake Victoria,面積約6.8萬平方公里)兩倍的大湖破裂後,形成廣袤的溼地,人類的祖先就誕生於此。

海斯說:「我們談的是構造上的現代人種,即現今的人類。現今人類事實上最老就是回溯到L0支系,這個支系全回溯到這個起源地。」

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

【其他文章推薦】

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

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

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

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

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

※教你寫出一流的銷售文案?

歐洲電動自行車熱銷 美利達搶攻市場

歐洲人一向喜歡騎自行車旅遊、運動,看中銀髮族人數增加,讓退休老年人也能享受騎車樂趣的電動自行車,也成為最夯運動商品,各大車廠積極搶攻電動自行車市場。 比利時最大的自行車展於本周在庫特萊 (Kortrijk) 舉行,吸引超過 10 萬人次參觀。台灣自行車廠商美利達也從荷蘭前來參展。   看中銀髮商機,這幾年各大車廠都把焦點放到電動自行車領域,從一開始以通勤用為主,到現在不少車廠都針對高單價的公路車、登山車,推出電動車款,讓銀髮族也能輕鬆和朋友騎自行車出遊。   美利達荷蘭分公司總經理柯柏芮德表示,電動自行車將是未來歐洲自行車市場的一大主流商品,成長速度也相當快。歐洲 1 年的電動自行車銷售量達 20 萬輛,他樂觀預估市場至少可以擴大到數百萬輛。美利達也於 2 年前在德國生產基地擴充電動自行車生產線,搶攻歐洲電動自行車市場。        

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

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

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

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

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

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

※教你寫出一流的銷售文案?

TUV萊茵移駕深圳 設電動車電池實驗室

德國萊茵TUV集團19日宣佈其位於深圳的全新電動車電池實驗室正式啟動。該實驗室新增設備涵蓋大尺寸電動車電池測試和更多認證服務,可依據 UN/ECE R100標準提供全尺寸電動汽車電池和非可擕式電池的測試服務,也可按照企業需求定製檢測方案,已獲 CNAS、DAkkS、CBTL、NRTL、CATL、CTIA 等多項國際認可和授權。   TUV萊茵的深圳電池實驗室除了提供動力電池相關測試外,還可為客戶提供歐洲、北美、日本、韓國、俄羅斯、巴西等國際市場准入服務。其先進的電池性能和安全測試設備,以及來自世界各國的資深專家團隊,可根據歐盟、美國等主要國家與地區的相關標準和要求,對原電池、鉛酸蓄電池、二次鋰離子電池、鎳鎘電池、鎳氫電池、輕型電動自行車電池等產品提供檢測認證服務,以保證電池符合安全、性能、儲存、運輸、化學及電磁相容等各項要求。

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】

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

台北網頁設計公司這麼多該如何選擇?

※智慧手機時代的來臨,RWD網頁設計為架站首選

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

※幫你省時又省力,新北清潔一流服務好口碑

※回頭車貨運收費標準

Java工具類—包裝類

Java工具類——包裝類

我們都知道,JDK 其實給我們提供了很多很多 Java 開發者已經寫好的現成的類,他們其實都可以理解成工具類,比如我們常見的集合類,日期相關的類,數學相關的類等等,有了這些工具類,你會發現它能很大程度的幫你節省時間,能很方便的實現你的需求。當然,沒有這些包,你也能實現你的需求,但是你需要時間,今天我們主要是來學習一下包裝類。

一、包裝類介紹

1、為什麼需要包裝類?

我們知道 Java 語言是一個面向對象的編程語言,但是 Java 中的基本數據類型卻不是面向對象的,但是我們在實際使用中經常需要將基本數據類型轉換成對象,便於操作,比如,集合的操作中,這時,我們就需要將基本類型數據轉化成對象,所以就出現了包裝類。

2、包裝類是什麼呢?

包裝類,顧名思義就是將什麼經過包裝的類,那麼是將什麼包裝起來的呢,顯然這裡是將基本類型包裝起來的類。包裝類的作用就是將基本類型轉成對象,將基本類型作為對象來處理。

Java 中我們知道,基本數據類型有8個,所以對應的包裝類也是8個,包裝類就是基本類型名稱首字母大寫。但Integer 和 Character 例外,它們显示全稱,如下面表格所示:

基本數據類型 對應包裝類
byte Byte
short Short
int Integer
long Long
float Float
double Double
char Character
boolean Boolean

二、包裝類的繼承關係

通過閱讀 Java8 的 API 官方文檔或者看源代碼我們可以得知8個包裝類的繼承關係如下:

通過以上的繼承關係圖,我們其實可以這樣記憶,包裝類裏面有6個與数字相關的都是繼承自 Number 類,而其餘兩個不是與数字相關的都是默認繼承 Object 類。通過看 API 官方文檔,我們還可以得知這8個包裝類都實現了Serializable , Comparable 接口。比如下圖的 Integer 類

public final class Integer extends Number implements Comparable<Integer> {}

三、包裝類的使用方法(基本操作)

接下來關於包裝類的講解我就講Integer包裝類,其他的都依此類推,用法和操作都是差不多的,只是名字不一樣而已。

1、包裝類的構造方法

8個包裝類都有帶自己對應類型參數的構造方法,其中8個包裝類中除了Character還有構造方法重載,參數是String類型的。

Integer one = new Integer(666);
Integer two = new Integer("666");

2、包裝類的自動拆裝箱

在了解自動拆裝箱之前,我們得先知道什麼是拆箱和裝箱。其實拆裝箱主要應對基本類型與包裝類型的相互轉換問題。

  • 裝箱:將基本類型轉換成包裝類型的過程叫做裝箱。

  • 拆箱:將包裝類型轉換成基本類型的過程叫做拆箱。

其實,在 JDK1.5 版本之前,是沒有自動拆裝箱的,開發人員要手動進行裝拆箱:

//手動裝箱,也就是將基本類型10轉換為引用類型
Integer integer = new Integer(10);
//或者
Integer integer1 = Integer.valueOf(10);

//手動拆箱,也就是將引用類型轉換為基本類型
int num = integer.intValue();

而在在 JDK1.5 版本之後,為了減少開發人員的工作,提供了自動裝箱與自動拆箱的功能。實現了自動拆箱和自動裝箱,如下方代碼所示:

//自動裝箱
Integer one = 1;
//自動拆箱
int two = one + 10;

其實以上兩種方式本質上是一樣得,只不過一個是自動實現了,一個是手動實現了。至於自動拆裝箱具體怎麼實現的我這裏不做深入研究。

四、包裝類的緩存機制

我們首先來看看以下代碼,例1:

public static void main(String[] args) {
  Integer i1 = 100;
  Integer i2 = 100;
  Integer i3 = new Integer(100);
  Integer i4 = new Integer(100);
  System.out.println(i1 == i2);//true
  System.out.println(i1 == i3);//false
  System.out.println(i3 == i4);//false
  System.out.println(i1.equals(i2));//true
  System.out.println(i1.equals(i3));//true
  System.out.println(i3.equals(i4));//true
}

當我們修改了值為200的時候,例2:

public static void main(String[] args) {
  Integer i1 = 200;
  Integer i2 = 200;
  Integer i3 = new Integer(200);
  Integer i4 = new Integer(200);
  System.out.println(i1 == i2);//false
  System.out.println(i1 == i3);//false
  System.out.println(i3 == i4);//false
  System.out.println(i1.equals(i2));//true
  System.out.println(i1.equals(i3));//true
  System.out.println(i3.equals(i4));//true
}

通過上面兩端代碼,我們發現修改了值,第5行代碼的執行結果竟然發生了改變,為什麼呢?首先,我們需要明確第1行和第2行代碼實際上是實現了自動裝箱的過程,也就是自動實現了 Integer.valueOf 方法,其次,比較的是地址,而 equals 比較的是值(這裏的 eauals 重寫了,所以比較的是具體的值),所以顯然最後五行代碼的執行結果沒有什麼疑惑的。既然比較的是地址,例1的第5行代碼為什麼會是true呢,這就需要我們去了解包裝類的緩存機制。

其實看Integer類的源碼我們可以發現在第780行有一個私有的靜態內部類,如下:

private static class IntegerCache {
    static final int low = -128;
    static final int high;
    static final Integer cache[];

    static {
        // high value may be configured by property
        int h = 127;
        String integerCacheHighPropValue =
            sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
        if (integerCacheHighPropValue != null) {
            try {
                int i = parseInt(integerCacheHighPropValue);
                i = Math.max(i, 127);
                // Maximum array size is Integer.MAX_VALUE
                h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
            } catch( NumberFormatException nfe) {
                // If the property cannot be parsed into an int, ignore it.
            }
        }
        high = h;

        cache = new Integer[(high - low) + 1];
        int j = low;
        for(int k = 0; k < cache.length; k++)
            cache[k] = new Integer(j++);

        // range [-128, 127] must be interned (JLS7 5.1.7)
        assert IntegerCache.high >= 127;
    }

    private IntegerCache() {}
}

我們知道,靜態的內部類是在整個 Integer 加載的時候就已經加載完成了,以上代碼初始化了一個 Integer 類型的叫 cache 的數組,取值範圍是[-128, 127]。緩存機制的作用就是提前實例化相應範圍數值的包裝類對象,只要創建處於緩存範圍的對象,就使用已實例好的對象。從而避免重複創建多個相同的包裝類對象,提高了使用效率。如果我們用的對象範圍在[-128, 127]之內,就直接去靜態區找對應的對象,如果用的對象的範圍超過了這個範圍,會幫我們創建一個新的 Integer 對象,其實下面的源代碼就是這個意思:

public static Integer valueOf(int i) {
    if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i);
}

所以 例1 代碼里,i1 和i2 是100,值的範圍在[-128, 127],所以直接區靜態區找,所以i1和i2指向的地址是同一個,所以 i1==i2;而在例2的代碼里,i1 和i2 是200,值的範圍不在在[-128, 127],所以分別創建了一個新的對象,放在了堆內存里,各自指向了不同的地址,所以地址都不同了,自然 i1 不等於 i2。

通過分析源碼我們可以發現,只有 double 和 float 的自動裝箱代碼沒有使用緩存,每次都是 new 新的對象,其它的6種基本類型都使用了緩存策略。
使用緩存策略是因為,緩存的這些對象都是經常使用到的(如字符、-128至127之間的数字),防止每次自動裝箱都創建一次對象的實例。

五、包裝類和基本數據類型的區別

  • 默認值不同

包裝類的默認值是null,而基本數據類型是對應的默認值(比如整型默認值是0,浮點型默認值是0.0)

  • 存儲區域不同

基本數據類型是把值保存在棧內存里,包裝類是把對象放在堆中,然後通過對象的引用來調用他們

  • 傳遞方式不同

基本數據類型變量空間裏面存儲的是值,傳遞的也是值,一個改變,另外一個不變,而包裝類屬於引用數據類型,變量空間存儲的是地址(引用),傳遞的也是引用,一個變,另外一個跟着變。

五、小結

​ 以上就是我對於Java包裝類的個人理解,其實學習這些工具類還有一個更好的學習方式,就是去看官方文檔(API官方文檔地址:https://docs.oracle.com/javase/8/docs/api/)

公眾號:良許Linux

有收穫?希望老鐵們來個三連擊,給更多的人看到這篇文章

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

【其他文章推薦】

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

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

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

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

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

※教你寫出一流的銷售文案?

.NET 5.0預覽版6發布:支持Windows ARM64設備

2020年6月25日,微軟dotnet團隊在博客宣布了第六個 .NET 5.0 的預覽版:https://devblogs.microsoft.com/dotnet/announcing-net-5-0-preview-6/,在改進性能的同時增加了一些新的功能。ASP.NET Core和 EF Core也將於今日發布了。注意:EF Core 5.0 不支持 .NET Standard 2.0 或 .NET Framework,但是EF Core 5.0是支持.NET Core 3.1。 將所有內容組合在一起的里程碑式版本離預覽版 8 中完成功能只有兩步之遙,最終的 GA 版本定於 11 月發布,2019年Build大會上宣布.NET 5時,微軟就明確說了,”未來將只有一個.NET,您將能夠使用它來定位Windows、Linux、macOS、iOS、Android、tvOS、watchOS和WebAssembly等等。 微軟在4 月份宣布預覽版 2時宣布,它已經處理了其 .NET 站點上 50% 的流量。

 

自那時以來,一系列穩定的預覽版本一直在逐步修復Issue,完善現有功能和添加新的功能,雖然通常是一個小範圍,不斷敏捷迭代,小步快跑。 今天的預覽版 6 依然如此,Microsoft 將其描述為包含”一小組新功能和性能改進”。

本次更新的主要功能是在 Windows ARM64 上支持 Windows Forms 應用程序。此前.NET 5 Preview 4,Windows ARM64 上只支持控制台和 ASP.NET Core 應用程序。 通過這項支持,開發者可以在 Surface Pro X 等 Windows ARM64 設備上構建和運行 Windows Forms 應用。微軟還透露,他們仍在努力為 Windows ARM64 設備提供 WPF支持。 同時.NET 5移除了對WinRT 的內置支持,通過外部工具鏈進行支持,這麼做的最直接的好處是簡化 .NET 運行時代碼庫(一下就刪除 6 萬行代碼),而且這麼多代碼和跨平台無關。這次版本更新的內容如下:

  • Windows 窗體改進:開發人員可以強制其應用程序是單實例的,這意味着一次啟動一個實例。
  • RyuJIT 代碼質量改進:其中大量涉及常規改進(結構處理等)、ARM64 硬件內部功能和 ARM64 生成的代碼改進,從而大大減少了 ARM64 代碼大小。
  • 單個文件應用改進:添加了在單個文件中包含本機二進制文件和任何其他內容(如圖片)的新選項,.NET 5目標是為 Windows、macOS 和 Linux 啟用將應用作為一個文件發布。這個裡程碑進一步接近了。
  • 本機託管應用程序改進:一位貢獻者提供了一種新的模型,用於在本機應用程序中的 .NET 託管模型。
  • 突破性的改變 — 刪除內置 WinRT 支持: “已經用 Windows 團隊在 .NET 5.0 中提供的C#/WinRT工具鏈取代了內置 WinRT 支持。WinRT 互操作中的此更改是一個突破性的變化,使用 WinRT 的 .NET Core 3.x 應用將需要重新編譯。我們將在即將到來的預覽版中提供有關此內容的更多信息。

開發工具支持上需要Visual Studio 16.7 預覽版才支持.NET 5, Visual Studio For Mac 也支持.NET 5, 當然Visual Studio Code 安裝最新版的C#擴展插件也支持.NET 5. Visual Studio .NET遠程調試器對Windows ARM64的支持將在Visual Studio 16.7版本中提供。Visual Studio Code .NET遠程調試器支持將在以後推出。

Richard 在博客結束時說:”我們現在已經過了這個發布周期的一半。”事實上,我們開始’關閉發布’。如果您密切關注我們的代碼倉庫,您會看到我們正開始更仔細地管理問題的里程碑。 在發布了多個.NET 5 版本之後,我可以告訴你,這是一個偉大的時間。 是時候在一組我們構建的功能上取得勝利,並把它們打磨到您樂於使用它們。 這就是我們現在在家裡遠程工作所做的。 儘管 11 月首次亮相仍有望實現,但 .NET 5 不會擁有 Microsoft 最初計劃的所有特性和功能。這是因為COVID-19大流行引起的併發症。因此,完整的包將會在 2021 年 11 月與 .NET 6 一起發布。

您可以使用以下鏈接下載新的 .NET 5.0 的第六個預覽版,適用于于Windows、macOS和Linux: 

  • Windows and macOS installers
  • Binaries
  • Docker images
  • Snap installer

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

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

台北網頁設計公司這麼多該如何選擇?

※智慧手機時代的來臨,RWD網頁設計為架站首選

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

※幫你省時又省力,新北清潔一流服務好口碑

※回頭車貨運收費標準

四川綿陽2020年產15萬輛新能源車 總產值達5059億

中國四川省綿陽市政府常務會議審議並原則通過了《綿陽市新能源汽車產業發展規劃(2015—2020年)》。規劃提出欲在綿陽科技城集中發展區建設集新能源汽車核心技術研發、核心零件生產製造、整車製造與體驗、國家級專業孵化器、中國國家級工程技術實驗與檢測中心為一體的國家新能源汽車研究與產業發展基地。到2020年,實現年產15萬輛新能源汽車的產能,新能源汽車及關鍵零部件產業總產值1000億元人民幣(折合新台幣約5059億元)。   綿陽新能源汽車產業已擁有川汽、華晨汽車南方基地、中國重汽綿陽分公司等整車製造企業,還擁有長虹、安縣英志鋰電池等一批新能源汽車零配件企業。規劃提出,綿陽要「全域規劃」,加快新能源汽車在公共交通、公務、出租等領域的示範應用,政府採購的特種車輛也要優先選擇新能源汽車;大力發展農用低速電動車,不斷擴大新能源汽車應用範圍。

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【【其他文章推薦】

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

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

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

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

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

※教你寫出一流的銷售文案?

新北市:電動車牌照稅再延長 3 年

新北市政府稅捐稽徵處表示,為提高民眾購置電動汽車的意願,加速建立新北市成為綠色交通城市,凡民眾購買完全以電能為動力的電動汽車並於該市完成車籍登記,免徵使用牌照稅優惠延至 107 年 1 月 5 日止。   該處說,「完全以電能為動力的車輛」享有免徵使用牌照的優惠自 101 年 1 月 5 日施行起至今已滿 3 年,原優惠至今年 1 月 5 日截止。為繼續扶植國內電動車產業發展,並鼓勵民眾使用低汙染車輛,總統於 104 年 2 月 4 日公布修正使用牌照稅法第 5 條條文,繼續授權地方政府得對完全以電能為動力的汽車使用牌照稅免稅期間再延長 3 年。   稅捐處表示,配合國際新能源車輛的發展動向,及響應行政院繼續推動使用智慧電動車政策,新北市配合使用牌照稅法第 5 條修正,延長免徵牌照稅優惠期間至 107 年 1 月 5 日止。

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】

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

台北網頁設計公司這麼多該如何選擇?

※智慧手機時代的來臨,RWD網頁設計為架站首選

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

※幫你省時又省力,新北清潔一流服務好口碑

※回頭車貨運收費標準

解惑3:時間頻度,算法時間複雜度

一、概述

先放百科上的說法:

算法的時間複雜度(Time complexity)是一個函數,它定性描述該算法的運行時間。這是一個代表算法輸入值的字符串的長度的函數。

時間複雜度常用大O符號表述,不包括這個函數的低階項和首項係數。使用這種方式時,時間複雜度可被稱為是漸近的,亦即考察輸入值大小趨近無窮時的情況。

例如,如果一個算法對於任何大小為 n (必須比 n0 大)的輸入,它至多需要 5n3 + 3n 的時間運行完畢,那麼它的漸近時間複雜度是 O(n3).

二、時間頻度

要理解時間複雜度,需要先理解時間頻度,而時間頻度簡單的說,就是算法中語句的執行次數

舉個例子:

要計算1+2+…+100,現在有兩種算法

public int fun1(int n){
    int total;
    for(int i = 0; i <= n; i++){
        total+=i;
    }
    return total;
}

public int fun2(int n){
    int total = (1 + n)*n/2;
    return total;
}

我們可以看見,對於fun1()這個方法,不管n多大,永遠需要執行n+1次,也就是說他的時間頻度是T(n)=n+1,

而對與fun2()來說,不管n多大都只需要執行1次,所以他的時間頻度T(n)=1。

當n趨向無窮大時,有三個忽略

1.忽略常數項

比如T(n)=2n+1,當n趨向無窮大時,可以忽略常數項1;

參見下圖:

  • 2n+20 和 2n 隨着n 變大,執行曲線無限接近, 20可以忽略
  • 3n+10 和 3n 隨着n 變大,執行曲線無限接近, 10可以忽略

2.忽略低次項

比如T(n)=2n+3n^8,當n趨向無窮大時,可以忽略低次項及其係數2n;

參見下圖:

  • 2n^2+3n+10 和 2n^2 隨着n 變大, 執行曲線無限接近, 可以忽略 3n+10
  • n^2+5n+20 和 n^2 隨着n 變大,執行曲線無限接近, 可以忽略 5n+20

3.忽略係數

比如T(n)=2n^8,當n趨向無窮大時,可以忽略係數2。

參見下圖:

  • 隨着n值變大,5n^2+7n 和 3n^2 + 2n ,執行曲線重合, 說明 這種情況下, 5和3可以忽略。
  • 而n^3+5n 和 6n^3+4n ,執行曲線分離,說明多少次方式關鍵

三、時間複雜度

我們現在理解了時間頻度的T(n)的含義,假設當有一個輔助函數f(n),使得當n趨近無窮大時,T(n)/f(n)的極限值為不等於0的常數,就叫f(n)為T(n)的同量級函數,記作T(n)=O(f(n)),

稱O(f(n))為算法的時間漸進複雜度,也就是時間複雜度

又根據時間頻度T(n)的“三個忽略”原則,我們可以知道時間複雜度是這樣得到的:

  1. 忽略所有常數
  2. 只保留函數中的最高階項
  3. 去掉最高階項的係數

舉個例子:

某算法T(n)=2n^3+4n-5,按步驟走:

  1. T(n)=2n^3+4n
  2. T(n)=2n^3
  3. T(n)=n^3

即可得該算法時間複雜度為O(n^3)

四、常見時間複雜度

這裏按複雜度從低到高列舉常見的時間複雜度:

  1. 常數階O(1)

    // 無論代碼執行了多少行,只要是沒有循環等複雜結構,那這個代碼的時間複雜度就都是O(1) 。
    public void fun(int n){
        n+=1;
    }
    
  2. 對數階O(log2n)

    // 根據公式有 n = 2^x,也就是 x = log2n,x即為循環代碼執行次數,所以時間複雜度為O(log2n)
    public void fun(int n){
        int i = 1;
        while(i < n){
            i = i *2
        }
    }
    
  3. 線性階O(n)

    // 一般來說,只要代碼里只有一個循環結構,即輸入規模和執行次數呈線性相關,那這個代碼的時間複雜度就都是O(n) 。
    public void fun(int n){
        for(int i = 0; i < n; i++){
            n+=i;
        }
    }
    
  4. 線性對數階O(nlogn)

    // 可以簡單理解為對數階的程序被放入了循環結構中,也就是n*O(logn),下面的代碼的複雜度就是O(nlog2n)
    public void fun(int n){
        int j = 1;
        for(int i = 0; i < n; i++){
            while(i < n){
                j = j *2
            }
        }
    }
    
  5. 平方階O(n²),立方階O(n3),K次方階O(nk)

    // 平方階可以簡單理解為線性階中嵌套一個線性階,也就是O(logn)*O(logn),下面的代碼複雜度就是O(n^2)
    // 立方階同理,就是三個線性階的嵌套,K次方階同理
    public void fun(int n){
        for(int i = 0; i < n; i++){
            for(int j = 0; j < n; i++){
    			i=i+j;
            } 
        }
    }
    

五、複雜度的四個概念

  1. 最壞情況時間複雜度:代碼在最理想情況下執行的時間複雜度。
  2. 最好情況時間複雜度:代碼在最壞情況下執行的時間複雜度。
  3. 平均時間複雜度:用代碼在所有情況下執行的次數的加權平均值表示
  4. 均攤時間複雜度:在代碼執行的所有複雜度情況中絕大部分是低級別的複雜度,個別情況是高級別複雜度且發生具有時序關係時,可以將個別高級別複雜度均攤到低級別複雜度上。基本上均攤結果就等於低級別複雜度。

舉個例子:

長度為n的數組查找一個給定元素k

public void fun(int[] arr,int k){
    for(int i = 0; i < arr.length; i++){
        if(arr[i] == k){
            //找到了
        }
    }
}

上面這個方法,最好的情況下元素k就在數組第一位,複雜度為O(1),但是最壞的情況下,元素k在數組最後一位,複雜度為O(n)。

同一段代碼在不同情況下時間複雜度會出現量級差異,為了更全面,更準確的描述代碼的時間複雜度,我們引入這4個概念,當然,在大多數時候我們是不用特意區分這四種情況的。

六、總結

總結一下如何快速判斷程序的時間複雜度:

  • 只關注循環最多的那部分代碼
  • 總複雜度等於量級最大的那段代碼的複雜度
  • 嵌套代碼的複雜度等於嵌套內外代碼複雜度的乘積

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

【【其他文章推薦】

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

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

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

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

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

※教你寫出一流的銷售文案?

Jmeter系列(35)- 使用 ServerAgent 監控服務器

如果你想從頭學習Jmeter,可以看看這個系列的文章哦

https://www.cnblogs.com/poloyy/category/1746599.html

 

前言

  • 做性能測試,監控服務器資源指標是必須有的一步
  • 這一篇博客將講解通過 Jmeter 插件來監控服務器,再通過 Jmeter 觀察監控結果

 

下載、安裝、運行插件

  1. JMeterPlugins-Extras.jar
  2. JMeterPlugins-Standard.jar
  3. ServerAgent-2.2.3.zip

可以通過官方下載:https://jmeter-plugins.org/downloads/old/

注意

  • 前兩個插件最新版本在官網已經不提供下載了,只能下載舊版本,官方建議通過 Plugins Manager 下載需要的插件哦
  • 博主安裝了以下插件,已經包含上面講的前兩個插件了

 

這裏也提供百度雲下載鏈接哈

鏈接:https://pan.baidu.com/s/1bAaKqGoyaTVoq5picgBGMw 

提取碼:q92i

 

客戶端(Jmeter 端)

  1. 如果通過官網下載的話,就將 JMeterPlugins-Extras.jar 和 JMeterPlugins-Standard.jar 放到  D:\apache-jmeter-5.2.1\lib\ext 
  2. 然後通過 PerfMon Metrics Collector 監聽器進行服務器性能數據显示

 

服務端(Linux)

將 ServerAgent-2.2.3.zip 放到任意目錄下,解壓

unzip  ServerAgent-2.2.3.zip 

 

進入 ServerAgent 目錄

 

我提供的 ServerAgent 裏面,兩個 start 腳本已經是可執行腳本了,直接運行即可

./startAgent.sh

 

運行成功,則會出現下圖

 

如果無法運行,則需要給腳本賦權

chmod 777 startAgent.sh

 

如果是想監控 Window 機器,則將 ServerAgent 放到 Window 電腦的目錄下,然後直接雙擊運行  startAgent.bat 即可

 

划重點

  • 啟動 ServerAgent 的前提是系統已安裝配置好 Java 環境
  • 默認佔用端口是 4444

 

啟動 ServerAgent 可能會出現的問題

端口被佔用

殺掉佔用 4444 端口的進程

  1. 先查出 4444 端口是什麼進程佔用
  2. 然後查看進程詳情,確認是否能殺掉
  3. 如果可以,則殺掉、

 

ServerAgent 通過其他端口啟動

./startAgent.sh --udp-port 0 --tcp-port 1234

 

0 代表不開啟該端口,一般我們只用 tcp 足以

 

端口未對外開放

  • 如果服務器開啟了防火牆,而且之前沒用過 4444 端口,那麼該端口很可能會被禁用
  • 為了解決防火牆和開放端口的問題,可以參考這篇博文:https://www.cnblogs.com/poloyy/p/12213297.html

 

Jmeter 監控服務器全流程

一個簡單的負載測試線程組結構樹

一般做負載測試,會監控服務器資源、活動線程數、響應時間、TPS等等,所以加了一堆監聽器

 

PerfMon Metrics Collector

IP 自然就是填需要監控的服務器 IP啦,如果是監控本機就填 127.0.0.1 就好了

 

可監控的指標列表

還挺多,不過一般重點關注前面四個就好了

 

運行結果

我的 cpu 真高…因為數據庫出現死鎖了,回頭可以好好性能分析一波了!

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

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

台北網頁設計公司這麼多該如何選擇?

※智慧手機時代的來臨,RWD網頁設計為架站首選

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

※幫你省時又省力,新北清潔一流服務好口碑

※回頭車貨運收費標準