分類
發燒車訊

Hystrix微服務容錯處理及回退方法源碼分析_貨運

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

網動結合了許多網際網路業界的菁英共同研發簡單易操作的架站工具,及時性的更新,為客戶創造出更多的網路商機。

前言

在 SpringCloud 微服務項目中,我們有了 Eureka 做服務的註冊中心,進行服務的註冊與發現和服務治理。使得我們可以摒棄硬編碼式的 ip:端口 + 映射路徑 來發送請求。我們有了 Feign 作為聲明式服務調用組件,可以像調用本地服務一樣來調用遠程服務。基於 Ribbon 我們又實現了客戶端負載均衡,輕鬆的在集群環境下選取合適的服務提供者。這樣看來我們的微服務貌似很完善了。是這樣的嗎?

並非如此,想想我們在編碼過程中進行的健壯性檢查。類比一下服務與服務調用是否也應該更加健壯一些呢?我們目前的微服務在正常運行的時候是沒有問題的,但若是某個偏下游的服務提供者不可用,造成服務積壓,接連引起上游的服務消費者宕機,引法雪崩效應。是不是就顯得我們的微服務不堪一擊呢?因此我們需要一個組件來解決這樣的問題,前輩們參考生活中保險絲的原理做出了微服務中的保險絲-Hystrix熔斷器。下面讓我們來一起使用一下

聲明:本文首發於博客園,作者:后青春期的Keats;地址:https://www.cnblogs.com/keatsCoder/ 轉載請註明,謝謝!

Hystrix簡介

Hystrix主要實現了下面的功能:

  • 包裹請求:使用 HystrixCommand(或 HystrixObservableCommand) 包裹對依賴的調用邏輯。每個命令在獨立的線程中執行,使用了設計模式中的‘命令模式’
  • 跳閘機制:當某微服務的錯誤率超過一定閾值時,可以自動跳閘,停止請求該服務一段時間
  • 資源隔離:Hystrix 為每個微服務都維護了一個小型的線程池(或信號量)如果該線程池已滿,發往該依賴的請求就會被立即拒絕
  • 監控:Hystrix 可以近乎實時的監控運行指標和配置的變化,例如成功、失敗、超時和被拒絕的請求等
  • 回退機制:當請求成功、失敗、超時和被拒絕或者斷路器打開時,執行回退邏輯。回退邏輯可由開發人員自行提供
  • 自我修復:斷路器打開一段時間后,會進入‘半開’狀態,允許一個請求訪問服務提供方,如果成功。則關閉斷路器

使用 Hystrix

引入依賴

        <!-- 熔斷器 hystrix -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        </dependency>

在啟動類上添加 @EnableHystrix

兩種情況下的回退方法

非 Feign 調用下的回退方法

編寫回退方法
/**
 * getUserByAge 方法 Hystrix 回退方法
 * @param age
 * @return
 */
public User getUserByAgeFallBack(Integer age){
    User user = new User();
    user.setName("默認用戶");
    user.setAge(age);
    return user;
}
在客戶端的方法上聲明
@HystrixCommand(fallbackMethod = "getUserByAgeFallBack")

測試:將服務提供方的代碼打斷點。調用服務消費方,會發現返回了默認用戶

需要注意:

  1. 回退方法的返回值類型需要和原來方法返回值類型相同(否則會報 FallbackDefinitionException: Incompatible return types)
  2. 回退方法的參數列表也要和原來方法相同(否則會報 FallbackDefinitionException: fallback method wasn’t found: getUserByAgeFallBack([class java.lang.Integer]))
  3. 當我寫下第二句時,發現書中下一節介紹說可以通過在回退方法中添加第二個參數:ThrowEable 來捕獲異常,分析調用失敗的原因,我就知道我錯了。為了避免繼續得到錯誤的結論,我決定讀一讀 Hystrix 處理回退方法的源碼
加點料:Hystrix 對回退方法的封裝的源碼如下:
com.netflix.hystrix.contrib.javanica.utils.MethodProvider
public FallbackMethod find(Class<?> enclosingType, Method commandMethod, boolean extended) {
	// 首先判斷該方法的 HystrixCommand 註解上有沒有 defaultFallback / fallbackMethod 配置回退方法名稱
    if (this.canHandle(enclosingType, commandMethod)) {
    	// 調用 doFind 方法
        return this.doFind(enclosingType, commandMethod, extended);
    } else {
    	// 沒有配置的化就接着下一個判斷
        return this.next != null ? this.next.find(enclosingType, commandMethod, extended) : FallbackMethod.ABSENT;
    }
}

find 方法在用戶所請求的方法的 HystrixCommand 註解上有用 defaultFallback / fallbackMethod 配置回退方法名稱的時候,會調用 doFind 方法來尋找回退方法。該方法的參數有兩個,enclosingType 是用戶所請求的方法的類字節碼文件,commandMethod 是用戶所請求的方法

首先通過 this.getFallbackName 獲取回退方法名稱,接着通過獲取 commandMethod 的參數類型們

接着分兩種情況:

  1. 回調方法繼承於 commandMethod 且最後一個參數類型是 Throwable,則去掉回退方法參數列表中的 Throwable 類型進行匹配
  2. 回調方法不繼承於 commandMethod ,則存在兩個可能的參數類型列表: fallbackParameterTypes 和 extendedFallbackParameterTypes 前者是 commandMethod 是參數列表,後者是前者 + Throwable。然後兩個都進行匹配。接着使用 Java8 Optional API,按順序選取前者匹配到的方法 / 後者 / 空返回
private FallbackMethod doFind(Class<?> enclosingType, Method commandMethod, boolean extended) {
    String name = this.getFallbackName(enclosingType, commandMethod);
    Class<?>[] fallbackParameterTypes = null;
    if (this.isDefault()) {
        fallbackParameterTypes = new Class[0];
    } else {
        fallbackParameterTypes = commandMethod.getParameterTypes();
    }

    if (extended && fallbackParameterTypes[fallbackParameterTypes.length - 1] == Throwable.class) {
        fallbackParameterTypes = (Class[])ArrayUtils.remove(fallbackParameterTypes, fallbackParameterTypes.length - 1);
    }

    Class<?>[] extendedFallbackParameterTypes = (Class[])Arrays.copyOf(fallbackParameterTypes, fallbackParameterTypes.length + 1);
    extendedFallbackParameterTypes[fallbackParameterTypes.length] = Throwable.class;
    Optional<Method> exFallbackMethod = MethodProvider.getMethod(enclosingType, name, extendedFallbackParameterTypes);
    Optional<Method> fMethod = MethodProvider.getMethod(enclosingType, name, fallbackParameterTypes);
    Method method = (Method)exFallbackMethod.or(fMethod).orNull();
    if (method == null) {
        throw new FallbackDefinitionException("fallback method wasn't found: " + name + "(" + Arrays.toString(fallbackParameterTypes) + ")");
    } else {
        return new FallbackMethod(method, exFallbackMethod.isPresent(), this.isDefault());
    }
}

由源碼可以得到結論:回退方法要麼參數列表和原始方法相同,要麼加且僅加一個類型為 Throwable 的參數。其他的都不行

Feign 客戶端下的回退方法

  1. 設置:feign.hystrix.enabled: true

    ※回頭車貨運收費標準

    宇安交通關係企業,自成立迄今,即秉持著「以誠待人」、「以實處事」的企業信念

  2. Feign 客戶端接口上的 @FeignClient 添加 fallback 屬性,指向回退類

  3. 回退類實現客戶端接口

# feign的配置
feign:
  hystrix:
    enabled: true # 打開 feign 的 hystrix 支持

注意回退類加上 @Component 接口,避免因為 Spring 容器找不到該類而啟動報錯

// Feign 客戶端接口上的 @FeignClient 添加 fallback 屬性,指向回退類
@FeignClient(name = "SERVICE-PROVIDER", fallback = UserServiceFeignClientFallBack.class)
public interface UserServiceFeignClient {

    @GetMapping("/api/v1/user/{age}")
    User getUser(@PathVariable("age") Integer age);

    /**
     * 用戶列表
     * @return
     */
    @GetMapping("/api/v1/users")
    List<User> getUsers();
}
// 回退類實現客戶端接口
@Component 
public class UserServiceFeignClientFallBack implements UserServiceFeignClient {
    @Override
    public User getUser(Integer age) {
        return null;
    }

    @Override
    public List<User> getUsers() {
        return null;
    }
}

當採用 Feign 客戶端來實現回退的時候,前面的捕捉異常方法就不起作用了,那我們應該如何來處理異常呢?可以使用 @FeignClient 的 fallbackFactory 屬性

@FeignClient(name = "SERVICE-PROVIDER", fallbackFactory = UserServiceFallbackFactory.class)

@Component
@Slf4j
public class UserServiceFallbackFactory implements FallbackFactory<UserServiceFeignClient> {
    @Override
    public UserServiceFeignClient create(Throwable t) {
        // 日誌最好寫在各個 fallback 方法中,而不要直接卸載 create方法中
        // 否則引用啟動時就會打印該日誌

        return new UserServiceFeignClient() {
            @Override
            public User getUser(Integer age) {
                log.info("調用User服務提供者失敗", t);
                User user = new User();
                user.setName("默認用戶");
                user.setAge(age);
                return user;
            }

            @Override
            public List<User> getUsers() {
                return null;
            }
        };
    }
}

注意: **fallback 和 fallbackFactory 屬性同時存在時,fallback 的優先級更高。因此開發中如果需要處理異常,只需配置 fallbackFactory 屬性即可 **

避免業務異常走進回退方法

在某些場景下,當發生業務異常時,我們並不想觸發 fallback。例如業務中判斷年齡 age 不能小於 1,否則拋出異常

if(age < 1){
    throw new KeatsException(ExceptionEnum.NUM_LESS_THAN_MIN);
}

這時 Hystrix 會捕捉到異常然後執行 fallback 方法,我們可以通過下面兩個方法來避免:

  1. 繼承 HystrixBadRequestException 該類繼承自 RunntimeException
  2. 在 @HystrixCommand 添加屬性 ignoreExceptions = {KeatsException.class}

