《見字如面4》先導片催淚上線_潭子電動車

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

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

“我是菲利普,菲利普的眼睛;我是菲利普,菲利普的肝;我是菲利普,菲利普的腎……”日前,令人期待已久的《見字如面》第四季上線了公益先導片,一名西南大學外教菲利普跨國捐獻器官的故事溫暖到了網友,著名音樂人小柯現場朗讀捐贈者父親寫的一封信,也令無數網友感動流淚。

怎麼證明一個人還活着?一封澳大利亞首位在華器官捐獻者菲利普的父親寫給兒子的信《你的離去是父母永難痊癒的傷》,讓觀眾體會到生命延續的感動。喜歡彈吉他唱歌的菲利普,因為深愛中國這片土地,在大學畢業後來到中國,成了重慶西南大學的一名外教。然而就在去年的5月9日,27歲的菲利普卻因病醫治無效,不幸離世。按照菲利普的遺願,他的父母捐獻了他的多個器官,這讓三名中國人的生命得到挽救,兩位中國人的眼睛重獲光明。

菲利普生前極其熱愛音樂,五位受捐者為了實現他的夢想,組建了視頻中的“一個人的樂隊”。這支特殊樂隊的成員來到了《見字如面》的現場,他們身穿印着菲利普名字的隊服,讓人感受到菲利普的生命仍然還在,在五个中國人的身上得到了延續。

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

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

在這一切發生18個月後,當得知接受兒子捐獻器官挽救的五位移植受者為了完成菲利普的音樂夢想,組成了“一個人的樂隊”,菲利普63歲的父親彼得·漢考克先生按捺不住自己激動的心情,連夜寫了一封家書給陰陽兩隔的愛子。深受感動的音樂人小柯來到《見字如面》現場,替老人家把信讀給天堂里的菲利普和各位觀眾。

父親彼得在信中說:“你走了,留給這個世界最珍貴的禮物是希望,是五個等待已久的生命,因你重獲新生。我和你母親知道你還活着,從未離開,空氣中還有你的氣息,你還在親歷這個精彩的世界。你就是他們,他們和你一個樣,我們失去了一個菲利普,卻獲得了五個菲利普……”

當得知接受菲利普捐獻器官的5位移植受者想組建樂隊,為菲利普圓一場音樂夢時,彼得說:“我和你母親激動了好幾天,看到‘一個人的樂隊’,印着菲利普名字的隊服,我們一家人也要一人一件,想穿上它去給你鼓掌、吶喊。菲兒,你就是我們的王子。”

菲利普已逝,他的生命不僅在五位移植受者身上得到了延續,他身上散發的人間大愛也永遠閃耀着人道主義的光輝,使得越來越多的人關注器官捐獻這一公益行為,更促使更多的人成為了器官捐獻登記者。(記者 祖薇)

本站聲明:網站內容來http://www.societynews.cn/html/wh/fq/,如有侵權,請聯繫我們,我們將及時處理

※超省錢租車方案

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

【原創】Linux中斷子系統(一)-中斷控制器及驅動分析_租車

※超省錢租車方案

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

背景

  • Read the fucking source code! –By 魯迅
  • A picture is worth a thousand words. –By 高爾基

說明:

  1. Kernel版本:4.14
  2. ARM64處理器,Contex-A53,雙核
  3. 使用工具:Source Insight 3.5, Visio

1. 概述

從這篇文章開始,來聊一聊中斷子系統。
中斷是處理器用於異步處理外圍設備請求的一種機制,可以說中斷處理是操作系統管理外圍設備的基石,此外系統調度、核間交互等都離不開中斷,它的重要性不言而喻。

來一張概要的分層圖:

  • 硬件層:最下層為硬件連接層,對應的是具體的外設與SoC的物理連接,中斷信號是從外設到中斷控制器,由中斷控制器統一管理,再路由到處理器上;
  • 硬件相關層:這個層包括兩部分代碼,一部分是架構相關的,比如ARM64處理器處理中斷相關,另一部分是中斷控制器的驅動代碼;
  • 通用層:這部分也可以認為是框架層,是硬件無關層,這部分代碼在所有硬件平台上是通用的;
  • 用戶層:這部分也就是中斷的使用者了,主要是各類設備驅動,通過中斷相關接口來進行申請和註冊,最終在外設觸發中斷時,進行相應的回調處理;

中斷子系統系列文章,會包括硬件相關、中斷框架層、上半部與下半部、Softirq、Workqueue等機制的介紹,本文會先介紹硬件相關的原理及驅動,前戲結束,直奔主題。

2. GIC硬件原理

  • ARM公司提供了一個通用的中斷控制器GIC(Generic Interrupt Controller)GIC的版本包括V1 ~ V4,由於本人使用的SoC中的中斷控制器是V2版本,本文將圍繞GIC-V2來展開介紹;

來一張功能版的框圖:

  • GIC-V2從功能上說,除了常用的中斷使能、中斷屏蔽、優先級管理等功能外,還支持安全擴展、虛擬化等;
  • GIC-V2從組成上說,主要分為DistributorCPU Interface兩個模塊,Distributor主要負責中斷源的管理,包括優先級的處理,屏蔽、搶佔等,並將最高優先級的中斷分發給CPU InterfaceCPU Interface主要用於連接處理器,與處理器進行交互;
  • Virtual DistributorVirtual CPU Interface都與虛擬化相關,本文不深入分析;

