“南北奧迪”來了 上汽大眾與奧迪品牌正式牽手

而坊間盛傳,上汽大眾與奧迪合資以後的第一款車型預計將會在2017年4月正式發布。其實上汽才是奧迪最初的國產始祖奧迪品牌與上汽大眾合作並非偶然,早在八十年代,最早的國產奧迪汽車就是由上海大眾公司進行組裝,而當年的“奧迪100”轎車,也是奧迪品牌進入國人視野較早的經典車型。

就在人們都在某寶某東上瘋狂買買買的時候,國內汽車界也出現了一個震動幅度不算小的新聞,11月11日,上汽大眾與奧迪正式簽署合作協議,這意味着大眾旗下豪華品牌奧迪在不久的將來將會在國內有兩家合資企業。

根據相關消息透露,上汽大眾與奧迪合資成立的的銷售公司二者股權各佔50%,雙方合作形式類似於上汽大眾與斯柯達品牌之間的合作形式,即是在未來,上汽大眾以產品代工的形式生產以及銷售奧迪品牌的產品。

上汽大眾與一汽大眾,常常被人稱為“南北大眾”,上汽大眾與奧迪的合作,或許也就意味着將來即將呈現“南北奧迪”爭相奪取豪車市場的局面。而坊間盛傳,上汽大眾與奧迪合資以後的第一款車型預計將會在2017年4月正式發布。

其實上汽才是奧迪最初的國產始祖

奧迪品牌與上汽大眾合作並非偶然,早在八十年代,最早的國產奧迪汽車就是由上海大眾公司進行組裝,而當年的“奧迪100”轎車,也是奧迪品牌進入國人視野較早的經典車型。

在八十年代末,一汽與奧迪簽署了技術轉讓合同,從彼時開始,一汽大眾奧迪迎來了一個長盛不衰的王朝,直至今天,奧迪汽車仍舊是國人心中極具分量的豪華汽車品牌。

奧迪與上汽大眾合作,將會生產出什麼樣的車型是所有車迷最關心的問題,由於大眾集團是將“汽車生產平台模塊化”玩得最溜的汽車廠商,在一汽大眾產品線已經非常成熟的今天進行合作,將來的“上汽大眾奧迪”是以引進奧迪品牌在國內從未生產過的車型進行投產,還是利用現有的產品布局生產同平台但不同命名的車型,我們也將對“上汽大眾奧迪”保持高度關注與跟進。本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

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

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

※回頭車貨運收費標準

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

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

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

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

基於上汽全新架構MIP打造 榮威i6將於明年上半年上市

其中,榮威i6搭載的上汽“藍芯”SGE 16T發動機,採用缸內中置直噴渦輪增壓等國際領先技術,將引領汽車黃金排量的變革。“藍芯”SGE 20T發動機,最大功率達到169馬力,最大扭矩250牛米,動力性能超越主流2。0L自然吸氣發動機。

今日,“全球首款量產互聯網轎車”榮威i6官圖首次曝光,新車將於明年上半年上市。榮威i6基於上汽全新架構MIp打造,軸距達2715mm。該軸距超過目前市場上主流中級轎車,配合1835mm同級最寬車身和同級最大後排座艙,榮威i6達到了准B級的空間表現,為用戶帶來比肩豪華車的空間享受。

從曝光的官圖來看,榮威i6延續了Vision-R概念車的律動設計精髓,展現了上汽比肩豪華汽車品牌的設計實力和精湛製造工藝,不僅風阻係數達到0.25,在目前全球量產車中排名領先,而且整體設計層次分明,線條鋒銳挺拔,形面飽滿。榮威i6車頭下壓,形成蓄勢待發的姿態;高腰線360度貫穿車身,線條洗鍊流暢,一氣呵成;車尾內切,極具動感,視覺上使整車的重心有一種向後的拉拽感。

榮威i6與其新能源版——榮威ei6,均基於上汽全新MIp架構開發,採用世界級動力總成,將為用戶帶來超低油耗、超高效率、超高品質的出行體驗。其中,榮威i6搭載的上汽“藍芯”SGE 16T發動機,採用缸內中置直噴渦輪增壓等國際領先技術,將引領汽車黃金排量的變革;“藍芯”SGE 20T發動機,最大功率達到169馬力,最大扭矩250牛米,動力性能超越主流2.0L自然吸氣發動機。榮威ei6則搭載“藍芯SGE 16T+綠芯EDU”動力組合,綜合油耗領先同級20%,三電效率領先同級20%,充電時間領先同級20%,將為消費者提供更綠色環保、更便利的出行體驗。

此外,作為上汽與阿里巴巴集團聯手打造的全球首款量產互聯網轎車,榮威i6將搭載最新一代智能互聯繫統,以創新思維與数字賦能,為用戶提供智能出行“時代之選”。