為 Feign 禁用 Hystrix

只要打開 feign 的 hystrix 支持開關,feign 就會使用斷路器包裹 feign 客戶端的所有方法,但很多場景並不需要這樣。該如何禁用呢?

  • 為指定客戶端禁用。需要藉助 Feign 的自定義配置。首先添加一個自定義配置類,然後配置到 @FeignClient 的 configuration 屬性中
@Configuration
public class FeignDisableHystrixConfiguration {
    @Bean
    @Scope("prototype")
    public Feign.Builder feignBuilder(){
        return Feign.builder();
    }
}

@FeignClient(name = "SERVICE-PROVIDER", configuration = {FeignDisableHystrixConfiguration.class})
  • 全局禁用: feign.hystrix.enabled: false

本博客中所有示例代碼都已上傳至 github倉庫: https://github.com/keatsCoder/cloud-cli

參考文獻:《Spring Cloud與Docker 微服務架構實戰》 — 周立

碼字不易,如果你覺得讀完以後有收穫,不妨點個推薦讓更多的人看到吧!

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

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

搬家價格與搬家費用透明合理,不亂收費。本公司提供下列三種搬家計費方案,由資深專業組長到府估價,替客戶量身規劃選擇最經濟節省的計費方式

分類
發燒車訊

【Java8新特性】關於Java8中的日期時間API,你需要掌握這些!!_網頁設計公司

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

透過選單樣式的調整、圖片的縮放比例、文字的放大及段落的排版對應來給使用者最佳的瀏覽體驗,所以不用擔心有手機版網站兩個後台的問題,而視覺效果也是透過我們前端設計師優秀的空間比例設計,不會因為畫面變大變小而影響到整體視覺的美感。

寫在前面

Java8之前的日期和時間API,存在一些問題,比如:線程安全的問題,跨年的問題等等。這些問題都在Hava8中的日期和時間API中得到了解決,而且Java8中的日期和時間API更加強大。立志成為架構師的你,必須掌握Java8中的日期和時間API。

本地時間和時間戳

主要方法:

  • now:靜態方法,根據當前時間創建對象
  • of:靜態方法,根據指定日期/時間創建對象
  • plusDays,plusWeeks,plusMonths,plusYears:向當前LocalDate 對象添加幾天、幾周、幾個月、幾年
  • minusDays,minusWeeks,minusMonths,minusYears:從當前LocalDate 對象減去幾天、幾周、幾個月、幾年
  • plus,minus:添加或減少一個Duration 或Period
  • withDayOfMonth,withDayOfYear,withMonth,withYear:將月份天數、年份天數、月份、年份修改為指定的值並返回新的LocalDate 對象
  • getDayOfYear:獲得年份天數(1~366)
  • getDayOfWeek:獲得星期幾(返回一個DayOfWeek枚舉值)
  • getMonth:獲得月份, 返回一個Month 枚舉值
  • getMonthValue:獲得月份(1~12)
  • getYear:獲得年份
  • until:獲得兩個日期之間的Period 對象,或者指定ChronoUnits 的数字
  • isBefore,isAfter:比較兩個LocalDate
  • isLeapYear:判斷是否是閏年

使用 LocalDate、 LocalTime、 LocalDateTime

LocalDate、 LocalTime、 LocalDateTime 類的實例是不可變的對象,分別表示使用 ISO-8601日曆系統的日期、時間、日期和時間。它們提供了簡單的日期或時間,並不包含當前的時間信息。也不包含與時區相關的信息。

注: ISO-8601日曆系統是國際標準化組織制定的現代公民的日期和時間的表示法

方法 描述 示例
now() 靜態方法,根據當前時間創建對象 LocalDate localDate = LocalDate.now(); LocalTime localTime = LocalTime.now(); LocalDateTime localDateTime = LocalDateTime.now();
of() 靜態方法,根據指定日期/時間創建 對象 LocalDate localDate = LocalDate.of(2016, 10, 26); LocalTime localTime = LocalTime.of(02, 22, 56); LocalDateTime localDateTime = LocalDateTime.of(2016, 10, 26, 12, 10, 55);
plusDays, plusWeeks, plusMonths, plusYears 向當前 LocalDate 對象添加幾天、 幾周、 幾個月、 幾年
minusDays, minusWeeks, minusMonths, minusYears 從當前 LocalDate 對象減去幾天、 幾周、 幾個月、 幾年
plus, minus 添加或減少一個 Duration 或 Period
withDayOfMonth, withDayOfYear, withMonth, withYear 將月份天數、 年份天數、 月份、 年 份 修 改 為 指 定 的 值 並 返 回 新 的 LocalDate 對象
getDayOfMonth 獲得月份天數(1-31)
getDayOfYear 獲得年份天數(1-366)
getDayOfWeek 獲得星期幾(返回一個 DayOfWeek 枚舉值)
getMonth 獲得月份, 返回一個 Month 枚舉值
getMonthValue 獲得月份(1-12)
getYear 獲得年份
until 獲得兩個日期之間的 Period 對象, 或者指定 ChronoUnits 的数字
isBefore, isAfter 比較兩個 LocalDate
isLeapYear 判斷是否是閏年

示例代碼如下所示。

// 獲取當前系統時間
LocalDateTime localDateTime1 = LocalDateTime.now();
System.out.println(localDateTime1);
// 運行結果:2019-10-27T13:49:09.483

// 指定日期時間
LocalDateTime localDateTime2 = LocalDateTime.of(2019, 10, 27, 13, 45,10);
System.out.println(localDateTime2);
// 運行結果:2019-10-27T13:45:10

LocalDateTime localDateTime3 = localDateTime1
        // 加三年
        .plusYears(3)
        // 減三個月
        .minusMonths(3);
System.out.println(localDateTime3);
// 運行結果:2022-07-27T13:49:09.483

System.out.println(localDateTime1.getYear());       // 運行結果:2019
System.out.println(localDateTime1.getMonthValue()); // 運行結果:10
System.out.println(localDateTime1.getDayOfMonth()); // 運行結果:27
System.out.println(localDateTime1.getHour());       // 運行結果:13
System.out.println(localDateTime1.getMinute());     // 運行結果:52
System.out.println(localDateTime1.getSecond());     // 運行結果:6

LocalDateTime localDateTime4 = LocalDateTime.now();
System.out.println(localDateTime4);     // 2019-10-27T14:19:56.884
LocalDateTime localDateTime5 = localDateTime4.withDayOfMonth(10);
System.out.println(localDateTime5);     // 2019-10-10T14:19:56.884

Instant 時間戳

用於“時間戳”的運算。它是以Unix元年(傳統的設定為UTC時區1970年1月1日午夜時分)開始所經歷的描述進行運算 。

示例代碼如下所示。

Instant instant1 = Instant.now();    // 默認獲取UTC時區
System.out.println(instant1);
// 運行結果:2019-10-27T05:59:58.221Z

// 偏移量運算
OffsetDateTime offsetDateTime = instant1.atOffset(ZoneOffset.ofHours(8));
System.out.println(offsetDateTime);
// 運行結果:2019-10-27T13:59:58.221+08:00

// 獲取時間戳
System.out.println(instant1.toEpochMilli());
// 運行結果:1572156145000

// 以Unix元年為起點,進行偏移量運算
Instant instant2 = Instant.ofEpochSecond(60);
System.out.println(instant2);
// 運行結果:1970-01-01T00:01:00Z

Duration 和 Period

Duration:用於計算兩個“時間”間隔。

Period:用於計算兩個“日期”間隔 。

Instant instant_1 = Instant.now();
try {
    Thread.sleep(1000);
} catch (InterruptedException e) {
    e.printStackTrace();
}
Instant instant_2 = Instant.now();

Duration duration = Duration.between(instant_1, instant_2);
System.out.println(duration.toMillis());
// 運行結果:1000

LocalTime localTime_1 = LocalTime.now();
try {
    Thread.sleep(1000);
} catch (InterruptedException e) {
    e.printStackTrace();
}
LocalTime localTime_2 = LocalTime.now();

System.out.println(Duration.between(localTime_1, localTime_2).toMillis());
// 運行結果:1000
LocalDate localDate_1 = LocalDate.of(2018,9, 9);
LocalDate localDate_2 = LocalDate.now();

Period period = Period.between(localDate_1, localDate_2);
System.out.println(period.getYears());      // 運行結果:1
System.out.println(period.getMonths());     // 運行結果:1
System.out.println(period.getDays());       // 運行結果:18

日期的操縱

TemporalAdjuster : 時間校正器。有時我們可能需要獲取例如:將日期調整到“下個周日”等操作。

TemporalAdjusters : 該類通過靜態方法提供了大量的常用 TemporalAdjuster 的實現。

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

搬家費用:依消費者運送距離、搬運樓層、有無電梯、步行距離、特殊地形、超重物品等計價因素後,評估每車次單

例如獲取下個周日,如下所示:

LocalDate nextSunday = LocalDate.now().with(TemporalAdjusters.next(DayOfWeek.SUNDAY));

完整的示例代碼如下所示。

LocalDateTime localDateTime1 = LocalDateTime.now();
System.out.println(localDateTime1);     // 2019-10-27T14:19:56.884

// 獲取這個第一天的日期
System.out.println(localDateTime1.with(TemporalAdjusters.firstDayOfMonth()));            // 2019-10-01T14:22:58.574
// 獲取下個周末的日期
System.out.println(localDateTime1.with(TemporalAdjusters.next(DayOfWeek.SUNDAY)));       // 2019-11-03T14:22:58.574

// 自定義:下一個工作日
LocalDateTime localDateTime2 = localDateTime1.with(l -> {
    LocalDateTime localDateTime = (LocalDateTime) l;
    DayOfWeek dayOfWeek =  localDateTime.getDayOfWeek();

    if (dayOfWeek.equals(DayOfWeek.FRIDAY)) {
       return localDateTime.plusDays(3);
    } else if (dayOfWeek.equals(DayOfWeek.SATURDAY)) {
       return localDateTime.plusDays(2);
    } else {
       return localDateTime.plusDays(1);
    }
});
System.out.println(localDateTime2);
// 運行結果:2019-10-28T14:30:17.400

