學者:再生能源是貧窮國家度過疫病大流行和氣候危機的利器_包裝設計

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

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

環境資訊中心綜合外電;姜唯 編譯;林大利 審校

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

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

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

國外多位用戶反應 Pixel 4a 5G 升級 12 月更新之後,出現螢幕觸控的問題_網頁設計公司

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

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

Pixel 手機 12 月更新加入很多新功能,特別是 Pixel 5 不少特色都下放,也因此基本上只要是能升級的人,一定都會更新上去。不過,對於習慣使用底部導航按鈕的 Pixel 4a 5G 用戶來說,或許等等會更好,最近不少 Pixel 4a 5G 戶反應出現螢幕觸控反應不靈敏的問題,而且連 Google 官方都確認有這 Bug,目前還尚未改善。

Pixel 4a 5G 升級 12 月更新之後,出現螢幕觸控的問題

近期在國外 Google 官方論壇、Google Issue Tracker 與 XDA 開發者論壇上,都有用戶反應升級 12 月更新之後,螢幕的觸控有 Bug,主要集中在下方,特別是有開啟底部導航按鈕的人會明顯感受到。

根據這位用戶說明,他一開始使用約兩週 Pixel 4a 5G 時,一切都非常正常,而升級到 12 月版本之後,底部的螢幕觸控按鈕反應變得很差,有時候按完全沒反應,已經嘗試過恢復出廠設置與啟用 / 不啟用觸控靈敏度都一樣:

而最近 Google 也公布 1 月更新內容,但沒有提到任何關於修復螢幕觸控的內容,他嘗試更新以後也確定沒改善,Bug 依舊存在。

詳細可以參考下方影片,左下方返回按鈕靠近邊緣處有時候按會沒反應,中間的話就沒問題:

 

一位官方人員也在貼文下方回覆,表示他們已經知道這問題,未來將透過新更新來修復,目前可以透過以下方法來提升反應速度:

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

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

  • 點擊螢幕邊緣的觸控按鈕時,請點擊中心點或邊緣的另一側。
  • 點擊觸控按鈕時,請改用手指或拇指的最尖處,這將有助於改善觸控辨識。

如果你沒有開啟底部按鈕,大多都是用手勢操作的話,那就不用太在意這 Bug,基本上應該不影響。

話說回來,既然官方 12 月底就回覆知道這 Bug,1 月更新竟然還沒加入修復內容,也讓人奇怪,或許是問題沒那麼好解決吧。無論如何,至少之後確定會修復就是了。

資料來源:Android Police

Google Pixel 4a 5G 開箱實測,擁有旗艦級的拍照能力,加上甜到令人蛀牙的價格,帶你體驗 5G 高速世界

您也許會喜歡:

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

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

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

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

msi 電競筆電全面升級,最新 Tiamat 強勢降臨_網頁設計公司

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

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

這回 msi 在 CES 2021 舉辦的發表會光是特效就非常驚人,適逢 msi 的 35 周年之際,整個高規格、大製作、大工程的鋪墊下,就是為了迎接本次全電競筆電陣容的更新與最新「眾神之母 Tiamat」的強勢降臨,接下來就一起看看到底這回端出哪些好菜來以饗玩家。

msi 電競筆電全面升級,最新 Tiamat 強勢降臨

整個發表會中,一開場就直接宣布 2021 年率先將旗下 GE、GS、GP、GF 系列電競筆電升級搭載甫發表的最新一代 Nvidia GeForce RTX 30 系列獨立顯卡,就由新世代顯示卡與筆電其他硬體、軟體調校完美搭配,能將系統效能完整釋放,為玩家帶來如同電影場景般的極致沉浸遊戲體驗。

GE76 Raider 系列與 GE76 Raider Dragon Edition Tiamat
在 GE76 Raider Dragon Edition Tiamat 的外殼上刻畫了象徵無窮力量的古老神獸。GE 系列採用炫彩華麗 Mystic Light 設計,最高搭載最新 Nvidia GeForce RTX 3080 獨立顯卡與第 11 代 Intel Core i9 處理器,採用最新Wi-Fi 6E 打造超高速連線速度。為確保筆電能在極致遊戲中依然維持穩定,GE 系列採用 Cooler Boost 5 散熱模組,強大雙風扇搭配 6 組熱導管,能帶來更多的氣流量以有效使筆電冷卻。

GS66 Stealth
GS66 Stealth 採用磨砂黑低調質感設計,為內心隱藏著熱血遊戲魂的商務人士提供了最完美的保護色,不論任何情境你都可以毫無違和感的隱身其中。現在,GS66 Stealth 領先升級搭載最新 GeForce RTX 30 系列獨立顯示卡, DLSS2.0將 AI 人工智慧技術運用在 GPU 的影像處理,能提供極致順暢的 4k 超高解析度畫面、即時光線追蹤以及 60FPS 以上近乎真實的遊戲畫面呈現。GS66 Stealth也將最新第 11 代 Intel 高達 8 核心處理器的高運算能力發揮到極致,提供更佳的遊戲效能表現。

GP66 / GP76 Leopard
全新 GP66 / GP76 Leopard 電競筆電,專為工程師繁複的程式工作打造,全新的外型設計更具低調質感,GP Leopard 系列展現比以往更加強大的效能。GP66 、 GP76 Leopard 最高搭載 GeForce RTX 3080 獨立顯卡,以及最新第 11 代 Intel Core  i7-10870H 處理器,展現極致的 8 核心運算處理能力。此外,全新配置的 I/O 連接埠能支援各種類型的資料傳輸,同時亦支援最高 8K 的顯示輸出,能在大尺寸螢幕上完整呈現細緻的畫面,是複雜的工程與設計專案工作的絕佳配備。

GF75 / 65 Thin系列
對於熱愛遊戲的玩家來說,纖薄設計的 GF75 / GF65 Thin 絕對是多數人推薦的遊戲配備首選。GF Thin 系列搭載最高第 11 代 Intel Core i7-10750H 處理器與 GeForce RTX 30 系列獨立顯示卡,最高 144Hz 更新率的 IPS 等級窄邊框面板設計,提供前所未有的速度感和視覺清晰度。

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

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

Stealth 15M
發表會的另一個亮點是 msi 推出的這款世界最輕巧纖薄的 15 吋電競筆電 – Stealth 15M。源自於都會風格的靈感,Stealth 15M 重量僅 1.7kg,機身只有 16.15mm,纖薄機身中卻蘊藏著不妥協的效能。Stealth 15M 是全球首款搭載第 11代 Intel H 系列處理器的電競筆電,最大渦輪頻率 5GHz 頻率 。Stealth 15M 同時升級搭載 GeForce RTX 30 系列獨立顯卡,讓遊戲玩家能暢玩遊戲大作,也讓年輕的商務人士能輕鬆完成日常工作。

Creator 15
最後,msi 也率先為創意工作者量身打造絕佳的創作平台。Creator 15 是一款全能型的筆記型電腦,True Pixel 顯示技術包括 4K UHD 超高畫質解析度的面板,透過 True Color 校正技術調校出更精準的色彩,支援 100% AdobeRGB 廣色域提供更完整範圍顏色呈現,同時,True Pixel 技術也經過 CalMAN 專業色彩認證,提供最準確且真實的視覺呈現。透過最新的 GeForce RTX 30 系列獨立顯卡,能加快影片與 3D 動畫的渲染時間。此外,Creator 15 亦推出可觸控 FHD 面板的規格選擇,可多指觸控的面板讓您更輕鬆、更高效率地揮灑創意。透過螢幕更快速的滑動、縮放畫面,更加直覺性的的操作。99.9Whr 大容量電池能提供長時間的續航力,你只需要專注在創意工作,沒有後顧之憂。

MSI全新系列筆電 強勢登場 限時預購登錄送

本次發表會新品於 1/14 – 1/25 開放搶先預購,第一波將提供多達 11 款規格供消費者選擇,於 msi 官方商城、PChome 24h 購物、momo 購物網預購搭載 GeForce RTX 30 系列獨立顯卡之 msi 電競筆電,上網登錄即可獲得「城市襲擊者電競後背包」( 市價NT$3,899 ) 乙個,數量有限,兌換完畢為止。
【活動詳情,點這裡】

