【原創】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地圖已可更新顯示潭子電動車充電站設置地點!!

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

深入淺出Spring MVC_包裝設計

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

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

摘要

本文旨在詳細分析SpringMVC工作原理以及作為開發者如何基於SpringMVC做擴展。因為SpringMVC分析的文章比較多,所以本文重點講解如何利用SpringMVC的擴展點實現我們的需求。

什麼是Spring MVC

SpringMVC的作用是什麼呢?需要解決什麼問題呢?

下圖是一個客戶端與服務端的交互

在之前的詳解http報文(2)-web容器是如何解析http報文的一文中我也提到過。
這次再更細緻的分析一遍。一個請求如何中客戶端發到服務端,再從服務端返回內容。乾的這件事在web中叫請求動態內容,區別於靜態內容。在java語言中,為了解決這件事定義了一個規範就是servlet。具體的實現由各大廠商自己定義。

大體部分分為兩部分一塊是建立連接、一塊是傳輸內容。所以servlet規範包括兩大部分,,一部分是servlet接口,定義處理請求的規範。一部分是servlet容器的,去管理加載servlet實例。

輕量級的servlet容器有tomcat/jetty/undertow,servlet框架有SpringMVC/Struts/Webx這些,本篇重點講解SpringMVC

SpringMVC工作流程

Spring MVC 顧名思義就是處理Controll-Model-View的。

  1. DispatchServlet 是入口,doDispatch方法開始處理請求
  2. 首先經過controll,controll包含兩部分,一部分是url處理映射,將url與具體的處理bean映射起來。也就是HandleMapping,另一部分是具體的Handle,因為需要不同的handle,所以定義了HandleAdapter.
  3. Model比較簡單,主要就是ModelView對象,
  4. View 包含兩部分,一部分是ViewName的解析,另一部分是ViewName的對應的模板引擎,來渲染出最終的模板引擎。

常見擴展點

基於以上,Spring MVC 提供了不同層面的擴展,方便開發者實現定製化的功能,而不需要底層代碼的修改

一. Filter

Filter其實不算是SpringMVC,是servlet的,這時候請求還沒有到DispatchServlet。Filter允許對請求和響應做一些統一的定製化處理,比如你限流、日誌、trace。

實現javax.servlet.Filter接口即可

二. Controll – HandleMapping,HandlerAdapter

HandleMapping屬於Controll層面,我們可以編寫任意的HandlerMapping實現類,然後定義策略來決定一個web請求到HandlerExecutionChain對象的生成。

繼承RequestMappingHandlerMapping 類即可。
這個具體案例可以看下fredal的博客-使用基於 SpringMVC 的透明 RPC 開發微服務

簡要來說,他的rpc通信協議是基於http的。所以rpc調用就是基於服務端還是原來的restful api。寫法給普通的前端去掉無異,然後包一層rpc client。方便客戶端調用。但是這樣太麻煩了,對於不需要暴露給前端的API,單純是服務間的rpc調用。再走一遍servlet-SpringMVC沒必要。

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

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

所以他基於RequestMappingHandlerMapping做了一個改造。不再基於SpringMVC,而是自己定義了一套rpc的範式,然後轉換為springmvc。

三. Controll – Interceptor

Interceptor屬於Controll層面,我們可以自定義各種攔截器,在一個請求被真正處理之前、請求被處理但還沒輸出到響應中、請求已經被輸出到響應中之後這三個時間點去做任何我們想要做的事情。廣泛應用於Log,Session,鑒權等場景。

實現HandlerInterceptor接口即可

四. View – HandlerMethodArgumentResolver

解析方法參數的,可以很方便的擴展http請求參數。
實現HandlerMethodArgumentResolver接口即可

比如需要從http header中處理設備信息

@Component
public class DeviceResolver implements HandlerMethodArgumentResolver {
    @Override
    public boolean supportsParameter(final MethodParameter methodParameter) {
        return methodParameter.getParameterType().equals(DeviceInfo.class);
    }

    @Override
    public Object resolveArgument(final MethodParameter methodParameter,
            final ModelAndViewContainer modelAndViewContainer,
            final NativeWebRequest nativeWebRequest,
            final WebDataBinderFactory webDataBinderFactory) throws Exception {
        HttpServletRequest request =
                (HttpServletRequest)  nativeWebRequest.getNativeRequest(HttpServletRequest.class);

        // 從head頭中獲取設備信息
        String id = request.getHeader("x-device-id");
        if (id != null) {
            DeviceInfo deviceInfo = new DeviceInfo();
            deviceInfo.setId("id");
            return deviceInfo;
        }
        return null;
    }
}

五. View – Converter

類型轉換器,主要和序列化相關,參數綁定時springmvc會對將前端傳來的參數通過某種規則轉化成方法定義的參數的類型,默認實現的有StringHttpMessageConverterByteArrayHttpMessageConverter等等,默認的不能滿足需求時我們可自己定義此接口來實現自己的類型的轉換。

繼承AbstractHttpMessageConverter 即可。

六. View- HandlerExceptionResolver

異常處理,通常需要定義的全局異常。