再來一張細節圖看看DistributorCPU Interface的功能:

  • GIC-V2支持三種類型的中斷:

    1. SGI(software-generated interrupts):軟件產生的中斷,主要用於核間交互,內核中的IPI:inter-processor interrupts就是基於SGI,中斷號ID0 - ID15用於SGI
    2. PPI(Private Peripheral Interrupt):私有外設中斷,每個CPU都有自己的私有中斷,典型的應用有local timer,中斷號ID16 - ID31用於PPI
    3. SPI(Shared Peripheral Interrupt):共享外設中斷,中斷產生后,可以分發到某一個CPU上,中斷號ID32 - ID1019用於SPIID1020 - ID1023保留用於特殊用途;
  • Distributor功能:

    1. 全局開關控制Distributor分發到CPU Interface
    2. 打開或關閉每个中斷;
    3. 設置每个中斷的優先級;
    4. 設置每个中斷將路由的CPU列表;
    5. 設置每個外設中斷的觸發方式:電平觸發、邊緣觸發;
    6. 設置每个中斷的Group:Group0或Group1,其中Group0用於安全中斷,支持FIQ和IRQ,Group1用於非安全中斷,只支持IRQ;
    7. SGI中斷分發到目標CPU上;
    8. 每个中斷的狀態可見;
    9. 提供軟件機制來設置和清除外設中斷的pending狀態;
  • CPU Interface功能:

    1. 使能中斷請求信號到CPU上;
    2. 中斷的確認;
    3. 標識中斷處理的完成;
    4. 為處理器設置中斷優先級掩碼;
    5. 設置處理器的中斷搶佔策略;
    6. 確定處理器的最高優先級pending中斷;

中斷處理的狀態機如下圖:

  • Inactive:無中斷狀態;
  • Pending:硬件或軟件觸發了中斷,但尚未傳遞到目標CPU,在電平觸發模式下,產生中斷的同時保持pending狀態;
  • Active:發生了中斷並將其傳遞給目標CPU,並且目標CPU可以處理該中斷;
  • Active and pending:發生了中斷並將其傳遞給目標CPU,同時發生了相同的中斷並且該中斷正在等待處理;

GIC檢測中斷流程如下:

  1. GIC捕獲中斷信號,中斷信號assert,標記為pending狀態;
  2. Distributor確定好目標CPU后,將中斷信號發送到目標CPU上,同時,對於每個CPU,Distributor會從pending信號中選擇最高優先級中斷髮送至CPU Interface
  3. CPU Interface來決定是否將中斷信號發送至目標CPU;
  4. CPU完成中斷處理后,發送一個完成信號EOI(End of Interrupt)給GIC;

3. GIC驅動分析

3.1 設備信息添加

ARM平台的設備信息,都是通過Device Tree設備樹來添加,設備樹信息放置在arch/arm64/boot/dts/

下圖就是一个中斷控制器的設備樹信息:

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

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

  • compatible字段:用於與具體的驅動來進行匹配,比如圖片中arm, gic-400,可以根據這個名字去匹配對應的驅動程序;
  • interrupt-cells字段:用於指定編碼一个中斷源所需要的單元個數,這個值為3。比如在外設在設備樹中添加中斷信號時,通常能看到類似interrupts = <0 23 4>;的信息,第一個單元0,表示的是中斷類型(1:PPI,0:SPI),第二個單元23表示的是中斷號,第三個單元4表示的是中斷觸發的類型;
  • reg字段:描述中斷控制器的地址信息以及地址範圍,比如圖片中分別制定了GIC Distributor(GICD)GIC CPU Interface(GICC)的地址信息;
  • interrupt-controller字段:表示該設備是一个中斷控制器,外設可以連接在該中斷控制器上;
  • 關於設備數的各個字段含義,詳細可以參考Documentation/devicetree/bindings下的對應信息;

設備樹的信息,是怎麼添加到系統中的呢?Device Tree最終會編譯成dtb文件,並通過Uboot傳遞給內核,在內核啟動後會將dtb文件解析成device_node結構。關於設備樹的相關知識,本文先不展開,後續再找機會補充。來一張圖,先簡要介紹下關鍵路徑:

  • 設備樹的節點信息,最終會變成device_node結構,在內存中維持一個樹狀結構;
  • 設備與驅動,會根據compatible字段進行匹配;

3.2 驅動流程分析

GIC驅動的執行流程如下圖所示:

  • 首先需要了解一下鏈接腳本vmlinux.lds,腳本中定義了一個__irqchip_of_table段,該段用於存放中斷控制器信息,用於最終來匹配設備;
  • 在GIC驅動程序中,使用IRQCHIP_DECLARE宏來聲明結構信息,包括compatible字段和回調函數,該宏會將這個結構放置到__irqchip_of_table字段中;
  • 在內核啟動初始化中斷的函數中,of_irq_init函數會去查找設備節點信息,該函數的傳入參數就是__irqchip_of_table段,由於IRQCHIP_DECLARE已經將信息填充好了,of_irq_init函數會根據arm,gic-400去查找對應的設備節點,並獲取設備的信息。中斷控制器也存在級聯的情況,of_irq_init函數中也處理了這種情況;
  • or_irq_init函數中,最終會回調IRQCHIP_DECLARE聲明的回調函數,也就是gic_of_init,而這個函數就是GIC驅動的初始化入口函數了;
  • GIC的工作,本質上是由中斷信號來驅動,因此驅動本身的工作就是完成各類信息的初始化,註冊好相應的回調函數,以便能在信號到來之時去執行;
  • set_smp_process_call設置__smp_cross_call函數指向gic_raise_softirq,本質上就是通過軟件來觸發GIC的SGI中斷,用於核間交互;
  • cpuhp_setup_state_nocalls函數,設置好CPU進行熱插拔時GIC的回調函數,以便在CPU熱插拔時做相應處理;
  • set_handle_irq函數的設置很關鍵,它將全局函數指針handle_arch_irq指向了gic_handle_irq,而處理器在進入中斷異常時,會跳轉到handle_arch_irq執行,所以,可以認為它就是中斷處理的入口函數了;
  • 驅動中完成了各類函數的註冊,此外還完成了irq_chip, irq_domain等結構體的初始化,這些結構在下文會進一步分析;
  • 最後,完成GIC硬件模塊的初始化設置,以及電源管理相關的註冊等工作;

3.3 數據結構分析