您也許會喜歡:

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

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

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

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

ASUS ZenBook、VivoBook、Chromebook、ExpertBook多款筆電亮相,ProArt 外接螢幕延伸你的工作台_網頁設計

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

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

除了專為遊戲玩家們打造的 ROG 新品,這回 Asus 本家品牌的筆電們也一口氣多機型傾巢而出,其中包含甫於去年推出的雙螢幕筆電在今年也有新品推出,還有各式輕薄筆電與為專業工作打造的 ProArt 產品,都對過去的自己有所突破,看起來 Asus  2021 年新品項將會相當精彩。

ASUS ZenBook、VivoBook 、Chromebook、ExpertBook多款筆電亮相,ProArt 外接螢幕延伸你的工作台

Asus ZenBook Pro Duo 15 OLED / Pro Duo 14
在今年新的 Pro Duo 雙螢幕系列兩款產品的更新,最顯著的就是招牌雙螢幕為了能夠讓使用時更順手,將位於鍵盤上方的副螢幕設計改為下方採用極輕薄短小的轉軸來幫助螢幕的活動,當你掀開筆電時自動抬起 7 – 9.5 度的結構,讓主螢幕與副螢幕、鍵盤之間呈現 147 度角,視覺上有如一體,清晰無死角,下方所預留的空間也讓散熱通道更流暢。

Pro Duo 15 OLED 配備雙 4K 顯示器,OLED 主螢幕可支援 HDR,色域覆蓋 DCI-P3 100%。配備 Intel Core i9  8 核心處理器、最新 Nvidia GrForce RTX 顯卡,記憶體與儲存容量最大可達 32GB DDR4 與 1TB PCIe 3.0 SSD。在機身上配置有 2 個 Thunderbolt 連接埠可支援 2 個外接 4K 顯示器,且支援高速 Wi-Fi 6 無線網路連接,另外還配有 1 個最新的 HDMI 2.1 連接埠。至於小老弟 Pro Duo 14,擁有 14 吋 FHD 觸控螢幕,色域可覆蓋 100% sRGB,搭載第 11 代 Intel Core i7 處理器,內部配置 MX450 / Iris Xe 顯卡。Duo 系列兩款新品皆配備有 70Wh 電池,可提供最長達 17 小時的續航力。

Asus VivoBook S14 
以輕薄隨身行動力為主打的 VivoBook 系列這回也端出新品,以更輕、更小、更纖薄的體型將占比達 90% 的四面窄邊框 14 吋顯示器放入其中,重量僅有 1.3 Kg。搭載第 11 代 Intel Core 處理器與 Iris Xe 顯卡,通過最新 Intel Evo 認證, 最長續航可達 17 小時,支援 Thunderbolt 4 與 Wi-Fi 6 高速有線與無線連接。

Chromebook Flip CX5
如果你對 Chromebook 的印象還停留在最早為預算有限者或是學生、教育用途而設,那你可得更新一下了。由於 Chrome OS 的高自由度與 Google Play Store 中的大量資源,成為越來越多人的選擇之一。這次新推出 Flip CX5 就是一款專為消費者市場打造的產品。外型輕薄簡約,ErgoLift 轉軸可供其 15.6 吋、81% 佔比的三邊窄邊框螢幕  360 度翻轉。

在硬體配備方面,Flip CX5 最高可配第 11 代 Intel Core i7 處理器、Intel Iris Xe 顯卡、16GB記憶體與 512GB SSD,最長續航力可達到 12 小時。機身上設置有 2 個 USB-C 3.2 Gen 2 可支援快速充電, HDMI 2.0 連接埠則可以供你外接一部 4K 60Hz 顯示器。這款 Chromebook 通過美國軍規 MIL-STD 810H 認證,對於較為嚴峻的環境具有相當大的抵抗力。

ExpertBook B9400CEAV
號稱全球最輕 14 吋商務筆電的 ExpertBook B9400CEAV ,從專設的鏡頭蓋與軟硬體等方面對安全性的強化就能看出這款機型專為差旅人士所設計,擁有非常輕薄的外型,鎂合金外殼經過多道工藝精雕細琢,重量僅有 880g 至 1kg 左右 ,但卻是通過美國軍規 MIL-STD 810H 的認證的硬朗身骨,轉軸的開闔耐用度更比普通比電高出 150%。在 13 吋的機身上配備 14 吋 FHD 顯示器,極窄邊框設計讓它的螢幕佔比來到 94%,並且可覆蓋 100% sRGB 色域。

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

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

這款筆電配備第 11 代 Intel Core 處理器、32GB 記憶體與最高 2TB 儲存容量,如果你有重度的資料儲存需求,內部的雙儲存設能幫助你將它升級至最高 4TB。ExpertBook B9400CEAV 通過 Intel 最新的 Evo 認證,擁有一秒喚醒、長續航、快充、快速回饋、高速連接等多方面能力。在電池配置上有兩種規格,33Whr 機種最長續航可達 9.5 小時,66Whr 機種最長續航可達 20.7 小時。

ProArt Display PA148CTV
這款專為多螢幕使用而設計的 14 吋 IPS 觸控型螢幕重量只有 740g,可支援 10 點觸控,並且覆蓋 100% sRGB 色域,在機身上配置了豐富的連接埠以適配於這種外接需求。機身後方配置了可調整 15 度至 75 度的腳架,讓用戶以最舒適、順手的方式調節使用。用戶可以自訂軟體熱鍵與面板樣貌進行快速切換控制,作為主螢幕延伸出去的另一個工作台。

機身後方配置了一個 Asus Dial 轉輪,支援 Adobe、Microsoft 等軟體的快捷鍵的使用,還能自行定義它的每一個動作按鈕,快速旋轉選擇與呼叫,讓工作流程更簡易流暢。

您也許會喜歡:

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

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

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

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

msi 2021 零組件、螢幕、周邊大有看頭,電競、創作及高階商務新品登場_貨運

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

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

筆電之外,msi 這次在 CES 2021 的「Tech For The Future」線上發表會中還展示了自家全系列最新零組件與螢幕等產品,涵蓋電競、創作者與高階商務需求,將無論娛樂或工作所需全面升級,將你的設備與系統等生產力工具推升到進階的全新境界。

msi 2021 零組件、螢幕、周邊大有看頭,電競、創作及高階商務新品登場

msi Sea Hawk 
這款顯卡是經過全方面科技驗證的革命性產品,搭載最新 GeForce RTX 30 系列晶片,效能更加強悍,結合空冷和水冷的優勢,加上專用風扇的冷卻和效率,配備寂靜且無需維護的多合一封閉式水冷套件,有效解決惱人的散熱問題。

msi Suprim
這是一脈新的顯卡系列,實現了玩家夢寐以求的渴望。搭載 TRI FROZR 2S 三風扇散熱系統,強化冷卻,確保效能強悍及堅固耐用,不僅兼顧現代美學,也符合時下玩家追求效率的生活方式,完美詮釋逼真電競和數位創作方面的終極目標。

MEG Z590 GODLIKE 主機板
旗艦主機板 MEG Z590 GODLIKE 是為重新定義極限電競主機板而生,為業界樹立新的標竿。GODLIKE 的精神在勇於創新並打破常規,如第一代 GODLIKE 是首款搭載 RGB 燈光的主機板,進而帶動電競行業應用 RGB 的潮流。如今,最新的 MEG Z590 GODLIKE主機板採用頂尖規格、創新功能和增強玩家體驗,MEG Z590 GODLIKE 將在市面上的電競主機板脫穎而出。

MPG CORELIQUID K360 水冷套件
MPG CORELIQUID K360 是一款冷卻效能強大兼俱外觀令人驚艷的水冷套件。搭配 msi 獨有的 TORX FAN 4.0 風扇產生強勁氣流給散熱器,達成快速冷卻的效果。此外,將 60mm 的 TORX FAN 3.0 風扇建置在水冷頭內,可以強化冷卻並解決電源配置的難題;MPG CORELIQUID K360 水冷套件在水冷頭上還加載一片 2.4 吋的 LCD,能夠顯示重要信息和自訂圖案,如:系統的硬體效能信息、照片和時鐘。

