使用Blueprint管理模块的加载、服务依赖和配置

使用Blueprint管理模块的加载、服务依赖和配置

本文来自:http://www.deepsdn.com/archives/36

什么是blueprint?

Blueprint 是 OSGi Service Platform Enterprise Specification 标准的一 部分,被设计用来为OSGi容器提供依赖注入的框架. 它来源于Spring DM,因此它们很类似. Karaf中包括一个blueprint的实现,即 (the Apache Aries blueprint 实现).

Blueprint是以xml文档来构建应用,但它也有采用Annotation的方式,我们在此只介绍xml的方式。
在Bundle里,这个xml默认的位置在OSGI-INF/blueprint下,也可以在manifest.mf里指定其它位置上的xml文档。
当一个包含blueprint xml文档的bundle install并resolved,并且active后,Aries blueprint container就会开始解析这个文档。
在处理这些xml文档的过程中,bundle还会有个blueprint的状态,区别于bundle的状态。这些状态包括Graceperiod,Created,Fail。其中Created就是blueprint container已经解析完文档,并且文档中mandatory的依赖都得到满足了,这时blueprint的应用已经组装完毕。而Graceperiod则是应用正在组装中。Fail是当blueprint无法解析xml文档或者是mandatory的依赖在超时时间内未能获得满足。

在Blueprint里,还可以发布和组装OSGI service。

blueprint xml文档,有四种主要元素: beanservicereference and reference-list:

  • bean – 用来描述创建Java实例的元素,可以指定实例初始化的类名,构造方法,构造方法的入参及属性.
  • service – 把bean发布为OSGi service
  • reference – 通过接口名引用一个OSGi service,可以指定一个特定的属性过滤器
  • reference-list – 通过接口名引用多个 OSGi services ,可以指定一个特定的属性过滤器

1.引用基础的MD-SAL binging服务,比如DataBrokerRpcProviderRegistry, and NotificationPublishService




  
  
  

对于一个接口有多个实现的,odl:type可以用来确定某个具体实现,比如对于DataBroker,有一个默认实现和一个特殊实现PingPongDataBroker,如果不明确指定type,则获取的服务实现是不确定的,如果想要某个具体实现,必须指定type,odl:type=”default”表示默认实现,odl:type=”pingpong”表示PingPongDataBroker实现。

服务获取的动态性

在blueprint内部,reference 元素为服务实例创建了一个动态代理. 之所以如此做,就是考虑到OSGi 服务的动态本质,所有服务实现都可能因为bundle的动态启停,重启而生效或者失效. 当然,实际上,在像Opendaylight这样具有几百个bundle的大规模的平台里,真正实现完全的动态性是存在一定难度的(but that’s another topic).

在bundle启动时,blueprint container 会首先等待依赖的服务得到满足, 默认的等待超时时间是 5 分钟.如果超时,blueprint container会马上把bundle状态标记为失败. 另外,如果某个服务在启动后状态变为不可用,再调用该服务时,该调用将会被阻塞,直到新的服务实例可用或者超时. 如果服务调用超时,系统会抛出一个运行时异常. 这样就可以在应用代码里做相应处理以支持bundle的动态更新.

2.通过bean初始化业务逻辑类




  

  
    
  

  
    
  


3. 发布服务



  
    
  

  



MD-SAL blueprint扩展