@ControllerAdvice 註解即可
在一次和前端的相互甩鍋的問題記錄中有總結過這種

七. 修改requestbody 內容

當我們需要對RequestBody的內容進行統一處理時,因為HandlerMethodArgumentResolver只能處理特定類型的,做不到這點要求。

實現RequestBodyAdvice 接口即可。比如我需要處理requestbody中的內容,將emoji輸入轉換掉

@RestControllerAdvice
public class EmojiReplaceAdvice implements RequestBodyAdvice {
    @Override
    public boolean supports(final MethodParameter methodParameter, final Type targetType,
            final Class<? extends HttpMessageConverter<?>> converterType) {
        return methodParameter.hasParameterAnnotation(EmojiReplace.class);
    }

    @Override
    public Object handleEmptyBody(final Object body, final HttpInputMessage inputMessage,
            final MethodParameter parameter, final Type targetType,
            final Class<? extends HttpMessageConverter<?>> converterType) {
        return body;
    }

    @Override
    public HttpInputMessage beforeBodyRead(final HttpInputMessage inputMessage,
            final MethodParameter parameter,
            final Type targetType, final Class<? extends HttpMessageConverter<?>> converterType)
            throws IOException {
        return new HttpInputMessage() {
            @Override
            public InputStream getBody() throws IOException {
                final String content = IOUtils.toString(inputMessage.getBody());
                final String emojiUnicodeToAlias = StringUtil.parseEmojiUnicodeToAlias(content);
                return new ByteArrayInputStream(
                        emojiUnicodeToAlias.getBytes(StandardCharsets.UTF_8));
            }

            @Override
            public HttpHeaders getHeaders() {
                return inputMessage.getHeaders();
            }
        };
    }

    @Override
    public Object afterBodyRead(final Object body, final HttpInputMessage inputMessage,
            final MethodParameter parameter, final Type targetType,
            final Class<? extends HttpMessageConverter<?>> converterType) {
        return body;
    }
}

總結

這篇文章主要是系統的概括了SpringMVC的工作原理和各種擴展機制,屬於高度概括,細節不足。具體的每個擴展點的實現、坑、應用場景需要在之後的文章繼續闡述。

參考

https://fredal.xin/develop-with-transparent-rpc

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

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

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

一個 static 還能難得住我?_台中搬家

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

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

static 是我們日常生活中經常用到的關鍵字,也是 Java 中非常重要的一個關鍵字,static 可以修飾變量、方法、做靜態代碼塊、靜態導包等,下面我們就來具體聊一聊這個關鍵字,我們先從基礎開始,從基本用法入手,然後分析其原理、優化等。

初識 static 關鍵字

static 修飾變量

static 關鍵字表示的概念是 全局的、靜態的,用它修飾的變量被稱為靜態變量

public class TestStatic {
    
    static int i = 10; // 定義了一個靜態變量 i 
}

靜態變量也被稱為類變量,靜態變量是屬於這個類所有的。什麼意思呢?這其實就是說,static 關鍵字只能定義在類的 {} 中,而不能定義在任何方法中。

就算把方法中的 static 關鍵字去掉也是一樣的。

static 屬於類所有,由類來直接調用 static 修飾的變量,它不需要手動實例化類進行調用

public class TestStatic {

    static int i = 10;

    public static void main(String[] args) {
        System.out.println(TestStatic.i);
    }
}

這裏你需要理解幾個變量的概念

  • 定義在構造方法、代碼塊、方法的變量被稱為實例變量,實例變量的副本數量和實例的數量一樣。
  • 定義在方法、構造方法、代碼塊的變量被稱為局部變量;
  • 定義在方法參數的變量被稱為參數。

詳情參考

static 修飾方法

static 可以修飾方法,被 static 修飾的方法被稱為靜態方法,其實就是在一個方法定義中加上 static 關鍵字進行修飾,例如下面這樣

static void sayHello(){}

《Java 編程思想》在 P86 頁有一句經典的描述

static 方法就是沒有 this 的方法,在 static 內部不能調用非靜態方法,反過來是可以的。而且可以在沒有創建任何對象的前提下,僅僅通過類本身來調用 static 方法,這實際上是 static 方法的主要用途

其中有一句非常重要的話就是 static 方法就是沒有 this 的方法,也就是說,可以在不用創建對象的前提下就能夠訪問 static 方法,如何做到呢?看下面一段代碼

在上面的例子中,由於 staticMethod 是靜態方法,所以能夠使用 類名.變量名進行調用。

因此,如果說想在不創建對象的情況下調用某個方法,就可以將這個方法設置為 static。平常我們見的最多的 static 方法就是 main方 法,至於為什麼 main 方法必須是 static 的,現在應該很清楚了。因為程序在執行 main 方法的時候沒有創建任何對象,因此只有通過類名來訪問。

static 修飾方法的注意事項

  • 首先第一點就是最常用的,不用創建對象,直接類名.變量名 即可訪問;
  • static 修飾的方法內部不能調用非靜態方法;
  • 非靜態方法內部可以調用 static 靜態方法。