解析與格式化

java.time.format.DateTimeFormatter 類:該類提供了三種格式化方法:

  • 預定義的標準格式
  • 語言環境相關的格式
  • 自定義的格式

示例代碼如下所示。

DateTimeFormatter dateTimeFormatter1 = DateTimeFormatter.ISO_DATE;
LocalDateTime localDateTime = LocalDateTime.now();
String strDate1 = localDateTime.format(dateTimeFormatter1);
System.out.println(strDate1);
// 運行結果:2019-10-27

// Date -> String
DateTimeFormatter dateTimeFormatter2 = DateTimeFormatter.ofPattern("yyyy-MM-dd  HH:mm:ss");
String strDate2 = dateTimeFormatter2.format(localDateTime);
System.out.println(strDate2);
// 運行結果:2019-10-27  14:36:11

// String -> Date
LocalDateTime localDateTime1 = localDateTime.parse(strDate2, dateTimeFormatter2);
System.out.println(localDateTime1);
// 運行結果:2019-10-27T14:37:39

時區的處理

Java8 中加入了對時區的支持,帶時區的時間為分別為:ZonedDate、 ZonedTime、 ZonedDateTime。

其中每個時區都對應着 ID,地區ID都為 “{區域}/{城市}”的格式,例如 : Asia/Shanghai 等。

  • ZoneId:該類中包含了所有的時區信息
  • getAvailableZoneIds() : 可以獲取所有時區時區信息
  • of(id) : 用指定的時區信息獲取 ZoneId 對象

示例代碼如下所示。

// 獲取所有的時區
Set<String> set = ZoneId.getAvailableZoneIds();
System.out.println(set);
// [Asia/Aden, America/Cuiaba, Etc/GMT+9, Etc/GMT+8, Africa/Nairobi, America/Marigot, Asia/Aqtau, Pacific/Kwajalein, America/El_Salvador, Asia/Pontianak, Africa/Cairo, Pacific/Pago_Pago, Africa/Mbabane, Asia/Kuching, Pacific/Honolulu, Pacific/Rarotonga, America/Guatemala, Australia/Hobart, Europe/London, America/Belize, America/Panama, Asia/Chungking, America/Managua, America/Indiana/Petersburg, Asia/Yerevan, Europe/Brussels, GMT, Europe/Warsaw, America/Chicago, Asia/Kashgar, Chile/Continental, Pacific/Yap, CET, Etc/GMT-1, Etc/GMT-0, Europe/Jersey, America/Tegucigalpa, Etc/GMT-5, Europe/Istanbul, America/Eirunepe, Etc/GMT-4, America/Miquelon, Etc/GMT-3, Europe/Luxembourg, Etc/GMT-2, Etc/GMT-9, America/Argentina/Catamarca, Etc/GMT-8, Etc/GMT-7, Etc/GMT-6, Europe/Zaporozhye, Canada/Yukon, Canada/Atlantic, Atlantic/St_Helena, Australia/Tasmania, Libya, Europe/Guernsey, America/Grand_Turk, US/Pacific-New, Asia/Samarkand, America/Argentina/Cordoba, Asia/Phnom_Penh, Africa/Kigali, Asia/Almaty, US/Alaska, Asia/Dubai, Europe/Isle_of_Man, America/Araguaina, Cuba, Asia/Novosibirsk, America/Argentina/Salta, Etc/GMT+3, Africa/Tunis, Etc/GMT+2, Etc/GMT+1, Pacific/Fakaofo, Africa/Tripoli, Etc/GMT+0, Israel, Africa/Banjul, Etc/GMT+7, Indian/Comoro, Etc/GMT+6, Etc/GMT+5, Etc/GMT+4, Pacific/Port_Moresby, US/Arizona, Antarctica/Syowa, Indian/Reunion, Pacific/Palau, Europe/Kaliningrad, America/Montevideo, Africa/Windhoek, Asia/Karachi, Africa/Mogadishu, Australia/Perth, Brazil/East, Etc/GMT, Asia/Chita, Pacific/Easter, Antarctica/Davis, Antarctica/McMurdo, Asia/Macao, America/Manaus, Africa/Freetown, Europe/Bucharest, Asia/Tomsk, America/Argentina/Mendoza, Asia/Macau, Europe/Malta, Mexico/BajaSur, Pacific/Tahiti, Africa/Asmera, Europe/Busingen, America/Argentina/Rio_Gallegos, Africa/Malabo, Europe/Skopje, America/Catamarca, America/Godthab, Europe/Sarajevo, Australia/ACT, GB-Eire, Africa/Lagos, America/Cordoba, Europe/Rome, Asia/Dacca, Indian/Mauritius, Pacific/Samoa, America/Regina, America/Fort_Wayne, America/Dawson_Creek, Africa/Algiers, Europe/Mariehamn, America/St_Johns, America/St_Thomas, Europe/Zurich, America/Anguilla, Asia/Dili, America/Denver, Africa/Bamako, Europe/Saratov, GB, Mexico/General, Pacific/Wallis, Europe/Gibraltar, Africa/Conakry, Africa/Lubumbashi, Asia/Istanbul, America/Havana, NZ-CHAT, Asia/Choibalsan, America/Porto_Acre, Asia/Omsk, Europe/Vaduz, US/Michigan, Asia/Dhaka, America/Barbados, Europe/Tiraspol, Atlantic/Cape_Verde, Asia/Yekaterinburg, America/Louisville, Pacific/Johnston, Pacific/Chatham, Europe/Ljubljana, America/Sao_Paulo, Asia/Jayapura, America/Curacao, Asia/Dushanbe, America/Guyana, America/Guayaquil, America/Martinique, Portugal, Europe/Berlin, Europe/Moscow, Europe/Chisinau, America/Puerto_Rico, America/Rankin_Inlet, Pacific/Ponape, Europe/Stockholm, Europe/Budapest, America/Argentina/Jujuy, Australia/Eucla, Asia/Shanghai, Universal, Europe/Zagreb, America/Port_of_Spain, Europe/Helsinki, Asia/Beirut, Asia/Tel_Aviv, Pacific/Bougainville, US/Central, Africa/Sao_Tome, Indian/Chagos, America/Cayenne, Asia/Yakutsk, Pacific/Galapagos, Australia/North, Europe/Paris, Africa/Ndjamena, Pacific/Fiji, America/Rainy_River, Indian/Maldives, Australia/Yancowinna, SystemV/AST4, Asia/Oral, America/Yellowknife, Pacific/Enderbury, America/Juneau, Australia/Victoria, America/Indiana/Vevay, Asia/Tashkent, Asia/Jakarta, Africa/Ceuta, Asia/Barnaul, America/Recife, America/Buenos_Aires, America/Noronha, America/Swift_Current, Australia/Adelaide, America/Metlakatla, Africa/Djibouti, America/Paramaribo, Europe/Simferopol, Europe/Sofia, Africa/Nouakchott, Europe/Prague, America/Indiana/Vincennes, Antarctica/Mawson, America/Kralendijk, Antarctica/Troll, Europe/Samara, Indian/Christmas, America/Antigua, Pacific/Gambier, America/Indianapolis, America/Inuvik, America/Iqaluit, Pacific/Funafuti, UTC, Antarctica/Macquarie, Canada/Pacific, America/Moncton, Africa/Gaborone, Pacific/Chuuk, Asia/Pyongyang, America/St_Vincent, Asia/Gaza, Etc/Universal, PST8PDT, Atlantic/Faeroe, Asia/Qyzylorda, Canada/Newfoundland, America/Kentucky/Louisville, America/Yakutat, Asia/Ho_Chi_Minh, Antarctica/Casey, Europe/Copenhagen, Africa/Asmara, Atlantic/Azores, Europe/Vienna, ROK, Pacific/Pitcairn, America/Mazatlan, Australia/Queensland, Pacific/Nauru, Europe/Tirane, Asia/Kolkata, SystemV/MST7, Australia/Canberra, MET, Australia/Broken_Hill, Europe/Riga, America/Dominica, Africa/Abidjan, America/Mendoza, America/Santarem, Kwajalein, America/Asuncion, Asia/Ulan_Bator, NZ, America/Boise, Australia/Currie, EST5EDT, Pacific/Guam, Pacific/Wake, Atlantic/Bermuda, America/Costa_Rica, America/Dawson, Asia/Chongqing, Eire, Europe/Amsterdam, America/Indiana/Knox, America/North_Dakota/Beulah, Africa/Accra, Atlantic/Faroe, Mexico/BajaNorte, America/Maceio, Etc/UCT, Pacific/Apia, GMT0, America/Atka, Pacific/Niue, Australia/Lord_Howe, Europe/Dublin, Pacific/Truk, MST7MDT, America/Monterrey, America/Nassau, America/Jamaica, Asia/Bishkek, America/Atikokan, Atlantic/Stanley, Australia/NSW, US/Hawaii, SystemV/CST6, Indian/Mahe, Asia/Aqtobe, America/Sitka, Asia/Vladivostok, Africa/Libreville, Africa/Maputo, Zulu, America/Kentucky/Monticello, Africa/El_Aaiun, Africa/Ouagadougou, America/Coral_Harbour, Pacific/Marquesas, Brazil/West, America/Aruba, America/North_Dakota/Center, America/Cayman, Asia/Ulaanbaatar, Asia/Baghdad, Europe/San_Marino, America/Indiana/Tell_City, America/Tijuana, Pacific/Saipan, SystemV/YST9, Africa/Douala, America/Chihuahua, America/Ojinaga, Asia/Hovd, America/Anchorage, Chile/EasterIsland, America/Halifax, Antarctica/Rothera, America/Indiana/Indianapolis, US/Mountain, Asia/Damascus, America/Argentina/San_Luis, America/Santiago, Asia/Baku, America/Argentina/Ushuaia, Atlantic/Reykjavik, Africa/Brazzaville, Africa/Porto-Novo, America/La_Paz, Antarctica/DumontDUrville, Asia/Taipei, Antarctica/South_Pole, Asia/Manila, Asia/Bangkok, Africa/Dar_es_Salaam, Poland, Atlantic/Madeira, Antarctica/Palmer, America/Thunder_Bay, Africa/Addis_Ababa, Asia/Yangon, Europe/Uzhgorod, Brazil/DeNoronha, Asia/Ashkhabad, Etc/Zulu, America/Indiana/Marengo, America/Creston, America/Punta_Arenas, America/Mexico_City, Antarctica/Vostok, Asia/Jerusalem, Europe/Andorra, US/Samoa, PRC, Asia/Vientiane, Pacific/Kiritimati, America/Matamoros, America/Blanc-Sablon, Asia/Riyadh, Iceland, Pacific/Pohnpei, Asia/Ujung_Pandang, Atlantic/South_Georgia, Europe/Lisbon, Asia/Harbin, Europe/Oslo, Asia/Novokuznetsk, CST6CDT, Atlantic/Canary, America/Knox_IN, Asia/Kuwait, SystemV/HST10, Pacific/Efate, Africa/Lome, America/Bogota, America/Menominee, America/Adak, Pacific/Norfolk, Europe/Kirov, America/Resolute, Pacific/Tarawa, Africa/Kampala, Asia/Krasnoyarsk, Greenwich, SystemV/EST5, America/Edmonton, Europe/Podgorica, Australia/South, Canada/Central, Africa/Bujumbura, America/Santo_Domingo, US/Eastern, Europe/Minsk, Pacific/Auckland, Africa/Casablanca, America/Glace_Bay, Canada/Eastern, Asia/Qatar, Europe/Kiev, Singapore, Asia/Magadan, SystemV/PST8, America/Port-au-Prince, Europe/Belfast, America/St_Barthelemy, Asia/Ashgabat, Africa/Luanda, America/Nipigon, Atlantic/Jan_Mayen, Brazil/Acre, Asia/Muscat, Asia/Bahrain, Europe/Vilnius, America/Fortaleza, Etc/GMT0, US/East-Indiana, America/Hermosillo, America/Cancun, Africa/Maseru, Pacific/Kosrae, Africa/Kinshasa, Asia/Kathmandu, Asia/Seoul, Australia/Sydney, America/Lima, Australia/LHI, America/St_Lucia, Europe/Madrid, America/Bahia_Banderas, America/Montserrat, Asia/Brunei, America/Santa_Isabel, Canada/Mountain, America/Cambridge_Bay, Asia/Colombo, Australia/West, Indian/Antananarivo, Australia/Brisbane, Indian/Mayotte, US/Indiana-Starke, Asia/Urumqi, US/Aleutian, Europe/Volgograd, America/Lower_Princes, America/Vancouver, Africa/Blantyre, America/Rio_Branco, America/Danmarkshavn, America/Detroit, America/Thule, Africa/Lusaka, Asia/Hong_Kong, Iran, America/Argentina/La_Rioja, Africa/Dakar, SystemV/CST6CDT, America/Tortola, America/Porto_Velho, Asia/Sakhalin, Etc/GMT+10, America/Scoresbysund, Asia/Kamchatka, Asia/Thimbu, Africa/Harare, Etc/GMT+12, Etc/GMT+11, Navajo, America/Nome, Europe/Tallinn, Turkey, Africa/Khartoum, Africa/Johannesburg, Africa/Bangui, Europe/Belgrade, Jamaica, Africa/Bissau, Asia/Tehran, WET, Europe/Astrakhan, Africa/Juba, America/Campo_Grande, America/Belem, Etc/Greenwich, Asia/Saigon, America/Ensenada, Pacific/Midway, America/Jujuy, Africa/Timbuktu, America/Bahia, America/Goose_Bay, America/Virgin, America/Pangnirtung, Asia/Katmandu, America/Phoenix, Africa/Niamey, America/Whitehorse, Pacific/Noumea, Asia/Tbilisi, America/Montreal, Asia/Makassar, America/Argentina/San_Juan, Hongkong, UCT, Asia/Nicosia, America/Indiana/Winamac, SystemV/MST7MDT, America/Argentina/ComodRivadavia, America/Boa_Vista, America/Grenada, Asia/Atyrau, Australia/Darwin, Asia/Khandyga, Asia/Kuala_Lumpur, Asia/Famagusta, Asia/Thimphu, Asia/Rangoon, Europe/Bratislava, Asia/Calcutta, America/Argentina/Tucuman, Asia/Kabul, Indian/Cocos, Japan, Pacific/Tongatapu, America/New_York, Etc/GMT-12, Etc/GMT-11, Etc/GMT-10, SystemV/YST9YDT, Europe/Ulyanovsk, Etc/GMT-14, Etc/GMT-13, W-SU, America/Merida, EET, America/Rosario, Canada/Saskatchewan, America/St_Kitts, Arctic/Longyearbyen, America/Fort_Nelson, America/Caracas, America/Guadeloupe, Asia/Hebron, Indian/Kerguelen, SystemV/PST8PDT, Africa/Monrovia, Asia/Ust-Nera, Egypt, Asia/Srednekolymsk, America/North_Dakota/New_Salem, Asia/Anadyr, Australia/Melbourne, Asia/Irkutsk, America/Shiprock, America/Winnipeg, Europe/Vatican, Asia/Amman, Etc/UTC, SystemV/AST4ADT, Asia/Tokyo, America/Toronto, Asia/Singapore, Australia/Lindeman, America/Los_Angeles, SystemV/EST5EDT, Pacific/Majuro, America/Argentina/Buenos_Aires, Europe/Nicosia, Pacific/Guadalcanal, Europe/Athens, US/Pacific, Europe/Monaco]

