You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 5 Next »

While we are refactoring CloudStack architecture, to lay out a better component oriented foundation, be open to tools that most developers are familiar with in Java community, we started to experience the usage of Apache Spring Framework, switching to Spring touches a lot of existing CloudStack codebase, however, it does not bring any business logic changes, but it does introduce changes that CloudStack developers need to be aware of.

1. CloudStack Framework components and business logic components

With old component container managed by ComponentLocator class, we don't distinguish framework components and regular components that implement varios CloudStack business logic, we started to separate framework components and business logic components, there are separated context configuration file, these two files are applicationContext.xml.in and componentContext.xml.in, following is some sample content from Javelin

applicationContext.xml.in

<beans xmlns="http://www.springframework.org/schema/beans"

  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 

  xmlns:context="http://www.springframework.org/schema/context"

  xmlns:tx="http://www.springframework.org/schema/tx" 

  xmlns:aop="http://www.springframework.org/schema/aop"

  xsi:schemaLocation="http://www.springframework.org/schema/beans

_                      http://www.springframework.org/schema/beans/spring-beans-3.0.xsd_

_                      http://www.springframework.org/schema/tx _

_                      http://www.springframework.org/schema/tx/spring-tx-3.0.xsd_

_                      http://www.springframework.org/schema/aop_

_                      http://www.springframework.org/schema/aop/spring-aop-3.0.xsd_

_                      http://www.springframework.org/schema/context_

                      http://www.springframework.org/schema/context/spring-context-3.0.xsd">                     

 

  <context:annotation-config />

 

  <context:component-scan base-package="org.apache.cloudstack, com.cloud" />

 

  <!--

    @DB support

  -->

  <aop:config proxy-target-class="true">

    <aop:aspect id="dbContextBuilder" ref="transactionContextBuilder">

        <aop:pointcut id="captureAnyMethod"

            expression="execution(* *(..))" 

        />

 

        <aop:around pointcut-ref="captureAnyMethod" method="AroundAnyMethod"/> 

    </aop:aspect>

    <aop:aspect id="actionEventInterceptorAspect" ref="actionEventInterceptor">

        <aop:pointcut id="captureEventMethod"

            expression="execution(* *(..)) and @annotation(com.cloud.event.ActionEvent)" 

        />

        <aop:around pointcut-ref="captureEventMethod" method="AroundAnyMethod"/> 

    </aop:aspect>

 

  </aop:config>

 

  <bean id="transactionContextBuilder" />

  <bean id="actionEventInterceptor" />

  

  <!--

    RPC/Async/EventBus

  -->

  <bean id="onwireRegistry"

    init-method="scan" >

    <property name="packages">

      <list>

        <value>org.apache.cloudstack.framework</value>

      </list>

    </property>

  </bean>

 

  <bean id="messageSerializer">

    <property name="onwireClassRegistry" ref="onwireRegistry" />

  </bean>

 

  <bean id="transportProvider"  init-method="initialize">

    <property name="workerPoolSize" value="5" />

    <property name="nodeId" value="Node1" />

    <property name="messageSerializer" ref="messageSerializer" />

  </bean>

  <bean id="rpcProvider" init-method="initialize">

    <constructor-arg ref="transportProvider" />

    <property name="messageSerializer" ref="messageSerializer" />

  </bean>

 

  <bean id="eventBus" class = "org.apache.cloudstack.framework.eventbus.EventBusBase" />

  <bean id="apiServlet" class = "com.cloud.api.ApiServlet" />

</beans>

Components that offer framework level services are collected in applicationContext.xml.in, these framework components usually help define the runtime environment for all other business logic components, for example, middle-ware service components that are for inter-component communication, CloudStack Database, general DB transaction management etc. CloudStack customers may have various combination of activated business logic components in a particular setup, but most of time, a same set of framework components is usually used.

componentContext.xml.in

