CloudStack源码分析_第1页
CloudStack源码分析_第2页
CloudStack源码分析_第3页
CloudStack源码分析_第4页
CloudStack源码分析_第5页
已阅读5页,还剩39页未读 继续免费阅读

下载本文档

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

文档简介

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中。可选组件,特定于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. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论