SPRINGIOC的詳解_第1頁
SPRINGIOC的詳解_第2頁
SPRINGIOC的詳解_第3頁
SPRINGIOC的詳解_第4頁
SPRINGIOC的詳解_第5頁
已閱讀5頁,還剩10頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)

文檔簡介

1、ioc與di 首先想說說ioc(inversion of control,控制倒轉(zhuǎn))。這是spring的核心,貫穿始終。所謂ioc,對于spring框架來說,就是由spring來負(fù)責(zé)控制對象的生命周期和對象間的關(guān)系。這是什么意思呢,舉個簡單的例子,我們是如何找女朋友的?常見的情況是,我們到處去看哪里有長得漂亮身材又好的mm,然后打聽她們的興趣愛好、qq號、電話號、ip號、iq號,想辦法認(rèn)識她們,投其所好送其所要,然后嘿嘿這個過程是復(fù)雜深奧的,我們必須自己設(shè)計和面對每個環(huán)節(jié)。傳統(tǒng)的程序開發(fā)也是如此,在一個對象中,如果要使用另外的對象,就必須得到它(自己new一個,或者從jndi中查詢一個),使用

2、完之后還要將對象銷毀(比如connection等),對象始終會和其他的接口或類藕合起來。 那么ioc是如何做的呢?有點像通過婚介找女朋友,在我和女朋友之間引入了一個第三者:婚姻介紹所?;榻楣芾砹撕芏嗄心信馁Y料,我可以向婚介提出一個列表,告訴它我想找個什么樣的女朋友,比如長得像李嘉欣,身材像林熙雷,唱歌像周杰倫,速度像卡洛斯,技術(shù)像齊達(dá)內(nèi)之類的,然后婚介就會按照我們的要求,提供一個mm,我們只需要去和她談戀愛、結(jié)婚就行了。簡單明了,如果婚介給我們的人選不符合要求,我們就會拋出異常。整個過程不再由我自己控制,而是有婚介這樣一個類似容器的機(jī)構(gòu)來控制。spring所倡導(dǎo)的開發(fā)方式就是如此,所有的類

3、都會在spring容器中登記,告訴spring你是個什么東西,你需要什么東西,然后spring會在系統(tǒng)運行到適當(dāng)?shù)臅r候,把你要的東西主動給你,同時也把你交給其他需要你的東西。所有的類的創(chuàng)建、銷毀都由 spring來控制,也就是說控制對象生存周期的不再是引用它的對象,而是spring。對于某個具體的對象而言,以前是它控制其他對象,現(xiàn)在是所有對象都被spring控制,所以這叫控制反轉(zhuǎn)。如果你還不明白的話,我決定放棄。ioc的一個重點是在系統(tǒng)運行中,動態(tài)的向某個對象提供它所需要的其他對象。這一點是通過di(dependency injection,依賴注入)來實現(xiàn)的。比如對象a需要操作數(shù)據(jù)庫,以前我

4、們總是要在a中自己編寫代碼來獲得一個connection對象,有了 spring我們就只需要告訴spring,a中需要一個connection,至于這個connection怎么構(gòu)造,何時構(gòu)造,a不需要知道。在系統(tǒng)運行時,spring會在適當(dāng)?shù)臅r候制造一個connection,然后像打針一樣,注射到a當(dāng)中,這樣就完成了對各個對象之間關(guān)系的控制。a需要依賴 connection才能正常運行,而這個connection是由spring注入到a中的,依賴注入的名字就這么來的。那么di是如何實現(xiàn)的呢? java 1.3之后一個重要特征是反射(reflection),它允許程序在運行的時候動態(tài)的生成對象、

5、執(zhí)行對象的方法、改變對象的屬性,spring就是通過反射來實現(xiàn)注入的。關(guān)于反射的相關(guān)資料請查閱java doc。 理解了ioc和di的概念后,一切都將變得簡單明了,剩下的工作只是在spring的框架中堆積木而已。如果還不明白,放棄java吧! 下面來讓大家了解一下spring到底是怎么運行的。 java代碼 public static void main(string args) applicationcontext context = new filesystemxmlapplicationcontext( "applicationcontext.xml"); anima