<beans xmlns="http://www.springframework.org/schema/beans"

  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 

  xmlns:context="http://www.springframework.org/schema/context"

  xmlns:tx="http://www.springframework.org/schema/tx" 

  xmlns:aop="http://www.springframework.org/schema/aop"

  xsi:schemaLocation="http://www.springframework.org/schema/beans

                      http://www.springframework.org/schema/beans/spring-beans-3.0.xsd

                      http://www.springframework.org/schema/tx&nbsp;

                      http://www.springframework.org/schema/tx/spring-tx-3.0.xsd

                      http://www.springframework.org/schema/aop

                      http://www.springframework.org/schema/aop/spring-aop-3.0.xsd

                      http://www.springframework.org/schema/context

                      http://www.springframework.org/schema/context/spring-context-3.0.xsd">                     

  <!--

      Compose a CloudStack deployment with selected components here

  -->

  <bean id="databaseUpgradeChecker" />

  <bean id="management-server" class ="com.cloud.server.ManagementServerExtImpl" />

  <bean id="configuration-server" />

  <bean id="clusterManagerImpl" />

  <bean id="clusteredAgentManagerImpl" />

  <bean id="clusteredVirtualMachineManagerImpl" />

  <bean id="highAvailabilityManagerExtImpl" />

  <!- bean id="bareMetalVmManagerImpl" / ->

  <bean id="userVmManagerImpl" />

  <bean id="consoleProxyManagerImpl" />

  <bean id="securityGroupManagerImpl2" />

  <bean id="premiumSecondaryStorageManagerImpl" />

  <bean id="randomlyIncreasingVMInstanceDaoImpl" /> 

  <!--

      Network Elements

  -->

  <bean id="Ovs">

    <property name="name" value="Ovs"/>

  </bean>

  <bean id="ExternalDhcpServer">

    <property name="name" value="ExternalDhcpServer"/>

  </bean>

  <bean id="BareMetal">

    <property name="name" value="BareMetal"/>

  </bean>

  <bean id="SecurityGroupProvider">

    <property name="name" value="SecurityGroupProvider"/>

  </bean>

  <bean id="VirtualRouter">

    <property name="name" value="VirtualRouter"/>

  </bean>

  <bean id="VpcVirtualRouter">

    <property name="name" value="VpcVirtualRouter"/>

  </bean>

  <bean id="NiciraNvp">

    <property name="name" value="NiciraNvp"/>

  </bean>

  ...

  ...

</beans> 

2. How to declare to be a CloudStack component

In Spring term, CloudStack uses both singleton components and prototype components, Spring component is nothing else more than a Java POJO object, you can either declare it with @Component annotation or in <bean> declaration in applicationContext.xml or componentContext.xml. CloudStack uses a lot of singleton components, for example, managers, DAOs, following is an example of such components

@Component

@Local(value=ClusterDao.class)

public class ClusterDaoImpl extends GenericDaoBase<ClusterVO, Long> implements ClusterDao {

    protected final SearchBuilder<ClusterVO> PodSearch;

    protected final SearchBuilder<ClusterVO> HyTypeWithoutGuidSearch;

    protected final SearchBuilder<ClusterVO> AvailHyperSearch;

    protected final SearchBuilder<ClusterVO> ZoneSearch;

    protected final SearchBuilder<ClusterVO> ZoneHyTypeSearch;

    private static final String GET_POD_CLUSTER_MAP_PREFIX = "SELECT pod_id, id FROM cloud.cluster WHERE cluster.id IN( ";

    private static final String GET_POD_CLUSTER_MAP_SUFFIX = " )";

    @Inject

    protected HostPodDao _hostPodDao;

    public ClusterDaoImpl()

Unknown macro: { }  ... ... ... }


For most of low-level built-in components like DAOs, in Javelin practice, we use @Component annotation, since it saves us a lot of typing and can take advantage of Eclipse IDE's powerful refactoring and type-infer feature to help us coding. However, if you are developing high level components and you want to give flexibility for customer to choose to compose a particular CloudStack deployment, declare in componentContext.xml would be a better choice.

3. Auto-wiring

One of the biggest advantage of switching to Spring is that Auto-wiring in Component has now become consistent. With previous ComponentLocator, there are a lot of places that have to use run-time wiring, for example, using ComponentLocator.getManager() to wire a reference to a manager component. The reason for developers to do so is that ComponentLocator does not fully resolved dependent injection for components, so when inter-component relationship becomes complex in a large system like CloudStack, lots of hacking ways rise up inside CloudStack codebase. Although it solves the immediate needs, but it also creates a lot of confusion for developers, the more components being involved into injection business, the more the system is tightly coupled with ComponentLocator itself.

Following is an example of such hacking way, inside BaseCmd class, developer tried to resolve all the references for every used components into static variables.

public abstract class BaseCmd

Unknown macro: {     private static final Logger s_logger = Logger.getLogger(BaseCmd.class.getName());\     public static final String USER_ERROR_MESSAGE = "Internal error executing command, please contact your system administrator";     public static final int PROGRESS_INSTANCE_CREATED = 1;\     public static final String RESPONSE_TYPE_XML = "xml";     public static final String RESPONSE_TYPE_JSON = "json";\     public enum CommandType    ...    private Object _responseObject = null;     private Map<String, String> fullUrlParams;\     @Parameter(name = "response", type = CommandType.STRING)     private String responseType;\ *    public static ConfigurationService _configService;* *    public static AccountService _accountService;* *    public static UserVmService _userVmService;* *    public static ManagementService _mgr;* *    public static StorageService _storageService;* *    public static ResourceService _resourceService;* *    public static NetworkService _networkService;* .. .. .. }


With Spring, developer can now always use @Inject annotation to declare such reference. One of the top two reasons for us to try Spring experiments in Javelin, since with more complete dependency injection, it gives us a cleaner component coding practice. (the other top reason is that we have broader integration supports from many other third-party vendors, i.e., JUnit)

  • No labels