




版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
1、目錄CLOUDSTACK源碼分析31.用CLOUDSTACK的源碼進行工作31.1.源碼獲得方式32.包與依賴32.1.包32.2.依賴42.3.未來53.異常與日志53.1.日志53.2.異常和異常捕獲63.3.CloudStack異常84.代碼聯合工作94.1.組件94.2.組件加載105.CLOUDSTACK API開發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.公用構造器206.4.3.組件自主初始化206.4.4.運行時注入216.4.5.CloudStack定制化AOP(面向切面的編程)216.4.6.可插拔適配器246.4.7.模塊和組件266.4.8.什么時候用或者不用Inject286.5.組件生命周期287.數據訪問層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實現servercloud-server.jar管理服務器agentcloud-agent.jar代理容器ovmcloud-ovm.jarOracle VM的ServerResource未來的ServerResource包agent-simulatorServerResource模擬與回歸測試vmware-baseVMWare的ServerResource2.2. 依賴包的依賴關系反應了CloudStack設計的重要性,因此不
5、應該改變包的關系。ovm、vmware-base、agent-simulator和core是所有ServerResource基于cloud-api的實現,按照這種設計,這些包都不會訪問數據庫。cloud-agent是基于cloud-api的序列化和反序列化實現,但是理想情況下,cloud-agent僅僅作為容器并且應當基于cloud-util。2.3. 未來CloudStack在未來會向上面這種結構進行轉變,并且將API劃分為以下三種:包作用格式cloud-api運行、管理、維護和配置(OAM&P)、最終用戶RESTcloud-plugin-api補充功能APIJavacloud-ag
6、ent-api與ServerResource溝通APIJSON3. 異常與日志CloudStack沒有一個非常強大的異常與日志,不是我們只說不做,是因為我們并不擅長,不過我們一直努力在做好這些事情。3.1. 日志CloudStack使用log4j進行日志記錄,可以使用一些日志方案。雖然log4j很老,但是確實很好,并且真正重要的不是工具而是內容。CloudStack應當部署在INFO或者以上級別,并使用GMT標準時間。修改日志級別并不需要重啟CloudStack,下面是推薦日志級別以供參考:級別何時使用FATAL服務宕機或者JVM宕機ERROR系統出現了不能修復的問題,但是不影響系統的運行,只
7、會造成特定請求失敗WARNING系統出現了問題,并且可以修復,管理員如果想了解,可以看看此類日志INFO管理員比較關注這些信息DEBUG此類信息有助于管理員調試問題,出現FATAL或ERROR信息時,可以打開DEBUG,以提供足夠的信息調試問題TRACE重復并且討厭的日志,不應該在正常調試中打開它,不過實在解決不了問題的時候可能有用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拋出的,調用者可能會忘記處理XenAPIException / 2. 如果異常是從runtimeExceptionMethod拋出的,調用者會重復處理異常 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任何發生了不能捕獲的異常盡可能多的輸出可調試信息ResourceUnvailableException組件的處理與資源分配物理資源不能使用異常必須在某個范圍內,告訴調用者異常影響的是主機、存儲池、集群、提供點還是區域,以便調用者重試InsufficientCapacityException組件的處理與資源分配物理資源超出范圍異常必須在某個范圍內,告訴調用者異常影響的是主機、存儲池、集群、提供點還是區域,以便調用者重試4. 代碼聯合工
17、作目前,你可能看到了很多不同的代碼,是不是感覺非常混亂?怎么下手?怎么讓他們工作起來?下面就來告訴你。4.1. 組件CloudStack部署了下面一些組件,它們都是單例并且數據處理都經過它們,不過每個組件有不同的作用。類型作用示例Manager單獨控制過程VirtualMachineManagerAdapter不同的方式實現相同的功能,適配器通常用于到達一個步驟時,用多種方式實現這個步驟FirstFitDeploymentPlannerDAO數據訪問層HostDAOService支持平臺API的Java APIUserVmServicePluggableService定義了一套平臺API插入到
18、CloudStack中F5ExternalLoadBalancerElementServiceSystemIntegrityChecker保證管理節點啟動的完整性DatabaseUpgradeCheckerComponenLibrary部署管理、適配器、DAO的集合DefaultComponentLibraryInterceptor為執行過程提供面向切面的實現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開發5.1. 如何編寫API1、在plugins文件夾中創建文件夾,例如:cloudstack/plugins/api/timeofday2、在文件夾中創建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、創建src、target、test目錄5、創建代碼包結構,plugins/api/timeofday/src/com/cloud/test6、創建接口,繼承PluggableServicepackage com.cloud.test;import ponent.PluggableService;public interface TimeOfDayManager extends PluggableSer
35、vice 7、創建接口實現類,重寫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、編寫一個類來實現注解方式的命令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 參數name 參數名稱(字符串,默認空)descri
55、ption 描述(字符串,默認空)required 必填(boolean,默認false)type 參數類型(CommandType枚舉)entityType 映射數據庫實體類型collectionType 如果參數類型為list,需要指定集合泛型(CommandType枚舉)expose 如果設置false,將忽略傳遞的參數(boolean,默認true)includeInApiDoc 聲明是否包含在API文檔中(boolean,默認true)length 參數的最大長度(整形,默認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 響應參數description 描述(字符串,默認空)includeInApiDoc 聲明是否包含在API文檔中(boolean,默認true)since 命令在哪個版本加入的(字符串,默認空)responseObject 示例查看UserVmResponse的nics6. CloudStack中使用S
57、pringApache重構了CloudStack的架構,奠定了一個更高的面向組件的根基,使用了在Java社區中大部分開發人員都熟悉的工具,Apache將現有的很多CloudStack代碼切換到Spring框架上,雖然不會導致業務邏輯的變化,但是開發人員仍需知道CloudStack的改變。6.1. CloudStack組件CloudStack管理服務器包含了不同的組件,通常為通用框架組件、管理者組件、適配器組件和DAO組件。在部署期間,CloudStack允許經驗豐富的用戶通過編輯配置文件,組成一個自定義的設置。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中的設置不同,它應該配置到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的最大好處之一是統一使用了Auto-wiring,遺留代碼中很多地方是run-time方式,這樣會使系統變得更加復雜。下面的示例中,開發者嘗試將子類中所有用到的組件以靜態變量方式寫入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,開發人員可以使用Inject注解來聲明這些引用,更重要的是,當只在個別命令類中注入這些應用時,可以使命令類更加獨立,這就是使用Spring的兩個原因之一,可以讓我們的代碼更加整潔。(另一個原因是充足的第三方組件)雖然我們將代碼切換到了Spring,但是還有一些遺留代碼仍然沒有切換,如果你看到了,希望你能修改并提交它們。6.4. CloudStack Spring組件的編碼約定6.4.1. 注意自動注入的時間在Spring中,遺留的ComponentLocato
66、r已經無法工作,解決方法是不要在構造函數中注入,并且使用Spring的Auto-wiring6.4.2. 公用構造器protected或private構造器可能是一個不錯的編碼習慣,然而,在Spring中這并不友好,請始終使用public構造器。出于同樣的原因,POJO如果想注冊為Spring組件,不要用final來修飾類。6.4.3. 組件自主初始化自主初始化可以很好的解決對其他組件初始化的依賴,使用PostConstruct注解來讓Spring自動調用,下面是示例: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(面向切面的編程)如果想實現自己的攔截器,需要實現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. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
- 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 畜牧良種繁殖產業技術創新戰略聯盟構建考核試卷
- 傳動部件的故障樹分析考核試卷
- 影視道具制作的材料研發考核試卷
- 電力儀表的長期穩定性研究考核試卷
- 電力系統電力市場交易考核試卷
- 煤炭國際貿易結算考核試卷
- 文具用品零售業的人力資源招聘與選拔考核試卷
- 2025園林綠化管理合同協議書范本
- (高清版)DB5110∕T 56.4-2023 內江黑豬種豬飼養技術規程 第4部分:后備母豬
- 10月自考外國法制史串講筆記
- 2023年中國鐵路南寧局集團有限公司招聘考試真題
- DB11T 1539-2018 商場、超市碳排放管理規范
- 《冠心病病人的護理》課件
- DB11T 1796-2020 文物建筑三維信息采集技術規程
- 完整版2024年注安法規真題及答案(85題)
- 《Python程序設計基礎教程(微課版)》全套教學課件
- 牧場物語-礦石鎮的伙伴們-完全攻略
- 汽車營銷知識競賽題庫及答案(295題)
- 員工工資表范本
- 腎病綜合征的實驗室檢查
- 高中物理必修三《電磁感應現象的應用》說課課件
評論
0/150
提交評論