榮威i6與榮威ei6將在11月18日廣州車展全球首次亮相,揭開神秘面紗。除了最新一代智能互聯繫統、世界級動力技術、媲美豪華車的0.25超低風阻係數以及同級最寬適空間之外,榮威i6還將帶來哪些驚喜?在“爆款”榮威RX5月銷量一舉突破2萬輛,並以最快速度挺進SUV銷量榜前8之後,上汽榮威的第二款互聯網汽車榮威i6,又將給市場帶來多大衝擊,值得期待。本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

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

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

※回頭車貨運收費標準

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

※超省錢租車方案

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

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

從品質啟程:啟辰全新70系邀你見證“航天品質”

無論是航天製造,還是汽車製造,都離不開富有工匠精神的“螺絲釘”,他們貢獻者微小卻關鍵的力量,在打造“高品質”的道路上不息探索。啟辰T70是東風日產啟辰品牌傾力打造的首款SUV車型,在上市之初贏得了不錯的市場表現,啟辰T70基於雷諾日產C平台打造,和老款奇駿,逍客是出自同一平台,在9月8號啟辰70系列迎來了它的新款車型,新款啟辰T70,T70X外觀方面,啟辰T70採用家族式前臉,大量平直線條的運用,讓整個車身看起來更加動感時尚,新款啞光飾條的前雙輻的進氣格柵,熏黑處理的大燈,使得整體外觀看上去更加精緻,車燈

11月14日,由東風日產啟辰品牌與鳳凰網聯合主辦、以“從品質啟程”為主題的航天品質沙龍在北京舉行。航空航天領域的專家與啟辰品牌代表、工程師共同探討了中國航天的革新之路,以及航天品質背後精益求精的匠心精神。繼日前神舟十一號載人飛船成功發射之後,此次航天技術與汽車工業的跨界對話,讓“高大上”的航天工程再次走進大眾的視野,為各個領域的製造者實現人類更高品質的未來生活帶來啟發與思考。

自2011年起,東風日產就成立了以啟辰領銜的品質聯盟。2013年,啟辰發起了品質透明行動,通過百媒見證、萬里測試、千人證言共同見證了啟辰的高品質。可以說,啟辰的高品質已經深入人心,本次沙龍的一大主角——啟辰全新70系,正是啟辰高品質的體現,其經過了1697道質量檢驗工序的重重把關,從根本上就確保了品質的“零缺陷”。

我們可以看到,啟辰每一項技術進步的背後,都離不開人對更高品質生活的追求。此外,東風日產乘用車公司技術中心啟辰品牌開發總姚斌也與大家分享了啟辰的航天品質是如何煉成的。以啟辰T70為例,從商品企劃到整車下線、量產上市,整個過程都用工業製作的最高標準來要求自己。無論是航天製造,還是汽車製造,都離不開富有工匠精神的“螺絲釘”,他們貢獻者微小卻關鍵的力量,在打造“高品質”的道路上不息探索。

啟辰T70是東風日產啟辰品牌傾力打造的首款SUV車型,在上市之初贏得了不錯的市場表現,啟辰T70基於雷諾日產C平台打造,和老款奇駿,逍客是出自同一平台,在9月8號啟辰70系列迎來了它的新款車型,新款啟辰T70,T70X

外觀方面,啟辰T70採用家族式前臉,大量平直線條的運用,讓整個車身看起來更加動感時尚,新款啞光飾條的前雙輻的進氣格柵,熏黑處理的大燈,使得整體外觀看上去更加精緻,車燈部分的鍍鉻裝飾也提升了整車的質感。

內飾方面,採用T字型的中控布局,層次分明,線條比較簡潔,銀色裝飾條讓車廂看起來具有年輕,活力的氛圍,多媒體系統新增了流行的手機互聯功能百度Carlife,安全配置方面,360度全景影像,定速巡航,制動力分配和剎車輔助系統均有配備

啟辰T70的長寬高分別是4542mm.1786mm,1642mm,軸距為2630mm,啟辰T70X長寬高分別為458,2mm,1840mm,1644mm,軸距為2630mm,啟辰T70X增加了黑色外包圍,配置也更豐富。

動力方面,啟辰T70使用的是1.6和2.0自然吸氣發動機,1.6發動機最大功率121馬力,最大扭矩154牛米,2.0發動機最大功率144馬力,最大扭矩198牛米,兩款發動機均來自老款日產逍客,匹配手動擋和XTRONIC CVT變速箱,延續了日產品牌質量好,省油,大空間,舒適性好的優勢。

啟辰T70在外觀設計硬朗,空間方面也比較令人滿意,動力系統匹配成熟,質量可靠性和品質相比同級別車型有一定的優勢,相信新款啟辰70系列會將有一個不錯的市場表現.本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※回頭車貨運收費標準

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

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

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

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

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

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

疫情影響人類海洋活動大減 瀕危欖蠵龜在墨西哥孵化數創新高

