CloudStack源碼分析_第1頁
CloudStack源碼分析_第2頁
CloudStack源碼分析_第3頁
CloudStack源碼分析_第4頁
CloudStack源碼分析_第5頁
已閱讀5頁,還剩39頁未讀, 繼續(xù)免費閱讀

下載本文檔

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

文檔簡介

1、目錄CLOUDSTACK源碼分析31.用CLOUDSTACK的源碼進行工作31.1.源碼獲得方式32.包與依賴32.1.包32.2.依賴42.3.未來53.異常與日志53.1.日志53.2.異常和異常捕獲63.3.CloudStack異常84.代碼聯(lián)合工作94.1.組件94.2.組件加載105.CLOUDSTACK API開發(fā)115.1.如何編寫API115.2.API注解165.2.1.API命令注解165.2.2.API響應注解176.CLOUDSTACK中使用SPRING176.1.CloudStack組件186.2.如何聲明一個CloudStack組件196.3.Auto-wiring

2、196.4.CloudStack Spring組件的編碼約定206.4.1.注意自動注入的時間206.4.2.公用構(gòu)造器206.4.3.組件自主初始化206.4.4.運行時注入216.4.5.CloudStack定制化AOP(面向切面的編程)216.4.6.可插拔適配器246.4.7.模塊和組件266.4.8.什么時候用或者不用Inject286.5.組件生命周期287.數(shù)據(jù)訪問層297.1.需要知道的297.2.在哪能找到例子297.3.DAO297.4.寫一個新的VO和DAO307.5.使用347.5.1.使用DAO347.5.2.更新VOs347.5.3.搜索347.5.4.使用事務36

3、7.5.5.處理嵌套事務387.5.6.處理鎖388.使用JUNIT和SPRING進行單元測試38CloudStack源碼分析1. 用CloudStack的源碼進行工作1.1. 源碼獲得方式使用git將源碼克隆到本地:git clone /repos/asf/cloudstack.git切換版本:git checkout <分支>2. 包與依賴2.1. 包下面的表格列出了所有的包與其作用,如果你想為CloudStack添加代碼,請閱讀這個列表再決定將代碼添加到哪個包里面項目包名作用說明utilscloud-util.jar可以

4、在任何項目中使用此工具集apicloud-api.jarREST APIAgent APIJava APIcorecloud-core.jarServerResource實現(xiàn)servercloud-server.jar管理服務器agentcloud-agent.jar代理容器ovmcloud-ovm.jarOracle VM的ServerResource未來的ServerResource包agent-simulatorServerResource模擬與回歸測試vmware-baseVMWare的ServerResource2.2. 依賴包的依賴關(guān)系反應了CloudStack設(shè)計的重要性,因此不

5、應該改變包的關(guān)系。ovm、vmware-base、agent-simulator和core是所有ServerResource基于cloud-api的實現(xiàn),按照這種設(shè)計,這些包都不會訪問數(shù)據(jù)庫。cloud-agent是基于cloud-api的序列化和反序列化實現(xiàn),但是理想情況下,cloud-agent僅僅作為容器并且應當基于cloud-util。2.3. 未來CloudStack在未來會向上面這種結(jié)構(gòu)進行轉(zhuǎn)變,并且將API劃分為以下三種:包作用格式cloud-api運行、管理、維護和配置(OAM&P)、最終用戶RESTcloud-plugin-api補充功能APIJavacloud-ag

6、ent-api與ServerResource溝通APIJSON3. 異常與日志CloudStack沒有一個非常強大的異常與日志,不是我們只說不做,是因為我們并不擅長,不過我們一直努力在做好這些事情。3.1. 日志CloudStack使用log4j進行日志記錄,可以使用一些日志方案。雖然log4j很老,但是確實很好,并且真正重要的不是工具而是內(nèi)容。CloudStack應當部署在INFO或者以上級別,并使用GMT標準時間。修改日志級別并不需要重啟CloudStack,下面是推薦日志級別以供參考:級別何時使用FATAL服務宕機或者JVM宕機ERROR系統(tǒng)出現(xiàn)了不能修復的問題,但是不影響系統(tǒng)的運行,只