// 通過時區構建LocalDateTime
LocalDateTime localDateTime1 = LocalDateTime.now(ZoneId.of("America/El_Salvador"));
System.out.println(localDateTime1);
// 2019-10-27T00:46:21.268

// 以時區格式显示時間
LocalDateTime localDateTime2 = LocalDateTime.now();
ZonedDateTime zonedDateTime1 = localDateTime2.atZone(ZoneId.of("Africa/Nairobi"));
System.out.println(zonedDateTime1);
// 2019-10-27T14:46:21.273+03:00[Africa/Nairobi]

與傳統日期處理的轉換

寫在最後

如果覺得文章對你有點幫助,請微信搜索並關注「 冰河技術 」微信公眾號,跟冰河學習Java8新特性。

最後,附上Java8新特性核心知識圖,祝大家在學習Java8新特性時少走彎路。

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

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

節能減碳愛地球是景泰電動車的理念,是創立景泰電動車行的初衷,滿意態度更是服務客戶的最高品質,我們的成長來自於你的推薦。

分類
發燒車訊

穩定性五件套-限流的原理和實現_租車

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

有別於一般網頁架設公司,除了模組化的架站軟體,我們的營業主軸還包含:資料庫程式開發、網站建置、網頁設計、電子商務專案開發、系統整合、APP設計建置、專業網路行銷。

背景

 

最近了解到很多朋友對限流、熔斷、降級、隔離、超時重試的概念和應用場景理解的不是很到位,所以想用五篇的篇幅稍微系統的介紹一下。

 

本篇是第一篇,是限流做詳解,如果反饋好的話,我會繼續寫下面四篇。不好的話就算了,算我理解不夠,再自己總結總結。

 

限流的概念

 

有朋友問我限流和熔斷有什麼區別,我的理解很簡單。限流作用是防禦上游流量超過處理能力的手段,熔斷作用是容錯下游的快速失敗手段。

 

舉個生活中的限流例子:

 

小A最近打算找個女朋友,他拜託了很多朋友幫自己介紹,朋友們也很給力,很多姑娘都願意和小A聊一聊。小A發現時間忙不開了,他就制定了一個計劃,一天見2個。這就是限流。

 

舉個生活中的熔斷例子:

 

小A在見這些姑娘的時候,如果有的姑娘不守時,超過約定時間半小時還沒有出現,那小A就會離開。不然會耽誤見下一位姑娘,這是一種熔斷手段。另外,如果有的姑娘特別能說,聊天超過了3小時,小A也會打斷姑娘,把姑娘先送走,不然也會耽誤見下一位姑娘。這也是需要的熔斷措施。

 

限流的原理

 

不管任何編程語言的實現,目前主流的底層就是基於令牌桶算法和漏斗算法。這兩種算法達到的效果有所不同。

 

令牌桶算法

 

令牌桶算法是先有個固定容量的桶,一個任務會以固定的速率往桶里放token,請求來了會去取token。如果桶滿了,token就溢出了。多出來的token就不要了。如果請求太快,token生產速度跟不上消費速率,桶空了,有的請求取不到token,這時候就會直接返回錯誤而不繼續處理。

 

舉個例子:

 

比如小A最後找到了心儀的女朋友小C。他倆相處融洽,一起包餃子吃。小A負責擀皮,小C負責包。小A會把擀好的皮放到一塊案板上。這個案板可以放20張皮。如果皮擀多了,就放不下,這時候小A就會停下來等。如果皮擀的慢,小C沒的包,也就只能停下來。這裏的皮就相當於是token,包餃子就相當於是處理業務的請求。用圖表示如下:

 

 

 

漏斗算法

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

日本、大陸,發現這些先進的國家已經早就讓電動車優先上路,而且先進國家空氣品質相當好,電動車節能減碳可以減少空污

 

漏斗算法也是先有個固定容量的桶,請求來了先經過桶,從桶里出去的速率是一定的。如果請求量讓桶滿了,多出來的請求就不處理了。如果桶是空的,新來的請求就能馬上處理。

 

事實上,各種MQ比如kafka就是典型漏斗算法。broker就是這個固定容量的桶,生產者會不斷的將數據寫到broker里,消費者是採用的拉取模式,總是以固定的速率來消費。

 

令牌桶算法和漏洞算法的比較

 

限流的實現

 

基礎實現

 

在Java中業界用的比較多的是Google出品的Guava RateLimiter和另外的一款resilience4j-ratelimiter來實現限流。原理差不多。

 

