Tomcat系统架构与设计模式

上传人:d**** 文档编号:134517765 上传时间:2022-08-13 格式:DOCX 页数:31 大小:781.53KB
收藏 版权申诉 举报 下载
Tomcat系统架构与设计模式_第1页
第1页 / 共31页
Tomcat系统架构与设计模式_第2页
第2页 / 共31页
Tomcat系统架构与设计模式_第3页
第3页 / 共31页
资源描述:

《Tomcat系统架构与设计模式》由会员分享,可在线阅读,更多相关《Tomcat系统架构与设计模式(31页珍藏版)》请在装配图网上搜索。

1、Tomcat系统架构与设计模式,第1部分:工作 原理简介:这个分为两个部分的系列文章将研究Apache Tomcat的系统架构以及其运用的很多经典 设计模式。本文是第1部分,将主要从Tomcat如何分发请求、如何处理多用户同时请求,还 有它的多级容器是如何协调工作的角度来分析Tomcat的工作原理,这也是一个Web服务器首 要解决的关键问题。发布日期:2010年5月20日本文以Tomcat 5为基础,也兼顾最新的Tomcat 6和Tomcat 4。Tomcat的基本设计思路和架 构是具有一定连续性的。Tomcat总体结构Tomcat的结构很复杂,但是Tomcat也非常的模块化,找到了 Tomc

2、at最核心的模块,您就抓 住了 Tomcat的“七寸”。下面是Tomcat的总体结构图: 图l.Tomcat的总体结构从上图中可以看出Tomcat的心脏是两个组件:Connector和Container,关于这两个组件将在 后面详细介绍。Connector组件是可以被替换,这样可以提供给服务器设计者更多的选择,因为 这个组件是如此重要,不仅跟服务器的设计的本身,而且和不同的应用场景也十分相关,所以一 个Container可以选择对应多个Connector。多个Connector和一个Container就形成了一 个Service, Service的概念大家都很熟悉了,有了 Service就可以

3、对外提供服务了,但是 Service还要一个生存的环境,必须要有人能够给她生命、掌握其生死大权,那就非Server莫 属了。所以整个Tomcat的生命周期由Server控制。以Service作为“婚姻”我们将Tomcat中Connector Container作为一个整体比作一对情侣的话,Connector主要负 责对外交流,可以比作为Boy,Container主要处理Connector接受的请求,主要是处理内部 事务,可以比作为Girl。那么这个Service就是连接这对男女的结婚证了。是Service将它 们连接在一起,共同组成一个家庭。当然要组成一个家庭还要很多其它的元素。说白了,Ser

4、vice只是在Connector和Container外面多包一层,把它们组装在一起,向外面 提供服务,一个Service可以设置多个Connector,但是只能有一个Container容器。这个 Service接口的方法列表如下:图 2. Service 接口O S&rvi ce6 getCcntairiei- 0。 zetContainer (Cuntainete getiTif.:- 0为 getN:diri& (.J6 setiraiiie (5tring)。 EGtS注糜:r lgurver)0 =idlC orLTiH ctor l.CDn-nect口r。 L Fl lie OrLT

5、L e C t u r 3 QG r em oveC mm已 c t mr CC onne c t or)Q ini t isdli iq Q从Service接口中定义的方法中可以看出,它主要是为了关联Connector和Container,同时 会初始化它下面的其它组件,注意接口中它并没有规定一定要控制它下面的组件的生命周期。所 有组件的生命周期在一个Lifecycle的接口中控制,这里用到了一个重要的设计模式,关于这 个接口将在后面介绍。Tomcat中Service接口的标准实现类是StandardService它不仅实现了 Service借口同时 还实现了 Lifecycle接口,这样它

6、就可以控制它下面的组件的生命周期了。StandardService类 结构图如下:图3. StandardService的类结构图S t :工ndmr dS er vi c e口corLTiectore : CijriTiect or 口 winer : Centainsr口debug: int亍info : String口ini:ed :bciule:dTLrL:=dTit :StringS11fecycle : LitecycleSupporteti : Str ingM :mager eerver : S&rverst:i2_Aed ;zup p mr t : Fr up er tyCh