先來張圖:

  • GIC驅動中,使用struct gic_chip_data結構體來描述GIC控制器的信息,整個驅動都是圍繞着該結構體的初始化,驅動中將函數指針都初始化好,實際的工作是由中斷信號觸發,也就是在中斷來臨的時候去進行回調;
  • struct irq_chip結構,描述的是中斷控制器的底層操作函數集,這些函數集最終完成對控制器硬件的操作;
  • struct irq_domain結構,用於硬件中斷號和Linux IRQ中斷號(virq,虛擬中斷號)之間的映射;

還是上一下具體的數據結構代碼吧,關鍵註釋如下:

struct irq_chip {
	struct device	*parent_device;     //指向父設備
	const char	*name;      //  /proc/interrupts中显示的名字
	unsigned int	(*irq_startup)(struct irq_data *data);  //啟動中斷,如果設置成NULL,則默認為enable
	void		(*irq_shutdown)(struct irq_data *data);     //關閉中斷,如果設置成NULL,則默認為disable
	void		(*irq_enable)(struct irq_data *data);   //中斷使能,如果設置成NULL,則默認為chip->unmask
	void		(*irq_disable)(struct irq_data *data);  //中斷禁止

	void		(*irq_ack)(struct irq_data *data);  //開始新的中斷
	void		(*irq_mask)(struct irq_data *data); //中斷源屏蔽
	void		(*irq_mask_ack)(struct irq_data *data); //應答並屏蔽中斷
	void		(*irq_unmask)(struct irq_data *data);   //解除中斷屏蔽
	void		(*irq_eoi)(struct irq_data *data);  //中斷處理結束后調用

	int		(*irq_set_affinity)(struct irq_data *data, const struct cpumask *dest, bool force); //在SMP中設置CPU親和力
	int		(*irq_retrigger)(struct irq_data *data);    //重新發送中斷到CPU
	int		(*irq_set_type)(struct irq_data *data, unsigned int flow_type); //設置中斷觸發類型
	int		(*irq_set_wake)(struct irq_data *data, unsigned int on);    //使能/禁止電源管理中的喚醒功能

	void		(*irq_bus_lock)(struct irq_data *data); //慢速芯片總線上的鎖
	void		(*irq_bus_sync_unlock)(struct irq_data *data);  //同步釋放慢速總線芯片的鎖

	void		(*irq_cpu_online)(struct irq_data *data);
	void		(*irq_cpu_offline)(struct irq_data *data);

	void		(*irq_suspend)(struct irq_data *data);
	void		(*irq_resume)(struct irq_data *data);
	void		(*irq_pm_shutdown)(struct irq_data *data);

	void		(*irq_calc_mask)(struct irq_data *data);

	void		(*irq_print_chip)(struct irq_data *data, struct seq_file *p);
	int		(*irq_request_resources)(struct irq_data *data);
	void		(*irq_release_resources)(struct irq_data *data);

	void		(*irq_compose_msi_msg)(struct irq_data *data, struct msi_msg *msg);
	void		(*irq_write_msi_msg)(struct irq_data *data, struct msi_msg *msg);

	int		(*irq_get_irqchip_state)(struct irq_data *data, enum irqchip_irq_state which, bool *state);
	int		(*irq_set_irqchip_state)(struct irq_data *data, enum irqchip_irq_state which, bool state);

	int		(*irq_set_vcpu_affinity)(struct irq_data *data, void *vcpu_info);

	void		(*ipi_send_single)(struct irq_data *data, unsigned int cpu);
	void		(*ipi_send_mask)(struct irq_data *data, const struct cpumask *dest);

	unsigned long	flags;
};

struct irq_domain {
	struct list_head link;  //用於添加到全局鏈表irq_domain_list中
	const char *name;   //IRQ domain的名字
	const struct irq_domain_ops *ops;   //IRQ domain映射操作函數集
	void *host_data;    //在GIC驅動中,指向了irq_gic_data
	unsigned int flags; 
	unsigned int mapcount;  //映射中斷的個數

	/* Optional data */
	struct fwnode_handle *fwnode;
	enum irq_domain_bus_token bus_token;
	struct irq_domain_chip_generic *gc;
#ifdef	CONFIG_IRQ_DOMAIN_HIERARCHY
	struct irq_domain *parent;  //支持級聯的話,指向父設備
#endif
#ifdef CONFIG_GENERIC_IRQ_DEBUGFS
	struct dentry		*debugfs_file;
#endif

	/* reverse map data. The linear map gets appended to the irq_domain */
	irq_hw_number_t hwirq_max;  //IRQ domain支持中斷數量的最大值
	unsigned int revmap_direct_max_irq;
	unsigned int revmap_size;   //線性映射的大小
	struct radix_tree_root revmap_tree; //Radix Tree映射的根節點
	unsigned int linear_revmap[];   //線性映射用到的查找表
};

struct irq_domain_ops {
	int (*match)(struct irq_domain *d, struct device_node *node,
		     enum irq_domain_bus_token bus_token);      // 用於中斷控制器設備與IRQ domain的匹配
	int (*select)(struct irq_domain *d, struct irq_fwspec *fwspec,
		      enum irq_domain_bus_token bus_token);
	int (*map)(struct irq_domain *d, unsigned int virq, irq_hw_number_t hw);    //用於硬件中斷號與Linux中斷號的映射
	void (*unmap)(struct irq_domain *d, unsigned int virq);
	int (*xlate)(struct irq_domain *d, struct device_node *node,
		     const u32 *intspec, unsigned int intsize,
		     unsigned long *out_hwirq, unsigned int *out_type);     //通過device_node,解析硬件中斷號和觸發方式

#ifdef	CONFIG_IRQ_DOMAIN_HIERARCHY
	/* extended V2 interfaces to support hierarchy irq_domains */
	int (*alloc)(struct irq_domain *d, unsigned int virq,
		     unsigned int nr_irqs, void *arg);
	void (*free)(struct irq_domain *d, unsigned int virq,
		     unsigned int nr_irqs);
	void (*activate)(struct irq_domain *d, struct irq_data *irq_data);
	void (*deactivate)(struct irq_domain *d, struct irq_data *irq_data);
	int (*translate)(struct irq_domain *d, struct irq_fwspec *fwspec,
			 unsigned long *out_hwirq, unsigned int *out_type);
#endif
};