6、l animal = (animal) context.getbean("animal"); animal.say(); public static void main(string args) applicationcontext context = new filesystemxmlapplicationcontext( "applicationcontext.xml"); animal animal = (animal) context.getbean("animal"); animal.say(); 這段代碼你一定很熟悉吧,不

7、過還是讓我們分析一下它吧,首先是applicationcontext.xmljava代碼 <bean id="animal" class="phz.springframework.test.cat"> <property name="name" value="kitty" /> </bean> <bean id="animal" class="phz.springframework.test.cat"> <property

8、 name="name" value="kitty" /> </bean>他有一個類phz.springframework.test.catjava代碼 public class cat implements animal private string name; public void say() system.out.println("i am " + name + "!"); public void setname(string name) = name; public

9、class cat implements animal private string name; public void say() system.out.println("i am " + name + "!"); public void setname(string name) = name; 實現(xiàn)了phz.springframework.test.animal接口java代碼 public interface animal public void say(); public interface animal public voi

10、d say();很明顯上面的代碼輸出i am kitty! 那么到底spring是如何做到的呢? 接下來就讓我們自己寫個spring 來看看spring 到底是怎么運行的吧! 首先,我們定義一個bean類,這個類用來存放一個bean擁有的屬性java代碼 /* bean id */ private string id; /* bean class */ private string type; /* bean property */ private map<string, object> properties = new hashmap<string, object>(

11、); /* bean id */ private string id; /* bean class */ private string type; /* bean property */ private map<string, object> properties = new hashmap<string, object>();一個bean包括id,type,和properties。 接下來spring 就開始加載我們的配置文件了,將我們配置的信息保存在一個hashmap中,hashmap的key就是bean 的 id ,hasmap 的value是這個bean,只有這

12、樣我們才能通過context.getbean("animal")這個方法獲得animal這個類。我們都知道 spirng可以注入基本類型,而且可以注入像list,map這樣的類型,接下來就讓我們以map為例看看spring是怎么保存的吧 map配置可以像下面的java代碼 <bean id="test" class="test"> <property name="testmap"> <map> <entry key="a"> <value&g

13、t;1</value> </entry> <entry key="b"> <value>2</value> </entry> </map> </property> </bean> <bean id="test" class="test"> <property name="testmap"> <map> <entry key="a"> <

14、value>1</value> </entry> <entry key="b"> <value>2</value> </entry> </map> </property> </bean>spring是怎樣保存上面的配置呢?,代碼如下:java代碼 if (beanproperty.element("map") != null) map<string, object> propertiesmap = new hashmap<s