最後,msi 將重寫電競 SSD 的定義,這些即將推出的 SSD 能提供高達 4TB 的存儲容量,高達 7000MB/s 的讀取速度和 6900MB/s 的寫入速度。平均使用長達 160 萬小時才有可能發生故障,並提供端點到端點的路徑保護,進而保存重要數據。

螢幕、電腦系統與周邊系列

msi Creator P50 桌機
體現專業及風格美學的創作者系列桌機,5L 小體積卻蘊含高效能,搭載第 11 代 Intel Core i9 處理器加上最新顯卡,高速 Thunderbolt 4 支援 10GbE 極速網路傳輸,呈現超流暢的創作體驗。

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

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

MPG ARTYMIS系列螢幕
採用最適合人眼視覺的 1000R 曲率,也因為完全符合人眼視覺的曲率,所以在使用螢幕時眼睛不會感到疲勞。曲面設計可以增進覆蓋感和沈浸感,不會受到外界環境的干擾,進而大幅提升電競體驗。除了 1000R 曲率設計,MPG ARTYMIS 系列螢幕還導入專屬的 AI 功能。

MODERN MD 系列商用螢幕
Modern MD271 與 MD241 系列採用德國萊茵 TÜV 認證的 msi 防閃爍、減藍光設計,以減輕對眼睛的負擔與傷害。還有符合人體工學的上下傾斜角度以及高低調整功能,達到舒適的觀看體驗。內建 Type-C 方便連接其它裝置及充電,另有免工具支援 VESA 壁掛安裝或拆卸。

Summit 241
專為精英設計的一體成型電腦,是首款可轉換螢幕方向的一體成型電腦。內建智慧型感測器,可偵測距離、人體移動、到光源等周遭環境的變化,除此之外,還能自動調整亮度及其它螢幕設定,擁有愜意的視覺體驗。

Clutch GM41 Lightweight 電競滑鼠
在結構設計上極盡輕巧,玩家操控更靈敏。高端光學傳感器提供高達16000 DPI的快速和精確的定位感應,配備專門訂製的MSI FriXionFree線纜,確保玩家在滑鼠墊或桌上使用幾乎感受不到任何阻力。

您也許會喜歡:

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

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

※回頭車貨運收費標準

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

帶你走入虛擬社交新世界:XRSPACE MANOVA 開箱_包裝設計

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

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

為大家介紹全新 VR 虛擬社交平台 XRSPACE MANOVA 開箱,相信很多人都看過前年的電影「一級玩家」,電影中的世界除了描繪了 VR 遊戲的各種可能性以外,其實還有一個很大的重點就是社群,其實VR設備如 HTC VIVE或 OCULUS之類的產品早就已經發表很久了,在應用與遊戲方面的內容也越來越多,但是卻一直沒有「社群」的概念,大家每天戴上 VR 設備如果只是玩遊戲的話,其實很容易膩。也缺乏互動的感覺,而在疫情肆虐的當下,其實很多人與人的交流都被迫中斷;尤其是與國外友人、同事遠距離或跨國的交流也越來越困難,傳統的視訊通話也不一定能完全滿足人們在社交、工作、商務等各方面的需求,此時 VR 就是一個蠻不錯的選擇,不管對方在天涯海角,都能在同一個虛擬空間中一同交流互動。

XRSPACE MANOVA 開箱

開箱,最外層先提醒要安裝 XRSPACE APP(支援 iPhone 與 Android),裡面放置了 XRSPACE MANOVA 攜行盒:

XRSPACE MANOVA 攜行盒體積不小,而且設計的相當有質感,也方便使用者隨身攜帶:

所有配件包括了 XRSPACE MANOVA HMD、手把、電池、說明書、USB 連接線、旅充與手帶:

硬體部分 XRSPACE MANOVA 搭載 Qualcomm Snapdragon 845處理器、6GB RAM、64GB ROM,支援 802.11 a/b/g/n/ac,也有 5G 高速聯網版本,在正前方配置了三顆鏡頭,分別為支援 6DoF 定位與手勢追蹤的兩顆 MONO 鏡頭,與一顆用於掃描空間的 RGB 鏡頭,鏡頭 FOV 分別為水平 127.2度、垂直79.5度,為了追蹤手勢命令前方鏡頭面板稍微向下:

上方則配置充電用的 TYPE-C 連接埠、散熱孔與實體按鍵,上方頭帶長度可自由調整,由於設計得當,470公克的重量戴起來並不會感到吃力:

實體按鍵部分配置有電源鍵、確認鍵與音量鍵:

下方則是有一組 3.5mm的耳機孔,XRSPACE MANOVA 內建擴音喇叭,但如果想要更好的沉浸在影音世界中可以連接自己的耳機搭配使用:

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

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

在鏡頭部分,則採用了1440×1440(單眼)超高解析度顯示器及90Hz螢幕更新率鏡頭,解析度為 702DPI,四周採用親膚棉打造,而且配戴眼鏡的朋友也可以無壓力直接戴著使用:

XRSPACE MANOVA 是一款標準的「VR 一體機」,所以不需要連接電腦、也沒有線材,直接就能使用,除了使用控制器操控以外,也可以透過手勢直接使用:

講了這麼多,相信大家可能沒法理解 XRSPACE MANOVA 所帶來的虛擬體驗吧?的確如果只有圖文真的無法詳細說明,所以詳細功能與介紹阿達也拍了影片作介紹,大家直接看影片就會瞭解 XRSPACE 想要打造的 VR 虛擬社交平台是長怎樣與如何運作,另外如果想親身體驗 XRSPACE的魅力,強力建議大家去中華電信門市體驗看看,也有租賃方案一週才350元,相當便宜,覺得喜歡再買也不遲:

 

XRSPACE MANOVA 銷售管道(電腦王阿達讀者九折折扣代碼:KOCPC) 

中華電信購買

中華電信租賃方案(七天只要350元)

 

結語

老實說我個人覺得 XRSPACE MANOVA 是一款相當有想法的 VR 一體機設備,它的最終目標就是想要打造一個與全世界連結在一起的虛擬 VR 社交平台,阿達在體驗的過程中也遇到幾個外國人來打招呼聊天,是相當有趣的經驗。不過目前台灣使用人數還不算多,外國人大都出現在晚上,XRSPACE 的概念就是要越多人玩越好玩,我也建議官方除了社群互動以外,也可以加入更多的影音服務,如Netflix(超大螢幕看起來會超爽)、YouTube 360 頻道等等,這樣會更有趣,強力建議大家可以先去中華電信門市體驗看看,如果想試試可租回家玩一週也只要350元,覺得好玩再帶回家!

您也許會喜歡:

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

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

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

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

學Linux驅動: 應該先了解驅動模型_網頁設計公司

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

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

[導讀] Linux設備林林總總,嵌入式開發一個繞不開的話題就是設備驅動開發,在做具體設備驅動開發之前,有必要對Linux設驅動模型有一個相對清晰的認識,將會幫助驅動開發,明白具體驅動接口操作符相應都做些什麼。

個人對於驅動模型的理解概括起來就是一句話:利用面向對象編程思想,實現設備分層管理軟件體繫結構

注:代碼分析基於linux-5.4.31

為啥要驅動模型

隨着系統結構演化越來越複雜,Linux內核對設備描述衍生出一般性的抽象描述,形成一個分層體繫結構,從而引入了設備驅動模型。這樣描述還是不夠讓人理解,來看一下這些需求就好理解些:

  • Linux內核可以在各種體繫結構和硬件平台上運行,因此需要最大限度地提高代碼在平台之間的可重用性。
  • 分層實現也實現了軟件工程的高內聚-低耦合的設計思想。低耦合體現在對外提供統一的抽象訪問接口,高內聚將相關度緊密的集中抽象實現。
  • Linux內核驅動程序模型是先前在內核中使用的所有不同驅動程序模型的統一。 它旨在通過將一組數據和操作整合到全局可訪問的數據結構中,來擴展基於基礎總線來橋接設備驅動程序。

傳統的驅動模型為它們所控制的設備實現了某種類似於樹的結構(有時只是一個列表)。不同類型的總線之間沒有任何一致性。

驅動模型抽象了啥