3.3.1 IRQ domain

IRQ domain用於將硬件的中斷號,轉換成Linux系統中的中斷號(virtual irq, virq),來張圖:

  • 每个中斷控制器都對應一個IRQ Domain;
  • 中斷控制器驅動通過irq_domain_add_*()接口來創建IRQ Domain;
  • IRQ Domain支持三種映射方式:linear map(線性映射),tree map(樹映射),no map(不映射);
    1. linear map:維護固定大小的表,索引是硬件中斷號,如果硬件中斷最大數量固定,並且數值不大,可以選擇線性映射;
    2. tree map:硬件中斷號可能很大,可以選擇樹映射;
    3. no map:硬件中斷號直接就是Linux的中斷號;

三種映射的方式如下圖:

  • 圖中描述了三个中斷控制器,對應到三種不同的映射方式;
  • 各個控制器的硬件中斷號可以一樣,最終在Linux內核中映射的中斷號是唯一的;

4. Arch-speicific代碼分析

  • 中斷也是異常模式的一種,當外設觸發中斷時,處理器會切換到特定的異常模式進行處理,而這部分代碼都是架構相關的;ARM64的代碼位於arch/arm64/kernel/entry.S
  • ARM64處理器有四個異常級別Exception Level:0~3,EL0級對應用戶態程序,EL1級對應操作系統內核態,EL2級對應Hypervisor,EL3級對應Secure Monitor;
  • 異常觸發時,處理器進行切換,並且跳轉到異常向量表開始執行,針對中斷異常,最終會跳轉到irq_handler中;

代碼比較簡單,如下:

/*
 * Interrupt handling.
 */
	.macro	irq_handler
	ldr_l	x1, handle_arch_irq
	mov	x0, sp
	irq_stack_entry
	blr	x1
	irq_stack_exit
	.endm

來張圖:

  • 中斷觸發,處理器去異常向量表找到對應的入口,比如EL0的中斷跳轉到el0_irq處,EL1則跳轉到el1_irq處;
  • 在GIC驅動中,會調用set_handle_irq接口來設置handle_arch_irq的函數指針,讓它指向gic_handle_irq,因此中斷觸發的時候會跳轉到gic_handle_irq處執行;
  • gic_handle_irq函數處理時,分為兩種情況,一種是外設觸發的中斷,硬件中斷號在16 ~ 1020之間,一種是軟件觸發的中斷,用於處理器之間的交互,硬件中斷號在16以內;
  • 外設觸發中斷後,根據irq domain去查找對應的Linux IRQ中斷號,進而得到中斷描述符irq_desc,最終也就能調用到外設的中斷處理函數了;

GIC和Arch相關的介紹就此打住,下一篇文章會接着介紹通用的中斷處理框架,敬請期待。

參考

ARM Generic Interrupt Controller Architecture version 2.0

歡迎關注公眾號,不定期更新Linux內核機制相關文章,謝謝。

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

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

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

經過了四年,微軟至今依舊提供 Windows 10 免費升級優惠_租車

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

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

微軟早在 2016 年就宣布將停止 Windows 10 免費升級優惠,官方部落格也有特別發出公告,不過去年底時我們曾發現依舊有效,至今又過了一年的時間,微軟取消這優惠了嗎?事實證明還沒有,最近就有外媒實測一樣成功,意味著如果你目前還在使用 Windows 7,只要是正版序號,那現在還是可以免費升級到 Windows 10。

微軟至今依舊提供 Windows 10 免費升級優惠

過去微軟曾公告免費升級 Windows 10 優惠會在 2016/7/29 結束,但過了 4 年這項優惠還是存在:

根據外媒 Windows Latest 的報導,雖然微軟訂定取消優惠的日期早就過了好幾年,但他們最近實測後發現,只要是擁有正版序號的 Windows 7 作業系統用戶,至今仍然可以免費升級到 Windows 10。

以下是免費升級 Windows 10 的操作步驟:

  1. 首先,電腦安裝的 Windows 7 必須是正版序號。
  2. 進入 Windows 10 下載頁面後,點擊 “立即下載工具”。
  3. 打開下載好的工具後,選擇 “立即升級此電腦”,然後接受相關微軟條款說明。
  4. 記得選擇保留檔案的升級選項,如果是全新安裝,很可能沒辦法獲得免費升級 Windows 10 的資格。
  5. 安裝完成後,電腦連上網路並打開 Windows Update –> 啟用。
  6. 當完成微軟伺服器連接後,應該就會顯示啟用成功。
  7. 如果沒有,也能輸入你的 Windows 7 正版序號來啟用作業系統。

過去是 Windows 7、Windows 8.x 用戶都符合 Windows 10 免費升級優惠,不過這次文中只有提到 Windows 7,因此不太確定 Windows 8.x 還行不行,這部分就讓讀者自行測試看看(如果你也想免費升級 Windows 10)。

※超省錢租車方案

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

沒意外這優惠應該會持續存在,畢竟都過這麼久,微軟還是沒關閉,再加上之前也有前微軟團隊成員透露「一年免費升級計畫,超過就必須付費」優惠是行銷手法,微軟早就不靠 Windows 賺錢,只是為了提升裝置升級數。

資料來源:Windows Latest

你為什麼該選「Intel Evo」?全方位筆電認證一文看懂

您也許會喜歡:

【推爆】終身$0月租 打電話只要1元/分

立達合法徵信社-讓您安心的選擇

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

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

到底要不要附充電頭,小米這回把選擇權交給消費者_租車

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

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

今年 iPhone 12 系列推出以來最大的爭議點,在於取消了隨附充電器與耳機這兩樣在過去被視為標配的手機隨附配件,雖說一開始輿論頻頻,但後續緊接著有些 Android 手機廠商也陸續有這同樣的想法。小米在昨日發表的小米 11 則是提供兩種選擇,讓消費者在不加價的情況下可依個人情況自由選擇。