static 修飾代碼塊

static 關鍵字可以用來修飾代碼塊,代碼塊分為兩種,一種是使用 {} 代碼塊;一種是 static {} 靜態代碼塊。static 修飾的代碼塊被稱為靜態代碼塊。靜態代碼塊可以置於類中的任何地方,類中可以有多個 static 塊,在類初次被加載的時候,會按照 static 代碼塊的順序來執行,每個 static 修飾的代碼塊只能執行一次。我們會面會說一下代碼塊的加載順序。下面是靜態代碼塊的例子

static 代碼塊可以用來優化程序執行順序,是因為它的特性:只會在類加載的時候執行一次。

static 用作靜態內部類

內部類的使用場景比較少,但是內部類還有具有一些比較有用的。在了解靜態內部類前,我們先看一下內部類的分類

  • 普通內部類
  • 局部內部類
  • 靜態內部類
  • 匿名內部類

靜態內部類就是用 static 修飾的內部類,靜態內部類可以包含靜態成員,也可以包含非靜態成員,但是在非靜態內部類中不可以聲明靜態成員。

靜態內部類有許多作用,由於非靜態內部類的實例創建需要有外部類對象的引用,所以非靜態內部類對象的創建必須依託於外部類的實例;而靜態內部類的實例創建只需依託外部類;

並且由於非靜態內部類對象持有了外部類對象的引用,因此非靜態內部類可以訪問外部類的非靜態成員;而靜態內部類只能訪問外部類的靜態成員;

  • 內部類需要脫離外部類對象來創建實例
  • 避免內部類使用過程中出現內存溢出
public class ClassDemo {
  
    private int a = 10;
    private static int b = 20;

    static class StaticClass{
        public static int c = 30;
        public int d = 40;
      
        public static void print(){
            //下面代碼會報錯,靜態內部類不能訪問外部類實例成員
            //System.out.println(a);
     
            //靜態內部類只可以訪問外部類類成員
            System.out.println("b = "+b);
            
        }
      
        public void print01(){
            //靜態內部內所處的類中的方法,調用靜態內部類的實例方法,屬於外部類中調用靜態內部類的實例方法
            StaticClass sc = new StaticClass();
            sc.print();
        }   
    }
}

靜態導包

不知道你注意到這種現象沒有,比如你使用了 java.util 內的工具類時,你需要導入 java.util 包,才能使用其內部的工具類,如下

但是還有一種導包方式是使用靜態導包,靜態導入就是使用 import static 用來導入某個類或者某個包中的靜態方法或者靜態變量。

import static java.lang.Integer.*;

public class StaticTest {

    public static void main(String[] args) {
        System.out.println(MAX_VALUE);
        System.out.println(toHexString(111));
    }
}

static 進階知識

我們在了解了 static 關鍵字的用法之後,來看一下 static 深入的用法,也就是由淺入深,慢慢來,前戲要夠~

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

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

關於 static 的所屬類

static 所修飾的屬性和方法都屬於類的,不會屬於任何對象;它們的調用方式都是 類名.屬性名/方法名,而實例變量和局部變量都是屬於具體的對象實例。

static 修飾變量的存儲位置

首先,先來認識一下 JVM 的不同存儲區域。

  • 虛擬機棧 : Java 虛擬機棧是線程私有的數據區,Java 虛擬機棧的生命周期與線程相同,虛擬機棧也是局部變量的存儲位置。方法在執行過程中,會在虛擬機棧種創建一個 棧幀(stack frame)

  • 本地方法棧: 本地方法棧也是線程私有的數據區,本地方法棧存儲的區域主要是 Java 中使用 native 關鍵字修飾的方法所存儲的區域

  • 程序計數器:程序計數器也是線程私有的數據區,這部分區域用於存儲線程的指令地址,用於判斷線程的分支、循環、跳轉、異常、線程切換和恢復等功能,這些都通過程序計數器來完成。

  • 方法區:方法區是各個線程共享的內存區域,它用於存儲虛擬機加載的 類信息、常量、靜態變量、即時編譯器編譯后的代碼等數據,也就是說,static 修飾的變量存儲在方法區中

  • : 堆是線程共享的數據區,堆是 JVM 中最大的一塊存儲區域,所有的對象實例,包括實例變量都在堆上進行相應的分配。

static 變量的生命周期

static 變量的生命周期與類的生命周期相同,隨類的加載而創建,隨類的銷毀而銷毀;普通成員變量和其所屬的生命周期相同。

static 序列化

我們知道,序列化的目的就是為了 把 Java 對象轉換為字節序列。對象轉換為有序字節流,以便其能夠在網絡上傳輸或者保存在本地文件中。

聲明為 static 和 transient 類型的變量不能被序列化,因為 static 修飾的變量保存在方法區中,只有堆內存才會被序列化。而 transient 關鍵字的作用就是防止對象進行序列化操作。

類加載順序

我們前面提到了類加載順序這麼一個概念,static 修飾的變量和靜態代碼塊在使用前已經被初始化好了,類的初始化順序依次是