7、 ;mge Supp or tgetCinntairLsr ClQtC i:mt ainyr IjZ i:m tain er )QEetllbug l.int JKetlritij IJge+N=iine (;i5etN:iin& fStriiLE)get 5 er Yer CJe st Sergei-=iddCc t -r匚 ohtl巨己 t -:-r )kj a。4 rem ijveCoTLrL&c tQr mm :-ve Fr op si- tythm t enei- (fr? p t yCh:in gmLi s * sn er)O 届 toS tri.ng 0。占:idiiLi tec

8、yrleLi stener ILl fecycleLi EterLer:ij“ Q 4 firniLL tecjrcl Li z tene?_s:)iG a rerri ciVtjLi 色Li 巳七屯f巨i:Li ft cycl eLi e)O心三七ar土 Ij若 a stop I.1O a ini ti :ali ze L):idiUr up er 上 yChaiLM Li s tene r I.Pr up er tyChaiL 莒 aL i st eTier .J l riIC uniL e c tor s L.Jur I.CoriiLector.l从上图中可以看出除了 Service接口

9、的方法的实现以及控制组件生命周期的Lifecycle接口 的实现,还有几个方法是用于在事件监听的方法的实现,不仅是这个Service组件,Tomcat中 其它组件也同样有这几个方法,这也是一个典型的设计模式,将在后面介绍。下面看一下StandardService中主要的几个方法实现的代码,下面是setContainer和 addConnector方法的源码:清单 1. StandardService. SetContainer public void setContainer(Container container) (Container oldContainer = this.contain

10、er;if (oldContainer != null) & (oldContainer instanceof Engine)(Engine) oldContainer).setService(null);this.container = container;if (this.container != null) & (this.container instanceof Engine)(Engine) this.container).setService(this);if (started & (this.container != null) & (this.container instanc

11、eof Lifecycle) try (Lifecycle) this.container).start(); catch (LifecycleException e) ;synchronized (connectors) for (int i = 0; i 心 String getInFo()Q Naming Resources getGlobalNarningReeourceefO void setGlobalNamingRescurces(NanriingResoLirces globaiNamingResources)e int getPortOQ void setPort(int p

12、ort)O String getShutdown() void setShutdcwnfString shutdown)Q void add5BrvicB(5Brvic& service。void aiuaitQq Service find5ervice(5tring name)Q 5ervice findServicesO。void removeService(Service service) void initialis&O它的标准实现类StandardServer实现了上面这些方法,同时也实现了 Lifecycle、 MbeanRegistration两个接口的所有方法,下面主要看一下S

13、tandardServer重要的一个方法 addService 的实现:清单 3. StandardServer.addServicepublic void addService(Service service) service.setServer(this);synchronized (services) Service results = new Serviceservices.length + 1;System.arraycopy(services, 0, results, 0, services.length); resultsservices.length = service; se

14、rvices = results; if (initialized) try service.initialize(); catch (LifecycleException e) e.printStackTrace(System.err);if (started & (service instanceof Lifecycle) try (Lifecycle) service).start(); catch (LifecycleException e) ;support.firePropertyChange(service, null, service);从上面第一句就知道了 Service和S

15、erver是相互关联的,Server也是和Service管理 Connector 一样管理它,也是将Service放在一个数组中,后面部分的代码也是管理这个新加 进来的Service的生命周期。Tomcat6中也是没有什么变化的。组件的生命线“ Lifecycle”前面一直在说Service和Server管理它下面组件的生命周期,那它们是如何管理的呢? Tomcat中组件的生命周期是通过Lifecycle接口来控制的,组件只要继承这个接口并实现其中 的方法就可以统一被拥有它的组件控制了,这样一层一层的直到一个最高级的组件就可以控制 Tomcat中所有组件的生命周期,这个最高的组件就是Serve

16、r,而控制Server的是Startup, 也就是您启动和关闭Tomcat o下面是Lifecycle接口的类结构图:图5. Lifecycle类结构图V 曜 -Q void ad dLfe cycleLi ete ner (Lifecy cl eListener listener)4 LiF ec/cl eListener FindLiFecy cl eListeners()e void removeLifecycleLi5tener(LiF8cycleLi5tener listener)Q void start()令 void stup()除了控制生命周期的Start和Stop方法外还有一

17、个监听机制,在生命周期开始和结束的时候 做一些额外的操作。这个机制在其它的框架中也被使用,如在Spring中。关于这个设计模式会 在后面介绍。Lifecycle接口的方法的实现都在其它组件中,就像前面中说的,组件的生命周期由包含它的父 组件控制,所以它的Start方法自然就是调用它下面的组件的Start方法,Stop方法也是一 样。如在Server中Start方法就会调用Service组件的Start方法,Server的Start方 法代码如下:清单 4. StandardServer.Start public void start() throws LifecycleException if

18、 (started) log.debug(sm.getString(standardServer.start.started);return;lifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null); lifecycle.fireLifecycleEvent(START_EVENT, null);started = true;synchronized (services) for (int i = 0; i services.length; i+) if (servicesi instanceof Lifecycle) (Lifecycle)

19、 servicesi).start();lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null);监听的代码会包围Service组件的启动过程,就是简单的循环启动所有Service组件的Start 方法,但是所有Service必须要实现Lifecycle接口,这样做会更加灵活。Server 的 Stop 方法代码如下:清单 5. StandardServer.Stoppublic void stop() throws LifecycleException if (!started)return;lifecycle.fireLifecycleEv