當前驅動程序模型為描述總線和總線下可能出現的設備提供了一個通用的、統一的模型。統一總線模型包括一組所有總線都具有的公共屬性和一組公共回調,如總線探測期間的設備發現、總線關閉、總線電源管理等。

通用的設備和橋接接口反映了現代計算機的目標:即執行無縫設備“即插即用”,電源管理和熱插拔的能力。 特別是,英特爾和微軟規定的模型(即ACPI)可確保與x86兼容的系統上幾乎任何總線上的幾乎所有設備都可以在此範式下工作。 當然,雖然大多數總線都支持其中大多數操作,但並不是每條總線都能夠支持所有此類操作。

那麼哪些通用需求被抽象出來了呢?

  • 電源系統和系統關機,對於電源管理與系統關機對於設備相關的操作進行抽象實現。關機為什麼要被抽象出來管理,比如設備操作正在進行此時系統收到關機指令,那麼在設備模型層就會遍歷系統設備硬件,確保系統正確關機。

  • 用戶空間訪問:sysfs虛擬文件系統實現與設備模型對外的訪問抽象,這也是為什麼說Linux 設備也是文件的由來。實際從軟件架構層面看,這其實是一個軟件橋接模塊,抽象出統一用戶訪問接口,橋接了設備驅動。

  • 熱插拔管理:熱插拔管理機制定義統一的抽象接口操作符kset_hotplug_ops,不同設備利用操作符實現差異化。

  • 設備類型:設備分類機制,從高層級抽象描述設備類型,具體可以在sysfs下面體現。

用戶空間訪問

由於具有系統中所有設備的完整分層視圖,因此將完整的分層視圖導出到用戶空間變得相對容易。 這是通過實現名為sysfs虛擬文件系統來完成的。

sysfs的自動掛載通常是通過/etc/fstab文件中的以下條目來完成的:

none   /sys	sysfs  defaults	 0 0

對於Debian系統而言,可能在/lib/init/fstab採用下面的形式掛載:

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

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

none  /sys    sysfs    nodev,noexec,nosuid    0 0

當然也可以採用手動方式掛載:

# mount -t sysfs sysfs /sys

當將設備插入樹中時,都會為其創建一個目錄。該目錄可以填充在發現的每個層(全局層,總線層或設備層)中。

全局層當前創建兩個文件-‘name’和’power’。 前者報告設備名稱。 後者報告設備的當前電源狀態。 它還將用於設置當前電源狀態。

總線層為探測總線時發現的設備創建文件。 例如,PCI層當前為每個PCI設備創建“ irq”和“resource”文件。

特定於設備的驅動程序也可以在其目錄中導出文件,以暴露特定於設備的數據或可用接口。

驅動模型實現

先來梳理一下內部幾個主要與驅動模型相關的數據結構:

./include/linux/Device.h 定義設備驅動主要數據結構

  • bus_type:抽象描述總線類型,如USB/PCI/I2C/MMC等
  • device_driver:實現具體連接在總線上的設備驅動。
  • device:描述連接在總線上的設備

./include/linux/Kobject.h中定義了隱藏在後台的類似於基類的數據結構:

  • kset:可以認為是kobject的頂層容器類。每個kset內部都包含了自己的kobject.
  • kobject:在 sysfs 中出現的每個對象都對應一個 kobject, 它和內核交互來創建它的可見表述,每一個 kobject 對應 文件系統 /sys 里的一個 目錄,目錄的名字就是結構體中的 name

bus_type

bus_type用以驅動總線,具體的驅動USB/I2C/PCI/MMC等:

  • 註冊總線,利用bus_register註冊總線,bus_unregister刪除總線。如下例子,每種總線須定義一個bus_type對象,並利用bus_register註冊總線,或bus_unregister刪除總線。
/*i2c-core-base.c*/
struct bus_type i2c_bus_type = {
	.name		= "i2c",
	.match		= i2c_device_match,
	.probe		= i2c_device_probe,
	.remove		= i2c_device_remove,
	.shutdown	= i2c_device_shutdown,
};
EXPORT_SYMBOL_GPL(i2c_bus_type);
static int __init i2c_init(void)
{
	int retval;

	retval = of_alias_get_highest_id("i2c");

	down_write(&__i2c_board_lock);
	if (retval >= __i2c_first_dynamic_bus_num)
		__i2c_first_dynamic_bus_num = retval + 1;
	up_write(&__i2c_board_lock);
    /*註冊I2C總線*/
	retval = bus_register(&i2c_bus_type);
	if (retval)
		return retval;

	is_registered = true;

#ifdef CONFIG_I2C_COMPAT
	i2c_adapter_compat_class = class_compat_register("i2c-adapter");
	if (!i2c_adapter_compat_class) {
		retval = -ENOMEM;
		goto bus_err;
	}
#endif
	retval = i2c_add_driver(&dummy_driver);
	if (retval)
		goto class_err;

	if (IS_ENABLED(CONFIG_OF_DYNAMIC))
		WARN_ON(of_reconfig_notifier_register(&i2c_of_notifier));
	if (IS_ENABLED(CONFIG_ACPI))
		WARN_ON(acpi_reconfig_notifier_register(&i2c_acpi_notifier));

	return 0;

class_err:
#ifdef CONFIG_I2C_COMPAT
	class_compat_unregister(i2c_adapter_compat_class);
bus_err:
#endif
	is_registered = false;
    /*錯誤時刪除總線*/
	bus_unregister(&i2c_bus_type);
	return retval;
}
  • 註冊適配器驅動程序(USB控制器,I2C適配器等),以檢測連接的設備,並提供與設備的通信機制
  • 圖中的match函數接口用於將驅動程序與設備進行匹配。match回調的目的是使總線有機會通過比較驅動程序支持的設備ID與特定設備的設備ID來確定特定驅動程序是否支持特定設備,而不會犧牲特定於總線的功能或類型安全性 。當向總線註冊驅動程序時,將遍歷總線的設備列表,併為每個沒有與之關聯的驅動程序的設備調用match回調。
  • 提供API函數以實現適配器驅動以及設備驅動。
  • 同時dev_pm_ops *pm實現對於總線的功耗管理接口抽象。對於特定總線實現這個操作符對應的函數。
struct dev_pm_ops {
	int (*prepare)(struct device *dev);
	void (*complete)(struct device *dev);
	int (*suspend)(struct device *dev);
	int (*resume)(struct device *dev);
	int (*freeze)(struct device *dev);
	int (*thaw)(struct device *dev);
	int (*poweroff)(struct device *dev);
	int (*restore)(struct device *dev);
	int (*suspend_late)(struct device *dev);
	int (*resume_early)(struct device *dev);
	int (*freeze_late)(struct device *dev);
	int (*thaw_early)(struct device *dev);
	int (*poweroff_late)(struct device *dev);
	int (*restore_early)(struct device *dev);
	int (*suspend_noirq)(struct device *dev);
	int (*resume_noirq)(struct device *dev);
	int (*freeze_noirq)(struct device *dev);
	int (*thaw_noirq)(struct device *dev);
	int (*poweroff_noirq)(struct device *dev);
	int (*restore_noirq)(struct device *dev);
	int (*runtime_suspend)(struct device *dev);
	int (*runtime_resume)(struct device *dev);
	int (*runtime_idle)(struct device *dev);
};
  • iommu_ops 操作符提供總線相關的IOMMU抽象。
  • 設備驅動註冊到總線上時,將在sysfs管理總線/設備/設備驅動的層次關係,以PCI為例:
/*在總線上註冊的驅動程序會在總線的驅動程序目錄中獲得一個目錄*/
/sys/bus/pci/
        |-- devices
        `-- drivers
            |-- Intel ICH
            |-- Intel ICH Joystick
            |-- agpgart
            `-- e100
/*在該類型的總線上發現的每個設備都會在總線的設備目錄中獲得到物理層次結構中該設備目錄的符號鏈接*/
/sys/bus/pci/
          |-- devices
          |   |-- 00:00.0 -> ../../../root/pci0/00:00.0
          |   |-- 00:01.0 -> ../../../root/pci0/00:01.0
          |   `-- 00:02.0 -> ../../../root/pci0/00:02.0
          `-- drivers
  • 總線屬性:bus_groups/設備屬性dev_groups/驅動屬性drv_groups。