摘錄自2020年10月29日自由時報報導

武漢肺炎(COVID-19)疫情持續影響全球,人類因防疫降低活動量,生態保育因此出現改善跡象;近期,墨西哥北部有一批瀕臨絕種的欖蠵龜(Olive ridley sea turtle)在海灘上孵化,數量創下新紀錄,普遍看法解讀為武漢肺炎期間,人類海洋活動減少的因素導致。

根據《BBC》報導,欖蠵龜在今年5月至9月間,在墨西哥一些沿海州上產卵;根據墨國索諾拉州(Sonora)原住民社區「斯里(Seri)」統計指出,已有超過2250隻小欖蠵龜在今年孵化並成功回到加利福尼亞灣中。

比較過往平均紀錄,今年較以往每年僅約500隻回歸大海的數量多出不少,判斷與武漢肺炎疫情期間,觀光客與捕魚作業大減有關;這些海洋活動降低,可以大幅降低欖蠵龜的巢被干擾的機率,使更多欖蠵龜寶寶得以順利孵化。

生物多樣性
海洋
國際新聞
墨西哥
海龜
瀕危物種

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

【其他文章推薦】

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

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

※回頭車貨運收費標準

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

※超省錢租車方案

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

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

澳研究:吃下塑膠的魚類行為更大膽活躍 生存率降低

摘錄自2020年10月28日聯合新聞網報導

澳洲最新研究指出,塑膠微粒能夠改變魚類的行為,吃下塑膠微粒的魚類,牠們傾向於變得更大膽、活躍,比起其他魚類生存率更低。

每日郵報報導,澳洲詹姆斯庫克大學(James Cook University)研究團隊在澳洲大堡礁水域捕捉幼魚,並連續四天餵食牠們除了豐年蝦(brine shrimp)以外的塑膠微粒。科學家將牠們標記後放回海裡觀察其行為,研究塑膠微粒是否對魚類造成影響。

科學家表示,他們不認為這是因為塑膠對魚類產生有毒影響,而是魚類在吃進塑膠後會更飢餓,這種「營養需求壓力」促使牠們更傾向於冒險尋找食物,而該冒險行為使牠們更容易被掠食者吃掉。

該研究領導學者麥考密克(Mark McCormick)表示,魚類行為上的改變及其對生存的影響,是因魚類吃下塑膠微粒後變得飽足但事實上卻沒有獲得營養。

海洋
污染治理
國際新聞
澳洲
塑膠微粒

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

【其他文章推薦】

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

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

※回頭車貨運收費標準

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

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

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

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

核食檢測眉角多 日政府無心 民間自發學習輻射測定

文:宋瑞文(媽媽監督核電廠聯盟特約撰述)

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

【其他文章推薦】

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

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

※回頭車貨運收費標準

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

※超省錢租車方案

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

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

颶風伊塔威力增強 預計登陸中美洲地區

摘錄自2020年11月3日中央社報導

颶風伊塔(Eta)在加勒比海(Caribbean Sea)增強威力後,今(3日)預計登陸中美洲地區,宏都拉斯和尼加拉瓜等國恐面臨災難性的強風及洪水威脅。

法新社報導,美國國家颶風中心(National Hurricane Center)在午夜預警指出,這個「極度危險」颶風的風速達到每小時240公里,正往尼加拉瓜海岸前進。中美洲部分地區預計將出現暴潮、強風、暴洪及土石流等災情。

尼加拉瓜近海的密斯基多群島(Miskito Cays)當地的婦女和孩童已從村莊撤離,只剩男性留下來看顧房子,倘若情況變得更加危險,男性也會撤離避難。

加勒比海與中美洲的其他地區也可能面臨颶風伊塔的侵襲,國家颶風中心指出,牙買加、墨西哥東南部、薩爾瓦多、海地南部及開曼群島都可能出現洪患。

氣候變遷
國際新聞
中美洲
颶風

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

【其他文章推薦】

※回頭車貨運收費標準

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

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

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

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

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

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

降低產銷流程碳排 IKEA設二手家具店

摘錄自2020年11月10日公視新聞網報導

瑞典家具品牌IKEA,這個月開了第一間賣二手家具的示範店面,他們把回收而來的家具重新整修,希望能夠延長傢俱的使用壽命。

客戶在上千坪的店面參觀選購,看起來跟全球其他400多間IKEA店面沒有兩樣。不過在另一個角落,卻有幾位員工把舊傢俱堆放在一起,有的負責表面清潔,有的檢查各部位零件是否牢固,以及外表是否有髒污或刮痕。

標榜產品製程環保高標準的IKEA,為了在2030年之前,達成進一步降低產銷流程碳排放的目標,今年下半年展開一系列回收二手家具再降價轉賣的試辦計畫。首先是在9月間,位於英國愛丁堡格拉斯哥的分店,試辦接受消費者把以前購買,後來卻不敷所需的IKEA傢俱,賣回給業者。由於試辦相當成功,11月開始還要擴大到全英國,以及鄰近的愛爾蘭。

