C#和JAVA的插件机制-个人总结_第1页
C#和JAVA的插件机制-个人总结_第2页
C#和JAVA的插件机制-个人总结_第3页
C#和JAVA的插件机制-个人总结_第4页
C#和JAVA的插件机制-个人总结_第5页
已阅读5页,还剩23页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、插件框架插件介绍概念肯先山卄发人员编坷系统框架,井预先定义好 系统的扩展接口a插件由其他开发人员根据系 统预泄的接口编耳的护展功虑 实际上就是系 统的扩巖功能模块。插件都是以个独立文件 的形式出现*对于系统宋说并不知道插件的具体功能* UW 是为插件带下预定的接口,系毓启动的时候棍 据插II的配貰4找插件.根拥预疋的按口把插 件抹接到系统中。Eclipse插件架构Eclipse插件架构 Eclipsed Mi件结沟圧由父插件符理产插件* Miff Z间由扩展点琏接.£1终形成树形的结构。插件内部结构插件的内部结构runtime屁性描述了具需婆的Jar包.利发布的Jar包require

2、s属性描述了依赖的插件 extension-point描述了本插件过布可护廡的扩翹 extension屈性则描谜了扩展点的实现典型插件定义淸单文件描述(Plugin.xml)<piugin idquery-url* 件的ID name=''URL Query Filter 插件的名字 versions .OO11插件的版本provider-name-Mnu1ch,org S 插件的提供 1VID<runtime>library name=Hquery url.Jar"> 杭較的J前包 <export name=,m,/> 发布的Ja

3、rfl<library><runtinie><requires>< import plugi n= 'n utch - ex tension points* > 依帧的期件 </requires>extension id-org,apache.nutcksea cher urLURlQuer/Fifter''扩展前IDname=Nulch URL Query Filter1* 扩巖的若字poin:='ong.apache notch searcher OjeryFilterS 前愿|国丁 战点ID<

4、;iinplementa1ion id="URLQuEyFili打 丈现的IDclassog apachennutch.searcher.url.URLQueryF lterh> 1'洋交<parameter name 'fields' value'url 7> < 见餉和关属性c implcrr0ntu1ion> <extension></plugin>这个沽啊描述了捕件的绝人多数缶息,J 插件的id1 name- 木,和功类鸽飞同时 I圻 仃的扩展=扩驱点也都在这里定义,此插件对 外提供的嫌(包

5、牯Native/)以廉遥源也都妥这个文件的名称是* plugin.xml Eclipse启动 的时候会扫描"plugins%下的斫右 SlugirLxrmr文利,进血装戏所有刖插件”插件加载I插件加我插件基本结构ApplicationPlugin.xmlPlugin.xml应川程序加载插件时首先解析毎个插件的描述文件,然 后再应用程序屮动态加载抽f I屮的类,)调用耒中方法插件类加载-ClassLoader1 丨门!IU 载ClassLoaderCl日ssLo日de一顾名思义,就7L:JavaJp.llj来装 载类的部分,要将一个类的名字装载为JVM中 实际的二进制类数据。在JVM中

6、,任何一个类 被加载都是通过Class Loader来实现的同 时,每个Class对彖也都有一个引用指向装载 他的 ClassLoader,你可以通 jgetClassLoader() 方法得到它。插件加载ClassLoader ClassLoader使川所谓的"Delegation Model'* ( “双亲委托模型”)来 化找、定位类资源。每一个ClassLoader祁有口己一个父ClassLoader 实例(在构造的时候传入),当这个ClassLoader被要求加载一个类 时,它首先会询问自己的父ClassLoader,看看他是否能加载(注意: 这个过程是一宜递归向上的

7、),如果不能的话,才口己加载。 Java ClassLoader的体系结构是插件加较ClassLoader叮见,ClassLoader闫先会查找该类是否已经 被装载,如果没有,就询问自己的父 ClassLoader,如果还不能装载,就调用 findClass()方法来装载类。所以,一般简单的 自定义ClassLoaderH需要皤弓findClass方法 就可以了。插件加载过程简单插件加载过程现有一个主程序用Java语言写成。现在要允许 第三方开发人员编写扩展的类,约定第二方开 发的类必须包含个实现了某个已知接口)的 类,名称不限。如果要求第三力的类必须与主 程序的bytecode分开发布,把心