device

  • 作用:抽象描述具體的設備

  • 設備註冊:發現設備的總線驅動程序使用下面的函數來向內核註冊設備

int device_register(struct device * dev);
  • 利用device_unregister()從總線上刪除設備

device_driver

  • 作用:抽象描述連接在總線上的具體設備的驅動
  • 驅動註冊,通過下面的函數將設備驅動程序註冊
int driver_register(struct device_driver *drv);
  • 使用它使用以下命令從驅動程序目錄中添加和刪除屬性
  int driver_create_file(struct device_driver *, const struct driver_attribute *);
  void driver_remove_file(struct device_driver *, const struct driver_attribute *);

class

  • 作用:抽象設備的高層視圖,描述的是設備的集合。抽象了同類型的設備的底層實現細節。比如所有的網絡接口都位於/sys/class/net下
  • struct subsys_private *p描述類鏈表

kobject/kset

  • kobject類似於面向對象中的內核基類,內核利用它將各個對象連接起來組成分層的機構體系,其parent指針將形成一個樹狀分層結構。
  • kset內部包含了kobject。重心在描述對象的聚集於集合。這也是set一詞的含義。每一個kset添加到系統中,都將在sysfs中創建一個目錄
  • kobject/kset一起實現了sysfs虛擬文件系統中設備/總線/設備驅動樹狀分層結構的最關鍵的底層實現由來。

總體上而言:

通過上面一些關鍵數據結構關係分析,總線設備驅動模型最終目的是實現如下這樣一個分層驅動模型。

文章出自微信公眾號:嵌入式客棧,更多內容,請關注本人公眾號,嚴禁商業使用,違法必究

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

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

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

曹工說Spring Boot源碼(29)– Spring 解決循環依賴為什麼使用三級緩存,而不是二級緩存_網頁設計公司_網頁設計公司

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

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

寫在前面的話

相關背景及資源:

曹工說Spring Boot源碼(1)– Bean Definition到底是什麼,附spring思維導圖分享

曹工說Spring Boot源碼(2)– Bean Definition到底是什麼,咱們對著接口,逐個方法講解

曹工說Spring Boot源碼(3)– 手動註冊Bean Definition不比遊戲好玩嗎,我們來試一下

曹工說Spring Boot源碼(4)– 我是怎麼自定義ApplicationContext,從json文件讀取bean definition的?

曹工說Spring Boot源碼(5)– 怎麼從properties文件讀取bean

曹工說Spring Boot源碼(6)– Spring怎麼從xml文件裡解析bean的

曹工說Spring Boot源碼(7)– Spring解析xml文件,到底從中得到了什麼(上)

曹工說Spring Boot源碼(8)– Spring解析xml文件,到底從中得到了什麼(util命名空間)

曹工說Spring Boot源碼(9)– Spring解析xml文件,到底從中得到了什麼(context命名空間上)

曹工說Spring Boot源碼(10)– Spring解析xml文件,到底從中得到了什麼(context:annotation-config 解析)

曹工說Spring Boot源碼(11)– context:component-scan,你真的會用嗎(這次來說說它的奇技淫巧)

曹工說Spring Boot源碼(12)– Spring解析xml文件,到底從中得到了什麼(context:component-scan完整解析)

曹工說Spring Boot源碼(13)– AspectJ的運行時織入(Load-Time-Weaving),基本內容是講清楚了(附源碼)

曹工說Spring Boot源碼(14)– AspectJ的Load-Time-Weaving的兩種實現方式細細講解,以及怎麼和Spring Instrumentation集成

曹工說Spring Boot源碼(15)– Spring從xml文件裡到底得到了什麼(context:load-time-weaver 完整解析)

曹工說Spring Boot源碼(16)– Spring從xml文件裡到底得到了什麼(aop:config完整解析【上】)

曹工說Spring Boot源碼(17)– Spring從xml文件裡到底得到了什麼(aop:config完整解析【中】)

曹工說Spring Boot源碼(18)– Spring AOP源碼分析三部曲,終於快講完了(aop:config完整解析【下】)

曹工說Spring Boot源碼(19)– Spring 帶給我們的工具利器,創建代理不用愁(ProxyFactory)

曹工說Spring Boot源碼(20)– 碼網恢恢,疏而不漏,如何記錄Spring RedisTemplate每次操作日誌

曹工說Spring Boot源碼(21)– 為了讓大家理解Spring Aop利器ProxyFactory,我已經拼了

曹工說Spring Boot源碼(22)– 你說我Spring Aop依賴AspectJ,我依賴它什麼了

曹工說Spring Boot源碼(23)– ASM又立功了,Spring原來是這麼遞歸獲取註解的元註解的

曹工說Spring Boot源碼(24)– Spring註解掃描的瑞士軍刀,asm技術實戰(上)

曹工說Spring Boot源碼(25)– Spring註解掃描的瑞士軍刀,ASM + Java Instrumentation,順便提提Jar包破解

曹工說Spring Boot源碼(26)– 學習字節碼也太難了,實在不能忍受了,寫了個小小的字節碼執行引擎

曹工說Spring Boot源碼(27)– Spring的component-scan,光是include-filter屬性的各種配置方式,就夠玩半天了

曹工說Spring Boot源碼(28)– Spring的component-scan機制,讓你自己來進行簡單實現,怎麼辦

工程代碼地址思維導圖地址

工程結構圖:

什麼是三級緩存

在獲取單例bean的時候,會進入以下方法:

org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String, boolean)
    
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
                // 1
		Object singletonObject = this.singletonObjects.get(beanName);
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
			synchronized (this.singletonObjects) {
                                // 2
				singletonObject = this.earlySingletonObjects.get(beanName);
				if (singletonObject == null && allowEarlyReference) {
                                        // 3
					ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
					if (singletonFactory != null) {
                                                // 4
						singletonObject = singletonFactory.getObject();
						this.earlySingletonObjects.put(beanName, singletonObject);
						this.singletonFactories.remove(beanName);
					}
				}
			}
		}
		return singletonObject;
	}

這裏面涉及到了該類中的三個field。

	/** 1級緩存 Cache of singleton objects: bean name to bean instance. */
	private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

	/** 2級緩存 Cache of early singleton objects: bean name to bean instance. */
	private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);

	/** 3級緩存 Cache of singleton factories: bean name to ObjectFactory. */
	private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

接著說前面的代碼。

  • 1處,在最上層的緩存singletonObjects中,獲取單例bean,這裏面拿到的bean,直接可以使用;如果沒取到,則進入2處

  • 2處,在2級緩存earlySingletonObjects中,查找bean;

  • 3處,如果在2級緩存中,還是沒找到,則在3級緩存中查找對應的工廠對象,利用拿到的工廠對象(工廠對像中,有3個field,一個是beanName,一個是RootBeanDefinition ,一個是已經創建好的,但還沒有註入屬性的bean),去獲取包裝後的bean,或者說,代理後的bean。

    什麼是已經創建好的,但沒有註入屬性的bean?

    比如一個bean,有10個字段,你new了之後,對像已經有了,內存空間已經開闢了,堆裡已經分配了該對象的空間了,只是此時的10個field還是null。

ioc容器,普通循環依賴,一級緩存夠用嗎

說實話,如果簡單寫寫的話,一級緩存都沒問題。給大家看一個我以前寫的渣渣ioc容器:

曹工說Tomcat4:利用Digester 手擼一個輕量的Spring IOC容器

@Data
public class BeanDefinitionRegistry {
    /**
     * map:存儲 bean的class-》bean實例
     */
    private Map<Class, Object> beanMapByClass = new ConcurrentHashMap<>();
    