下面以RateLimiter為例進行講解。要實現一個限流總共需要用到RateLimiter的兩個方法:

 

1>RateLimiter.create() 靜態方法創建對象,初始化桶容量

 

2>acquire()或者tryAcquire()  獲取請求token,兩者使用一個即可。acquire方法是阻塞式的,用來實現漏斗算法;tryAcquire是非阻塞式的,用來實現令牌桶算法。

 

阻塞式是如果到達指定條件前一直不返回結果,通過下面的源碼可看到內部實際上是用sleep來實現的阻塞。因為所有的請求獲取權限時都會sleep固定的時間才返回,就達到了勻速的目的。

 

非阻塞是立即返回是否獲取到權限(token)。這時候請求如果獲取權限成功就處理請求,獲取權限失敗就直接返回一個自定義的快速失敗處理方式。平時請求速率小於token產生速率,桶漸漸滿了。一旦有突發流量,因為桶里有存量token,也可以直接獲取到權限,就是為什麼令牌桶算法可以應對突發流量的原理。

 

高階實現

 

上面實現里講的是工具組件,如果只使用工具組件有個問題。限流實際上需要定期進行容量評估,是一個動態的過程,如果只使用工具組件就需要每次修改代碼。當然也可以將每個值寫到一個統一配置里,比如zookeeper來進行管理。

 

如果規模大的情況下更好的一個解決方法是使用專門的平台。這個平台可以支撐更多維度的配置,比如集群維度的限流。集群維度和單機維度的區別是如果設置了一個總的閾值,系統可以根據機器資源情況自動計算出每台機器的限流情況。

 

在業界,阿里有個sentinel,有人稱為微服務哨兵。它是一套更完整的生態,除了我上面提到的功能之外,還提供了動態系統保護、熱點限流等功能。

 

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

※超省錢租車方案

商務出差、學生出遊、旅遊渡假、臨時用車!GO 神州租賃有限公司!合法經營、合法連鎖、合法租賃小客車!

分類
發燒車訊

漢字不能編程?只是看着有點豪橫!容易被開除!_包裝設計

南投搬家公司費用需注意的眉眉角角,別等搬了再說!

上新台中搬家公司提供您一套專業有效率且人性化的辦公室搬遷、公司行號搬家及工廠遷廠的搬家服務

作者:小傅哥
博客:https://bugstack.cn

沉澱、分享、成長,讓自己和他人都能有所收穫!

一、前言

在編程的路上你是否想過,用漢字寫一寫代碼?

最近有初學編程的小夥伴問小傅哥,漢字可以寫代碼嗎。自己英文不好,要是漢字可以寫代碼就好了。難道你要的是易語言?其實並不是,小夥伴也是學習 Java 的初學者,剛剛學習到 Spring 看着一片沒有註釋的代碼實在不好理解,要是都是漢字寫的,那不和讀作文一樣了嗎!

說道註釋,我想到大部分程序員討厭的兩件事

  1. 不喜歡寫註釋
  2. 不喜歡別人不寫註釋

其實對於學習編程來說,初學時寫寫案例,完成簡單的功能,反覆練習夯實基礎。數學和英文都還並不是你的絆腳石,因為你不需要做複雜的邏輯處理,比如算法。也不需要查閱大量的資料,比如原版的英文資料以及國內沒有翻譯的技術書籍等。所以這個時候對你來說,只是需要不斷的學,不斷的寫。並逐步強加自己的數學和英文能力。

回到我們的說的,既然你問漢字可以寫代碼嗎。其實在 java 里,原則上你可以寫漢字的屬性方法JVM虛擬機也是可以通過編譯執行的。只是這樣的代碼並不能很好的維護,甚至說亂碼了也很麻煩。再者,有人寫方言怎麼辦!

好!那麼我們接下來就使用漢字的方式來編寫一段關於 SpringAop 的案例!

二、開發環境

  1. JDK 1.8.0
  2. Spring 4.3.24.RELEASE
  3. 本篇涉及的源碼下載,可以關注公眾號bugstack蟲洞棧 獲取,並且還可以獲取更多原創案例。

三、技術實現

為了這個案例更加真實,我們模擬電影清朝韋小寶時期,太監入宮的過程。說白了也就是 SpringAOP 面向切面,的編程。

在做案例之前,我們先了解一下 AOP 的基本概念;

  1. @Aspect,定義切面的註解
  2. @Pointcut,切入點,一般會在方法上設定通配符表達式
  3. @Around,環繞,也就是你原本的方法會在這裏處理
  4. @Before,前置處理
  5. @After,後置處理

1. 定義切面

紫禁城.內務府.敬事房.臏.太監臏.凈身監管.java

※產品缺大量曝光嗎?你需要的是一流包裝設計!

窩窩觸角包含自媒體、自有平台及其他國家營銷業務等,多角化經營並具有國際觀的永續理念。

@Aspect
@Component
public class 凈身監管 {

    @Pointcut("execution(public * 紫禁城.內務府.敬事房.利器庫..*.軍刺切(..))")
    public void 監管員(){

    }

    @Before("監管員()")
    public void 敬事前(){
        System.out.println("敬事前:---------準備下刀... ...");
    }

    @After("監管員()")
    public void 敬事後(){
        System.out.println("敬事後:---------切面完成... ...");
    }

    @Around("監管員()")
    public Object aroundMethod(ProceedingJoinPoint pjp) throws Throwable {

        System.out.println("待切身份:"+pjp.getArgs()[0]);
        System.out.println("執行工具:"+pjp.getSignature().getName());

        //獲得傳遞對象,並做處理
        太監臏 太監 = (太監臏) pjp.getArgs()[0];
        SimpleDateFormat timeFormat = new SimpleDateFormat("yyyy-MM-dd");
        太監.set敬事日期(timeFormat.format(new Date()));

        //此處可以傳遞更改后的參數
        Object obj = pjp.proceed(new Object[]{太監});

        return obj;

    }

}
  • @Aspect,定義切面類,用於處理程序中的切面編程操作。
  • @Pointcut("execution(public * 紫禁城.內務府.敬事房.利器庫..*.軍刺切(..))"),定義切點處,對那些方法進行執行切面操作。除了這樣的操作外,還可以定義成自定義註解。那麼後續只要把某個你需要的方法上面添加這樣的自定義註解,就可以被 AOP 攔截。
  • @Before("監管員()")@After("監管員()"),記錄切面執行前後的記錄。
  • @Around("監管員()"),用於環繞方法增強,可以這裏去處理方法中的一些屬性信息,比如添加給某個字段添加時間。太監.set敬事日期(timeFormat.format(new Date()));

2. 設置切面可執行方法

紫禁城.內務府.敬事房.利器庫.切除器具.java

@Component("切除")
public class 切除器具 {

    public 太監臏 軍刺切(太監臏 太監){
        太監.set性別(宦官.太監.name());
        System.out.println("... 啊 ... ...老子被切面了!"+太監.get姓名());
        return 太監;
    }

}
  • 這裏類的方法就是上面定義的切點,Pointcut,也就是會被切面處理的方法。

3. 執行切面操作類

紫禁城.內務府.敬事房.執刀人.張三豐執刀.java

public class 張三豐執刀 {

    public static void main(String[] args) {

        ApplicationContext ctx = new ClassPathXmlApplicationContext("皇太極.xml");

        太監刑 太監行刑 = ctx.getBean("太監刑",太監刑.class);

        太監臏 太監 = new 太監臏();
        太監.set姓名("小德張");
        太監.set年齡("9");
        太監.set性別(宦官.男.name());

        太監 = 太監行刑.執行切除(太監);

        System.out.println("\r\n切除狀態:"+太監);
    }

}
  • 首先這裏定義了獲取 Spring 註解的 Application,用於我們獲取 Bean
  • 接下來定義一個對象類,主要傳遞具體參數信息交給執行切面的方法,進行操作。
  • 最後輸出結果信息,也就是我們可以看到具體被切面操作的方法。

四、測試結果

1. 執行內容

啟動方法;紫禁城.內務府.敬事房.執刀人.張三豐執刀.java

待切身份:太監臏 [姓名=小德張, 年齡=9, 性別=男, 敬事日期=]
執行工具:軍刺切
敬事前:---------準備下刀... ...
... 啊 ... ...老子被切面了!小德張
敬事後:---------切面完成... ...

切除狀態:太監臏 [姓名=小德張, 年齡=9, 性別=太監, 敬事日期=2020-05-05]

Process finished with exit code 0

2. 效果圖

五、總結

  • 漢字編程,好奇可以試試,但別真的用到項目里。本文也只是通過這樣的例子,向你展示學習過程的樂趣,建立一些學習過程的好感。

  • 最近加了很多剛入門學習編程的小夥伴,有很多小問號。比如;

    我是非常建議先跑起來,多寫代碼后再慢慢的去探究原理!

  • 最近聽到一首詩,不錯;廿四橋邊廿四風,憑欄猶憶舊江東。夕陽返照桃花渡,柳絮飛來片片紅。,白色的柳絮在夕陽桃花的映襯下就是成了片片紅。只要你敢學識淵博,就敢讓你擁有翻江倒海之力。

六、彩蛋

CodeGuide | 程序員編碼指南 Go!

本代碼庫是作者小傅哥多年從事一線互聯網 Java 開發的學習歷程技術匯總,旨在為大家提供一個清晰詳細的學習教程,側重點更傾向編寫Java核心內容。如果本倉庫能為您提供幫助,請給予支持(關注、點贊、分享)!

七、推薦閱讀

  • 用Java實現JVM虛擬機(漢字真的可以處理為關鍵字進行編碼)
  • 重學 Java 設計模式:實戰單例模式(Effective Java 作者推薦使用枚舉的方式解決單例模式)
  • 重學 Java 設計模式:實戰原型模式(多套試卷亂序題目)
  • 重學 Java 設計模式:實戰建造者模式(裝修套餐選配)
  • 重學 Java 設計模式:實戰抽象工廠模式(Redis集群使用升級)
  • 重學 Java 設計模式:實戰工廠方法模式(多種商品發獎)

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

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