20、ent(BEFORE_STOP_EVENT, null); lifecycle.fireLifecycleEvent(STOP_EVENT, null);started = false;for (int i = 0; i services.length; i+) if (servicesi instanceof Lifecycle) (Lifecycle) servicesi).stop();lifecycle.fireLifecycleEvent(AFTER_STOP_EVENT, null); 它所要做的事情也和Start方法差不多。回页首Connector 组件Connector组件是T

21、omcat中两个核心组件之一,它的主要任务是负责接收浏览器的发过来的 tcp连接请求,创建一个Request和Response对象分别用于和请求端交换数据,然后会产生 一个线程来处理这个请求并把产生的Request和Response对象传给处理这个请求的线程,处 理这个请求的线程就是Container组件要做的事了。由于这个过程比较复杂,大体的流程可以用下面的顺序图来解释:图6. Connector处理一次请求顺序图IJ砰拍比嵌舞j 羽酒的索2. jEllUaIjic :J rI札沱5抵1花丘耳皿耻幻史*却硕行E请求割未f共SMkS:别0胎T 物宕hW睬.开用ml:讨细*行4 熨一宅丈小的W炬

22、他诵住湛IMS#、T.ZF.ZOX.4*FS&Sfc-sk+tlTXjitiiStriEmtp*甘重恒里旺姓鼬析!,叩独-以有巨谊吾个对客理 cumm.r 曰怦 F.:ae#iTF 洁CRt MlJL 卷河rrq i-、rWpBfiT用源L?心扣 &僦记客户共(杳看清晰大图Tomcat5中默认的Connector是Coyote,这个Connector是可以选择替换的。Connector最 重要的功能就是接收连接请求然后分配线程让Container来处理这个请求,所以这必然是多线 程的,多线程的处理是Connector设计的核心。Tomcat5将这个过程更加细化,它将Connector 划分成

23、Connector、Processor、Protocol,另外 Coyote 也定义自己的 Request 和 Response 对象。下面主要看一下Tomcat中如何处理多线程的连接请求,先看一下Connector的主要类图: 图7. Connector的主要类图s radnjnOc Service serslced trrigacd-es-s-d iht tn 肝5尚讦匚O Service qetSar84ffi()OService KrvkEi)4 rib 弓吐匚uno 三此 5 Time out)4 wod SStConncctionlEEUKkit CCTiniHtionTim-:.

24、 nt jcttcccpKaintOo void seCAiDcepKcuntth roint)O b如欢i g匚bunkhgAllg豚如HttpP.cqoDnteCnipl:? 5tnninFpbcobon alwCbjnhna。String gstirfrX) wd KtAlExChjnl-:jrib3dtan AJIoChdi.a bcoMn isChunhrqolwed():. 5trm gatPuotocalOQ !ciclreryde($ void senc&rorfrit istatuA String mesag司。vddreset()4 SeietCuqpLKTearj cre

25、a:E=OLi:pjtStr&3m)O.* wuEtalAighmM戚f Httpp旭i鸿wrtaoii&ai aydlahleHttpCEme-ctct ccnrsKtor i-1 debuginL idI i已:yrieGuppizrt IF&yd三趴知叫SEM5F0O.H NLaBlAxigmG旃曲UpOEneg-LflWrtn .& String tD5tring(),:, wid Migi(Sgrkj!t sockEt)Sachet wat()b vaki bgfsnrfl ides绍ce)3 Container g&tCont-ajrw0# xiridsetCart-aner(Cc