IKEA行銷經理夫亞爾說:「我們IKEA的目標,是(讓產銷成為)完整的循環,在2030年前達成兼顧永續跟獲利。從生產到如何做好售後服務,延長產品的使用壽命。」

氣候變遷
循環經濟
國際新聞
減碳
二手

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

【其他文章推薦】

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

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

※回頭車貨運收費標準

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

※超省錢租車方案

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

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

【Spring註解開發】組件註冊-使用@Configuration和@Bean給容器中註冊組件

寫在前面

在之前的Spring版本中,我們只能通過寫XML配置文件來定義我們的Bean,XML配置不僅繁瑣,而且很容易出錯,稍有不慎就會導致編寫的應用程序各種報錯,排查半天,發現是XML文件配置不對!另外,每個項目編寫大量的XML文件來配置Spring,也大大增加了項目維護的複雜度,往往很多個項目的Spring XML文件的配置大部分是相同的,只有很少量的配置不同,這也造成了配置文件上的冗餘。

項目工程源碼已經提交到GitHub:https://github.com/sunshinelyz/spring-annotation

Spring IOC和DI

在Spring容器的底層,最重要的功能就是IOC和DI,也就是控制反轉和依賴注入。

IOC:控制反轉,將類的對象的創建交給Spring類管理創建。
DI:依賴注入,將類裏面的屬性在創建類的過程中給屬性賦值。
DI和IOC的關係:DI不能單獨存在,DI需要在IOC的基礎上來完成。

在Spring內部,所有的組件都會放到IOC容器中,組件之間的關係通過IOC容器來自動裝配,也就是我們所說的依賴注入。接下來,我們就使用註解的方式來完成容器組件的註冊、管理及依賴、注入等功能。

在介紹使用註解完成容器組件的註冊、管理及依賴、注入等功能之前,我們先來看看使用XML文件是如何注入Bean的。

通過XML文件注入JavaBean

首先,我們在工程的io.mykit.spring.bean包下創建Person類,作為測試的JavaBean,代碼如下所示。

package io.mykit.spring.bean;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
import java.io.Serializable;

/**
 * @author binghe
 * @version 1.0.0
 * @description 測試實體類
 */
@Data
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class Person implements Serializable {
    private static final long serialVersionUID = 7387479910468805194L;
    private String name;
    private Integer age;
}

接下來,我們在工程的resources目錄下創建Spring的配置文件beans.xml,通過beans.xml文件將Person類注入到Spring的IOC容器中,配置如下所示。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id = "person" class="io.mykit.spring.bean.Person">
        <property name="name" value="binghe"></property>
        <property name="age" value="18"></property>
    </bean>
</beans>

到此,我們使用XML方式注入JavaBean就配置完成了。接下來,我們創建一個SpringBeanTest類來進行測試,這裏,我使用的是Junit進行測試,測試方法如下所示。

@Test
public void testXmlConfig(){
    ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
    Person person = (Person) context.getBean("person");
    System.out.println(person);
}

運行testXmlConfig()方法,輸出的結果信息如下。

Person(name=binghe, age=18)

從輸出結果中,我們可以看出,Person類通過beans.xml文件的配置,已經注入到Spring的IOC容器中了。

通過註解注入JavaBean

通過XML文件,我們可以將JavaBean注入到Spring的IOC容器中。那使用註解又該如何實現呢?別急,其實使用註解比使用XML文件要簡單的多,我們在項目的io.mykit.spring.plugins.register.config包下創建PersonConfig類,並在PersonConfig類上添加@Configuration註解來標註PersonConfig類是一個Spring的配置類,通過@Bean註解將Person類注入到Spring的IOC容器中。

package io.mykit.spring.plugins.register.config;

import io.mykit.spring.bean.Person;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @author binghe
 * @version 1.0.0
 * @description 以註解的形式來配置Person
 */
@Configuration
public class PersonConfig {
     @Bean
    public Person person(){
        return new Person("binghe001", 18);
    }
}

沒錯,通過PersonConfig類我們就能夠將Person類注入到Spring的IOC容器中,是不是很Nice!!主要我們在類上加上@Configuration註解,並在方法上加上@Bean註解,就能夠將方法中創建的JavaBean注入到Spring的IOC容器中。

接下來,我們在SpringBeanTest類中創建一個testAnnotationConfig()方法來測試通過註解注入的Person類,如下所示。

@Test
public void testAnnotationConfig(){
    ApplicationContext context = new AnnotationConfigApplicationContext(PersonConfig.class);
    Person person = context.getBean(Person.class);
    System.out.println(person);
}

運行testAnnotationConfig()方法,輸出的結果信息如下所示。