7、會造成特定請求失敗WARNING系統(tǒng)出現(xiàn)了問題,并且可以修復,管理員如果想了解,可以看看此類日志INFO管理員比較關(guān)注這些信息DEBUG此類信息有助于管理員調(diào)試問題,出現(xiàn)FATAL或ERROR信息時,可以打開DEBUG,以提供足夠的信息調(diào)試問題TRACE重復并且討厭的日志,不應該在正常調(diào)試中打開它,不過實在解決不了問題的時候可能有用3.2. 異常和異常捕獲下面是一些異常處理的示例:1、如果正在編寫切入點代碼,需要由你捕獲所有異常(檢查異常和非檢查異常),并且妥善記錄所有錯誤,你可以這樣做:try     code.; catch (Exception s

8、pecific to your code)     Specific exception handling and logging. catch (Exception e)     s_logger.warn("Caught unexpected exception", e);    exception handling code.2、如果你不是編寫切入點代碼,可以這樣做:try     code.; catch (

9、XenAPIException e)     / Do either this: s_logger.warn("Caught a xen api exception", e);    / or throw new CloudRuntimeException("Caught a xen api exception", e);    / Don't ever do JUST this.    

10、throw new CloudRuntimeException("Got a xen api exception"); 3、永遠不要聲明一個方法直接拋出異常public void irresponsibleMethod() throws Exception;public void responsibleMethod() throws XenAPIException;public void runtimeExceptMethod(); /拋出的CloudRuntimeException 不應該被記錄到切入點public void innocentCaller()  

11、   try         irresponsibleMethod();        responsibleMethod();        runtimeExceptionMethod();     catch(Exception e)     

12、;    s_logger.warn("Unable to execute", e);        throw new CloudRuntimeException("Unable to execute", e);        / 這里有什么錯?        / 1. 如果異

13、常是從responsibleMethod拋出的,調(diào)用者可能會忘記處理XenAPIException        / 2. 如果異常是從runtimeExceptionMethod拋出的,調(diào)用者會重復處理異常    4、永遠不要拋出異常本身,如果需要拋出檢查異常,你需要找到一個合適的去使用,如果是非檢查異常,例如空指針,你可以拋出CloudRuntimeException5、不要把原來的異常再次拋出try     some code;