到底要不要附充電頭,小米這回把選擇權交給消費者

在 12/26 時雷軍曾於微博宣布,為了響應環保,在新一代小米 11 上將取消隨附充電器,並使包裝更輕薄,希望獲得廣大用戶支持,但消息一出網友們多半持反對意見。在當時雷軍曾表示今時今日每個人都有很多閒置充電器,不僅造成收納的困擾也製造不少電子垃圾,雖說取消隨附充電器這點不容易被理解,但是否能夠有更好的解決方案。

在昨日,小米發表了全球首款搭載高通 S888 處理器、四面曲面螢幕與 1 億像素煮鏡頭的新旗艦機小米 11,最令人關注的點莫過於這款產品將會有兩種版本,一者為不含充電器、充電線的環保包裝,另一者則為隨附 55W GaN 充電器同捆版本,兩者價格一樣,等於消費者能夠自由選擇是否要充電設備。雷軍認為,Apple 在今年 iPhone 12 推出時取消充電器的舉措體現了環保意識與社會責任,但做法太過簡單粗暴,而小米的做法則是將選擇權交還給用戶,讓使用者自己來選擇需不需要充電器。

雖說是否真正環保與否這點對於消費者而言感覺不明顯,但 Apple 的做法似乎並沒有考慮到一般用戶家中是否擁有適配的快充充電器,使得消費者必須另外再添購 Apple 或來自第三方的快充產品,如此一來一往到底是否真正環保見仁見智,但可以肯定的是 Apple 與配件商在這一塊又有其他的新商機。

※超省錢租車方案

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

您也許會喜歡:

【推爆】終身$0月租 打電話只要1元/分

立達合法徵信社-讓您安心的選擇

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

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

指導價比瑞納更便宜但是更好看的悅納你買不買_租車

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

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

4L自動擋車型動力就有點弱,尤其是高速提速能力。其中1。4L車型的變速箱為6擋手動和6擋手自一體,1。6L的為6擋手自一體。最低配的車型不管是安全配置還是實用配置都很低,它存在的意義更多的只是為了拉低售價罷了。最推薦的車型當屬於2016款 1。

18日,北京現代的小型車—悅納三廂版正式上市。新車有1.4L和1.6L兩款動力系統,總計共6款車型供消費者選擇,指導價為7.28-10.58萬元。

悅納其實就是瑞納的換代車型,但是在外觀設計方面絕對是顛覆了以往的外觀設計,韓國車總是能在外觀設計方面給大家驚喜。

悅納基本繼承了其概念車的設計理念,前臉採用了現代最新的家族式設計,鍍鉻材質修飾的六邊形多橫幅格柵,看起來視覺效果很不錯。車身尺寸為4380*1728*1460mm,軸距為2600mm。基本維持了瑞納的尺寸。和領動一樣,悅納的車尾造型很漂亮,小巧的擾流板增添了悅納的運動氣息,可以說從外觀上,悅納領先瑞納很多。

內飾同樣進步很大,整體來看要比瑞納領先一個檔次,畢竟不是一個時代的產物。無論是做工還是用料,都有了很大的進步。

由於軸距較大,所以後排乘坐空間也比較寬裕,坐墊長度適中,腿部支撐較好。但是如果後排乘客身高超過了1.8米,頭部空間就有點局促了。畢竟悅納是小型車。

悅納的在日常行駛中轉向手感較輕,指向很准,但是基本什麼路感的回饋。懸架調教屬於舒適類型,

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

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

車內隔音不錯。不過1.4L自動擋車型動力就有點弱,尤其是高速提速能力。其中1.4L車型的變速箱為6擋手動和6擋手自一體,1.6L的為6擋手自一體。

最低配的車型不管是安全配置還是實用配置都很低,它存在的意義更多的只是為了拉低售價罷了。

最推薦的車型當屬於2016款 1.4L 自動活力版SpORT,指導價為9.08萬,這款車有了鋼琴漆裝飾條、真皮方向盤、皮/織物混搭座椅、擋把等以及專屬的紅黑色運動版內飾等,這都是看得見摸得着的配置,還有一鍵啟動,方便實用。同時還可以選裝天窗。但是不能選裝ESp,絕對是一個差評。

另外就是1.4L 自動炫酷版GLS,指導價為8.78萬,因為它的實用性配置將就可以滿足日常行車,同時它可以選裝無鑰匙啟動/進入系統,剎車輔助、牽引力控制和ESp這些安全配置。也是比較值得推薦的。

不過1.4L自動擋車型的動力不是很好,1.6L雖然配置齊全但是價格太貴了。悅納整體上顏值較高,空間較大,油耗不高,舒適性不錯。但是由於剛上市優惠肯定少,所以不建議現在出手。

現在轎車的優惠幅度都是一個比一個狠的,況且悅納的配置真心不高,你看看左鄰右舍的對手們,一向以摳門著稱的豐田致炫都標配了ESp,神二代pLOLO也有一萬多的優惠,飛度雖然配置也很低但是人家動力甩你兩條街啊!對手們都是那麼優秀而且還那麼努力,悅納你也要努力啊,你不優惠個兩萬,怎麼好意思跟對手們打招呼?本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

※超省錢租車方案

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

Google 語音助理新增「耍廢模式(Do Nothing Mode)」讓你不得不 Chill_租車

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

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

Google 與其他甜點品牌的聯名也許不算新聞(記得 Android KitKat 巧克力嗎?),但這次他們與吉百利 5 Star 巧克力棒聯名的功能,倒是真的有趣到… 或該說「Chill」到不行。繼續閱讀 Google 語音助理新增「耍廢模式(Do Nothing Mode)」讓你不得不 Chill 報導內文。

▲圖片來源: Cadbury 5 Star India

Google 語音助理新增「耍廢模式(Do Nothing Mode)」讓你不得不 Chill