26、i:-3nEr cd.9 bnshfln gftnatlsLactjpHya vad 3tfEriabbLod:ijp5bolMn B曲 SeerSsjctetFactorj gtPHory。 ycli SEtFacbarSarwSKtF.,Siring geUrfaf)rit gE.sdrectFtrtQ8 vrxd jddUfecjrtlcLi女wtjLfecydclhten.0 LifecycIgLstEnerf fniLfecycIgLstErersO q void remwUfEccteJEteretLfedeLl. rad tart()7?s(杳看清晰大图看一下 HttpConne

27、ctor 的 Start 方法:清单 6. HttpConnector.Start public void start() throws LifecycleException if (started)throw new LifecycleException(sm.getString(httpConnector.alreadyStarted);threadName = HttpConnector + port + ; lifecycle.fireLifecycleEvent(START_EVENT, null);started = true;threadStart();while (curPro

28、cessors 0) & (curProcessors = maxProcessors)break;HttpProcessor processor = newProcessor();recycle(processor);threadStart()执行就会进入等待请求的状态,直到一个新的请求到来才会激活它继续执行,这 个激活是在HttpProcessor的assign方法中,这个方法是代码如下:清单 7. HttpProcessor.assignsynchronized void assign(Socket socket) while (available) try wait(); catch

29、(InterruptedException e) this.socket = socket;available = true;notifyAll();if (debug = 1) & (socket != null)log( An incoming request is being assigned);创建HttpProcessor对象是会把available设为false,所以当请求到来时不会进入while 循环,将请求的socket赋给当期处理的socket,并将available设为true,当available设 为true是HttpProcessor的run方法将被激活,接下去将会处

30、理这次请求。Run方法代码如下:清单 8. HttpProcessor.Runpublic void run() while (!stopped) Socket socket = await();if (socket = null)continue;try process(socket); catch (Throwable t) log(process.invoke”, t);connector.recycle(this); synchronized (threadSync) threadSync.notifyAll(); 解析socket的过程在process方法中,process方法的代码

31、片段如下: 清单 9. HttpProcessor.processprivate void process(Socket socket) boolean ok = true; boolean finishResponse = true; SocketInputStream input = null; OutputStream output = null; try input = new SocketInputStream(socket.getInputStream(),connector.getBufferSize(); catch (Exception e) log(process.crea

32、te,e); ok = false; keepAlive = true; while (!stopped & ok & keepAlive) finishResponse = true; try request.setStream(input); request.setResponse(response); output = socket.getOutputStream(); response.setStream(output); response.setRequest(request); (HttpServletResponse) response.getResponse() .setHea

33、der(Server, SERVER_INFO); catch (Exception e) log(process.create, e); ok = false; try if (ok) parseConnection(socket); parseRequest(input, output); if (!request.getRequest().getProtocol().startsWith(HTTP/0) parseHeaders(input);if (http11) ackRequest(output);if (connector.isChunkingAllowed() response

34、.setAllowChunking(true);o ooooo try (HttpServletResponse) response).setHeader(Date”, FastHttpDateFormat.getCurrentDate();if (ok) connector.getContainer().invoke(request, response); o o o o o otry shutdownlnput(input);socket.close(); catch (lOException e) catch (Throwable e) log(process.invoke, e);so

35、cket = null;当Connector将socket连接封装成request和response对象后接下来的事情就交给Container 来处理了 回页首Servlet 容器 “Container”Container是容器的父接口,所有子容器都必须实现这个接口,Container容器的设计用的是典 型的责任链的设计模式,它有四个子容器组件构成,分别是:Engine、Host、Context、 Wrapper,这四个组件不是平行的,而是父子关系,Engine包含Host,Host包含Context, Context 包含 Wrapper。通常一个 Servlet class 对应一个 Wr

36、apper,如果有多个 Servlet 就 可以定义多个Wrapper,如果有多个Wrapper就要定义一个更高的Container 了,如Context, Context通常就是对应下面这个配置:清单 10. Server.xml容器的总体设计Context还可以定义在父容器Host中,Host不是必须的,但是要运行war程序,就必须要 Host,因为war中必有web.xml文件,这个文件的解析就需要Host 了,如果要有多个Host就 要定义一个top容器Engine 了。而Engine没有父容器了,一个Engine代表一个完整的 Servlet 引擎。那么这些容器是如何协同工作的呢?先

37、看一下它们之间的关系图:图8.四个容器的关系图& String getlnfo()Q Loader getLoader() void setLoader(Loader loader)3 Logger getLogqer()3 void setLogger(Logqer logger)3 Manager getManagerf) void setManagerfManager manager)3 Object getMappingObject()3 Pipeline getPipeline()OCluster getClusterf)布ContainerBackgroundProcessor v

38、oid run()StandardWrapper3 void remove Vai ve( Valve valve)Q void start()Q void stop() ObjectName preRegister(MBean5.& void postRegister(Boolean argO)9 void 口佗0巳regi&Er()O 5tandardEngine()Q Realm getRealmOQ String getDefaultHost()Q void setDefaultHost(5tring host) void setName(5tring name)宙 S Log log

39、 long available NotificationBroadcasterSupport.祖 5t日idardEngine 眇 3 Log log String defaultHost0即酬巴& Valve getBasicO void setBasic(Valve valve) void addValve(Valve valve)G Valve getValves()0. .:+: HashMap children F H Ci ln i 门& int getDebugO void setDebug(int debug) int getBackgroundProcessorDelayQ3

40、 5trinq getlnfof)Q c StdridardWrapperOG long getAvailable()& void setAvailable(long available)& int getCountAllocatedf)& int getDebugO& void setDebug(int debug)& String getEnqineNameO& String getlnfo()StandardContext5tandardHost矛 T Log log String altDDName口 String hostNamen U _I rL.Lj;Lrl-;rL.If矛 u

41、Log log 5tring aliasesG c 5tandardContext()Q void setNdme(5trinq name)G boolean isCachingAllowedO3 void setCachingAllowed(boolean cachin.G void setCase5ensitive(boolean caseSen. Q c 5tandardHost() String getAppBase()9 void 5etMppBase(5biQ+di0 boolean getAutoDeploy() void setAutoDeployftiLioleari a.

42、(查看清晰大图)当Connector接受到一个连接请求时,将请求交给Container, Container是如何处理这个请 求的?这四个组件是怎么分工的,怎么把请求传给特定的子容器的呢?又是如何将最终的请求交 给Servlet处理。下面是这个过程的时序图:图9. Engine和Host处理请求的时序图i1 孝 耐 wr 0T.糖用目己的盅赣6.此队家职 LTLVOk J3 甄认变ERi FiVilt4. Ltmlft5. t. igfi tHo Et 0C Dm2 c 3mnt 航诳 rE孑句EM EtSlang ilfgWtlN(查看清晰大图)这里看到了 Valve是不是很熟悉,没错Val

43、ve的设计在其他框架中也有用的,同样Pipeline 的原理也基本是相似的,它是一个管道,Engine和Host都会执行这个Pipeline,您可以在这 个管道上增加任意的Valve,Tomcat会挨个执行这些Valve,而且四个组件都会有自己的一套 Valve集合。您怎么才能定义自己的Valve呢?在server.xml文件中可以添加,如给Engine 和Host增加一个Valve如下:清单 11. Server.xmlStandardEngineValve 和 StandardHostValve 是 Engine 和 Host 的默认的 Valve,它们是最 后一个Valve负责将请求传给

44、它们的子容器,以继续往下执行。前面是Engine和Host容器的请求过程,下面看Context和Wrapper容器时如何处理请求的。T面是处理请求的时序图:图10. Context和wrapper的处理请求时序图L1悴威序君更慝9.1 rf口r1!:3.反用目条唱查性B-WF笆SS开晦牛摧听节-童蝠煎禅厕-5. reonjQsjt. csiflir npp ur 07. LnvckU0.1赚邑业执行i*1 ftlJSc fi-Ip rffljSprff I, G rSiiSl. r nrl srrlhT引 hnrlftrrih3?i p jsir Vm I wiSi Riiri=从Tomcat

45、5开始,子容器的路由放在了 request中,request中保存了当前请求正在处理的Host、 Context 和 wrapperoEngine 容器Engine容器比较简单,它只定义了一些基本的关联关系,接口类图如下:图11. Engine接口的类结构( EngineQ String getDeultHostf)Q void setDeFaultHost(5tring deFaultHosk) string getJYrnR.QLite() void 5etJvmRoute(5tring jvmR.outeId) Service g&tS&ryic&() void set5ervice(5

46、ervice service) void add DeFaul tContextfDef aultConte xt defaultcontext) DefaultContejct getDefaultContextOG void i m por tDeFault Ccntext(Co nte xt context)它的标准实现类是StandardEngine,这个类注意一点就是Engine没有父容器了,如果调用 setParent方法时将会报错。添加子容器也只能是Host类型的,代码如下:清单 12. StandardEngine. addChildpublic void addChild(C

47、ontainer child) if (!(child instanceof Host)throw new IllegalArgumentException(sm.getString(standardEngine.notHost);super.addChild(child);public void setParent(Container container) throw new IllegalArgumentException(sm.getString(standardEngine.notParent);它的初始化方法也就是初始化和它相关联的组件,以及一些事件的监听。Host 容器Host是E

48、ngine的字容器,一个Host在Engine中代表一个虚拟主机,这个虚拟主机的作用 就是运行多个应用,它负责安装和展开这些应用,并且标识这个应用以便能够区分它们。它的子 容器通常是Context,它除了关联子容器外,还有就是保存一个主机应该有的信息。下面是和Host相关的类关联图:图12. Host相关的类图(查看清晰大图)从上图中可以看出除了所有容器都继承的ContainerBase夕卜,StandardHost还实现了 Deployer接口,上图清楚的列出了这个接口的主要方法,这些方法都是安装、展开、启动和结 束每个 web application。Deployer接口的实现是Stand

49、ardHostDeployer,这个类实现了的最要的几个方法,Host可以 调用这些方法完成应用的部署等。ContextContextContextContextWrapper容器代表Servlet的Context,它具备了 Servlet运行的基本环境,理论上只要有就能运行Servlet 了。简单的Tomcat可以没有Engine和Host。最重要的功能就是管理它里面的Servlet实例,Servlet实例在Context中是以出现的,还有一点就是Context如何才能找到正确的Servlet来执行它呢? Tomcat5 以前是通过一个Mapper类来管理的,Tomcat5以后这个功能被移到

50、了 request中,在前面的 时序图中就可以发现获取子容器都是通过request来分配的。Context准备Servlet的运行环境是在Start方法开始的,这个方法的代码片段如下:清单 13. StandardContext.start public synchronized void start() throws LifecycleException if( !initialized ) try init(); catch( Exception ex ) throw new LifecycleException(Error initializaing , ex);lifecycle.fi

51、reLifecycleEvent(BEFORE_START_EVENT, null);setAvailable(false);setConfigured(false);boolean ok = true;File configBase = getConfigBase();if (configBase != null) if (getConfigFile() = null) File file = new File(configBase, getDefaultConfigFile(); setConfigFile(file.getPath();try File appBaseFile = new

52、 File(getAppBase();if (!appBaseFile.isAbsolute() appBaseFile = new File(engineBase(), getAppBase();String appBase = appBaseFile.getCanonicalPath();String basePath =(new File(getBasePath().getCanonicalPath();if (!basePath.startsWith(appBase) Server server = ServerFactory.getServer(); (StandardServer) server).storeContext(this); catch (Exception e) log.warn(Error storing config file, e); else try String canConfigFile = (new File(getConfigFile().getCanonicalPath();if (!canCon

展开阅读全文
温馨提示:
1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
2: 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
3.本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
关于我们 - 网站声明 - 网站地图 - 资源地图 - 友情链接 - 网站客服 - 联系我们

copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!