odl mdsal对blueprint的扩展(xmlns:odl=”http://opendaylight.org/xmlns/blueprint/v1.0.0″)

i. Global RPC注册




  
    
  

  

ii. Global RPC的获取




  

  
    
  

iii. Routed RPC的注册




  
    
  

  

  
    
  

iv. NotificationListenser的注册




  
    
  

  

还有一个需要了解的知识是blueprint的配置管理,可以直接使用blueprint的ConfigAdmin来配置某些本地参数,配置项是写在etc/*.cfg文件里的blueprint xml里要写上对namespace.

“http://aries.apache.org/blueprint/xmlns/blueprint-cm/v1.1.0″的使用,如下

  
    
      
    
  

  
    
  

也可以通过ODL的datastore实现集群内的全局配置

Opendaylight实现了一个不lueprint扩展,clustered-app-config,它可以令应用方便使用yang定义的配置数据,当然,这些配置必须定义在yang的顶层container或list内.

标签clustered-app-config从MD-SAL datastore里读取应用配置数据并封装配置数据为bean,这些配置bean具有与OSGi服务同样的依赖方式。如果配置数据不能从datastore读取并初始化(比如ODL 的datastore还没启动好),blueperint将会一直等待配置数据的依赖直至超时失败。

clustered-app-config元素内部注册了 ClusteredDataTreeChangeListener 监听器,以便在配置数据变化或者删除时,重启blueprint container.

使用 YANG container 实现应用配置

像下面这样定义一个 yang顶层 container:

module my-app-config {
    yang-version 1;
    namespace "urn:opendaylight:myapp:config";
    prefix my-app-config;

    description
      "Configuration for ...";

    revision "2016-06-24" {
        description
            "Initial revision.";
    }

    container my-config {
        leaf id {
            type string;
            mandatory true;
        }

        leaf connection-timeout {
            type uint16;
            default 3000;
        }
    }
}

在你的blueprint配置XML里, 添加 clustered-app-config 标签,该标签的binding-class属性设置为由my-config这个container生成的带包路径的Java interface名称.



clustered-app-config 元素从MD-SAL data store里获取数据,生成绑定的DataObject对象bean(这里就是MyConfig的对象),该bean可以被注入到其他bean里。如果datastore里该数据为空,则由yang模型里默认值生成一个bean实例,在上面例子里,会创建一个connection-timeout等于3000,id为null的MyConfig实例

如果不想用yang里定义的默认值,你可以自己通过default-config子标签在blueprint xml提供默认值..


  
      foo
    
  ]]>

这里,我们对id字段提供了一个默认值,default-config元素里包含了yang定义的数据的XML表示(包括namespace),数据体用 CDATA段封装,以让blueprint container不把这部分数据作为blueprint标记来处理,这部分的数据表示形式与通过RESTCONF设置datastore时的XML格式一致.

默认值也可以通过外部文件指定. 在自动化测试脚本中,这非常有用,而且,你能在控制器没有运行的情况下方便的修改配置。 clustered-app-config 将在目录etc/opendaylight/datastore/initial/config下查找形如 _.xml 的文件. 比如,上面的例子,就会查找etc/opendaylight/datastore/initial/config/my-app-config_my-config.xml. XML文件名也可以用属性default-config-file-name明确指定.

注意: 默认值只是在datastore里没有数据时的初始值.一旦在datastore里设置了值,默认值就没用了.

如果是在同一个文件里,可以直接把MyConfig通过bean id注入到业务逻辑的bean.




  
  
  
  
    
  


org.opendaylight.myapp.Foo类的构造方法入参就是类org.opendaylight.yang.gen.v1.urn.opendaylight.myapp.config.rev160624.MyConfig.

你可能还想直接把container里某个leaf字段的值注入到业务逻辑bean,而并不是整个container对象. 比如, 我们定义一个类 org.opendaylight.myapp.Bar  with ,在构造方法里希望能把MyConfig里的idconnection-timeout传进来.

public class Bar {
    public Bar(String id, int connectionTimeout) {
    }
}

这可以通过为构造方法的入参定义内部bean来实现,例子如下:


  
    
  
  
    
  

使用 YANG list 实现配置

如果你想同时初始化某个组件的多个实例, 每个都有自己的单独的配置, 不需要为每一个实例定义特定的container, 使用顶层的 list 元素就能实现.

我们象下面这样定义一个顶层的 list:

module my-component-config {
    yang-version 1;
    namespace "urn:opendaylight:myapp:config";
    prefix my-component-config;

    description
      "Configuration for ...";

    revision "2016-06-24" {
        description
            "Initial revision.";
    }

    list my-component-config {
        key "instance-name";
        leaf instance-name {
            type string;
        }

        leaf connection-timeout {
            type uint16;
            default 3000;
        }
    }
}

元素clustered-app-config 支持设置一个类型为type的 list key. 这个 key唯一标示一个实例. 通过属性list-key-value指定he instance value must be specified via the list-key-value attribute.


  
      instance1
      1000
    
  ]]>



  



 
      instance2
      2000
    
  ]]>



  

这里我们定义了两个配置,每个对应一个org.opendaylight.myapp.Foo的实例。

我们也为每个配置分别设置了默认值,对于yang list元素,在XML中,必须明确使用 list-key-value对list的key赋值。

你可能感兴趣的:(使用Blueprint管理模块的加载、服务依赖和配置)