網動廣告出品的網頁設計,採用精簡與質感的CSS語法,提升企業的專業形象與簡約舒適的瀏覽體驗,讓瀏覽者第一眼就愛上她。

分類
發燒車訊

MySql輕鬆入門系列——第一站 從源碼角度輕鬆認識mysql整體框架圖_台中搬家

台中搬家公司費用怎麼算?

擁有20年純熟搬遷經驗,提供免費估價且流程透明更是5星評價的搬家公司

一:背景

1. 講故事

最近看各大技術社區,不管是知乎,掘金,博客園,csdn基本上看不到有小夥伴分享sqlserver類的文章,看來在國內大環境下是不怎麼流行了,看樣子我再寫sqlserver是不可能再寫了,這輩子都不會寫了,只能靠技術輸出mysql維持生活這樣子。

二:了解架構圖

mysql最大的好處就是開源, 手握百萬源碼,有什麼問題搞不定呢? 這一點要比sqlserver爽多了,不用再dbcc搗來搗去。

1. 從架構圖入手

大家都知道做/裝修房子都要有一張圖紙,其實軟件也是一樣,只要有了這麼一張圖紙,大方向就定下來了,再深入到細節也不會亂了方向,然後給大家看一下我自己畫的架構圖,畫的不對請輕拍。

其實SqlServer,Oracle,MySql架構都大同小異,MySql的鮮明特點就是存儲引擎做成了插拔式,這就牛逼了,現行最常用的是InnoDB,這就讓我有了一個想法,有一套業務準備用 InMemory 模式跑一下,厲害了~~~

2. 功能點介紹

MySql其實就兩大塊,一塊是MySql Server層,一塊就是Storage Engines層。

<1> Client

不同語言的sdk遵守mysql協議就可以與mysqld進行互通。

<2> Connection/Thread Pool

MySql使用C++編寫,Connection是非常寶貴的,在初始化的時候維護一個池。

<3> SqlInterface,Parse,Optimizer,Cache

對sql處理,解析,優化,緩存等處理和過濾模塊,了解了解即可。

<4> Storage Engines

負責存儲的模塊,官方,第三方,甚至是你自己都可以自定義實現這個數據存儲,這就把生態做起來了,。

三: 源碼分析

關於怎麼去下載mysql源碼,這裏就不說了,大家自己去官網搗鼓搗鼓哈,本系列使用經典的 mysql 5.7.14版本。

1. 了解mysql是如何啟動監聽的

手握百萬行源碼,怎麼找入口函數呢??? ,其實很簡單,在mysqld進程上生成一個dump文件,然後看它的託管堆不就好啦。。。

台中搬家遵守搬運三大原則,讓您的家具不再被破壞!

台中搬家公司推薦超過30年經驗,首選台中大展搬家

從圖中可以看到,入口函數就是 mysqld!mysqld_main+0x227 中的 mysqld_main, 接下來就可以在源碼中全文檢索下。

<1> mysqld_main 入口函數 => sql/main.cc


extern int mysqld_main(int argc, char **argv);

int main(int argc, char **argv)
{
  return mysqld_main(argc, argv);
}

這裏大家可以用visualstudio打開C++源碼,使用查看定義功能,非常好用。

<2> 創建監聽


int mysqld_main(int argc, char **argv)
{
    //創建服務監聽線程
    handle_connections_sockets();
}

void handle_connections_sockets()
{
     //監聽連接
     new_sock= mysql_socket_accept(key_socket_client_connection, sock,
                                    (struct sockaddr *)(&cAddr), &length);

    if (mysql_socket_getfd(sock) == mysql_socket_getfd(unix_sock))
      thd->security_ctx->set_host((char*) my_localhost);

    //創建連接
    create_new_thread(thd);
}

//創建新線程處理處理用戶連接
static void create_new_thread(THD *thd){
   
   thd->thread_id= thd->variables.pseudo_thread_id= thread_id++;
   
   //線程進了線程調度器
   MYSQL_CALLBACK(thread_scheduler, add_connection, (thd));   
}

至此mysql就開啟了一個線程對 3306 端口進行監控,等待客戶端請求觸發 add_connection 回調。

2. 理解mysql是如何處理sql請求

這裏我以Insert操作為例稍微解剖下處理流程:

當用戶有請求sql過來之後,就會觸發 thread_scheduler的回調函數add_connection


static scheduler_functions one_thread_per_connection_scheduler_functions=
{
  0,                                     // max_threads
  NULL,                                  // init
  init_new_connection_handler_thread,    // init_new_connection_thread
  create_thread_to_handle_connection,    // add_connection
  NULL,                                  // thd_wait_begin
  NULL,                                  // thd_wait_end
  NULL,                                  // post_kill_notification
  one_thread_per_connection_end,         // end_thread
  NULL,                                  // end
};

scheduler_functions 中可以看到,add_connection 對應了 create_thread_to_handle_connection,也就是請求來了會觸發這個函數,從名字也可以看出,用一個線程處理一個用戶連接。

<1> 客戶端請求被 create_thread_to_handle_connection 接管及調用棧追蹤


void create_thread_to_handle_connection(THD *thd)
{
     if ((error= mysql_thread_create(key_thread_one_connection, &thd->real_id, &connection_attrib,
                                     handle_one_connection,(void*) thd))){}
}
//觸發回調函數  handle_one_connection
pthread_handler_t handle_one_connection(void *arg)
{
     do_handle_one_connection(thd);
}
//繼續處理
void do_handle_one_connection(THD *thd_arg){
    while (thd_is_connection_alive(thd))
    {
      mysql_audit_release(thd);
      if (do_command(thd))  break;  //這裏的 do_command 繼續處理
    }
}
//繼續分發
bool do_command(THD *thd)
{
    return_value= dispatch_command(command, thd, packet+1, (uint) (packet_length-1));
}
bool dispatch_command(enum enum_server_command command, THD *thd, char* packet, uint packet_length)
{
      switch (command) {
         case COM_INIT_DB: ....  break;
         ...
         case COM_QUERY:   //查詢語句:  insert xxxx
             mysql_parse(thd, thd->query(), thd->query_length(), &parser_state);  //sql解析
           break;
      }
}
//sql解析模塊
void mysql_parse(THD *thd, char *rawbuf, uint length, Parser_state *parser_state)
{
      error= mysql_execute_command(thd);
}

<2> 到這裏它的Parse,Optimizer,Cache都追完了,接下來看sql的CURD類型,繼續追。。。


//繼續執行
int mysql_execute_command(THD *thd)
{
  switch (lex->sql_command) 
  {
      case SQLCOM_SELECT:  res= execute_sqlcom_select(thd, all_tables);  break;

      //這個 insert 就是我要追的
      case SQLCOM_INSERT:   res= mysql_insert(thd, all_tables, lex->field_list, lex->many_values,
		                                      lex->update_list, lex->value_list,
                                              lex->duplicates, lex->ignore);
  }
}
//insert插入操作處理
bool mysql_insert(THD *thd,TABLE_LIST *table_list,List<Item> &fields, List<List_item> &values_list,
                  List<Item> &update_fields, List<Item> &update_values, 
                  enum_duplicates duplic, bool ignore)
{
      while ((values= its++))
      {
           error= write_record(thd, table, &info, &update);
      }
}
//寫入記錄
int write_record(THD *thd, TABLE *table, COPY_INFO *info, COPY_INFO *update)
{
    if (duplicate_handling == DUP_REPLACE || duplicate_handling == DUP_UPDATE)
    {
         // ha_write_row  重點是這個函數
         while ((error=table->file->ha_write_row(table->record[0])))
         {
             ....
         }
    }
}

可以看到,調用鏈還是挺深的,追到 ha_write_row 方法基本上算是追到頭了,再往下的話就是 MySql ServerStorage Engine提供的接口實現了,不信的話繼續看唄。。。

<3> 繼續挖 ha_write_row


int handler::ha_write_row(uchar *buf)
{
    MYSQL_TABLE_IO_WAIT(m_psi, PSI_TABLE_WRITE_ROW, MAX_KEY, 0,{ error= write_row(buf); })
}

//這是一個虛方法
virtual int write_row(uchar *buf __attribute__((unused)))
{
    return HA_ERR_WRONG_COMMAND;
}

看到沒有,write_row是個虛方法,也就是給底層方法實現的,在這裏就是給各大Storage Engines的哈。

3. 調用鏈圖

這麼多方法,看起來有點懵懵的吧,我來畫一張圖,幫助大家理解下這個調用堆棧。

三:總結

大家一定要熟讀架構圖,有了架構圖從源碼中找信息就方便多了,總之學習mysql成就感還是滿滿的。

如您有更多問題與我互動,掃描下方進來吧~

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

台中搬家公司費用怎麼算?

擁有20年純熟搬遷經驗,提供免費估價且流程透明更是5星評價的搬家公司

分類
發燒車訊

【asp.net core 系列】2 控制器與路由的恩怨情仇_台中搬家公司

台中搬家公司教你幾個打包小技巧,輕鬆整理裝箱!

還在煩惱搬家費用要多少哪?台中大展搬家線上試算搬家費用,從此不再擔心「物品怎麼計費」、「多少車才能裝完」

0. 前言

在上一篇文章中,我們初步介紹了asp.net core,以及如何創建一個mvc項目。從這一篇開始,我將為大家展示asp.net core 的各種內容,並且嘗試帶領大家來挖掘其中的內在邏輯。

當然,那是以後的事情。這一篇將通過自定義一個控制器來為大家介紹asp.net core mvc 中控制器和路由的相關知識。

1. 控制器

先在Controllers目錄下添加一個類,名叫:

public class DemoController
{
    public string Index()
    {
        return "你好";
    }
}

訪問地址:

http://localhost:5006/demo/index

如果不出意外的話,你應該能看到網頁上的“你好”兩個字。

再新建一個類:

using Microsoft.AspNetCore.Mvc;
public class NoContrl : Controller
{
    public IActionResult Index()
    {
        return Content("Test");
    }
}