加載父類的靜態字段 -> 父類的靜態代碼塊 -> 子類靜態字段 -> 子類靜態代碼塊 -> 父類成員變量(非靜態字段)

-> 父類非靜態代碼塊 -> 父類構造器 -> 子類成員變量 -> 子類非靜態代碼塊 -> 子類構造器

static 經常用作日誌打印

我們在開發過程中,經常會使用 static 關鍵字作為日誌打印,下面這行代碼你應該經常看到

private static final Logger LOGGER = LogFactory.getLoggger(StaticTest.class);

然而把 static 和 final 去掉都可以打印日誌

private final Logger LOGGER = LogFactory.getLoggger(StaticTest.class);
private Logger LOGGER = LogFactory.getLoggger(StaticTest.class);

但是這種打印日誌的方式存在問題

對於每個 StaticTest 的實例化對象都會擁有一個 LOGGER,如果創建了1000個 StaticTest 對象,則會多出1000個Logger 對象,造成資源的浪費,因此通常會將 Logger 對象聲明為 static 變量,這樣一來,能夠減少對內存資源的佔用。

static 經常用作單例模式

由於單例模式指的就是對於不同的類來說,它的副本只有一個,因此 static 可以和單例模式完全匹配。

下面是一個經典的雙重校驗鎖實現單例模式的場景

public class Singleton {
  
    private static volatile Singleton singleton;
 
    private Singleton() {}
 
    public static Singleton getInstance() {
        if (singleton == null) {
            synchronized (Singleton.class) {
                if (singleton == null) {
                    singleton = new Singleton();
                }
            }
        }
        return singleton;
    }
}

來對上面代碼做一個簡單的描述

使用 static 保證 singleton 變量是靜態的,使用 volatile 保證 singleton 變量的可見性,使用私有構造器確保 Singleton 不能被 new 實例化。

使用 Singleton.getInstance() 獲取 singleton 對象,首先會進行判斷,如果 singleton 為空,會鎖住 Singletion 類對象,這裡有一些小夥伴們可能不知道為什麼需要兩次判斷,這裏來解釋下

如果線程 t1 執行到 singleton == null 后,判斷對象為 null,此時線程把執行權交給了 t2,t2 判斷對象為 null,鎖住 Singleton 類對象,進行下面的判斷和實例化過程。如果不進行第二次判斷的話,那麼 t1 在進行第一次判空后,也會進行實例化過程,此時仍然會創建多個對象。

類的構造器是否是 static 的

這個問題我相信大部分小夥伴都沒有考慮過,在 Java 編程思想中有這麼一句話 類的構造器雖然沒有用 static 修飾,但是實際上是 static 方法,但是並沒有給出實際的解釋,但是這個問題可以從下面幾個方面來回答

  • static 最簡單、最方便記憶的規則就是沒有 this 引用。而在類的構造器中,是有隱含的 this 綁定的,因為構造方法是和類綁定的,從這個角度來看,構造器不是靜態的。
  • 從類的方法這個角度來看,因為 類.方法名不需要新創建對象就能夠訪問,所以從這個角度來看,構造器也不是靜態的
  • 從 JVM 指令角度去看,我們來看一個例子
public class StaticTest {

    public StaticTest(){}

    public static void test(){

    }

    public static void main(String[] args) {
        StaticTest.test();
        StaticTest staticTest = new StaticTest();
    }
}

我們使用 javap -c 生成 StaticTest 的字節碼看一下

public class test.StaticTest {
  public test.StaticTest();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void test();
    Code:
       0: return

  public static void main(java.lang.String[]);
    Code:
       0: invokestatic  #2                  // Method test:()V
       3: new           #3                  // class test/StaticTest
       6: dup
       7: invokespecial #4                  // Method "<init>":()V
      10: astore_1
      11: return
}

我們發現,在調用 static 方法時是使用的 invokestatic 指令,new 對象調用的是 invokespecial 指令,而且在 JVM 規範中 https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-6.html#jvms-6.5.invokestatic 說到

從這個角度來講,invokestatic 指令是專門用來執行 static 方法的指令;invokespecial 是專門用來執行實例方法的指令;從這個角度來講,構造器也不是靜態的。

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

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

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

為真實事迹所感動,田沁鑫創作民族歌舞劇《扶貧路上》_網頁設計

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

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

文化和旅遊部2019年度全國現實題材及革命歷史題材舞台藝術重點項目,由田沁鑫擔任總編劇、總導演,印青擔任音樂總監,宋小明作詞的民族歌舞劇《扶貧路上》將於2020年10月登上北京舞台。《扶貧路上》以廣西百色市原樂業縣百坭村駐村第一書記黃文秀為原型,從不被信任,到成為村民交口稱讚的好書記,樂觀的她埋頭苦幹,帶領全村走出困境,年僅30歲犧牲在扶貧路上的真實故事改編。

《扶貧路上》 總編劇、總導演田沁鑫。