雖然很可惜的,這個功能目前僅有在可以吃得到 Cadbury 的 5 Star 巧克力棒的區域可以玩到(連歐美都沒有)。但這超「廢」的 Google Assistant 語音助理功能,實在讓人很想要玩玩看!據稱,你只要在啟動 Google 語音助理功能的時候,以「Eat a 5 Star」為指令,即可啟動讓你不得不 Chill 耍廢起來的 Do Nothing 模式。

▲圖片來源: Cadbury 5 Star India

是的,這個直譯為啥都不做的模式,就如同其名,會將 Google Assistant 轉變成一個廢到笑死的無用助理。但與直接不回覆的靜音功能不同,Google 助理依然會回應你的問題,只是不會給你有用的答案。像在官方示範的影片裡,使用者希望撥打電話,結果 Google Assistant 卻直接拒絕(XD);詢問交通狀況、推薦美容院之類的問題,卻會回覆你導向「沒差啦」、「不用啦」、「不需要啦」這類的消極回覆(笑死)。

▲圖片來源: Cadbury 5 Star India

雖然你可能會因此想要噴髒話,不過畢竟是你自己啟動了吃零食的耍廢模式。Google 這波與 Cadbury 的品牌合作,就是希望給你一個最耍廢的點心品嚐時間。更多範例可以看看底下 Android Police 玩到的對話內容。

▲圖片來源:Android Police

既然語音助理沒有聰明到可以判斷你手上拿的是否是該牌的巧克力棒,相信可以玩到的朋友,應該會很樂意在想耍廢的時候就直接啟動此模式。並且不斷試探到底這 AI 語音助理是跟誰學來這麼多奇怪回覆的(Google Assistant:怪我囉?)。

引用來源

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

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

延伸閱讀:

Telegram 爆精確位置追蹤漏洞,官方似乎還沒打算修正(!?)

小米11 最新的無線麥克風功能怎麼用?官方直接示範了(影片)

您也許會喜歡:

【推爆】終身$0月租 打電話只要1元/分

立達合法徵信社-讓您安心的選擇

※超省錢租車方案

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

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

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

有別於一般網頁架設公司,除了模組化的架站軟體,我們的營業主軸還包含:資料庫程式開發、網站建置、網頁設計、電子商務專案開發、系統整合、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 神州租賃有限公司!合法經營、合法連鎖、合法租賃小客車!

越加價越多人買這些車型憑什麼這麼神?_包裝設計

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

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

目前加價1-5萬。我們今天不管你是小“S”還是大“C”,今天就是要把你加價提車的事情說一下,和GLC一樣,在同價位裏面,E級的內飾確實好看到爆,逼格也足夠,雖然上市之前飽受簡配全鋁車身事件的影響。但是照樣抵擋不住土豪加價提車的熱情。

中國現在已經是世界上最大的汽車市場之一了,但是在這個市場之內依然存在着一些很奇葩的現象-加價提車,說起加價提車,估計中國的車友都是深惡痛絕的,表示會堅決抵制的,但是現實就是還有不少車子依然加價銷售。

小編我就鬱悶了,現在的車市競爭如此激烈,動輒都是優惠幾萬才銷售的,怎麼還會加價買車呢?對於我這個寶駿310都嫌貴的人,看到那些加價幾千幾萬去買車的人,我真替他們心疼,下面我們就看看近期哪些車子加價比較凶。

東風本田-思域

思域的指導價為12.99-16.99萬,目前加價5000左右。坦白的說,這一代的思域實力確實很強大,曾經試過思域和2.0T 200馬力的指導價高達21.88萬的速騰GLI比加速,思域竟然能緊隨其後,甚至在速度上了一百多km/h之後,思域有些反超的趨勢,但是由於已經超速再加上那條路不夠長,只好作罷。不過思域除了加速快之外也沒有太牛逼的地方了,但是就是有很多人喜歡這種加速的快感,所以思域加價也是杠杠的。

有些地方甚至加價一萬,年前提車的話,還不能保證你要的顏色,誇張的是有些地方,就算加價而且也不能保證年前能提車。東本當時的CR-V加價比思域還要厲害的多,後來途觀接過了CR-V加價的接力棒之後,東本幾乎沒有一款熱銷的車子了,如今思域,又讓東本火了一把。但是就我來說,思域如果沒有一萬的現金優惠,我是不會買的,雖然我也很喜歡思域。但是我不會去慣加價提車這種可惡的毛病。

吉利汽車-博越

博越的價格為9.88-15.78萬,目前需要加2000-6000元的裝飾。博越目前可以說是自主緊湊型SUV的代表作之一,無論是外在和內在,原創度都很高,駕駛感受非常不錯,底盤紮實厚重,調教的很好,價格也算比較親民,沒有貴的那麼離譜。當博越熱銷的時候,吉利當局表示不會加價銷售,但是現實卻打臉了,由於吉利旗下的多款車型熱銷,供不應求,所以博越也不好意思的變相加價了。不過,

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

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

買這車的話,估計要等三個月以上吧!

北京奔馳-奔馳GLC

GLC的價格為39.60-57.90萬,屬於中型SUV,目前加價1-3萬,擺脫了GLK那刻板的外觀,現款的的GLC圓潤了不少,明顯符合了國人的審美,同時內飾也變得更加豪華,論內飾的豪華程度,GLC在同級別鮮有對手,所以啊,我長得這麼帥,就要加價賣,你能拿我怎麼樣?不過小編就是想吐槽一句,記得往車裡放一些炭包,因為擔心車裡內飾有味。

北京奔馳-奔馳E級

E級的價格為43.68-49.98萬,定位中大型豪華車。目前加價1-5萬。我們今天不管你是小“S”還是大“C”,今天就是要把你加價提車的事情說一下,和GLC一樣,在同價位裏面,E級的內飾確實好看到爆,逼格也足夠,雖然上市之前飽受簡配全鋁車身事件的影響。但是照樣抵擋不住土豪加價提車的熱情。弱弱的意淫一下,加價的錢購我買一台310了?土豪可不可以晚點提車,然後把這錢打給我們?