15、tring, object>(); element propertieslistmap = (element) beanproperty .elements().get(0); iterator<?> propertiesiterator = propertieslistmap .elements().iterator(); while (propertiesiterator.hasnext() element vet = (element) propertiesiterator.next(); if (vet.getname().equals("entry&quo

16、t;) string key = vet.attributevalue("key"); iterator<?> valuesiterator = vet.elements() .iterator(); while (valuesiterator.hasnext() element value = (element) valuesiterator.next(); if (value.getname().equals("value") propertiesmap.put(key, value.gettext(); if (value.getnam

17、e().equals("ref") propertiesmap.put(key, new string value .attributevalue("bean") ); bean.getproperties().put(name, propertiesmap); if (beanproperty.element("map") != null) map<string, object> propertiesmap = new hashmap<string, object>(); element properties

18、listmap = (element) beanproperty .elements().get(0); iterator<?> propertiesiterator = propertieslistmap .elements().iterator(); while (propertiesiterator.hasnext() element vet = (element) propertiesiterator.next(); if (vet.getname().equals("entry") string key = vet.attributevalue(&qu

19、ot;key"); iterator<?> valuesiterator = vet.elements() .iterator(); while (valuesiterator.hasnext() element value = (element) valuesiterator.next(); if (value.getname().equals("value") propertiesmap.put(key, value.gettext(); if (value.getname().equals("ref") propertiesm

20、ap.put(key, new string value .attributevalue("bean") ); bean.getproperties().put(name, propertiesmap); 接下來就進(jìn)入最核心部分了,讓我們看看spring 到底是怎么依賴注入的吧,其實依賴注入的思想也很簡單,它是通過反射機(jī)制實現(xiàn)的,在實例化一個類時,它通過反射調(diào)用類中set方法將事先保存在hashmap中的類屬性注入到類中。讓我們看看具體它是怎么做的吧。 首先實例化一個類,像這樣java代碼 public static object newinstance(string cl

21、assname) class<?> cls = null; object obj = null; try cls = class.forname(classname); obj = cls.newinstance(); catch (classnotfoundexception e) throw new runtimeexception(e); catch (instantiationexception e) throw new runtimeexception(e); catch (illegalaccessexception e) throw new runtimeexcept

22、ion(e); return obj; public static object newinstance(string classname) class<?> cls = null; object obj = null; try cls = class.forname(classname); obj = cls.newinstance(); catch (classnotfoundexception e) throw new runtimeexception(e); catch (instantiationexception e) throw new runtimeexceptio

23、n(e); catch (illegalaccessexception e) throw new runtimeexception(e); return obj; 接著它將這個類的依賴注入進(jìn)去,像這樣java代碼 public static void setproperty(object obj, string name, string value) class<? extends object> clazz = obj.getclass(); try string methodname = returnsetmthodname(name); method ms = clazz.g

24、etmethods(); for (method m : ms) if (m.getname().equals(methodname) if (m.getparametertypes().length = 1) class<?> clazzparametertype = m.getparametertypes()0; setfieldvalue(clazzparametertype.getname(), value, m, obj); break; catch (securityexception e) throw new runtimeexception(e); catch (i

25、llegalargumentexception e) throw new runtimeexception(e); catch (illegalaccessexception e) throw new runtimeexception(e); catch (invocationtargetexception e) throw new runtimeexception(e); public static void setproperty(object obj, string name, string value) class<? extends object> clazz = obj

26、.getclass(); try string methodname = returnsetmthodname(name); method ms = clazz.getmethods(); for (method m : ms) if (m.getname().equals(methodname) if (m.getparametertypes().length = 1) class<?> clazzparametertype = m.getparametertypes()0; setfieldvalue(clazzparametertype.getname(), value, m

27、, obj); break; catch (securityexception e) throw new runtimeexception(e); catch (illegalargumentexception e) throw new runtimeexception(e); catch (illegalaccessexception e) throw new runtimeexception(e); catch (invocationtargetexception e) throw new runtimeexception(e); 最后它將這個類的實例返回給我們,我們就可以用了。我們還是以

28、map為例看看它是怎么做的,我寫的代碼里面是創(chuàng)建一個hashmap并把該hashmap注入到需要注入的類中,像這樣,java代碼 if (value instanceof map) iterator<?> entryiterator = (map<?, ?>) value).entryset() .iterator(); map<string, object> map = new hashmap<string, object>(); while (entryiterator.hasnext() entry<?, ?> entrymap

29、 = (entry<?, ?>) entryiterator.next(); if (entrymap.getvalue() instanceof string) map.put(string) entrymap.getkey(), getbean(string) entrymap.getvalue()0); beanprocesser.setproperty(obj, property, map); if (value instanceof map) iterator<?> entryiterator = (map<?, ?>) value).entrys

30、et() .iterator(); map<string, object> map = new hashmap<string, object>(); while (entryiterator.hasnext() entry<?, ?> entrymap = (entry<?, ?>) entryiterator.next(); if (entrymap.getvalue() instanceof string) map.put(string) entrymap.getkey(), getbean(string) entrymap.getvalue

31、()0); beanprocesser.setproperty(obj, property, map); 好了,這樣我們就可以用spring 給我們創(chuàng)建的類了,是不是也不是很難???當(dāng)然spring能做到的遠(yuǎn)不止這些,這個示例程序僅僅提供了spring最核心的依賴注入功能中的一部分。1. ioc理論的背景我們都知道,在采用面向?qū)ο蠓椒ㄔO(shè)計的軟件系統(tǒng)中,它的底層實現(xiàn)都是由n個對象組成的,所有的對象通過彼此的合作,最終實現(xiàn)系統(tǒng)的業(yè)務(wù)邏輯。圖1:軟件系統(tǒng)中耦合的對象如果我們打開機(jī)械式手表的后蓋,就會看到與上面類似的情形,各個齒輪分別帶動時針、分針和秒 針順時針旋轉(zhuǎn),從而在表盤上產(chǎn)生正確的時間。圖1中描

32、述的就是這樣的一個齒輪組,它擁有多個獨立的齒輪,這些齒輪相互嚙合在一起,協(xié)同工作,共同完成某項 任務(wù)。我們可以看到,在這樣的齒輪組中,如果有一個齒輪出了問題,就可能會影響到整個齒輪組的正常運轉(zhuǎn)。齒輪組中齒輪之間的嚙合關(guān)系,與軟件系統(tǒng)中對象之間的耦合關(guān)系非常相似。對象之間的耦合關(guān)系是無法避免的,也是必要的,這是協(xié)同工作的基礎(chǔ)?,F(xiàn)在,伴隨著 工業(yè)級應(yīng)用的規(guī)模越來越龐大,對象之間的依賴關(guān)系也越來越復(fù)雜,經(jīng)常會出現(xiàn)對象之間的多重依賴性關(guān)系,因此,架構(gòu)師和設(shè)計師對于系統(tǒng)的分析和設(shè)計,將面臨 更大的挑戰(zhàn)。對象之間耦合度過高的系統(tǒng),必然會出現(xiàn)牽一發(fā)而動全身的情形。圖2:對象之間復(fù)雜的依賴關(guān)系耦合關(guān)系不僅會出

33、現(xiàn)在對象與對象之間,也會出現(xiàn)在軟件系統(tǒng)的各模塊之間,以及軟件系統(tǒng)和硬件系統(tǒng)之間。如何降低系統(tǒng)之間、模塊之間和對象之間的耦合度,是軟件工程永遠(yuǎn)追求的目標(biāo)之一。為了解決對象之間的耦合度過高的問題,軟件專家michael mattson提出了ioc理論,用來實現(xiàn)對象之間的“解耦”,目前這個理論已經(jīng)被成功地應(yīng)用到實踐當(dāng)中,很多的j2ee項目均采用了ioc框架產(chǎn)品spring。2. 什么是控制反轉(zhuǎn)(ioc)ioc是inversion of control的縮寫,多數(shù)書籍翻譯成“控制反轉(zhuǎn)”,還有些書籍翻譯成為“控制反向”或者“控制倒置”。1996年,michael mattson在一篇有關(guān)探討面向?qū)ο罂蚣?/p>

34、的文章中,首先提出了ioc 這個概念。對于面向?qū)ο笤O(shè)計及編程的基本思想,前面我們已經(jīng)講了很多了,不再贅述,簡單來說就是把復(fù)雜系統(tǒng)分解成相互合作的對象,這些對象類通過封裝以 后,內(nèi)部實現(xiàn)對外部是透明的,從而降低了解決問題的復(fù)雜度,而且可以靈活地被重用和擴(kuò)展。ioc理論提出的觀點大體是這樣的:借助于“第三方”實現(xiàn)具有依 賴關(guān)系的對象之間的解耦,如下圖:圖3:ioc解耦過程大家看到了吧,由于引進(jìn)了中間位置的“第三方”,也就是ioc容器,使得a、b、c、d這4個對象沒有了耦合關(guān)系,齒輪之間的傳動全部依靠“第三 方”了,全部對象的控制權(quán)全部上繳給“第三方”ioc容器,所以,ioc容器成了整個系統(tǒng)的關(guān)鍵核

35、心,它起到了一種類似“粘合劑”的作用,把系統(tǒng)中的所有 對象粘合在一起發(fā)揮作用,如果沒有這個“粘合劑”,對象與對象之間會彼此失去聯(lián)系,這就是有人把ioc容器比喻成“粘合劑”的由來。我們再來做個試驗:把上圖中間的ioc容器拿掉,然后再來看看這套系統(tǒng):圖4:拿掉ioc容器后的系統(tǒng)我們現(xiàn)在看到的畫面,就是我們要實現(xiàn)整個系統(tǒng)所需要完成的全部內(nèi)容。這時候,a、b、c、d這4個對象之間已經(jīng)沒有了耦合關(guān)系,彼此毫無聯(lián)系,這樣 的話,當(dāng)你在實現(xiàn)a的時候,根本無須再去考慮b、c和d了,對象之間的依賴關(guān)系已經(jīng)降低到了最低程度。所以,如果真能實現(xiàn)ioc容器,對于系統(tǒng)開發(fā)而言, 這將是一件多么美好的事情,參與開發(fā)的每一

36、成員只要實現(xiàn)自己的類就可以了,跟別人沒有任何關(guān)系!我們再來看看,控制反轉(zhuǎn)(ioc)到底為什么要起這么個名字?我們來對比一下:軟件系統(tǒng)在沒有引入ioc容器之前,如圖1所示,對象a依賴于對象b,那么對象a在初始化或者運行到某一點的時候,自己必須主動去創(chuàng)建對象b或者使用已經(jīng)創(chuàng)建的對象b。無論是創(chuàng)建還是使用對象b,控制權(quán)都在自己手上。軟件系統(tǒng)在引入ioc容器之后,這種情形就完全改變了,如圖3所示,由于ioc容器的加入,對象a與對象b之間失去了直接聯(lián)系,所以,當(dāng)對象a運行到需要對象b的時候,ioc容器會主動創(chuàng)建一個對象b注入到對象a需要的地方。通過前后的對比,我們不難看出來:對象a獲得依賴對象b的過程,

37、由主動行為變?yōu)榱吮粍有袨?,控制?quán)顛倒過來了,這就是“控制反轉(zhuǎn)”這個名稱的由來。3. ioc的別名:依賴注入(di)2004年,martin fowler探討了同一個問題,既然ioc是控制反轉(zhuǎn),那么到底是“哪些方面的控制被反轉(zhuǎn)了呢?”,經(jīng)過詳細(xì)地分析和論證后,他得出了答案:“獲得依賴對 象的過程被反轉(zhuǎn)了”??刂票环崔D(zhuǎn)之后,獲得依賴對象的過程由自身管理變?yōu)榱擞蒳oc容器主動注入。于是,他給“控制反轉(zhuǎn)”取了一個更合適的名字叫做“依賴 注入(dependency injection)”。他的這個答案,實際上給出了實現(xiàn)ioc的方法:注入。所謂依賴注入,就是由ioc容器在運行期間,動態(tài)地將某種依賴關(guān)系注入

38、到對 象之中。所以,依賴注入(di)和控制反轉(zhuǎn)(ioc)是從不同的角度的描述的同一件事情,就是指通過引入ioc容器,利用依賴關(guān)系注入的方式,實現(xiàn)對象之間的解耦。我們舉一個生活中的例子,來幫助理解依賴注入的過程。大家對usb接口和usb設(shè)備應(yīng)該都很熟悉吧,usb為我們使用電腦提供了很大的方便,現(xiàn)在有很多的外部設(shè)備都支持usb接口。圖5:usb接口和usb設(shè)備現(xiàn)在,我們利用電腦主機(jī)和usb接口來實現(xiàn)一個任務(wù):從外部usb設(shè)備讀取一個文件。電腦主機(jī)讀取文件的時候,它一點也不會關(guān)心usb接口上連接的是什么外部設(shè)備,而且它確實也無須知道。它的任務(wù)就是讀取usb接口,掛接的外部設(shè)備只要符 合usb接口標(biāo)準(zhǔn)

39、即可。所以,如果我給電腦主機(jī)連接上一個u盤,那么主機(jī)就從u盤上讀取文件;如果我給電腦主機(jī)連接上一個外置硬盤,那么電腦主機(jī)就從外置 硬盤上讀取文件。掛接外部設(shè)備的權(quán)力由我作主,即控制權(quán)歸我,至于usb接口掛接的是什么設(shè)備,電腦主機(jī)是決定不了,它只能被動的接受。電腦主機(jī)需要外部 設(shè)備的時候,根本不用它告訴我,我就會主動幫它掛上它想要的外部設(shè)備,你看我的服務(wù)是多么的到位。這就是我們生活中常見的一個依賴注入的例子。在這個過程 中,我就起到了ioc容器的作用。通過這個例子,依賴注入的思路已經(jīng)非常清楚:當(dāng)電腦主機(jī)讀取文件的時候,我就把它所要依賴的外部設(shè)備,幫他掛接上。整個外部設(shè)備注入的過程和一個被依賴的對

40、象在系統(tǒng)運行時被注入另外一個對象內(nèi)部的過程完全一樣。我們把依賴注入應(yīng)用到軟件系統(tǒng)中,再來描述一下這個過程:對象a依賴于對象b,當(dāng)對象 a需要用到對象b的時候,ioc容器就會立即創(chuàng)建一個對象b送給對象a。ioc容器就是一個對象制造工廠,你需要什么,它會給你送去,你直接使用就行了, 而再也不用去關(guān)心你所用的東西是如何制成的,也不用關(guān)心最后是怎么被銷毀的,這一切全部由ioc容器包辦。在傳統(tǒng)的實現(xiàn)中,由程序內(nèi)部代碼來控制組件之間的關(guān)系。我們經(jīng)常使用new關(guān)鍵字來實現(xiàn)兩個組件之間關(guān)系的組合,這種實現(xiàn)方式會造成組件之間耦合。ioc 很好地解決了該問題,它將實現(xiàn)組件間關(guān)系從程序內(nèi)部提到外部容器,也就是說由容

41、器在運行期將組件間的某種依賴關(guān)系動態(tài)注入組件中。4. ioc為我們帶來了什么好處我們還是從usb的例子說起,使用usb外部設(shè)備比使用內(nèi)置硬盤,到底帶來什么好處?第一、usb設(shè)備作為電腦主機(jī)的外部設(shè)備,在插入主機(jī)之前,與電腦主機(jī)沒有任何的關(guān)系,只有被我們連接在一起之后,兩者才發(fā)生聯(lián)系,具有相關(guān)性。所以,無 論兩者中的任何一方出現(xiàn)什么的問題,都不會影響另一方的運行。這種特性體現(xiàn)在軟件工程中,就是可維護(hù)性比較好,非常便于進(jìn)行單元測試,便于調(diào)試程序和診斷 故障。代碼中的每一個class都可以單獨測試,彼此之間互不影響,只要保證自身的功能無誤即可,這就是組件之間低耦合或者無耦合帶來的好處。第二、usb設(shè)

42、備和電腦主機(jī)的之間無關(guān)性,還帶來了另外一個好處,生產(chǎn)usb設(shè)備的廠商和生產(chǎn)電腦主機(jī)的廠商完全可以是互不相干的人,各干各事,他們之間 唯一需要遵守的就是usb接口標(biāo)準(zhǔn)。這種特性體現(xiàn)在軟件開發(fā)過程中,好處可是太大了。每個開發(fā)團(tuán)隊的成員都只需要關(guān)心實現(xiàn)自身的業(yè)務(wù)邏輯,完全不用去關(guān)心 其它的人工作進(jìn)展,因為你的任務(wù)跟別人沒有任何關(guān)系,你的任務(wù)可以單獨測試,你的任務(wù)也不用依賴于別人的組件,再也不用扯不清責(zé)任了。所以,在一個大中型 項目中,團(tuán)隊成員分工明確、責(zé)任明晰,很容易將一個大的任務(wù)劃分為細(xì)小的任務(wù),開發(fā)效率和產(chǎn)品質(zhì)量必將得到大幅度的提高。第三、同一個usb外部設(shè)備可以插接到任何支持usb的設(shè)備,可以

43、插接到電腦主機(jī),也可以插接到dv機(jī),usb外部設(shè)備可以被反復(fù)利用。在軟件工程中,這 種特性就是可復(fù)用性好,我們可以把具有普遍性的常用組件獨立出來,反復(fù)利用到項目中的其它部分,或者是其它項目,當(dāng)然這也是面向?qū)ο蟮幕咎卣?。顯 然,ioc不僅更好地貫徹了這個原則,提高了模塊的可復(fù)用性。符合接口標(biāo)準(zhǔn)的實現(xiàn),都可以插接到支持此標(biāo)準(zhǔn)的模塊中。第四、同usb外部設(shè)備一樣,模塊具有熱插拔特性。ioc生成對象的方式轉(zhuǎn)為外置方式,也就是把對象生成放在配置文件里進(jìn)行定義,這樣,當(dāng)我們更換一個實現(xiàn)子類將會變得很簡單,只要修改配置文件就可以了,完全具有熱插撥的特性。以上幾點好處,難道還不足以打動我們,讓我們在項目開發(fā)過程中使用ioc框架嗎?5. ioc容器的技術(shù)剖析ioc中最基本的技術(shù)就是“反射(reflecti

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論