2018年7月8日,在文化和旅遊部藝術司演出管理處處長程鵬的帶領下,十餘位專家組成了《扶貧路上》採風團,深入百色7個縣(市、區)展開了為期7天的採風活動。同年11月,《扶貧路上》音樂創作團隊一行5人來到百色隆林縣,開展原生態音樂專項採風。隆林縣的民歌、民俗、民情這些豐富的素材為《扶貧路上》的音樂創作打下了基礎。

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

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

從2019年2月中旬開始,總編劇、總導演田沁鑫帶領十餘位藝術家組成的《扶貧路上》採風團隊,深入到百色凌雲縣進行調研、採風,與农民、扶貧幹部面對面談心。通過此次基層一線採風,創作團隊意識到文化幫扶是鄉村振興和精準扶貧的重要渠道。採風期間,編劇組在田沁鑫的帶領下,着手展開了《扶貧路上》劇本的大綱創作。其後四個多月,作曲組、編劇組、作詞組等認真學習國家扶貧政策,深刻認識工作在扶貧一線的黨員幹部的堅定和勇氣,歷經數次創作會議,完成《扶貧路上》的定稿劇本。

與此同時, 時年30歲的廣西百色市樂業縣百坭村第一書記黃文秀遭遇山洪不幸遇難。噩耗傳來,田沁鑫帶領部分主創成員第一時間奔赴廣西凌雲縣,在黃文秀書記的遇難地點實地考察採風,了解到黃文秀的生前事迹,深受感動,短短一年零兩月的任職時間,黃文秀記下三大本扶貧日記,田沁鑫被這位素不相識的女孩的事迹深深打動。

此次採風回來之後,《扶貧路上》主創團隊迅速調整、確定了全新的創作方向,以犧牲在扶貧第一線的廣西百色市樂業縣百坭村第一書記黃文秀的事迹為創作架構,還原她的事迹的形式,致敬280多萬奮戰在“扶貧路上”的駐村幹部、第一書記,以及犧牲在扶貧崗位上的770餘位一線幹部。田沁鑫認為,“創作故事首先要打動自己,創作過程也是被人民感動的過程,通過我們的誠意與致良知的表達來影響更多人。黃文秀這樣的黨員幹部值得謳歌、值得抒寫。戲劇舞台需要這樣的正能量。”

據悉,民族歌舞劇《扶貧路上》將於3月在廣西百色演出,7月、8月在廣西南寧演出,預計將於10月登上北京舞台。(記者 劉臻 編輯 吳龍珍 校對 劉軍)

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

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

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

“00后”唐卡追夢人:傳千年非遺 繪世間萬象_貨運

※回頭車貨運收費標準

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

坐在四川阿壩州阿壩縣“特果”唐卡藝術傳習基地二樓的畫室里,“00后”唐卡畫師更姐左手端碗,右手執筆,小心翼翼地在身前畫布上勾勒,一條綠色橄欖枝的輪廓逐漸顯現。

和嚴格按照《度量經》創作的唐卡不同,更姐用古拉·班智達唐卡畫派的傳統畫技繪製的,是一隻嘴含橄欖枝飛過藍色地球的白鴿。

“除了這幅象徵著世界和平的唐卡,下學期我還準備畫一幅行駛中的高鐵。”更姐將羊脂筆隨手插在耳畔,抱來了她和同學這學期期末考試作品。畫中有憨態可掬的大熊貓,手持青龍偃月刀的關公,跳鍋莊的少女,與氂牛為伴的牧民,甚至還有2019年上映的電影男主角。

作為藏族獨特的繪畫形式,唐卡有着上千年歷史,題材內容涉及歷史、政治、文化和社會生活等諸多領域,被稱為“藏文化百科全書”。

更姐介紹,她正在繪製的唐卡屬於藝術唐卡。學員們縮小了藝術唐卡的尺寸以便攜帶,並根據自己所見、所聞、所感豐富了題材,這些充滿現實主義、人文關懷的唐卡大受遊客歡迎。

索朗卓瑪2016年來到“特果”唐卡藝術傳習基地學藝。最初兩年,她臨摹了超過三千張佛像素描,才通過基礎考核。這位“00”后女孩認真地說,師傅特布戈18歲時已可以一筆在小本上畫完十八羅漢共二十三像的素描,自己還需要繼續苦練。

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

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

“不少唐卡需要半年甚至數年才能完成,畫唐卡是一種修行,需要耐得住寂寞。”索朗卓瑪計劃在畢業后回到家鄉若爾蓋縣唐克鎮,那裡以“九曲黃河第一彎”聞名中外,她要把九曲黃河一年四季不同的美景記錄在唐卡之上。

在阿壩縣“象雄”唐卡藝術學院,“00后”藏族青年澤花正在師兄的幫助下,在一塊石頭上繪製以“高原之舟”氂牛為主題的唐卡。澤花告訴記者,他曾多次去外地參加唐卡藝術研討會,年輕畫師們最常討論的,便是如何讓有千年歷史的唐卡在創新中得到傳承。

“唐卡的載體、內容都可以創新,每個畫派自己佛像的比例、造型不能任意改變。”澤花說,他和同學曾嘗試用中國傳統水墨畫、歐洲油畫的技巧繪製佛像背後的山水,但所有的創新都是建立在擁有精湛的唐卡技藝之上。