結合兩個不常規的控制器類,讓我們初窺asp.net core MVC是如何識別控制器的。這正是我之前說的,約定優於配置最好的體現。這個哲學最早也是為MVC提出來的,後來被.net framework引申到各個方面。

asp.net core mvc識別控制器,會在項目中發現 以Controller結尾的公開類或者繼承自Controller的公開類,並將這些類標記為控制器。當接到用戶或者界面轉交的請求時,程序從請求路徑中解析出控制器名稱,然後尋找 <控制器>Controller 或者 <控制器> : Controller 的類。

在默認情況下,一個訪問URL會在程序中解析成如下格式:

http://<HOST>:<PORT>/<Controller>/<Action>[其他參數]

在上文中,我們知道了控制器的解析規則,那麼現在看一下Action的解析規則:

在DemoController中添加如下方法:

public int TestInt()
{
    return 10;
}

public object TestObject()
{
    return new
    {
        Name = "TestObject",
        Age = 1
    };
}

public string TestPublic()
{
    return "成功訪問 TestPublic";
}

    protected string TestProtect()
{
    return "成功訪問 TestProtect";
}

private string TestPrivate()
{
    return "成功訪問 TestPrivate";
}

重新啟動,后依次訪問如下地址:

http://localhost:5006/Demo/TestInt
http://localhost:5006/Demo/TestObject
http://localhost:5006/Demo/TestPublic
http://localhost:5006/Demo/TestProtect
http://localhost:5006/Demo/TestPrivate

然後可以看到,TestInt、TestObject以及TestPublic均能正常訪問,但TestProtect和TestPrivate都提示找不到網頁或無法訪問。

可以看到,對於程序而言,Action就是控制器類里的公開類方法,與方法的返回值無關。也就是說,程序會找到 XXXController 或者名為XXX但繼承了Controller的類作為XXX的控制器,然後繼續在這個類里尋找到Action,如果沒有找到就會返回404的請求。

2. 路由

在第一節中,我們介紹了一下asp.net core mvc如何尋找控制器和Action,那這一節將介紹程序如何從請求鏈接中解析出控制器和Action的名稱,也就是路由映射。

路由(Routing)負責匹配傳入的HTTP請求,然後將這些請求發送給應用的可執行終結點。終結點是應用的可執行請求處理代碼單元,也就是我們控制器里的方法(Action)。

2.1 路由的配置

對於所有的asp.net core模板都包括生成在代碼中的路由。通常,我們要求路由在Startup.Configure方法中進行配置。

注意,Startup類里有且只有一個Configure方法,不能出現其重載版本。

該方法的聲明一般情況如下:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env);

如果想要設置路由,需要先註明項目啟用路由:

※推薦台中搬家公司優質服務,可到府估價

台中搬鋼琴,台中金庫搬運,中部廢棄物處理,南投縣搬家公司,好幫手搬家,西屯區搬家

app.UseRouting();

然後使用如下方法配置路由:

app.UseEndpoints(endpoints =>
{
    // 配置路由
});

通常對於mvc項目而言,我們一般使用如下方式配置路由:

endpoints.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");

這行代碼的意思是:創建一個名字為 default 的映射控制器的路由,映射規則為 {controller}/{action}/{id?},也就是第一個為控制器,第二個為Action,第三個是ID,其中ID可以不存在,當Action無法從請求地址中解析出來時默認為Index,控制器默認為Home。

通過這個解析,我們可以得知 我們之前訪問的

http://localhost:5000/

是哪個控制器里的什麼方法來處理了——HomeController.Index。

那麼我們修改一下HomeController.Index來驗證一下,我們理解是否有誤:

public IActionResult Index()
{
    return View();
}
//  修改為
public IActionResult Index()
{
    return Content("測試");
}

重新運行程序,訪問

http://localhost:5000/

然後看到頁面出現:測試字樣,可以看到路由系統自動為我們補全了控制器名和action名。如果方法中出現參數,則自動按照參數名1=值1&參數名2=值2這種形式查看參數。Id為特殊的,會自動按照目錄其映射。所以:

http://localhost:5000/控制器1/方法1/id值
http://localhost:5000/控制器1/方法1?id=id值

是一個請求鏈接。

2.2 添加路由配置

那麼,我們回過頭來看一下聲明路由的方法:

public static ControllerActionEndpointConventionBuilder MapControllerRoute(this IEndpointRouteBuilder endpoints, string name, string pattern, object defaults = null, object constraints = null, object dataTokens = null);

默認情況下,我們不會設置 defaults、constraints、dataTokens,這三個參數都有含義,這裏不對后兩個做介紹,簡單介紹一下第一個:

在路由配置的方法里,添加以下內容:

endpoints.MapControllerRoute(
                    name : "test",
                    pattern: "DemoTest/{action=Index}/{id?}",
                    defaults : new 
                    {
                        Controller = "Demo",

                    });

至此,我們沒有創建名為DemoTest的控制器,但是我們在訪問:

http://localhost:5006/DemoTest

仍然能得到響應,而且控制器被解析為Demo。

這就是defaults的意義,路由在解析的時候,系統會把defaults中的值自動填充到路由連接中沒有設置的值里。

當我們設置多個路由的時候,路由系統會優先嘗試匹配最容易解析的配置。比如說,當我們訪問:

http://localhost:5000/DemoTest/

的時候,路由系統會優先從名為test的配置表中解析,只有當無法從這裏找到時才會從其他路由中解析。

3. 總結

這一篇我們簡單介紹了控制器與路由映射,可以訪問我們自己添加的路由。在開發中,通常情況下,創建的控制器都是以Controller結尾並繼承Controller類。這是因為Controller類有很多有用的屬性和方法供我們使用,以Controller結尾是為了統一規則,可以讓我們一眼看出哪些是控制器。

更多內容煩請關注我的博客《高先生小屋》

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

台中搬家公司教你幾個打包小技巧,輕鬆整理裝箱!

還在煩惱搬家費用要多少哪?台中大展搬家線上試算搬家費用,從此不再擔心「物品怎麼計費」、「多少車才能裝完」

分類
發燒車訊

解讀四大亮點——這輛車帶你尊享貴賓禮遇_網頁設計公司

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

台中景泰電動車行只是一個單純的理由,將來台灣的環境,出門可以自由放心的深呼吸,讓空氣回歸自然的乾淨,減少污染,留給我們下一代有好品質無空污的優質環境

2。異地維修享7天五星級酒店住宿權而當車輛在異地發生事故需要長時間維修時,沃爾沃、捷豹路虎和謳歌三大品牌會提供5星級酒店客房,免費供房的天數3-5天不等。奔馳、寶馬也不落後,都有這一服務,但免費住宿的標準稍低,為四星級酒店。

10月21日,萬眾矚目的上汽大眾pHIDEON 輝昂在中國第一高樓——上海中心正式上市。當晚,pHIDEON輝昂上市的消息就迅速登上了各大汽車媒體的頭條。但當各大媒體都把焦點放在售價上的同時,卻忽略了另一個重點,那就是與售價同時公布的針對輝昂車主專屬的“尊享權益”。這些權益到底能讓車主得到什麼密切的利益呢?小編就在這裏整理了四條和車主密切相關的權益,並利用数字來做進一步解讀。

亮點一:

最高4年/12萬公里質量擔保服務和全程無憂免費保養

長久以來,與豪華品牌車型價格“相配”的高昂保養費用,讓很多准車主們望而卻步。而這次輝昂針對其車主推出的專屬“尊享權益”。在眾多的尊享權益中,最讓人驚喜的是上汽大眾針對所有輝昂車主推出的質量擔保期內,所有保養手冊上列明的保養項目全都執行免費保養政策。而說到質量擔保期,除了入門款的車型按照國家規定提供3年10萬公里的常規質量擔保,其他7款車型,均可享受到廠家額外贈送的1年/2萬公里延長質量擔保期的服務,也就是說御尊豪華版及以上車型可享受4年/12萬公里質量擔保服務和免費保養。這一舉措不僅显示了對其自身產品的自信,而且真心誠意為消費者減輕用車養車的成本。為了能直觀表現這一免費政策,我們計算一下,傳統德系三強BBA車型,它們的保養費用到底為多少?通過對比保養費用,就能發現,這一權益能為輝昂車主省了多少後期養車費用。

與高配車型車主對保養數據不敏感相比,低配車主對於車輛保養這事兒還是比較在乎的,上述表格數據對應車型分別為:E200L運動型、A6L TFSI技術型、520Li典雅型。可以看出,除了奧迪贈送首保之外,奔馳和寶馬車主均不能享此項優惠。它們行駛6萬公里后的保養費用總額分別為12,468元、17,280.76元和14,586元。隨着車況的下降,行駛12萬公里的車輛保養費用,不只是簡單的翻倍而已。

除了保養方面輝昂車主可以節省一大筆支出外,輝昂的延保也是誠意十足。輝昂御尊版車型提供3年10萬公里質保的前提下,剩餘的7款車型均為4年12萬公里質保服務,

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

網站的第一印象網頁設計,決定了客戶是否繼續瀏覽的意願。台北網動廣告製作的RWD網頁設計,採用精簡與質感的CSS語法,提升企業的專業形象與簡約舒適的瀏覽體驗,讓瀏覽者第一眼就愛上它。

等於是廠家額外提供了1年/2萬公里的免費延保服務。而BBA方面,因為沒有官方的延保政策可循,媒體通過走訪多家4S店的形式,發現他們的一年延保費用大致都在5,000元左右,而這樣直觀的對比,表明了上汽大眾對輝昂車主足夠“大方”;更可看做輝昂車主在行駛12萬公里的過程中,僅需支付日常的油費和保險開銷,其他費用幾乎為零。

亮點二:

專屬品牌保險權益驚喜頗多

既然提到了保險,我們也來說一下輝昂的品牌保險權益。從本次公布的信息中不難發現,購買輝昂品牌車險的上汽大眾輝昂車主不但可以享受到不限里程不限次數的事故現場緊急維修救援服務,還能享受2人國內15天旅行的額外保障服務和事故維修期間的出行補償。小編就維修期補償這一權益,為大家做一下全面解析:

1.本地維修享7天(最高300元/天)打車報銷

有豪華車消費者反映,與豪華車銷售保持增長趨勢不同的是,豪華車的售後服務並無多大改善。比如說當車輛出現故障需要較長時間維修時,寶馬、雷克薩斯不會為車主提供任何權益;其他豪華品牌通常是調配經銷商處的試駕車給車主臨時使用。雖說這樣做也是出於給車主解決困難的目的,但並沒有考慮到如果車主對車輛性能並不了解,就會存在安全隱患。

上汽大眾在這一點上則顯得更為細心,如果輝昂在本地出現維修情況,車主即可享受7天打車費報銷權益,每天最高300元。這樣一來,既不會存在因對試駕車性能不熟悉引發意外事故的隱患,還可以在一周時間里依舊享受着便捷的有車生活,省時省心、無後顧之憂。

2.異地維修享7天五星級酒店住宿權

而當車輛在異地發生事故需要長時間維修時,沃爾沃、捷豹路虎和謳歌三大品牌會提供5星級酒店客房,免費供房的天數3-5天不等。奔馳、寶馬也不落後,都有這一服務,但免費住宿的標準稍低,為四星級酒店。豪華品牌中唯有奧迪不提供這一服務。

上汽大眾雖然是進軍豪華轎車市場的後來者,在異地住宿服務上反倒是表現得最有誠意。假如pHIDEON 輝昂出現異地維修情況,車主即可享受最長7天入住五星級酒店的住宿權益。以北上廣知名的幾家五星級酒店為例,平均算下來,7天房費至少有9205元。這可是一筆不小的開銷,上汽大眾願意出這份錢,既是對車主身在異地等待修車焦慮心情的撫慰,亦能使車主無論身在何處都能享受到貴賓級的尊榮體驗。

亮點三:

首付低至30% 兩年零利率信貸優本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

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

以設計的實用美學觀點,規劃出舒適、美觀的視覺畫面,有效提昇使用者的心理期待,營造出輕鬆、愉悅的網站瀏覽體驗。

分類
發燒車訊

美編現場冒死實拍 眾泰T600干翻瑞虎5_如何寫文案

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

擁有後台管理系統的網站,將擁有強大的資料管理與更新功能,幫助您隨時新增網站的內容並節省網站開發的成本。

一個電話之後,

※別再煩惱如何寫文案,掌握八大原則!

什麼是銷售文案服務?A就是幫你撰寫適合的廣告文案。當您需要販售商品、宣傳活動、建立個人品牌,撰寫廣告文案都是必須的工作。

小編美美便立即收拾行囊奔赴這個西南部的與邊境接壤的城市雲南騰衝最後上一張GIF圖眾泰T600干翻瑞虎5↓↓↓。

一個電話之後,小編美美便立即收拾行囊

奔赴這個西南部的

與邊境接壤的城市

雲南騰衝

最後上一張GIF圖

眾泰T600干翻瑞虎5

↓↓↓

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

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

銷售文案是什麼?A文案是廣告用的文字。舉凡任何宣傳、行銷、販賣商品時所用到的文字都是文案。在網路時代,文案成為行銷中最重要的宣傳方式,好的文案可節省大量宣傳資源,達成行銷目的。

分類
發燒車訊

為什麼10年車齡的超低價二手車不能買?其中有貓膩嗎_網頁設計公司

※想知道最厲害的網頁設計公司嚨底家"!

RWD(響應式網頁設計)是透過瀏覽器的解析度來判斷要給使用者看到的樣貌

不過在三年後售出時,殘值率下降就會迅猛不少,所以要看準時機將其售出。壯年時期II (3-6年,里程在16萬公里左右)此時的車輛狀況已經下降不少,各方面開始出現故障,也有着更多的零部件需要更換,發動機以及變速箱性能也開始逐漸下降,油耗會稍微上升一些,底盤零件由其是橡膠件基本都需要更換,此時維修保養費用是大幅度上升,但發動機變速箱方面大體上還是能保持未拆解的狀況,總的來說雖然動力油耗開始下降,但依然是處於可以接受的範圍。

前言

在筆者認為,汽車並不是一件將你從A點送到B點的工具,而是一個鮮活的生命,有着自己獨特的個性,並且和我們人類一樣有着壽命,也會經歷像嬰兒到老人一樣的時期。而今天筆者就要給大家介紹一下汽車使用的幾個周期,希望能給到想要購入二手車的用戶一些幫助。

准新車階段(0-1年車齡,里程少於2萬公里)

一輛車只要是小於或等於1年車齡,又或者是行駛里程是低於兩萬公里,我們都可以將其視作準新車,此時的它有着幾近最好的車況,各方面部件以及性能都可以說是處於嶄新的階段。只是可能還處於磨合期中,各部件可能配合不協調,會有着剎車異響、發動機比較嘈雜等小問題發生,此階段的車輛除了常規的更換油液以外是不會產生額外的使用費用,而且油耗也相對的低,是使用成本最低的階段。

對於二手車來說,買這樣的二手車是相當於買新車,殘值率還是較高的所以在價格上也是比較堅挺,總體價格往往和車身價相差無幾,僅僅是相差了一個購置稅以及保險的價格。若是能找到較好的車源以及能接受二手車,這種准新車是不錯的選擇。但是在幾年後再次出售的時候,價格就會因為已經過了一次戶而稍微低一點。

壯年階段 I(1-3年,里程在8萬公里以下)

這個階段的車輛是有着最好的性能,因為經過了磨合期的洗禮,各方面部件已經配合合拍,是使用最為舒心的時候,並不需要像磨合期時那麼多顧忌以及因為一些小問題而苦惱,而且動力油耗水平也幾乎是最為好的時期,正正因為配合合拍了,發動機以及變速箱之間的摩擦反而減少了,油耗也自然而然地小許下降。不過這個時候就是開始要更換一些易損件了,例如剎車油、剎車片、火花塞、輪胎等,

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

透過資料庫的網站架設建置,建立公司的形象或購物系統,並提供最人性化的使用介面,讓使用者能即時接收到相關的資訊

這樣就免不了增加一些花銷。

購買這個時期的二手車是整個二手車周期中最為划算的階段,雖然殘值率下降還是比較慢,售價並不會如後面階段下降那麼快,但是憑着較低的維修保養成本以及油耗使得它使用費用也相對的低廉。不過在三年後售出時,殘值率下降就會迅猛不少,所以要看準時機將其售出。

壯年時期II (3-6年,里程在16萬公里左右)

此時的車輛狀況已經下降不少,各方面開始出現故障,也有着更多的零部件需要更換,發動機以及變速箱性能也開始逐漸下降,油耗會稍微上升一些,底盤零件由其是橡膠件基本都需要更換,此時維修保養費用是大幅度上升,但發動機變速箱方面大體上還是能保持未拆解的狀況,總的來說雖然動力油耗開始下降,但依然是處於可以接受的範圍。

這個時期的二手車在殘值率上表現出來是開始猛跌,是筆者認為最不適合進行購買的,若是將其再次售出的時候價格往往非常的低,若是想要幾年後將其售出最好不要選擇這類車型。而打算長期使用的也要考慮一下維修保養的問題,畢竟此時整車性能已經下降有一定區間,使用成本也上升了一些。並且已經過了6年免過檢測線的年審,需要每兩年上檢測線檢測年審,這無形增加一部分成本。

中老年時期(6-10年,里程在20萬公里以上)

在這個時期車輛的性能狀況是大幅度下降,動力水平下降明顯,油耗明顯上升,維修保養費用也是大幅度增長,在使用的過程中總是需要到4S店或者是維修店進行檢修,以避免因為部件老化或者是部件的突然損壞而導致“趴窩”或者是“小病養成大病”,而且發動機變速箱此時也開始湧現不少問題,有可能需要進行中修或者大修,使用成本是每個時期中最高的,無論是貨幣成本還是時間成本。

對於二手車來說,這個時期的二手車基本達到車價的最低水平,殘值率已經達到幾乎最低的水平。但這也是不值得購買的,沒有再次售出的價值,瀕臨汽車使用的經濟使用壽命,要想將其再次售出基本是件不可能的事。

老年時期(10年以上車齡)

此時的車輛狀況已經處於整車的最低點,整車性能甚至沒有新車時的20%,動力表現極差,油耗奇高,而且此時的安全氣囊也有很大的可能失效,所以必須時刻注意安全氣囊指示燈的狀況,以便出現缺乏安全保護的情況下駕駛。

這個時期的二手車,筆者就只有一句話“不要買”,已經沒有任何價值,要做好下家是報廢廠的準備。本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

當全世界的人們隨著網路時代而改變向上時您還停留在『網站美醜不重要』的舊有思維嗎?機會是留給努力改變現況的人們,別再浪費一分一秒可以接觸商機的寶貴時間!

分類
發燒車訊

這地方美女如雲 竟然多個世界車神都喜歡來?_網頁設計

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

網動是一群專業、熱情、向前行的工作團隊,我們擁有靈活的組織與溝通的能力,能傾聽客戶聲音,激發創意的火花,呈現完美的作品

在這裏,你可以看到各種的進口車型,

網頁設計最專業,超強功能平台可客製化

窩窩以「數位行銷」「品牌經營」「網站與應用程式」「印刷品設計」等四大主軸,為每一位客戶客製建立行銷脈絡及洞燭市場先機。

它們出沒的身影,是每一個愛車人士不會放過的風景。澳門不僅有深厚的汽車文化、讓人流連忘返的景色、垂涎欲滴的美食、更有讓人血脈膨脹、激情四射的汽車賽事。又是一年十一月,太陽城集團第63屆澳門格蘭披治大賽車即將在這座絢麗的城市上演。
她坐落於世界東方,是祖國南部的一顆璀璨明本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

※推薦評價好的iphone維修中心

擁有專業的維修技術團隊,同時聘請資深iphone手機維修專家,現場說明手機問題,快速修理,沒修好不收錢