Person(name=binghe001, age=18)

可以看出,通過註解將Person類注入到了Spring的IOC容器中。

到這裏,我們已經明確,通過XML文件和註解兩種方式都可以將JavaBean注入到Spring的IOC容器中。那麼,使用註解將JavaBean注入到IOC容器中時,使用的bean的名稱是什麼呢? 我們可以在testAnnotationConfig()方法中添加如下代碼來獲取Person類型下的註解名稱。

//按照類型找到對應的bean名稱數組
String[] names = context.getBeanNamesForType(Person.class);
Arrays.stream(names).forEach(System.out::println);

完整的testAnnotationConfig()方法的代碼如下所示。

@Test
public void testAnnotationConfig(){
    ApplicationContext context = new AnnotationConfigApplicationContext(PersonConfig.class);
    Person person = context.getBean(Person.class);
    System.out.println(person);

    //按照類型找到對應的bean名稱數組
    String[] names = context.getBeanNamesForType(Person.class);
    Arrays.stream(names).forEach(System.out::println);
}

運行testAnnotationConfig()方法輸出的結果信息如下所示。

Person(name=binghe001, age=18)
person

那這裏的person是啥?我們修改下PersonConfig類中的person()方法,將person()方法修改成person01()方法,如下所示。

package io.mykit.spring.plugins.register.config;

import io.mykit.spring.bean.Person;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @author binghe
 * @version 1.0.0
 * @description 以註解的形式來配置Person
 */
@Configuration
public class PersonConfig {

    @Bean
    public Person person01(){
        return new Person("binghe001", 18);
    }
}

此時,我們再次運行testAnnotationConfig()方法,輸出的結果信息如下所示。

Person(name=binghe001, age=18)
person01

看到這裏,大家應該有種豁然開朗的感覺了,沒錯!!使用註解注入Javabean時,bean在IOC中的名稱就是使用@Bean註解標註的方法名稱。我們可不可以為bean單獨指定名稱呢?那必須可以啊!只要在@Bean註解中明確指定名稱就可以了。比如下面的PersonConfig類的代碼,我們將person01()方法上的@Bean註解修改成@Bean(“person”)註解,如下所示。

package io.mykit.spring.plugins.register.config;

import io.mykit.spring.bean.Person;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @author binghe
 * @version 1.0.0
 * @description 以註解的形式來配置Person
 */
@Configuration
public class PersonConfig {

    @Bean("person")
    public Person person01(){
        return new Person("binghe001", 18);
    }
}

此時,我們再次運行testAnnotationConfig()方法,輸出的結果信息如下所示。

Person(name=binghe001, age=18)
person

可以看到,此時,輸出的JavaBean的名稱為person。

結論:我們在使用註解方式向Spring的IOC容器中注入JavaBean時,如果沒有在@Bean註解中明確指定bean的名稱,就使用當前方法的名稱來作為bean的名稱;如果在@Bean註解中明確指定了bean的名稱,則使用@Bean註解中指定的名稱來作為bean的名稱。

好了,咱們今天就聊到這兒吧!別忘了給個在看和轉發,讓更多的人看到,一起學習一起進步!!

項目工程源碼已經提交到GitHub:https://github.com/sunshinelyz/spring-annotation

寫在最後

如果覺得文章對你有點幫助,請微信搜索並關注「 冰河技術 」微信公眾號,跟冰河學習Spring註解驅動開發。公眾號回復“spring註解”關鍵字,領取Spring註解驅動開發核心知識圖,讓Spring註解驅動開發不再迷茫。

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

【其他文章推薦】

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

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

※回頭車貨運收費標準

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

※超省錢租車方案

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

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