8、日爲放在 classpath相应位甕.或把j討丢在某个文件夹 内即可被动态装载使用,应如何实现?简单插件加载过不使用jar打包每个插件。里血包含一个实现已知 学1的类,在间的MANIFEST"F屮定义该类 的全略径(com.example.blah.MyPluginClass 这样。使 Hi java, util-jar 中的 JarFile 和 M anifest 类解析j日r包和Manifest文件用 URLCIassLoader装载该jar包。获得插件类斤, ffiClass.newlnstance() A 法创造实例L示例:简单的讦频播放器实现实现:先指定一个接口: 比如叫

9、com.g uoa o.l nterfaces. Playerinterface =. 插件必须包含一个类,实现这个接口。package com.guoao. interfaces; public interface Player Interface void LoadFile(String szFileName); void Play();void Paused;void Stop。;String GetSupportedFormal();创建一个插件。插件包含一个类,实现这个接口。这个类叫 com.guoao.MP3Playerpackage com.guoao;import com.gu

10、erfaces.Playerl nterface;public class MP3Player implements Playerinterface Overridepublic void LoadFile(String szFileName) System.out.println(szFileName+" is loading.Overridepublic String GetSupportedFormatO return new String(-mp3J;Overridepublic void Play() Systeni.out.println(wmp3 form

11、at is playing!");Overridepublic void Pause() System .out. pri nlln(” mp3 format is paused!');Overridepublic void Stop() System.out.pnnlln(”mp3 format is stopped!M);这个但将被打入一个jarRa我们还需耍一个MANIFEST. MF 文件Manifest 代码 Manifest-Version; 1.0Plugin-Class: com. guoao.MP3Player同理,音乐播放器对丁其他讥频格式的文件操作可以做

12、成 不同的插件,并打成jar包形式,应用程序会根据选择的不 同的苕频格式加载不冋的插件,从而实现了插件的功能。 Manifest-Version: 1.0 Plugin-Class: com. guoao.WMAPlayerMusicPIayer.classIcomguoaoLinterlacos Player Interface jluginsMP3PlayenjarWMAPlayer.jar总结总 .序并不了解plugins R录中有多少插件。 在运行时列举冃录.2.主程序对每个plugins文件(比如叫MP3Player.jar)的亍解只肴:MP3Player 的 METAJNF/MAN

13、IFEST.MF 中有 一个Plugin-Class属性,指左了该插件类的路 径(相当手plugin, xml作用),这个插件类拥有一个不带参数的构造方法。 这个插件类实现了com.guoa 0interfaces. Playerinterface 接 口。Eclipse插件加载过程Eclipse插件加载过程几个重要的类是: Plugin:插件类,描述每个具体插件; PluginDescriptor:插件描述符,记录了插件的ID片Name、Version依赖*扩亠展点等;PluginManager:插件管理器,负贵所何插件 资源的管理,包括扌击件的启动、停止、使能(Enable/Disable

14、)等等二PluginRegistry:插件注册表,提供了一个由插 件ID到Plugin的换射:系统启动流程系统的启幼流程;首先将所有的插件洁单读入("plugim.xmr),并 根据这个丈件解析UlPluginDescriptor (包括这个Plugin的所右导 出库、依赖插件、扩展点等等).放到PlugiriRegistry中。这个过 程也是整个插件平台的一个非常重要的部分,需要从插件清单中解 析的部分包插:1、每个插件所依赖的的插件列表(在"plugin.xml" fflrequire'1 element标识八2. 每个插件囉输出的资源利类(在&quo

15、t;plugin.xml*中用”library*' element标识八3, 每个插件所帀明的扩展点列衷:4、每个插件所声明的扩展列表(扩展其它扩展点的扩展)“当把所有的插件信息都读入到系统中,就可以 根据自己的需要来启动指定的插件了懒加载法则插件的外形(比如名字,ID,图标等等都在 插件描述淸单”plugin.xml冲芦明,而具体功能 封装在class文彳牛申。这种懒加载原则表现在务个方面,比如最基本 的插件启动。系统在启动的时候,只加载和启 动最必须的一些抽件,而其它抽件只有在真正 川到的时候才被加载和启动,这样可以最大限 度的节省系统启动时的资源和时间。而对用户 来说,每次启动也

16、确实有很多插件根本不会左 用到。构造Eclipse插件Eclipse中的插件用扩展点的机制连接起来,形成如下图所示的系统结 欷 插件必须实现扩展点,以此捕入到系统中.新増扩展点并不是必 须的,俣只仃新刑了扩展点的插件才可以被別人扩展。构造Eclipse插件在eclipse插件体系中,plugin.xml是插 件和Eclipse的接 U, Eclipse就彖一所火宅子,它的外瑞(plugin.xml) 很多的门(扩展点),我们更熟练进出这座大宅子,得 搞消楚它有哪些门示例;透视图的建立构造Eclipse插件 修改plugin.xml文件.设辻透视图的扩展点 打开plugin.xml文件的編耕帕

17、将如下代码块插入到戢祈彳r的v/plugin>Z前: oxtension= point=°org.eclipse.ui.perspectivesM>perspective name=wmyplugin 透视图' iconicons/selectalLgif class Jmyplugi n. actions. SamplePerspective” id=Mmyplugin.actio ns.SamplePerspective、</perspedive><extension>透视图类: /文件名:SamplePerspective.java

18、public class SamplePerspective implements I Perspective Factory Override public void createlnitialLayout(IPageLayout layout) Eclipse插件开发为透视添加视图:修改plugin.xml,实现扩展点<extensionpointorg.eclipse.ui.views<categoryname=Mmyplugin 视图”id=Hcom.guoao.myplugin.view"></category> <viewname视图什

19、icon 二” icons/prev.gif”category 二” com. guoao.myplugin.view” class=,'myplugin.actions.View1H id="myplugin.actions.Viewl '*> </view> <viewname=H 视图 2” icon:=”ic on s/prev.gif” category=,com.guoao.myplugin.viewH class="myplugin.actions.View2n id=nmyplugin.actions.View2,&g

20、t;</view></extensi on>视图类的实现Viewl .javaVie w2. java.在透视图屮显示视图:修改透视图类 SamplePerspectiveJava插件框架概述开放工厂 OSGi.NET插件框架,是 OSGi R4.2规范移植到.NET平台的实现。OSGi全称为Open Service Gateway Initiative,它一方面指由 IBM、Oracle、BEA SAP等国际 IT 巨头组成的 OSGi 联盟组织;另一方面指该组织制定的一个基于Java语言的服务规范 一一OSG服务平台。OSGi.NET插件框架提供了模块化与插件化、面

21、向服务架构和模块扩展三大功能,适用于控 制台、WinForm、Windows服务、WPF、ASPNET和移动平台等任意.NET应用环境。 目前,OSG i已经得到广泛的应用,如下所示。WebSphere,ORACLe4帶 ParemusE O ProSyst插件程序结构基于OSGi.NET插件框架的应用程序体系结构如下图所示。在这里,应用程序由主程序和插件组成。主程序 是具体的应用环境的入口,它用于启动OSGi.NET插件框架并进入插件框架暴露出来的入口点;应用插件则是实现软件不同功能的业务模块。OSGi.WET插件框架主程序(Console r WinFormASP.NET 等)OSGi.N

22、ET插件框架优点开放、规范、统一:符合规范的模块均可被OSGi.NET插件框架加载快速集成:将模块放在插件模块即实现功能集成。高度可重用:仅通过拷贝即可实现重用,无需修改任何代码。热插拔与动态:每一个模块都可被动态安装、启动、停止和卸载。标准模块化与模块物理隔离:模块具有统一规范且互相独立。面向服务编程支持:提供基于面向服务架构编程模型以支持模块通讯。 动态可扩展:通过暴露扩展点实现动态扩展。多环境支持:支持各种.NET应用环境。插件框架原理插件和插件运行时在OSGi.NET插件框架中,插件即 Bundle,它具备物理隔离、热插拔和动态特性。每一个插件都是完全可复 用的,可以被动态的安装、启动

23、、停止、卸载或更新。插件运行时即BundleRuntime,则是插件的运行容器,它负责从插件目录中加载和启动插件。面向服务在OSGi.NET插件框架中,插件具备高内聚、低耦合特性,也就是说插件间耦合度非常低。服务即Service,是插件通讯的方式。在这里,服务=接口 +实现”接口是服务的契约,服务提供商实现了服务的接口并将服务注册到服务总线,服务消费者则通过服务契约从服务总线搜索服务并绑定使用。这里,服务是动态,可以被动态注册、卸载和更新,一个服务契约也可能有多个服务实现。插件运行时BundleRuntime插件扩展在OSGi.NET插件框架,插件具备可扩展性,可以在不变更插件代码情况下,更改

24、或者扩展插件的行为。这 个扩展机制是通过一对基于 XML格式的扩展点+扩展”来实现的。一个插件可以通过定义扩展点”来实现 可扩展,而其它插件则通过定义对应的扩展”来注册/更新功能。扩展/扩展点在插件启动时注册到插件运行时,相反,在卸载时,则从插件运行时卸载。插件运行时Bun die Runtime片段插件在OSGi.NET有一种特殊的插件,称为片段插件,即Fragment Bundle。片段插件相当于子插件,其作用是为了扩充其它插件的类型空间、扩展信息。除了片段插件的插件,都是宿主插件(Host Bundle)。与宿主插件不同的是,片段插件不能被启动、停止,没有类加载器,不允许从片段插件加载类

25、型。当宿主插件被启 动后,片段插件会自动附加到宿主插件,即将片段插件的类型空间、扩展信息合并到宿主插件。片段插件片段插件FragmenTrragrherrBundleBundlemH扩展点 Ext ension Point扩廣Extens ion插件IL U赫件BundleBundleBundle服务 5ervi<e使用展务Service服务拾线Service Reg istry插件运行a寸BundleRuntime开放工厂原理开放工厂原理概述开放工厂主要由iOpenWorks开放工厂平台和 OSGi.NET插件SDK组成。开发者从iOpenWorks开放工厂平台中下载到OSGi.NET

26、插件SDK 并使用该SDK的项目模板来创建一个插件应用程序。开放工厂原理图如下所示。插件仓阵牺件版本曾理SDK,客户端管理OSGirtft相共哀仲骨理捕件仓ftOpenAPIiOpenW开放工厂平台iOpenWorkS$DK? OSGi-NETftti架、顶目模扳、工具、文档和示例iOpenWorks开放工厂平台主要由插件仓库和插件仓库OpenAPI组成。插件仓库实现插件的版本管理、OSGi.NET内核文件版本管理、SDK及客户端管理,而插件仓库 OpenAPI则向外 暴露了插件及其版本信息、内核文件及其版本信息从而为客户端提供内核及插件的自动升级支持。OSGi.NET插件SDK由开发者安装,

27、向开发者提供了 OSGi.NET插件框架、OSGi.NET Web扩展、 iOpenWorks启动程序这三个开发程序集,此外,还提供了插件项目模板、远程管理控制台(用于调试用,可以查看OSGi.NET内核情况)、文档、示例。开发者使用OSGi.NET插件SDK 的项目模板来创建 WinForm或者Web插件应用程序时,这个模板默认实现了:( 1)调用iOpenWorks启动程序程序集来检查内核文件版本并执行更新;(2 )创建插件运行时BundleRuntime并运行,从而启动插件内核,默认从Plugins目录加载插件;(3)高级模板默认包含了页面流服务插件、应用中心插件、插件管理服务插件、远程

28、管理服务插件、WebService包装器服务插件(插件自动升级插件没有在模板中包含,可以从插件仓库中下载)OSGi.NET插件应用程序运行流程及插件协作关系概述使用OSGi.NETf件SDK创建的插件应用程序结构如下所示。这个默认的模板中包含了开放工厂原理图所述的iOpenWorks启动程序、OSGi.NET插件框架、默认的几个插件。当这个插件程序运行后,它首先调用iOpenWorks启动程序来检测OSGi.NET插件框架等内核 文件版本并下载更新,接着启动插件运行时,从Plugins目录中加载并启动插件。在这里,iOpenWorks启动程序将调用开放工厂平台的插件仓库OpenAPI检查是否有

29、新版本的内核并从仓库中下载最新版本的文件(如原理图的箭头7所示)。在启动插件过程中,如果应用程序下载安装了自动更新插件,该插件会调用插件管理服务来检查插件仓库更新情况,并自动下载最新版本的更新包,等重新启动应用程序时,执行自动更新。在这里,插件管理服务将调用开放工厂平台的插件仓库OpenAPI来获取插件仓库的新插件 和新版本的插件并利用OpenAPI进行下载安装或升级插件(如原理图的箭头 5、6所示)。插件运行时启动完成后,主程序从运行时获取页面流服务,获取入口点并运行入口插件的程序,进入主界面或者插件中心插件(如原理图的箭头1所示)。插件中心插件也将调用插件管理服务,获取开放工厂插件仓库的新

30、插件和插件的最新版本, 当点击下载插件时,利用插件管理服务从插件仓库下载安装或升级插件(如原理图的箭头4、6所示)。此外,当插件运行时启动完成后,远程管理服务插件利用 WebService服务包装器将 OSGi.NET内核管理功能暴露成 Web服务,这样 OSGi.NET插件SDK的远程管理控制台运行起来后, 便可以调用该 Web服务实现内核插件、服务浏览以及插件启动、停止、卸载和安装操作, 方便插件程序的 调试(如原理图的箭头 2、3所示)。开放工厂插件机制插件在OSGi.NET插件框架中,插件是一个具备物理隔离性、完全重用的功能模块。在这里插件=Manifest.xml +类+资源” Ma

31、nifest.xml是插件的描述文件,位于插件目录的根目录下;类即插件的类型空间,由插件自 身的程序集和依赖的插件/依赖的程序集组成,资源类似与类,由插件本身的资源和依赖的资源组成。插件目录柘杵根冃录BundleLocatian插件由Manifest.xml插件清单文件、程序集、资源组成,程序集和资源位于插件根目录或者子目录下。其 标准目录结构如下。* Manifest.xmUf件清单文件>*.dll程序集文件>具它资源文件稈序集文件具它资忑丈n插件类加载在OSGi.NET插件框架中,插件拥有独立的目录结构,具备物理隔离性。相应地,每一个插件有独立的类型 空间,这个类型空间由插件程

32、序集、插件依赖的程序集、片段插件程序集和片段插件依赖的程序集组成。 插件的类型是由插件类加载器来加载的。.MET杠聖程序集脱鮒呈序案当你在插件中使用myClass = newMyClassInBundle(),插件类加载器会按照上面的顺序搜索需要加载的MyClasslnBundle类型。与此同时,你也可以通过调用插件对象的LoadClass方法(IBundle.LoadClass)从插件类型空间中动态加载一个类型。插件生命周期在OSGi.NET插件框架中,插件具有生命周期。 插件生命周期状态有:Installed、Resolved Active、Uninstalled 四个可见状态和 Star

33、ting、Stopping两个临时状态。其中,Installed表示插件已经安装;Resolved表示插件依赖的程序集或者依赖的插件已经满足,这个插件可以被正常启动;Active则表示插件已经被成功启动;Uninstalled表示插件已经被卸载。Starting是一个过渡状态,当启动插件时,如果插件使用了晚激活策略, 则插件在注册扩展信息、服务信息之后,直接返回,不会执行激活器的Start方法,这个方法会推迟到第一次从这个插件加载类型时调用并进入Active状态;反之,如果没有使用晚激活策略,插件会调用激活器 Start方法并进入Active状态。在启动过程,如果出现异常,则插件会自动转回Re

34、solved状态。Stopping是另一个临时状态,在停止插件时,首先进入该状态,然后调用激活器的Stop方法后进入Resolved状态。安装更新或屁斯StartingJActive)荐止Stmuiriq)Unin&tallEd丿插件运行时和插件启动过程插件框架启动时,首先从插件目录中发现并加载所有的插件;然后,对插件进行依赖解析, 判断插件依赖的程序集和依赖的插件是否满足;接着,按照启动级别顺序启动所需的插件; 一旦插件启动完成,则插件框架便完成启动。在插件启动过程中,将按照创建插件上下文、注册扩展点/扩展信息、注册服务信息、创建插件激活器并调用 Start方法的顺序完成一个插件的启