目前阿壩縣共有三個傳承唐卡的基地、學院,均對貧困家庭的農牧民子女免費開放。隨着拿起畫筆追夢唐卡的藏族青少年越來越多,古拉·班智達唐卡畫派第七代傳承人特布戈所創作的唐卡教材在2019年底已第八次再版。

“以前,唐卡各個畫派的技藝都不外傳,更別說唐卡教材了。”特布戈從書櫃中取出一本泛黃的《時裝繪畫入門》,是他30年前省下午飯錢購買的,是當時少有的繪圖教材。沒拜師之前,他每天都對照着臨摹,書上每一頁空白處都畫滿了素描。

在這位年過五旬的唐卡非遺傳承人看來,不少唐卡畫派曾因傳承方式的守舊而面臨失傳絕境,“00后”的加入為唐卡傳承帶來了新機遇。特布戈回憶,14歲時村裡來了一輛東方紅拖拉機,他把拖拉機畫在大門上,還被媽媽打了,因為當時大家不接受這種創新。“現在大家想畫什麼就畫什麼,千年唐卡迎來了它的‘黃金時代’。”(記者 賀劭清 安源)

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

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

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

十三陵水庫建設者將登大銀幕_網頁設計公司

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

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

本報電 (霍麒麟)近日,以北京十三陵水庫建設這一真實歷史事件為背景的電影《九蘭》,在北京昌平開機拍攝。影片將再現北京1958年40萬民眾160天建成十三陵水庫這一壯舉,展現上世紀50年代全民建設新中國的熱潮。

十三陵水庫修建時,9個名字都帶“蘭”字的年輕姑娘組成的“九蘭組”,成為新中國建設時期的傑出代表。電影《九蘭》以她們的事迹為原型,由三代人的文化和思想觀念的衝突,來呈現為祖國建設薪火相傳的無私奉獻精神以及新時期年輕建設者們如何不忘初心勇於奉獻的新風貌。

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

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

影片主創團隊走訪了“九蘭組”老人們,尋找到50多年前的大量珍貴影像資料。攝製團隊將用實景拍攝和影像相結合的製作方式,將“九蘭精神”呈現在大銀幕上。

該片由中國藝術節基金會影視藝術委員會監製,中共北京市昌平區委宣傳部、北京昌平區傳媒中心、北京華都新雨影視文化發展有限公司等聯合製作。

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

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

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

Apple 新專利打算造福身障者,只要用口腔內的運動就能操控 AirPods 耳機_網頁設計公司

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

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

AirPods 系列無線耳機這些年下來累積了許多使用者,有相當多的消費者十分喜歡這個聰明又輕巧的耳機產品,不過也有些人只能望而興嘆。因為 AirPods 耳機有不少需要雙手操作的地方。對於一些身障朋友來說並不方便。不過,近期外媒發現 Apple 的一項新專利有可能解決這個困擾。根據專利文件敘述,Apple 打算讓 AirPods 耳機多一種操控方式。就是用嘴:

▲AirPods 與 AirPods Pro 耳機俘虜了許多用戶的心,但對身障朋友來說多少有些不便。

Apple AirPods 耳機的操控方式通常是靠手勢。只要用手輕輕一碰,就可以對耳機或是播放軟體進行一些簡易的操控,減少大家從口袋中把手機拿出來的麻煩。不過就算是手勢,也對一部份手不方便的身障朋友來說相當不容易。或許這個新發現的專利,就是為了解決許多弱勢者的不便而生的功能。

用手不行,那麼用嘴試試

外媒 Patently Apple 發現 Apple 過去註冊的一項專利。該專利的美國專利編號為 US010873798 ,根據專利敘述,Apple 可能透過在 AirPods 耳機上嵌入額外的感測器,來偵測使用者的身體訊號,不論是手指的動作,甚至是牙齒與舌頭的敲擊,都可能被感測器收錄,並實際成為操控 AirPods 耳機的身體指令:

▲AirPods 與 AirPods Pro 通常的使用方式是針對耳機本體使用手勢,但新專利的影響下也許會轉變成對身體的某些部位進行手勢操作。

換句話說,若這項技術成熟並且實際用於產品上,只要一些手指的動作來控制 AirPods。更進一步的說,就連口腔中的牙齒、舌頭之間的碰觸,都能成為操控指令的一部份。比方說,用手指滑過臉頰可以選擇音量大小。點點額頭或身體其他地方。甚至咋一下舌,咬一下牙,都會成為某種操控指令:

▲在臉上滑過也能成為一種操控指令(圖片來源)

這些功能對手腳方便的人來說是個新奇的體驗,對於身體不夠方便的人來說,或許能成為輔助操控的技巧。唯一的問題大概就是 Apple 對這些「肢體語言」的掌控程度有多高。畢竟多加一個元件收集訊號理論上能做到,但是這些訊號是否穩定到足以使用,或者使用時如何避免誤用。都會是 Apple 研發產品時畢竟遇到的課題:

▲新專利看來很科幻,但未必是無法達成的幻想

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

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