    /**
     * 根據bean 定義獲取bean
     * 1、先查bean容器,查到則返回
     * 2、生成bean,放進容器(此時,依賴還沒注入,主要是解決循環依賴問題)
     * 3、注入依賴
     *
     * @param beanDefiniton
     * @return
     */
    private Object getBean(MyBeanDefiniton beanDefiniton) {
        Class<?> beanClazz = beanDefiniton.getBeanClazz();
        Object bean = beanMapByClass.get(beanClazz);
        if (bean != null) {
            return bean;
        }
		// 0
        bean = generateBeanInstance(beanClazz);


        // 1 先行暴露,解決循環依賴問題
        beanMapByClass.put(beanClazz, bean);
        beanMapByName.put(beanDefiniton.getBeanName(), bean);

        // 2 查找依賴
        List<Field> dependencysByField = beanDefiniton.getDependencysByField();
        if (dependencysByField == null) {
            return bean;
        }
		
        // 3
        for (Field field : dependencysByField) {
            try {
                autowireField(beanClazz, bean, field);
            } catch (Exception e) {
                throw new RuntimeException(beanClazz.getName() + " 創建失敗",e);
            }
        }

        return bean;
    }
}

大家看上面的代碼,我只定義了一個field,就是一個map,存放bean的class-》bean。

    /**
     * map:存儲 bean的class-》bean實例
     */
    private Map<Class, Object> beanMapByClass = new ConcurrentHashMap<>();
  • 0處,生成bean,直接就是new
  • 1處,先把這個不完整的bean,放進map
  • 2處,獲取需要注入的屬性集合
  • 3處,進行自動注入,就是根據field的Class,去map裡查找對應的bean,設置到field裡。

上面這個代碼,有啥問題沒?spring為啥整整三級?

ioc,一級緩存有什麼問題

一級緩存的問題在於,就1個map,裏面既有完整的已經ready的bean,也有不完整的,尚未設置field的bean。

如果這時候,有其他線程去這個map裡獲取bean來用怎麼辦?拿到的bean,不完整,怎麼辦呢?屬性都是null,直接空指針了。

所以,我們就要加一個map,這個map,用來存放那種不完整的bean。這裏,還是拿spring舉例。我們可以只用下面這兩層:

	/** 1級緩存 Cache of singleton objects: bean name to bean instance. */
	private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

	/** 2級緩存 Cache of early singleton objects: bean name to bean instance. */
	private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);

因為spring代碼裡是三級緩存,所以我們對源碼做一點修改。

修改spring源碼,只使用二級緩存

修改創建bean的代碼,不放入第三級緩存,只放入第二級緩存

創建了bean之後,屬性注入之前,將創建出來的不完整bean,放到earlySingletonObjects

這個代碼,在org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean,我這邊只有4.0版本的spring源碼工程,不過這套邏輯,算是spring核心邏輯,和5.x版本差別不大。

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) {
		BeanWrapper instanceWrapper = null;
		if (mbd.isSingleton()) {
			instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
		}
		if (instanceWrapper == null) {
            // 1
			instanceWrapper = createBeanInstance(beanName, mbd, args);
		}
		final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
		Class beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);
		...
		boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
				isSingletonCurrentlyInCreation(beanName));
		if (earlySingletonExposure) {
            // 2
			earlySingletonObjects.put(beanName,bean);
			registeredSingletonObjects.add(beanName);
			// 3
//			addSingletonFactory(beanName, new ObjectFactory() {
//				public Object getObject() throws BeansException {
//					return getEarlyBeanReference(beanName, mbd, bean);
//				}
//			});
		}
  • 1處,就是創建對象,就是new
  • 2處,這是我加的代碼,放入二級緩存
  • 3處,本來這就是增加三級緩存的位置,被我註釋了。現在,就不會往三級緩存放東西了

修改獲取bean的代碼,只從第一、第二級緩存獲取,不從第三級獲取

org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String, boolean)

之前的代碼是文章開頭那樣的,我這裏修改為:

	protected Object getSingleton(String beanName, boolean allowEarlyReference) {
		Object singletonObject = this.singletonObjects.get(beanName);
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
			synchronized (this.singletonObjects) {
				singletonObject = this.earlySingletonObjects.get(beanName);
				return singletonObject;
			}
		}
		return (singletonObject != NULL_OBJECT ? singletonObject : null);

這樣,就是只用兩級緩存了。

兩級緩存,有啥問題?

ioc循環依賴,一點問題都沒有,完全夠用了。

我這邊一個簡單的例子,


public class Chick{
    private Egg egg;

    public Egg getEgg() {
        return egg;
    }

    public void setEgg(Egg egg) {
        this.egg = egg;
    }
}

public class Egg {
    private Chick chick;

    public Chick getChick() {
        return chick;
    }

    public void setChick(Chick chick) {
        this.chick = chick;
    }
    <bean id="chick" class="foo.Chick" lazy-init="true">
        <property name="egg" ref="egg"/>
    </bean>
    <bean id="egg" class="foo.Egg" lazy-init="true">
        <property name="chick" ref="chick"/>
    </bean>
        ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(
                "context-namespace-test-aop.xml");

        Egg egg = (Egg) ctx.getBean(Egg.class);

結論:

所以,一級緩存都能解決的問題,二級當然更沒問題。

但是,如果我這裏給上面的Egg類,加個切面(aop的邏輯,意思就是最終會生成Egg的一個動態代理對象),那還有問題沒?

    <aop:config>
        <aop:pointcut id="mypointcut" expression="execution(public * foo.Egg.*(..))"/>
        <aop:aspect id="myAspect" ref="performenceAspect">
            <aop:after method="afterIncubate" pointcut-ref="mypointcut"/>
        </aop:aspect>
    </aop:config>

注意這裏的切點:

execution(public * foo.Egg.*(..))

就是切Egg類的方法。

加了這個邏輯後,我們繼續運行,在 Egg egg = (Egg) ctx.getBean(Egg.class);行,會拋出如下異常:

我塗掉了一部分,因為那是官方對這個異常的推論,因為我們改了代碼,所以推論不準確,因此乾脆隱去。

這個異常是說:

兄弟啊,bean egg已經被注入到了其他bean:chick中。(因為我們循環依賴了),但是,注入到chick中的,是Egg類型。但是,我們這裏最後對egg這個bean,進行了後置處理,生成了代理對象。那其他bean裡,用原始的bean,是不是不太對啊?

所以,spring給我們拋錯了。

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

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

怎麼理解呢?以io流舉例,我們一開始都是用的原始字節流,然後給別人用的也是字節流,但是,最後,我感覺不方便,我自己悄悄弄了個緩存字符流(類比代理對象) ,我是方便了,但是,別人用的,還是原始的字節流啊。

你bean不是單例嗎?不能這麼玩吧?

所以,這就是二級緩存,不能解決的問題。

什麼問題?aop情形下,注入到其他bean的,不是最終的代理對象。

三級緩存,怎麼解決這個問題

要解決這個問題,必須在其他bean(chick),來查找我們(以上面例子為例,我們是egg)的時候,查找到最終形態的egg,即代理後的egg。

怎麼做到這點呢?

加個三級緩存,裏面不存具體的bean,裏面存一個工廠對象。通過工廠對象,是可以拿到最終形態的代理後的egg。

ok,我們將前面修改的代碼還原:

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) {
		BeanWrapper instanceWrapper = null;
		if (mbd.isSingleton()) {
			instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
		}
		if (instanceWrapper == null) {
            // 1
			instanceWrapper = createBeanInstance(beanName, mbd, args);
		}
		final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
		Class beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);

		boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
				isSingletonCurrentlyInCreation(beanName));
		if (earlySingletonExposure) {
            // 2
//			Map<String, Object> earlySingletonObjects = this.getEarlySingletonObjects();
//			earlySingletonObjects.put(beanName,bean);
//
//			Set<String> registeredSingletonObjects = this.getRegisteredSingletonObjects();
//			registeredSingletonObjects.add(beanName);
			
            // 3
			addSingletonFactory(beanName, new ObjectFactory() {
				public Object getObject() throws BeansException {
					return getEarlyBeanReference(beanName, mbd, bean);
				}
			});
		}
  • 1處,創建bean,單純new,不注入

  • 2處,revert我們的代碼

  • 3處,這裏new了一個ObjectFactory,然後會存入到如下的第三級緩存。

    	/** 3級緩存 Cache of singleton factories: bean name to ObjectFactory. */
    	private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
    

    注意,new一個匿名內部類(假設這個匿名類叫AA)的對象,其中用到的外部類的變量,都會在AA中隱式生成對應的field。

    大家看上圖,裏面的3個字段,和下面代碼1處中的,幾個字段,是一一對應的。

    			addSingletonFactory(beanName, new ObjectFactory() {
    				public Object getObject() throws BeansException {
                        // 1
    					return getEarlyBeanReference(beanName, mbd, bean);
    				}
    			});
    