雷克薩斯-雷克薩斯RX

RX的指導為41.80-86.90萬,加價1-4萬,當時小編試駕的是86.9萬的頂配車型,感覺車子還是很OK了(廢話,都將近90萬了,還不OK么?),不過低配的車型也應該很不錯的。但是RX也是難逃加價的命運,要麼加三四萬的裝飾,要麼加現金一萬。

廣汽豐田-漢蘭達

漢蘭達的價格為23.98-42.28萬,目前加價幾千到2萬不等,當初我一個好基友還在意淫等着新漢蘭達降價一兩萬了再去提車,沒想到黃花菜都等涼了,漢蘭達還在加價。作為加價常青藤系類的漢蘭達,為什麼能如此堅挺?無外乎大七座SUV除了銳界,競爭對手實在太少了,另外漢蘭達積累的的口碑也起了決定性因素,同時很多消費者也想買到那個所謂的原裝進口的2.0T發動機,所以縱然加價,消費者也在所不辭。不過據說美版的漢蘭達改款都快要出來了,但是國內這邊…

豐田(進口)-埃爾法

真正的加價大王子來了-阿爾法,阿爾法的指導價為61.78-81.40萬,搭載3.5L 275馬力 V6和2.4L 167馬力發動機,雖然發動機不是很牛逼,但是加價的尺度絕對亮瞎眼,因為需要加價15-32萬不等,32萬購買我多少台QQ了啊,土豪的世界真是豐富多彩啊,買個車都能加價這麼多。小編曾經和一位加價買埃爾法的車主交談過,人家只是淡淡的說,我就是喜歡阿爾法…本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

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

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

草泥馬成人類救星? 研究:駱馬抗體能滅武漢肺炎病毒_租車

※超省錢租車方案

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

摘錄自2020年4月20日自由時報報導

武漢肺炎疫情肆虐全球,「草泥馬」可望成為人類救星?比利時一項最新研究發現,駱馬血液中的抗體,可能有助人類消滅病毒!

駱馬(llama)又名大羊駝或美洲駝,是分布於南美洲的駱駝科動物,和多種相似動物合稱為駱馬或美洲駝,體型比羊駝(Alpaca)還大。

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

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

英國《週日州泰晤士報》19日報導,比利時佛朗德生物技術研究院(Vlaams Instituut voor Biotechnologie Flanders Institute of Biotechnology)、與美國德州大學奧斯汀分校的研究團隊發現,駱馬血液中的抗體,可協助人類對抗病毒,讓特效藥研究不再限於現存藥物,更可跨物種進行。

這項研究成果刊登於生物學論文預印本文獻庫BioRxiv,將隨後正式發表。

永續發展
土地利用
國際新聞
控制疫情
羊駝
人口

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

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

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

OAuth + Security – 3 – JWT令牌_租車

※超省錢租車方案

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

PS:此文章為系列文章,建議從第一篇開始閱讀。

為什麼使用JWT令牌

在上面的資源服務器中,通過配置,我們了解到,當我們程序是前後端分離時,在拿着token去獲取資源時,程序會先去調用遠程認證服務器的端點去驗證解析token,這樣毫無疑問,當訪問量過大的時候,對認證服務器的壓力可想而知,所以為了解決上面的問題,我們採用JWT令牌格式,可以優化上面的問題。

令牌採用JWT格式即可解決上邊的問題,用戶認證通過會得到一個JWT令牌,JWT令牌中已經包括了用戶相關的信息,客戶端只需要攜帶JWT訪問資源服務,資源服務根據事先約定的算法自行完成令牌校驗,無需每次都請求認證服務完成授權。

改造認證服務器

  1. 修改TokenConfig類,如下:
@Configuration
public class TokenConfigure {

    private static final String SIGNING_KEY = "dimples";

    @Bean
    public TokenStore tokenStore() {
        return new JwtTokenStore(accessTokenConverter());
    }

    @Bean
    public JwtAccessTokenConverter accessTokenConverter() {
        JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
        //對稱秘鑰,資源服務器使用該秘鑰來驗證
        converter.setSigningKey(SIGNING_KEY);
        return converter;
    }


}
  1. 修改認證服務器的配置
private TokenStore tokenStore;

private ClientDetailsService clientDetailsService;

private JwtAccessTokenConverter jwtAccessTokenConverter;
//通過構造方法注入
...


/**
 * 令牌管理服務
 *
 * @return TokenServices
 */
@Bean
public AuthorizationServerTokenServices tokenServices() {
    DefaultTokenServices services = new DefaultTokenServices();
    // 客戶端詳情服務
    services.setClientDetailsService(clientDetailsService);
    // 支持令牌刷新
    services.setSupportRefreshToken(true);
    // 令牌存儲策略
    services.setTokenStore(tokenStore);
    
    // 配置令牌增強 JWT
    TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
    tokenEnhancerChain.setTokenEnhancers(Collections.singletonList(jwtAccessTokenConverter));
    services.setTokenEnhancer(tokenEnhancerChain);
    
    // 令牌默認有效期2小時(如果客戶端設置了會覆蓋該值)
    services.setAccessTokenValiditySeconds(7200);
    // 刷新令牌默認有效期2天
    services.setRefreshTokenValiditySeconds(259200);
    return services;
}
  1. 最後別忘了在pom中添加JWT的依賴,否則項目將會報錯
<dependency>
	<groupId>org.springframework.security</groupId>
	<artifactId>spring-security-jwt</artifactId>
	<version>1.1.0.RELEASE</version>
</dependency>

測試結果如下:

可以使用OAuth的/oauth/check_token端點來解析驗證一下該token

但是我們需要明白一點的是,這種令牌還是存儲在內存中的,後期我們如何將其存儲到redis中是我們研究的方向。

改造資源服務器