不過,若 Apple 最終搞定了一切讓這項技術的產物正式登場,也許未來連一些智慧家居產品都可透過「肢體語言」來操控,這樣看來,也許這個專利的未來發展性十分不可限量也說不定。

消息來源:Digital Trends、Patently Apple

 

您也許會喜歡:

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

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

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

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

小米11 實機外觀、包裝盒、高清晰渲染圖曝光!_台中搬家公司

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

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

小米即將在 12 月 28 日晚間發表首款高通 Snadpdragon 888 處理器的旗艦 5G 手機,這次在小米11 正式發表前,除了日前在街上被拍到,近期也陸續有大量的實機外觀照片被揭露。同時,小米官方也開始在發表會之前展開新機的相關重點規格預告。除了小米11 這款備受期待的新旗艦手機,屆時也將推出一款更高階的路由器產品。

▲圖片來源:微博

小米11 實機外觀、包裝盒、高清晰渲染圖曝光!

幾天前,小米才正式預告將於 12 月 28 日 19:30 舉行小米11 新機發表會,而在這幾天網路上也有更多小米11 的相關消息。首先是外觀渲染圖部分,隨著疑似小米11 實機的曝光後,也有人製作了高清晰版本的渲染圖,可以發現小米11 的機身厚度也趨於輕薄,似乎呼應著這次小米11 「2021 輕裝上陣」的宣傳標語。

▲圖片來源:Twitter

除了主打的天藍色配色,也傳聞小米11 將推出深灰色、銀白色以及紫色:

▲圖片來源:Twitter

相比之前遠處拍攝到的小米11 實機,現在網路上也開始流傳著小米11 外觀的特寫照片,仔細看會發現這款紫色的小米11 機身背殼表面採用環保皮革材質。在螢幕特寫的規格參數,小米11 除了搭載高通 Snapdragon 888 處理器,預計配備 12GB LPDDR5 RAM 並運行 Android 11 作業系統。
相機規格方面,傳聞小米11 將配備三鏡頭主相機,分別為 1.08 億像素主鏡頭(傳聞為 Samsung ISOCELL HM2 感光元件)、 1300 萬像素、500 萬像素的鏡頭組合。小米11 預計採用雙電池設計,換算等效容量 4780mAh ,快充方面預計支持 50W~55W 的快速充電。

▲圖片來源:微博

由於上圖在螢幕頂部關鍵的前置鏡頭剛好被裁切掉,也有另名網友分享了疑似小米11 螢幕正面的照片,小米11 將採用四曲面螢幕並配置螢幕挖孔的自拍前相機。

▲圖片來源:微博

另一張曝光的小米11 機身外觀照,可以發現機身頂部設有多個揚聲器孔,因此推測小米11 可能不緊支持立體聲揚聲器,在外放音效表現也將比前代再次升級:

▲圖片來源:微博

稍早在數碼閒聊站微博也曝光了小米11 的包裝盒,從與 iPhone 12 包裝盒對比可以發現兩款包裝盒厚度差不多,也因此有傳聞指出小米11 可能也會取消附贈充電器。
不過依照過往的慣例,若最終小米決定在小米11 取消附贈充電器,可能也會在中國市場以優惠價格讓消費者加購,或同時因應新機推出發表大功率的充電器或無線快充充電器。

▲圖片來源:數碼閒聊站(微博)

(12/26 17:00 更新)小米也正式宣佈為響應科技環保的號召,小米11 包裝盒中將取消附贈充電器。

▲圖片來源:雷軍(微博)

在包裝盒上方也透露了小米11 更多的規格重點,其中也包括確定搭載 1.08 億像素的 AI 相機、支持 HDR10+ 的 Samsung Super AMOLED 螢幕,另外這次小米11 在音效部分與知名音響大廠 harman/kadon 合作的揚聲器:

▲圖片來源:雷軍(微博)

小米手機官方微博上傳小米11 將採用 harman/kardon 立體聲揚聲器的資訊:

▲圖片來源:小米手機(微博)

不過原本最初的文宣不是上圖寫著「手機中的 harman/kardon」的排版設計,而是「手機中的哈曼卡頓」。敏感的「卡頓」字樣也引起網友突發奇想,直接將其他字圖抹掉只保留「手機卡頓」,這也逼得小米官方不得不趕緊將圖片撤換掉。

▲圖片來源:小米手機(微博)

在小米手機官方微博該則貼文的編輯紀錄,可以看到貼文的圖片確實是經過替換的:

▲圖片來源:小米手機(微博)

也有眼尖的網友將之前小米官方 Twitter 在小米10T Pro 推出期間的貼文翻出來,當時小米也提到不會取消盒裝標配充電器:

▲圖片來源:Xiaomi(Twitter)

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

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

關於處理器也是小米11 最早確定的硬體規格,小米11 將是全球首款發表搭載 Qualcomm Snapdragon 888 5G 旗艦處理器的手機,從之前高通分享的工程機跑分數據安兔兔跑分平均能有約 73 萬分,屆時小米11 不排除將能帶來更高的分數。