ok,現在,egg已經把自己存進去了,存在了第三級緩存,1級和2級都沒有,那後續chick在使用getSingleton查找egg的時候,就會進入下面的邏輯了(就是文章開頭的那段代碼,下面已經把我們的修改還原了):

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
//		Object singletonObject = this.singletonObjects.get(beanName);
//		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
//			synchronized (this.singletonObjects) {
//				singletonObject = this.earlySingletonObjects.get(beanName);
//				return singletonObject;
//			}
//		}
//		return (singletonObject != NULL_OBJECT ? singletonObject : null);

		Object singletonObject = this.singletonObjects.get(beanName);
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
			synchronized (this.singletonObjects) {
				singletonObject = this.earlySingletonObjects.get(beanName);
				if (singletonObject == null && allowEarlyReference) {
					ObjectFactory singletonFactory = this.singletonFactories.get(beanName);
					if (singletonFactory != null) {
                        // 1
						singletonObject = singletonFactory.getObject();
						this.earlySingletonObjects.put(beanName, singletonObject);
						this.singletonFactories.remove(beanName);
					}
				}
			}
		}
		return (singletonObject != NULL_OBJECT ? singletonObject : null);
	}

上面就會進入1處,調用singletonFactory.getObject();

而前面我們知道,這個factory的邏輯是:

			addSingletonFactory(beanName, new ObjectFactory() {
				public Object getObject() throws BeansException {
                    // 1
					return getEarlyBeanReference(beanName, mbd, bean);
				}
			});

1處就是這個工廠方法的邏輯,這裏面,簡單說,就會去調用各個beanPostProcessor的getEarlyBeanReference方法。

其中,主要就是aop的主力beanPostProcessor,AbstractAutoProxyCreator#getEarlyBeanReference

其實現如下:

	public Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
		Object cacheKey = getCacheKey(bean.getClass(), beanName);
		this.earlyProxyReferences.add(cacheKey);
        // 1
		return wrapIfNecessary(bean, beanName, cacheKey);
	}

這裏的1處,就會去對egg這個bean,創建代理,此時,返回的對象,就是個代理對象了,那,注入到chick的,自然也是代理後的egg了。

關於SmartInstantiationAwareBeanPostProcessor

我們上面說的那個getEarlyBeanReference就在這個接口中。

這個接口繼承了BeanPostProcessor

而創建代理對象,目前就是在如下兩個方法中去創建:

public interface BeanPostProcessor {
    Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
    
	Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;    
}

這兩個方法,都是在實例化之後,創建代理。那我們前面創建代理,是在依賴解析過程中:

public interface SmartInstantiationAwareBeanPostProcessor extends InstantiationAwareBeanPostProcessor {
    ...
	Object getEarlyBeanReference(Object bean, String beanName) throws BeansException;
}

所以,spring希望我們,在這幾處,要返回同樣的對象,即:既然你這幾處都要返回代理對象,那就不能返回不一樣的代理對象。

那我們再看看,到底,AbstractAutoProxyCreator有沒有遵守約定呢,這幾個方法裡,有沒有去返回同樣的代理包裝對象呢?

getEarlyBeanReference

	public Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
		Object cacheKey = getCacheKey(bean.getClass(), beanName);
        // 1
		this.earlyProxyReferences.add(cacheKey);
		return wrapIfNecessary(bean, beanName, cacheKey);
	}

1處,往field:

private final Set<Object> earlyProxyReferences =
      Collections.newSetFromMap(new ConcurrentHashMap<Object, Boolean>(16));

裡,加了個cachekey,這個cachekey,主要也就是如下的字符串,用來唯一標識而已。

	protected Object getCacheKey(Class<?> beanClass, String beanName) {
		return beanClass.getName() + "_" + beanName;
	}

我們可以看看這個field在哪裡被用到了。

也就兩處,一處就是當前位置;另外一處,下面講。

這裏,主要就是看看到底要不要生成代理對象,要的話,就生成,不要就算了,另外,做了個標記:在earlyProxyReferences加了當前bean的key,表示:當前bean,已經被getEarlyBeanReference方法處理過了。

至於,最終到底有沒有生成代理對象,另說。畢竟調用wrapIfNecessary也不是說,一定就滿足切面,要生成代理對象。

可能返回的仍然是原始對象。

postProcessBeforeInitialization

public Object postProcessBeforeInitialization(Object bean, String beanName) {
   return bean;
}

這一處,沒做處理。

postProcessAfterInitialization

public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		if (bean != null) {
			Object cacheKey = getCacheKey(bean.getClass(), beanName);
            // 1
			if (!this.earlyProxyReferences.contains(cacheKey)) {
				return wrapIfNecessary(bean, beanName, cacheKey);
			}
		}
		return bean;
	}

這裏,1處這個判斷哈,就用到了前面我們說的那個field。那個field,只在兩處用,一處就是調用getEarlyBeanReference,會往裡面把當前bean的key放進去;另外一處,就是這裏。

這裏判斷,如果field裡不包含當前bean,就去調用wrapIfNecessary;如果包含(意味著,getEarlyBeanReference處理過了),就不調用了。

這裏,說到底,就是保證了,wrapIfNecessary只被調用一次。

看吧,wrapIfNecessary也就這兩處被調用了。

所以,我們可以得出結論,在aop這個beanPostProcessor中,有多處機會可以返回一個proxy對象,但是,最終,只要在其中一處處理了,其他處,根本不再繼續處理。

另外,還有一點很重要,在這個aop beanPostProcessor中,傳入了原始的bean,我們會去判斷,是否要給它創建代理,如果要,就創建;如果不要則:

返回原始對象

整個流程串起來

上面這個後置處理器看明白了,接下來,再看看創建bean的核心流程:

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) {
		// 1 
		BeanWrapper instanceWrapper = createBeanInstance(beanName, mbd, args);
		final Object bean = instanceWrapper.getWrappedInstance();
		
		if (earlySingletonExposure) {
            // 2
			addSingletonFactory(beanName, new ObjectFactory() {
				@Override
				public Object getObject() throws BeansException {
					return getEarlyBeanReference(beanName, mbd, bean);
				}
			});
		}

		// 3 
		Object exposedObject = bean;
    	// 4
        populateBean(beanName, mbd, instanceWrapper);
		
    	// 5
        if (exposedObject != null) {
            exposedObject = initializeBean(beanName, exposedObject, mbd);
        }

		if (earlySingletonExposure) {
            // 6
			Object earlySingletonReference = getSingleton(beanName, false);
            
			if (earlySingletonReference != null) {
                // 7
				if (exposedObject == bean) {
					exposedObject = earlySingletonReference;
				}
				else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
                    // 8
                    ...
				}
			}
		}

		return exposedObject;
	}

上面流程中,做了部分刪減。但基本創建一個bean,就這幾步了。

  • 1處,創建bean對象,此時,屬性什麼的全是null,可以理解為,只是new了,field還沒設置

  • 2處,添加到第三級緩存;加進去的,只是個factory,只有循環依賴的時候,才會發揮作用

  • 3處,把原始bean,存到exposedObject

  • 4處,填充屬性;循環依賴情況下,A/B循環依賴。假設當前為A,那麼此時填充A的屬性的時候,會去:

    new B;

    填充B的field,發現field裡有一個是A類型,然後就去getBean(“A”),然後走到第三級緩存,拿到了A的ObjectFactory,然後調用ObjectFactory,然後調用AOP的後置處理器類:getEarlyBeanReference,拿到代理後的bean(假設此處切面滿足,要創建代理);

    經過上面的步驟後,B裏面,field已經填充ok,其中,且填充的field是代理後的A,這裏命名為proxy A。

    B 繼續其他的後續處理。

    B處理完成後,被填充到當前的origin A(原始A)的field中

  • 5處,對A進行後置處理,此時調用aop後置處理器的,postProcessAfterInitialization;前面我們說了,此時不會再去調用wrapIfNecessary,所以這裏直接返回原始A,即origin A

  • 6處,去緩存裡獲取A,拿到的A,是proxy A

  • 7處,我們梳理下:

    exposedObject:origin A

    bean:原始A

    earlySingletonReference: proxy A

    此時,下面這個條件是滿足的,所以,exposedObject,最終被替換為proxy A:

    if (exposedObject == bean) {
        exposedObject = earlySingletonReference;
    }
    