14、catch(XenAPIException e)     / catch generic error here.    s_logger.debug("There's an exception.  Rolling back code: " + e.getMessage();    .rollback some code;    throw e; / note there's no "

15、;new" here.6、如果你有一個后臺任務列表,處理每個任務的異常都非常重要,如果有任何一個異常沒有處理,可能會導致災難性后果:for (Task task : taskList)     try         process task;     catch (Exception e)         .handle exception an

16、d continue    3.3. CloudStack異常異常被誰拋出作用使用CloudRuntimeException任何發(fā)生了不能捕獲的異常盡可能多的輸出可調(diào)試信息ResourceUnvailableException組件的處理與資源分配物理資源不能使用異常必須在某個范圍內(nèi),告訴調(diào)用者異常影響的是主機、存儲池、集群、提供點還是區(qū)域,以便調(diào)用者重試InsufficientCapacityException組件的處理與資源分配物理資源超出范圍異常必須在某個范圍內(nèi),告訴調(diào)用者異常影響的是主機、存儲池、集群、提供點還是區(qū)域,以便調(diào)用者重試4. 代碼聯(lián)合工

17、作目前,你可能看到了很多不同的代碼,是不是感覺非常混亂?怎么下手?怎么讓他們工作起來?下面就來告訴你。4.1. 組件CloudStack部署了下面一些組件,它們都是單例并且數(shù)據(jù)處理都經(jīng)過它們,不過每個組件有不同的作用。類型作用示例Manager單獨控制過程VirtualMachineManagerAdapter不同的方式實現(xiàn)相同的功能,適配器通常用于到達一個步驟時,用多種方式實現(xiàn)這個步驟FirstFitDeploymentPlannerDAO數(shù)據(jù)訪問層HostDAOService支持平臺API的Java APIUserVmServicePluggableService定義了一套平臺API插入到

18、CloudStack中F5ExternalLoadBalancerElementServiceSystemIntegrityChecker保證管理節(jié)點啟動的完整性DatabaseUpgradeCheckerComponenLibrary部署管理、適配器、DAO的集合DefaultComponentLibraryInterceptor為執(zhí)行過程提供面向切面的實現(xiàn)DatabaseCallback4.2. 組件加載組件的加載聲明在components.xml中,下面是示例:<?xml version="1.0"?><components.xml><s

19、ystem-integrity-checker><checker name="ManagementServerNode"/><checker name="DatabaseIntegrityChecker"/><checker name="DatabaseUpgradeChecker"/></system-integrity-checker><interceptor library="com.cloud.configuration.DefaultInterceptor

20、Library"/><management-server library="com.cloud.configuration.DefaultComponentLibrary"><adapters key="work.guru.NetworkGuru"><adapter name="GuestNetworkGuru"/><adapter name="OvsGuestNetworkGuru"/><adapter name="PublicNet

21、workGuru"/><adapter name="PodBasedNetworkGuru"/><adapter name="ControlNetworkGuru"/><adapter name="DirectNetworkGuru"/><adapter name="DirectPodBasedNetworkGuru"/></adapters></management-server></components.xml>

22、5. CloudStack API開發(fā)5.1. 如何編寫API1、在plugins文件夾中創(chuàng)建文件夾,例如:cloudstack/plugins/api/timeofday2、在文件夾中創(chuàng)建pom.xml,確保parent定位到plugins/pom.xml,否則將無法編譯。<project xmlns="/POM/4.0.0" xmlns:xsi="/2001/XMLSchema-instance"  xsi:schemaLocation="

23、/POM/4.0.0 /xsd/maven-4.0.0.xsd">  <modelVersion>4.0.0</modelVersion>  <artifactId>cloud-plugin-api-timeofday</artifactId>  <name>Apache CloudStack Plugin - TimeOfDay</name> 

24、60;<parent>    <groupId>org.apache.cloudstack</groupId>    <artifactId>cloudstack-plugins</artifactId>    <version>4.1.0-SNAPSHOT</version>    <relativePath>././pom.xml<

25、/relativePath>  </parent>  <dependencies>    <dependency>      <groupId>org.apache.cloudstack</groupId>      <artifactId>cloud-api</artifactId>  

26、    <version>$project.version</version>    </dependency>    <dependency>      <groupId>org.apache.cloudstack</groupId>      <artifactId>cl

27、oud-utils</artifactId>      <version>$project.version</version>    </dependency>    <dependency>      <groupId>mysql</groupId>     &#

28、160;<artifactId>mysql-connector-java</artifactId>      <version>$cs.mysql.version</version>      <scope>provided</scope>    </dependency>  </dependencies> &#

29、160;<build>    <defaultGoal>install</defaultGoal>    <sourceDirectory>src</sourceDirectory>    <testSourceDirectory>test</testSourceDirectory>    <plugins>   

30、;   <plugin>        <artifactId>maven-surefire-plugin</artifactId>        <configuration>          <skipTests>true</skipTe

31、sts>        </configuration>        <executions>          <execution>            <phas

32、e>integration-test</phase>            <goals>              <goal>test</goal>           &

33、#160;</goals>          </execution>        </executions>      </plugin>    </plugins>  </build></project>3、為

34、新插件添加以下片段到cloudstack/plugins/pom.xml,mvn編譯時會知道這個插件需要編譯<module>api/timeofday</module>4、創(chuàng)建src、target、test目錄5、創(chuàng)建代碼包結(jié)構(gòu),plugins/api/timeofday/src/com/cloud/test6、創(chuàng)建接口,繼承PluggableServicepackage com.cloud.test;import ponent.PluggableService;public interface TimeOfDayManager extends PluggableSer

35、vice 7、創(chuàng)建接口實現(xiàn)類,重寫getCommands方法package com.cloud.test; import ponent.PluggableService;import java.util.List;import java.util.ArrayList;import org.apache.log4j.Logger;import com.cloud.test.GetTimeOfDayCmd;import javax.annotation.PostConstruct;import org.springframework.stereotype.Component;import

36、 javax.ejb.Local; ComponentLocal(value = TimeOfDayManager.class )public class TimeOfDayManagerImpl implements TimeOfDayManager     private static final Logger s_logger = Logger.getLogger(TimeOfDayManagerImpl.class);     public TimeOfDayManagerImpl()

37、        super();         Override    public List<Class<?>> getCommands()         List<Class<?>> cmdList = new ArrayList<Class<

38、;?>>();        cmdList.add(GetTimeOfDayCmd.class);        return cmdList;    8、編寫一個類來實現(xiàn)注解方式的命令package com.cloud.test; import javax.inject.Inject;import org.apache.log4j.Logger; import

39、org.apache.cloudstack.api.BaseCmd;import org.apache.cloudstack.api.APICommand;import org.apache.cloudstack.api.Parameter; APICommand(name = "getTimeOfDay", description="Get Cloudstack's time of day", responseObject = GetTimeOfDayCmdResponse.class, includeInApiDoc=true)pu

40、blic class GetTimeOfDayCmd extends BaseCmd     public static final Logger s_logger = Logger.getLogger(GetTimeOfDayCmd.class.getName();    private static final String s_name = "gettimeofdayresponse"     Parameter(name="ex

41、ample", type=CommandType.STRING, required=false, description="Just an example string that will be uppercased")    private String example;     public String getExample()         return this.example;

42、60;        Override    public void execute()            GetTimeOfDayCmdResponse response = new GetTimeOfDayCmdResponse();        if ( this.e

43、xample != null )             response.setExampleEcho(example);                 response.setObjectName("timeofday"); / the inner part of the json

44、structure        response.setResponseName(getCommandName(); / the outer part of the json structure         this.setResponseObject(response);         Override  &

45、#160; public String getCommandName()         return s_name;         Override    public long getEntityOwnerId()         return 0;   

46、0;9、為命令編寫響應類package com.cloud.test; import org.apache.cloudstack.api.ApiConstants;import com.cloud.serializer.Param;import com.google.gson.annotations.SerializedName;import org.apache.cloudstack.api.BaseResponse; import java.util.Date;import java.text.SimpleDateFormat; SuppressWarning

47、s("unused")public class GetTimeOfDayCmdResponse extends BaseResponse     SerializedName(ApiConstants.IS_ASYNC) Param(description="true if api is asynchronous")    private Boolean isAsync;    SerializedName("timeOfDa

48、y") Param(description="The time of day from CloudStack")    private String  timeOfDay;    SerializedName("exampleEcho") Param(description="An upper cased string")    private String  exampleEcho;&

49、#160;    public GetTimeOfDayCmdResponse()        this.isAsync   = false;         SimpleDateFormat dateformatYYYYMMDD = new SimpleDateFormat("yyyyMMdd hh:mm:ss");  &#

50、160;     this.setTimeOfDay( (new StringBuilder( dateformatYYYYMMDD.format( new Date() ) ).toString() );         public void setAsync(Boolean isAsync)         this.isAsync = isAsync; 

51、60;       public boolean getAsync()         return isAsync;         public void setTimeOfDay(String timeOfDay)         this.timeOfDay = time

52、OfDay;         public void setExampleEcho(String exampleEcho)         this.exampleEcho = exampleEcho.toUpperCase();    10、修改client/tomcatconf/componentContext.xml.in,添加新命令<bean id="timeOf

53、DayManagerImpl" class="com.cloud.test.TimeOfDayManagerImpl"></bean>11、修改client/tomcatconf/perties.in,添加命令名稱1 = ADMIN2 = RESOURCE_DOMAIN_ADMIN4 = DOMAIN_ADMIN8 = USER12、將插件作為依賴添加到client/pom.xml中,你可以看到里面的示例13、測試新的命令,打開瀏覽器訪問http:/localhost:8096/client/api?command=get

54、TimeOfDay&response=json&example=moo5.2. API注解5.2.1. API命令注解APICommand 命令name 名稱(字符串并且全局唯一)description 描述(字符串,默認空)usage 使用方法(字符串,默認空)includeInApiDoc 聲明是否包含在API文檔中(boolean,默認true)since 命令在哪個版本加入的(字符串,默認空)responseObject 命令的響應類(class<? Extends BaseResponse)Parameter 參數(shù)name 參數(shù)名稱(字符串,默認空)descri

55、ption 描述(字符串,默認空)required 必填(boolean,默認false)type 參數(shù)類型(CommandType枚舉)entityType 映射數(shù)據(jù)庫實體類型collectionType 如果參數(shù)類型為list,需要指定集合泛型(CommandType枚舉)expose 如果設(shè)置false,將忽略傳遞的參數(shù)(boolean,默認true)includeInApiDoc 聲明是否包含在API文檔中(boolean,默認true)length 參數(shù)的最大長度(整形,默認255)since 命令在哪個版本加入的(字符串,默認空)枚舉類型public enum CommandTyp

56、e BOOLEAN, DATE, FLOAT, INTEGER, SHORT, LIST, LONG, OBJECT, MAP, STRING, TZDATE, UUID 5.2.2. API響應注解EntityReference 實例引用SerializedName 響應序列化名稱Param 響應參數(shù)description 描述(字符串,默認空)includeInApiDoc 聲明是否包含在API文檔中(boolean,默認true)since 命令在哪個版本加入的(字符串,默認空)responseObject 示例查看UserVmResponse的nics6. CloudStack中使用S

57、pringApache重構(gòu)了CloudStack的架構(gòu),奠定了一個更高的面向組件的根基,使用了在Java社區(qū)中大部分開發(fā)人員都熟悉的工具,Apache將現(xiàn)有的很多CloudStack代碼切換到Spring框架上,雖然不會導致業(yè)務邏輯的變化,但是開發(fā)人員仍需知道CloudStack的改變。6.1. CloudStack組件CloudStack管理服務器包含了不同的組件,通常為通用框架組件、管理者組件、適配器組件和DAO組件。在部署期間,CloudStack允許經(jīng)驗豐富的用戶通過編輯配置文件,組成一個自定義的設(shè)置。CloudStack開放源代碼的默認配置分布在applicationContext.

58、xml.in和componentContext.xml.in中,對于non-OSS分布在applicationContext.xml.in和nonossComponentContext.xml.in中。組件如果在OSS和non-OSS中使用,它應當聲明在applicationContext.xml.in中??蛇x組件,特定于OSS或non-OSS的組件,可以聲明在componentContext.xml.in或nonossComponentContext.xml.in或者都聲明。如果某個組件在OSS和non-OSS中的設(shè)置不同,它應該配置到applicationContext.xml.in和no

59、nossComponentContext.xml.in。使用下面的流程來確定你的組件應該配置到哪里:if (component is mandatory to OSS/non-OSS )       if( component shares common configuration in both OSS and non-OSS distributions )         put it in applicationContext.xml.in 

60、;    else         put it in both componentContext.xml and nonossComponentContext.xml.in       else       / optional component    if(component is for OSS only) &

61、#160;      put it in componentContext.xml    else if(component is for non-OSS only)        put it in nonossComponentContext.xml    else        put in

62、both componentContext.xml.in and nonossComponentContext.xml.in 6.2. 如何聲明一個CloudStack組件Spring組件無非就是一個POJO,一旦確定哪個文件需要在上述代碼中使用,聲明它其實非常簡單,如下:<bean id="configurationDaoImpl" class="com.cloud.configuration.dao.ConfigurationDaoImpl" />id應當是唯一的,不要使用Component,它不符合JSR,我們不再支持自動掃描

63、加載組件。6.3. Auto-wiring切換到Spring的最大好處之一是統(tǒng)一使用了Auto-wiring,遺留代碼中很多地方是run-time方式,這樣會使系統(tǒng)變得更加復雜。下面的示例中,開發(fā)者嘗試將子類中所有用到的組件以靜態(tài)變量方式寫入BaseCmd。這意味著當你添加一個新的命令類時,你需要記住在BaseCmd中注冊你的Servicepublic abstract class BaseCmd     static public ConfigurationService _configService;    s

64、tatic public AccountService _accountService;    static public UserVmService _userVmService;    static public ManagementService _mgr;         / more code .         / code

65、to resolve above static references using runtime resolution借助Spring,開發(fā)人員可以使用Inject注解來聲明這些引用,更重要的是,當只在個別命令類中注入這些應用時,可以使命令類更加獨立,這就是使用Spring的兩個原因之一,可以讓我們的代碼更加整潔。(另一個原因是充足的第三方組件)雖然我們將代碼切換到了Spring,但是還有一些遺留代碼仍然沒有切換,如果你看到了,希望你能修改并提交它們。6.4. CloudStack Spring組件的編碼約定6.4.1. 注意自動注入的時間在Spring中,遺留的ComponentLocato

66、r已經(jīng)無法工作,解決方法是不要在構(gòu)造函數(shù)中注入,并且使用Spring的Auto-wiring6.4.2. 公用構(gòu)造器protected或private構(gòu)造器可能是一個不錯的編碼習慣,然而,在Spring中這并不友好,請始終使用public構(gòu)造器。出于同樣的原因,POJO如果想注冊為Spring組件,不要用final來修飾類。6.4.3. 組件自主初始化自主初始化可以很好的解決對其他組件初始化的依賴,使用PostConstruct注解來讓Spring自動調(diào)用,下面是示例:public class ConfigurationDaoImpl extends GenericDaoBase<Con

67、figurationVO, String> implements ConfigurationDao      PostConstruct  void initComponent()       / more code. 6.4.4. 運行時注入使用ComponentContext.inject()自動注入組件:Class<?> cmdClass = getCmdClass(command0);if (cmdClass != null)   

68、0; BaseCmd cmdObj = (BaseCmd) cmdClass.newInstance();    cmdObj = ComponentContext.inject(cmdObj);    cmdObj.configure();    cmdObj.setFullUrlParams(paramMap);    cmdObj.setResponseType(responseType);  

69、60;  . public class FooCmd      Inject FooService _fooService;    Inject GeniusService _geniusService;     . 6.4.5. CloudStack定制化AOP(面向切面的編程)如果想實現(xiàn)自己的攔截器,需要實現(xiàn)ComponentMethodInterceptor并將其聲明到applicationContext.xm

70、l.in,下面是示例:package com.cloud.event; import java.lang.reflect.Method; import org.apache.log4j.Logger; import com.cloud.user.UserContext;import ponent.ComponentMethodInterceptor; public class ActionEventInterceptor implements ComponentMethodInterceptor     priva

71、te static final Logger s_logger = Logger.getLogger(ActionEventInterceptor.class);     public ActionEventInterceptor()          Override    public Object interceptStart(Method method, Object target)   

72、      EventVO event = null;        ActionEvent actionEvent = method.getAnnotation(ActionEvent.class);        if (actionEvent != null)          &#

73、160;  boolean async = actionEvent.async();            if(async)                UserContext ctx = UserContext.current();     &

74、#160;          long userId = ctx.getCallerUserId();                long accountId = ctx.getAccountId();           &

75、#160;    long startEventId = ctx.getStartEventId();                String eventDescription = actionEvent.eventDescription();            

76、0;   if(ctx.getEventDetails() != null)                    eventDescription += ". "+ctx.getEventDetails();           

77、0;                    EventUtils.saveStartedEvent(userId, accountId, actionEvent.eventType(), eventDescription, startEventId);            &#

78、160;               return event;         Override    public void interceptComplete(Method method, Object target, Object event)      

79、60;  ActionEvent actionEvent = method.getAnnotation(ActionEvent.class);        if (actionEvent != null)             UserContext ctx = UserContext.current();     

80、0;      long userId = ctx.getCallerUserId();            long accountId = ctx.getAccountId();            long startEventId = ctx.getStartEventId();

81、0;           String eventDescription = actionEvent.eventDescription();            if(ctx.getEventDetails() != null)           

82、0;    eventDescription += ". "+ctx.getEventDetails();                        if(actionEvent.create()                /This start event has to be used for subsequent events of this action                startEventI

溫馨提示

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

評論

0/150

提交評論