35、动过程。如果插件实现的晚激活,则 推迟最后一步的执行, 直到第一次从插件加载类型;如果插件没有定义激活器,则忽略最后_. rH步0刨崖启动插曲运石时扣载插件r解析插件依赖r启前所*插件运行时启动完成创建插件上下文注開扩展点/T展信息注册服务涪息创產插件激活聽并调用5伯rt方法需眉就£存插件相关对象插件运行时BundleRuntime插件运行时BundleRuntime代表插件框架内核对象,它是所有插件的运行容器。在示例中,控制台主程序在 Program的Ma in函数中,通过创建Bun dleRu ntime对象并调用其 Start方法 来启动插件框架内核。当Start方法调用完成后

36、,BundleRuntime对象将从插件目录中加载插件并启动插件。通过以下代码,您就可以创建并启动插件框架,然后加载并启动所有插件。/创Matter时对象默认堀件吕录APlugir口录.lsing (Bundi更Rr time bundleRuntirr - new BLndl-=Runtifne()bundleRuri-J.me.Sta; /启动插杵运冇E,加载莽启动擂件目录下的所有插件+匚onsole.WritcLine"'Tress ny key to exit.,hJ;匚onsole,Read();认识插件插件也称为Bundle,从OSGi.NET规范上讲,插件=Ma

37、nifest.xml +类+资源”其中, Manifest.xml即插件清单文件,用于描述插件的基本信息、类型信息和扩展信息;插件具备隔离的类型空间,由插件本身的程序集和依赖的插件的程序集组成;插件拥有自己的资源,存放在私有的文件夹。在定义一个插件时,您只需要关注三个非常重要的接口,分别是:插件激活器IBundleActivator、插件IBundle和插件上下文IBundleContext。其中,插件激活器由开发人员自己定义;而插件 IBundle和插件上下文IBundleContext则由插件内核创建, 你可以在插件激活器获取中获取到这两个对象。插件清单 Manifest.xml插件清单文

38、件(Manifest.xml )位于模块标准目录结构的根目录之下,它定义了模块的基本信息、模块激活 信息、模块类加载相关的运行时信息、服务定义信息、模块扩展定义信息以及模块详细信息。< ?jtml version-" I er:ading-" j-、i Bundle Jtmln£-"urn : Liosp-bur dls-rar±rst-2*0h Symijollch3ellPluin"srmion -11二丽陆 - "ghwl-PL碍 ir In it 15 lizt! J5 ta te-"vs11 Sta

39、rtLeel'-"2"><Activator Type"ShellPlugln,Activat&r" Policy-"JrwiedlBte' /><Runtinie><Lienibly Pdth=Hbi AShllPugir.Jl_,* 百h(j任J'hhh /></Runti.Tie><ExtenslonPuin't Pain*t="5hellPlugir.Meriu5ta"ip" />< /liind

40、lo以上清单文件定义了该模块的一个本地程序集“binShellPlugin.dll ,'该程序集位置相对于模块的根目录,当然,你也可以指定一个绝对目录。模块还定义了一个激活器和扩展点。IBundleActivatorIBundleActivator表示插件激活器,是插件的入口和出口,用于在插件启动或停止时执行相关操作。插件激活器通过 Manifest.xml的Activator节点配置,当插件被启动时插件激活器的Start方法被调用, 当停止时Stop方法被调用。在插件激活器的 Start/Stop方法的context参数,即插件上下文IBundleContext对象,通过IBundleContext您 还可以获取对应的插件IBundle实例。以下是一个激活器定义的示例。你需要在插件清单文件Manifest.xml添加一个激活器配置:vActivatorType="HelloBundle.Activator" Policy="lmmediate" /> 。usi

温馨提示

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

评论

0/150

提交评论