當我們使用了JWT令牌以後,由於在JWT令牌中我們存儲了相應的用戶信息和權限,這時我們可以直接在資源服務器中直接去解析對應令牌,就不用每次都去請求認證服務器端點,加大認證服務器的壓力,下面我們開始改造資源服務器:

  1. 將上面認證服務器中寫的TokenConfigure類拷貝一份到資源服務器
  2. 在資源服務器中屏蔽調之前的資源服務器令牌解析服務( tokenService() )
  3. 注入TokenConfigure類,然後配置到ResourceServerSecurityConfigurer里

完整的配置如下:

@Configuration
@EnableResourceServer
@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
public class DimplesResourceServerConfigurerAdapter extends ResourceServerConfigurerAdapter {

    public static final String RESOURCE_ID = "dimples";

    private TokenStore tokenStore;
    

    @Autowired
    public DimplesResourceServerConfigurerAdapter(TokenStore tokenStore) {
        this.tokenStore = tokenStore;
    }

    @Override
    public void configure(ResourceServerSecurityConfigurer resources) {
        resources.resourceId(RESOURCE_ID)
                .tokenServices(tokenService())
                .stateless(true);
    }

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                // 配置客戶端權限scope
                .antMatchers("/**").access("#oauth2.hasScope('all')")
                .and().csrf().disable()
                // 關閉session
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
    }

}

然後重啟服務,重新獲取令牌,然後訪問之前的測試接口:

待解決的問題

在此處的JWT的配置中,我們獲取的令牌信息還是存在內存中的,這樣不利於我們程序的擴展。那麼我們如何將生產的令牌去存儲到數據庫中或者存儲到redis中呢?請關注後續的文章。

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

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

使用非對稱加密

在上面的jwt加密中,我們的JWT簽名是寫死的字符串,可能我們的項目為了安全考慮,需要使用非對稱的加密,我們該怎麼配置呢?

首先獲取加密文件的私鑰和公鑰,需要先安裝安裝OpenSSL工具,參考鏈接【https://blog.csdn.net/qq_39081974/article/details/81059022】

  1. 生成JKS Java KeyStore文件

命令行執行:keytool -genkeypair -alias dimples -keyalg RSA -keypass dimples -keystore dimples.jks -storepass dimples

將生成一個名為medical.jks的文件,其中包含我們的密鑰 – 公鑰和私鑰。 還要確保keypass和storepass是一樣的

  1. 導出公鑰

keytool -list -rfc –keystore dimples.jks | openssl x509 -inform pem -pubkey

或 keytool -importkeystore -srckeystore dimples.jks -destkeystore dimples.jks -deststoretype pkcs12

將其複製到我們的資源服務器 src/main/resources/public.txt 中

  1. 配置認證服務器(TokenConfigure)
/**
 * 配置jwt生成token的轉換
 * 使用RSA Sign Key 進行加密
 *
 * @return JwtAccessTokenConverter
 */
@Bean
public JwtAccessTokenConverter jwtAccessTokenConverter() {
    KeyStoreKeyFactory keyStoreKeyFactory = new KeyStoreKeyFactory(new ClassPathResource("medical.jks"), "medical".toCharArray());
    JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
    converter.setKeyPair(keyStoreKeyFactory.getKeyPair("medical"));
    return converter;
}
  1. 配置資源服務器(TokenConfigure)
/**
 * 配置jwt生成token的轉換
 *
 * @return JwtAccessTokenConverter
 */
@Bean
public JwtAccessTokenConverter accessTokenConverter() {
    JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
    Resource resource = new ClassPathResource("public.txt");
    String publicKey;
    try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(resource.getInputStream()))) {
        publicKey = bufferedReader.lines().collect(Collectors.joining("\n"));
    } catch (final IOException e) {
        throw new RuntimeException(e);
    }
    converter.setSigningKey(publicKey);
    return converter;
}

擴展JWT的存儲信息

當我們使用如上的配置獲取Token后,將access_token中的內容複製到https://jwt.io/網站解析下:

可以看到在jwt中只是保存了我們的user_name,那麼我們怎麼去擴展呢?讓其可以保存我們需要的用戶詳細信息,這裡有兩種方案:

  • 實現TokenEnhancer(Token增強器)
public class JWTokenEnhancer implements TokenEnhancer {
    @Override
    public OAuth2AccessToken enhance(OAuth2AccessToken oAuth2AccessToken, OAuth2Authentication oAuth2Authentication) {
        Map<String, Object> info = new HashMap<>();
        info.put("other", "hello world");
        ((DefaultOAuth2AccessToken) oAuth2AccessToken).setAdditionalInformation(info);
        return oAuth2AccessToken;
    }
}

然後在TokenConfigure 中配置該Bean:

@Configuration
public class TokenConfigure {
    ......

    @Bean
    public TokenEnhancer tokenEnhancer() {
        return new JWTokenEnhancer();
    }
}

最後在認證服務器里配置該增強器:

@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

    @Autowired
    private TokenEnhancer tokenEnhancer;

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
        .....
        
        TokenEnhancerChain enhancerChain = new TokenEnhancerChain();
        List<TokenEnhancer> enhancers = new ArrayList<>();
        enhancers.add(tokenEnhancer);
        enhancers.add(jwtAccessTokenConverter);
        enhancerChain.setTokenEnhancers(enhancers);

        endpoints.tokenEnhancer(enhancerChain);
    }
    ......
}
  • 擴展username的內容

比如存入json數據內容作為username的內容。相比較而言,方案二比較簡單還不用破壞UserDetails的結構

@Override 
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
    //登錄賬號
    System.out.println("username="+username);
    //根據賬號去數據庫查詢...
    UserDto user = userDao.getUserByUsername(username);
    if(user == null){
        return null;
    }
    //查詢用戶權限
    List<String> permissions = userDao.findPermissionsByUserId(user.getId());
    String[] perarray = new String[permissions.size()];
    permissions.toArray(perarray);
    //創建userDetails
    //這裏將user轉為json,將整體user存入userDetails
    String principal = JSON.toJSONString(user);
    UserDetails userDetails = User.withUsername(principal).password(user.getPassword()).authorities(perarray).build();
    return userDetails;
}

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

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

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