“造輪運動”之 ORM框架系列(三)~ 乾貨呈上

   這一趴裏面,我就來正式介紹一下CoffeeSQL的乾貨。

    首先要給CoffeeSQL來個定位:最開始就是由於本人想要了解ORM框架內部的原理,所以就四處搜尋有關的博客與學習資料,就是在那個夏天,在博客園上看到了一位7tiny老哥的博客(https://www.cnblogs.com/7tiny/p/9575230.html),裏面基本上包含了我所想要了解的全套內容。幸得7tiny老哥的博客和代碼都寫的非常清晰,所以沒花多久時間就看完了源碼並洞悉其中奧妙,於是自己就有個想法:在7tiny的開源代碼的基礎上歸納自己的ORM框架。於是出於學習與自我使用的目的就開始了擴展功能的道路,到現在為止,自己已經在公司的一個項目中用上了,效果還不錯。在這裏也感謝7tiny老哥對我提出的一些問題及時的回復和指導,真心感謝。

一、框架模塊介紹

  根據CoffeeSQL的功能模塊組成來劃分,可以分為:數據庫連接管理、SQL命令執行入口、SQL命令生成器、SQL查詢引擎、ORM緩存機制、實體數據驗證 這六個部分,CoffeeSQL的操作入口與其他的ORM框架一樣,都是以數據庫上下文(DBContext)的方式進行操作。整體結構圖如下:

 

下面就大致地介紹一下每一個模塊的具體功能與實現的思路:

1、數據庫連接管理(DBConnectionManagement)

   數據庫連接的管理實際上就是對數據庫連接字符串與其對應的數據庫連接對象的管理機制,它可以保證在進行一主多從的數據庫部署時ORM幫助我們自動地切換連接的數據庫,而且還支持 <最小使用>與 <輪詢>兩種數據庫連接切換策略。

 

2、SQL命令執行入口(QueryExecute)

   QueryExecute是CoffeeSQL生成的所有sql語句執行的入口,執行sql語句並返回結果,貫穿整個CoffeeSQL最核心的功能就是映射sql查詢結果到實體,這裏採用的是構建表達式樹的技術,性能大大優於反射獲取實體的方式,具體的兩者速度對比的實驗在7tiny的博客中有詳細介紹,大家可以移步觀看(https://www.cnblogs.com/7tiny/p/9861166.html),在我的博客(https://www.cnblogs.com/MaMaNongNong/p/12173620.html)中我使用表達式樹的技術造了個簡練版的OOM框架。

   這裏貼出核心代碼,方便查看:

   

  1     /// <summary>
  2     /// Auto Fill Adapter
  3     /// => Fill DataRow to Entity
  4     /// </summary>
  5     public class EntityFillAdapter<Entity>
  6     {
  7         private static readonly Func<DataRow, Entity> funcCache = GetFactory();
  8 
  9         public static Entity AutoFill(DataRow row)
 10         {
 11             return funcCache(row);
 12         }
 13 
 14         private static Func<DataRow, Entity> GetFactory()
 15         {
 16             #region get Info through Reflection
 17             var entityType = typeof(Entity);
 18             var rowType = typeof(DataRow);
 19             var convertType = typeof(Convert);
 20             var typeType = typeof(Type);
 21             var columnCollectionType = typeof(DataColumnCollection);
 22             var getTypeMethod = typeType.GetMethod("GetType", BindingFlags.Static | BindingFlags.Public, null, new[] { typeof(string) }, null);
 23             var changeTypeMethod = convertType.GetMethod("ChangeType", BindingFlags.Static | BindingFlags.Public, null, new[] { typeof(object), typeof(Type) }, null);
 24             var containsMethod = columnCollectionType.GetMethod("Contains");
 25             var rowIndexerGetMethod = rowType.GetMethod("get_Item", BindingFlags.Instance | BindingFlags.Public, null, new[] { typeof(string) }, new[] { new ParameterModifier(1) });
 26             var columnCollectionIndexerGetMethod = columnCollectionType.GetMethod("get_Item", BindingFlags.Instance | BindingFlags.Public, null, new[] { typeof(int) }, new[] { new ParameterModifier(1) });
 27             var entityIndexerSetMethod = entityType.GetMethod("set_Item", BindingFlags.Instance | BindingFlags.NonPublic, null, new[] { typeof(string), typeof(object) }, null);
 28             var properties = entityType.GetProperties(BindingFlags.Instance | BindingFlags.Public);
 29             #endregion
 30 
 31             #region some Expression class that can be repeat used
 32             //DataRow row
 33             var rowDeclare = Expression.Parameter(rowType, "row");
 34             //Student entity
 35             var entityDeclare = Expression.Parameter(entityType, "entity");
 36             //Type propertyType
 37             var propertyTypeDeclare = Expression.Parameter(typeof(Type), "propertyType");
 38             //new Student()
 39             var newEntityExpression = Expression.New(entityType);
 40             //row == null
 41             var rowEqualnullExpression = Expression.Equal(rowDeclare, Expression.Constant(null));
 42             //row.Table.Columns
 43             var rowTableColumns = Expression.Property(Expression.Property(rowDeclare, "Table"), "Columns");
 44             //int loopIndex
 45             var loopIndexDeclare = Expression.Parameter(typeof(int), "loopIndex");
 46             //row.Table.Columns[loopIndex].ColumnName
 47             var columnNameExpression = Expression.Property(Expression.Call(rowTableColumns, columnCollectionIndexerGetMethod, loopIndexDeclare), "ColumnName");
 48             //break;
 49             LabelTarget labelBreak = Expression.Label();
 50             //default(Student)
 51             var defaultEntityValue = Expression.Default(entityType);
 52             #endregion
 53 
 54             var setRowNotNullBlockExpressions = new List<Expression>();
 55                         
 56             #region entity = new Student();loopIndex = 0;
 57             setRowNotNullBlockExpressions.Add(Expression.Assign(entityDeclare, newEntityExpression));
 58             setRowNotNullBlockExpressions.Add(Expression.Assign(loopIndexDeclare, Expression.Constant(0)));
 59 
 60             #endregion
 61 
 62             #region loop Fill DataRow's field to Entity Indexer
 63             /*
 64              * while (true)
 65              * {
 66              *     if (loopIndex < row.Table.Columns.Count)
 67              *     {
 68              *         entity[row.Table.Columns[loopIndex].ColumnName] = row[row.Table.Columns[loopIndex].ColumnName];
 69              *         loopIndex++;
 70              *     }
 71              *     else break;
 72              * } 
 73              */
 74 
 75             setRowNotNullBlockExpressions.Add(
 76 
 77                 Expression.Loop(
 78                     Expression.IfThenElse(
 79                         Expression.LessThan(loopIndexDeclare, Expression.Property(rowTableColumns, "Count")),
 80                         Expression.Block(
 81                             Expression.Call(entityDeclare, entityIndexerSetMethod, columnNameExpression, Expression.Call(rowDeclare, rowIndexerGetMethod, columnNameExpression)),
 82                             Expression.PostIncrementAssign(loopIndexDeclare)
 83                         ),
 84                         Expression.Break(labelBreak)
 85                     ),
 86                     labelBreak
 87                 )
 88             );
 89             #endregion
 90 
 91             #region assign for Entity property
 92             foreach (var propertyInfo in properties)
 93             {
 94                 var columnAttr = propertyInfo.GetCustomAttribute(typeof(ColumnAttribute), true) as ColumnAttribute;
 95 
 96                 // no column , no translation
 97                 if (null == columnAttr) continue;
 98 
 99                 if (propertyInfo.CanWrite)
100                 {
101                     var columnName = Expression.Constant(columnAttr.GetName(propertyInfo.Name), typeof(string));
102 
103                     //entity.Id
104                     var propertyExpression = Expression.Property(entityDeclare, propertyInfo);
105                     //row["Id"]
106                     var value = Expression.Call(rowDeclare, rowIndexerGetMethod, columnName);
107                     //default(string)
108                     var defaultValue = Expression.Default(propertyInfo.PropertyType);
109                     //row.Table.Columns.Contains("Id")
110                     var checkIfContainsColumn = Expression.Call(rowTableColumns, containsMethod, columnName);
111                     //!row["Id"].Equals(DBNull.Value)
112                     var checkDBNull = Expression.NotEqual(value, Expression.Constant(System.DBNull.Value));
113                     
114                     var propertyTypeName = Expression.Constant(propertyInfo.PropertyType.ToString(), typeof(string));
115 
116                     /*
117                      * if (row.Table.Columns.Contains("Id") && !row["Id"].Equals(DBNull.Value))
118                      * {
119                      *     propertyType = Type.GetType("System.String");
120                      *     entity.Id = (string)Convert.ChangeType(row["Id"], propertyType);
121                      * }
122                      * else
123                      *     entity.Id = default(string);
124                      */
125                     setRowNotNullBlockExpressions.Add(
126 
127                         Expression.IfThenElse(
128                             Expression.AndAlso(checkIfContainsColumn, checkDBNull),
129                             Expression.Block(
130                                 Expression.Assign(propertyTypeDeclare, Expression.Call(getTypeMethod, propertyTypeName)),
131                                 Expression.Assign(propertyExpression, Expression.Convert(Expression.Call(changeTypeMethod, value, propertyTypeDeclare), propertyInfo.PropertyType))
132                             ),
133                             Expression.Assign(propertyExpression, defaultValue)
134                         )
135                     );
136                 }
137             }
138 
139             #endregion
140 
141             var checkIfRowIsNull = Expression.IfThenElse(
142                 rowEqualnullExpression,
143                 Expression.Assign(entityDeclare, defaultEntityValue),
144                 Expression.Block(setRowNotNullBlockExpressions)
145             );
146 
147             var body = Expression.Block(
148 
149                 new[] { entityDeclare, loopIndexDeclare, propertyTypeDeclare },
150                 checkIfRowIsNull,
151                 entityDeclare   //return Student;
152             );
153 
154             return Expression.Lambda<Func<DataRow, Entity>>(body, rowDeclare).Compile();
155         }
156     }
157 
158     #region
159     //public class Student : EntityDesign.EntityBase
160     //{
161     //    [Column]
162     //    public string Id { get; set; }
163 
164     //    [Column("StudentName")]
165     //    public string Name { get; set; }
166     //}
167     ////this is the template of "GetFactory()" created.
168     //public static Student StudentFillAdapter(DataRow row)
169     //{
170     //    Student entity;
171     //    int loopIndex;
172     //    Type propertyType;
173 
174     //    if (row == null)
175     //        entity = default(Student);
176     //    else
177     //    {
178     //        entity = new Student();
179     //        loopIndex = 0;
180 
181     //        while (true)
182     //        {
183     //            if (loopIndex < row.Table.Columns.Count)
184     //            {
185     //                entity[row.Table.Columns[loopIndex].ColumnName] = row[row.Table.Columns[loopIndex].ColumnName];
186     //                loopIndex++;
187     //            }
188     //            else break;
189     //        }
190 
191     //        if (row.Table.Columns.Contains("Id") && !row["Id"].Equals(DBNull.Value))
192     //        {
193     //            propertyType = Type.GetType("System.String");
194     //            entity.Id = (string)Convert.ChangeType(row["Id"], propertyType);
195     //        }
196     //        else
197     //            entity.Id = default(string);
198 
199     //        if (row.Table.Columns.Contains("StudentName") && !row["StudentName"].Equals(DBNull.Value))
200     //        {
201     //            propertyType = Type.GetType("System.String");
202     //            entity.Name = (string)Convert.ChangeType(row["StudentName"], propertyType);
203     //        }
204     //        else
205     //            entity.Name = default(string);
206     //    }
207 
208     //    return entity;
209     //}
210     #endregion

EntityFillAdapter(表達式樹技術)

 

3、SQL查詢引擎(QueryEngine)

  SQL查詢引擎的功能主要就是以函數的形式來構建查詢SQL的結構。將sql語句使用高級語言的函數來進行構建能大大減輕程序員必須一絲不苟編寫sql語句的壓力。特別是在使用強類型查詢引擎時以Lambda表達式的方式編寫程序,相當舒適的體驗;對於稍微複雜的sql,建議使用弱類型查詢引擎來構建sql查詢語句,同時也提供方便的分頁功能,用法與Dapper類似;再複雜一點的數據庫查詢邏輯可能你就要考慮使用存儲過程查詢引擎了,總之,有了這三個查詢引擎,所有的查詢需求都能滿足了。最後一個是update的執行引擎,它被用來構建update的語句。

 

4、實體數據驗證(EntityValidation)

  實體數據驗證是完全獨立的一部分,主要用來檢驗實體類中字段值的合法性,相當於在高級語言層面對即將持久化到數據庫表中的數據進行預先的字段合法性校驗,避免在持久化過程中發生不必要的字段格式不合法的錯誤。

 

5、ORM緩存機制(ORMCache)

  這裏的ORM緩存主要分為兩級緩存,一級緩存為以sql語句為緩存鍵的緩存,緩存的內容就是當前執行的sql語句的執行結果;而二級緩存則是以表名為緩存鍵的表緩存,就是會把一整個表的數據全部存入緩存中,所以表緩存最適合那些數據量不大且查詢頻繁的表

 

6、SQL命令生成器【強類型】(CommandTextGenerator)

  在使用諸如強類型查詢引擎、Update執行引擎等進行了強類型的SQL語句構造后,相應的sql構造信息都要通過SQL命令生成器來生成最終可由數據庫執行的sql語句。SQL命令生成器扮演的就是類似於翻譯官的角色,將高級語言中的語句轉化為數據庫中的sql語句。在實際的應用場景中還可以根據不同的數據庫類型將SQL命令生成器擴展成諸如Mysql-SQL命令生成器或者Oracle-SQL命令生成器以符合不同類型數據庫的不同sql語法。

 

7、數據庫上下文(DBContext)

  作為整個CoffeeSQL的操作入口,DBContext類涵蓋了各種配置參数字段與增刪改查的API調用函數。其中在事務處理中,由於寫操作都是通過對主庫的操作,所以在事務處理中是以主庫作為事務處理的對象。

二、使用方式

  下載CoffeeSql源碼進行編譯,你會得到 CoffeeSql.Core.dll、CoffeeSql.Oracle.dll、CoffeeSql.Mysql.dll 三個dll文件,其中CoffeeSql.Core.dll為必選,然後根據你的數據庫類型選擇是CoffeeSql.Oracle.dll或者CoffeeSql.Mysql.dll,目前還只支持這兩種數據庫,後續會支持更多數據庫。

 

 

三、展望

  路漫漫其修遠兮,吾將上下而求索,對比市面上火熱的ORM框架,CoffeeSQL還是缺少了一些實用的功能,對這個ORM框架的展望中我會考慮以下一些功能:

    1、CodeFirst、DbFirst功能的支持,可以快捷方便地進行實體類與數據庫建表sql的生成;

    2、批量插入操作的實現,可以提高批量插入數據的性能;

    3、對多表聯合查詢的lambda語法支持;

  

  介紹的再多都不如讀一遍源碼來的實在,有想深入了解orm原理的小夥伴可以閱讀一下源碼,真的SO EASY!

   源碼地址:https://gitee.com/xiaosen123/CoffeeSqlORM

   本文為作者原創,轉載請註明出處:https://www.cnblogs.com/MaMaNongNong/p/12896787.html

 

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

【其他文章推薦】

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

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

※回頭車貨運收費標準

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

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

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

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