源碼

文章用到的aop循環依賴的demo,自己寫一個也可以,很簡單:

https://gitee.com/ckl111/spring-boot-first-version-learn/tree/master/all-demo-in-spring-learning/spring-aop-xml-demo-cycle-reference

不錯的參考資料

https://blog.csdn.net/f641385712/article/details/92801300

總結

如果有問題,歡迎指出;歡迎加群討論;有幫助的話,請點個贊吧,謝謝

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

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

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

三星S21系列預購活動懶人包_網頁設計公司

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

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

三星5G新一代旗艦機Galaxy  S20、 S21+、S21 Ultra正式宣將在 1 月 29 日上市,並將於 1 月 15 日 15:30 起舉辦預購活動,並推出一系列預購禮與排隊禮。因應iPhone 12系列採取平價策略,這次三星S21系列,相較前一代S20系列,不但增加了一些新功能(如S21 Ultra多了可選購SPEN),建議售價還少了4000元以上,可以看出三星的企圖心!

三星S21系列的功能規格差異為何呢? 有哪些預購活動呢? 以下作一整理:

掌握最新電信資費訊息,請加入小丰子3C俱樂部粉絲頁!

小丰子3C俱樂部

 

1.S21系列建議售價與規格:

台灣三星1/29將在台上市5G新一代旗艦機Galaxy  S20、 S21+、S21 Ultra,其中S21 Ultra 首次加入S-Pen功能。 5G版本的 Galaxy S21系列的在台售價比較如下:

 

以下是三星S20、 S21+、S21 Ultra功能與規格比較:

 

2.預購活動:

A.Galaxy S21 5G 旗艦系列預購方案:

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

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

預購時間:1 月 15 日 15:30 至 1 月 25 日 23:59 期間開放預購登記。

預購好禮:
a.預購 Galaxy S21 Ultra 5G 並上網登錄送:Galaxy Buds Pro 真無線藍牙耳機(建議售價 NT$6,990)、Galaxy SmartTag 藍牙智慧防丟器(建議售價 NT$990)。
b.預購 Galaxy S21+ 5G︱Galaxy S21 5G 並上網登錄送:Galaxy Buds Live 真無線藍牙耳機(建議售價 NT$5,990)、Galaxy SmartTag 藍牙智慧防丟器(建議售價 NT$990)。

 

B.三星智慧館/三星商城預購方案:

a.預購取貨-限量線上排隊禮:
活動時間:1 月 15 日至 1 月 25 日止。
活動內容:於全台三星智慧館 Galaxy S21 5G 旗艦系列預購排隊網站登記,並於 1 月 27 日至 2 月 7 日憑預購 序號完成預購取機,即可獲得線上排隊禮郵政禮券 NT$1,000,限量 4,000 份。
指定店家優先取機排隊:三星微風南山旗艦體驗館限定取機加碼,於 1 月 27 日至 1 月 29 日至活動網頁預約,取機再送郵政禮券 NT$1,000,限量 350 份。

b.Samsung Care+全新上市三星智慧館獨家享悠遊卡加值回饋 NT$700:
活動時間:1 月 27 日至 3 月 31 日止。
活動內容:於全台三星智慧館購買 Galaxy S21 5G 旗艦系列手機,加購 Samsung Care+並繳滿六期保費,即可獲贈 Samsung Pay 悠遊卡加值回饋 NT$700。

 

C.Galaxy S21 5G 旗艦系列非預購方案:
非預購之消費者自 1 月 29 日起至 3 月 31 日期間,於全通路購買 Galaxy S21 5G 旗艦級系列手機並上網登錄,即可獲得【三合一無線閃充充電板(建議售價 NT$2,990)】、【Galaxy SmartTag 藍牙智慧防丟器(建議售價 NT$990)】; 購買 Galaxy S21 Ultra 5G 加贈【矽膠薄型背蓋(附 S Pen)(建議售價 NT$1,990)】。凡購買 Galaxy S21 5G 旗艦系列,可享 YouTube Premium 免費試用 4 個月。

 

您也許會喜歡:

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

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

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

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

國外 YouTube 頻道實測 PS5 vs 電腦 120FPS 模式的遊戲效能表現,GTX 1060 就贏過 PS5_網頁設計公司

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

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

PlayStation 5 顯示效能非常強大,這點相信很多人都知道,Sony 也曾透露最高能支援到 120FPS,這數字可說相當吸引遊戲玩家,而先前也有外媒實測確實有一些 PS5 遊戲可跑到 120FPS。為此近日就有國外 YouTube 頻道想到一個還蠻有趣的比較主題,如果以相同約 500 美金的電腦跟 PS5 相比,一樣的遊戲運行 120FPS,哪些顯示卡可以跟 PS5 表現一樣?結果沒想到四年前的 NVIDIA GTX 1060 就能擊敗 PS5。

國外 YouTuber 實測 PS5 vs 電腦 120FPS 模式的遊戲效能表現

開始介紹前也先說明一下,這位 YouTuber 的 PS5 vs PC 比較是以 120FPS 為前提,因此並不代表 PS5 效能這麼差,畢竟 PS5 都能運行 4K 遊戲,甚至未來還能支援到 8K,再加上 5.5 GB/s 客製化 NVME SSD,很多地方是這次測試表現不出來。

以下是先前外媒 PushSquare 分享 PS5 可運行 120FPS 的遊戲清單:

  • Borderlands 3 (PS5)
  • Call of Duty: Black Ops Cold War (PS5)
  • Destiny 2 (PS5)
  • Devil May Cry 5: Special Edition (PS5)
  • DIRT 5 (PS5)
  • Monster Boy and the Cursed Kingdom (PS5)
  • The Nioh Collection (PS5)
  • Tom Clancy’s Rainbow Six: Siege (PS5)

Gamers Nexus 就拿 Borderlands 3、Devil May Cry 5: Special Edition 與 DIRT 5 這三款遊戲進行測試。而畫質部分都是運行 1080p,品質設定基本上一模一樣,甚至把 PS5 的光追技術關掉。

首先是 Devil May Cry 5: Special Edition,這款遊戲幾乎不需要使用到 CPU 的效能,因此他們選擇 R3 3300X 就夠了,甚至還可以再往更低階挑,不過以 400~500 美金為前提,這顆跟 PS5 最接近。

下方是 PC 端的畫質設定:

顯示卡部分他們測試過 GTX 1070,會比 PS5 還要好,也因此降一級改用 GTX 1060 就差不多,測試時把光追關掉:

跑分結果,PC 部分平均可跑到 142.1 FPS,但 PS5 只能到 108.7 FPS:

DIRT 5 這款遊戲顯卡要用到 GTX 1080 才比較接近 PS5,不過以平均 FPS 來說,PS5 就以 119FPS 小勝 PC 的 108.9FPS:

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

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

PS5 與 PC 同一畫面的比較圖:

最後是 Borderlands 3,這款遊戲需要用到 GTX 1070 Ti 才跟 PS5 最接近,PC 以平均 130.3FPS 表現勝過 PS5 的 118.9FPS:

同一畫面比較圖:

有些人可能會覺得,測試這似乎沒什麼意義,事實上還是有一個可以總結的答案,就是以高 FPS 的畫面表現來說,遊戲機表現不會比 PC 還出色,因此如果你是看中這一點想買 PS5 的人,PC 會是你更好的選擇。

說實在 PS5 vs PC 本來就很難相提並論,畢竟 PC 還能做很多事情,像是文書、繪圖等等,非常多功能,而 PS5 則可以讓玩家無需擔心遊戲不順暢狀況,進而提供最佳體驗。

完整影片:

IKEA 開始提供 PS5 與 Xbox Series X 的紙模型,讓你買家具之前可以快速比對

您也許會喜歡:

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

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

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

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