▲圖片來源:小米手機(微博)

小米官方也公布搭載 Snapdragon 888 處理器的小米11 在 GeekBench 5 的性能跑分,多核跑分達到 3818 分、單核跑分也有 1135 分的表現:

▲圖片來源:雷軍(微博)

另外,小米11 也將是首發搭載 LPDDR5 滿血版的記憶體,而 WiFi 連接也將帶來首發 WiFi 6 增強版,網速高達 3.5Gbps :

▲圖片來源:小米手機(微博)

除了小米11 ,在 28 日晚間小米發表會也將首發新一代 WiFi6 增強版的高階路由器:

▲圖片來源:小米路由器(微博)

影像拍攝部分,小米11 這次預計在 AI 攝影演算調校方面下功夫,在夜間拍攝帶來更高品質的影像:

▲圖片來源:小米手機(微博)

小米11 的夜景模式不只能用於拍照,在錄影也能支持夜景模式,因此用戶即便在全黑的場景也能拍攝清晰、高品質的影片:

▲圖片來源:小米手機(微博)

小米官方已預告小米11 的螢幕可能是目前各款手機中成本最高的螢幕,傳聞小米11 將採用 6.67 吋 QHD+ 解析度的三星 AMOLED 四曲面螢幕,螢幕也將支持 120Hz 更新率。

▲圖片來源:小米手機(微博)

除了螢幕規格的升級,小米 11 在玻璃部分也將採用康寧最新大猩猩玻璃 Gorilla Glass Victus ,這款玻璃最早是在三星 Galaxy Note20 Ultra 搭載。Gorilla Glass Victus 在抗摔性提升 1.5倍、耐刮性能提升 2 倍。

▲圖片來源:小米手機(微博)

延伸閱讀:
OPPO Reno5 Pro+ 正式發表:搭載 S865 處理器、首發 5000 萬像素 SONY IMX766 感光元件相機、首款量產電致變色技術手機

MKBHD 公布 2020 年度智慧型手機獎 ,年度最佳手機獎落誰家?

您也許會喜歡:

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

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

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

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

Cyberpunk 2077 的諸多遊戲錯誤,導致 CD Projekt 遭到兩家律師事務所提起集體訴訟_網頁設計公司

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

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

許多人興沖沖的敲碗要 CD Projekt RED 盡快推出 Cyberpunk 2077,因為這款大作經過 CDPR 公司一延再延,使得許多玩家心急如焚。但就算它上市了,也出現許多 Bug 讓許多玩家憤而摔手把抗議。於是在廣大輿論壓力下,CDPR 公司總算是宣布要讓購買該遊戲的玩家退款。並承諾會為該遊戲釋出更新修補這些 Bug。不過。退款顯然還不能杜悠悠之口。在洛杉磯的律師事務所 The Schall 與位於紐約的律師事務所 Rosen 分別提出集體訴訟,要讓 CDPR 賠償玩家與投資者的損失:

▲Cyberpunk 2077 因為數量多如牛毛的 Bug 引發一些玩家怒火,憤而提起訴訟(圖片來源)

因為遊戲做得太糟糕而被告算是蠻常見的,隔壁棚的 EA 就帶給我們不少先例。通常會告得起來的訴訟通常都是知名度較高的遊戲專屬,若今天 Cyberpunk 2077 不是個聞名全球的 3A 大作,或許被玩家謾罵甚至告到法院上的機會也就小得多。

不管怎麼說,這次 Cyberpunk 2077 的 Bug 之多確實引起了玩家的怒火。洛杉磯的 The Schall 律師事務所就表示,該公司違反了 1934 年頒佈的《證券交易法》,根據訴訟內容,目前主要的原因仍出自於遊戲大量的 Bug 影響遊戲體驗,這些問題甚至誤導了投資人的期待,因此才引發這些訴訟:

▲Cyberpunk 2077 世界觀宏大,畫面呈現相當精美。若沒有這些 Bug ,或許還能讓 CD Projekt 增加不少獲利

因為 Bug 而惹來的官司

Cyberpunk 2077 目前在各大平台均有提供退款的服務。不過即便提供退款,仍難阻擋諸多玩家受到 Bug 影響的負面情緒。這些輿論壓力導致了目前仍有許多玩家給予遊戲負面評價,並在網路上指責開發公司並未善盡管理責任,讓遊戲中的問題進一步減少。這些批評加劇了 CD Projekt 的負面形象,以致於惹來官司纏身:

▲因為 Bug 惹來官司的遊戲公司不少,但最近最受關注的大概就只有 Cyberpunk 2077。

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

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

雖然不知道訴訟的結果如何,但對 CD Projekt 來說,這個年底顯然不會太好過。一方面來自 Xbox 與 Playstation 平台的退款潮多少造成財務上的損失,一方面則是訴訟可能影響到公司的營運。在度過這些困境之前,想必這家來自波蘭的遊戲公司需要一些時間來處理。

消息來源

您也許會喜歡:

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

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

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

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

經過了四年,微軟至今依舊提供 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設計建置、專業網路行銷。