`

SpringDM笔记13-OSGi服务注册与引用

 
阅读更多

1. Combining OSGi services and dependency injection

    SERVICE PROXYING:

    Spring DM’s service support is powerful and takes care of a lot of things under the hood by using

    a proxy mechanism between the service and the user of the service as a level of indirection for

    the service.

 

    Because OSGi is dynamic and services can come and go at any time, directly injecting a service

    instance into another bean isn’t a good idea. The instance could become stale over time if the 

    underlying service becomes unavailable. Instead, Spring DM uses a proxy that passes itself off as

    the target OSGi service, so the service user isn’t tied to the service.

 

    Spring DM’s proxy behavior can be configured to modify the way service dynamics are handled:

    references can be configured as mandatory or optional. For a single instance, Spring DM will

    automatically look for a replacement when the current service referent disappears. For 

    mandatory services, this lookup must always be successful, but this isn’t essential for optional

    services. For service collections, Spring DM will automatically add and remove services when

    service registrations  and unregistrations occur. If the service collection is configured as   

    mandatory, an empty collection won’t be allowed.

 

    Spring DM also provides support for when services become temporarily unavailable, such as

    during component updates. The framework makes it possible not to lose requests by making

    them block. When the service becomes available again, blocked calls will be executed on the

    target service. In addition, Spring DM provides a timeout-based mechanism for when services

    remain unavailable for an extended period. If services remain unavailable longer than the

    timeout, a ServiceUnavailableException exception is thrown.

2. XML-based registration and referencing

    SpringDM中注册的每个服务拥有一个属性:org.springframework.osgi.bean.name,该属性的值指向引用

的Bean:ref, 而该Bean是org.osgi.framework.ServiceRegistration类型的对象。注册服务时,SpringDM将

通过ServiceRegistration创建一个代理,该代理就是注册的Bean自己。

2.1 EXPORTING SERVICES:Simple service configuration within Spring XML configuration

    (1) 配置文件

    <?xml version="1.0" encoding="UTF-8"?>
    <beans:beans xmlns="http://www.springframework.org/schema/osgi"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xmlns:osgi="http://www.springframework.org/schema/beans"
               xsi:schemaLocation="http://www.springframework.org/schema/beans
               http://www.springframework.org/schema/beans/spring-beans.xsd
               http://www.springframework.org/schema/osgi
               http://www.springframework.org/schema/osgi/spring-osgi.xsd">

          <service id="serviceBean" ref="testServiceBean"
                   interface="com.manning.sdmia.springdm.service.TestService"/>

          <!-- 注册是一个服务实现多个接口-->

         <service ref="serviceBean">
                 <interfaces>
                     <value>com.apress.springosgi.FlightService</value>
                     <value>com.apress.springosgi.InFlightOperations</value>
                     <value>com.apress.springosgi.GroundCrewOperations</value>
                 </interfaces>
          </service>

      </beans:beans>

      见附件图:Spring-DM proxy exposing service interface(s) for backing a Spring bean.jpg。

      (2) SpringDM <service>元素的auto-expot属性值

      disabled: 默认值,表示采用无接口自动检测;SpringDM将采用interface或interfaces声明;

      interfaces:  注册服务使用Bean实现的接口;

      class-hierarchy:  注册服务使用自己的class 或超类(如果有);

      all-classes:注册服务使用自己的class 或超类,另外包括该Bean是实现的所有接口。

      见附件图:Spring-DM auto-export Registration Behaviors for Different Interface/Class

      Hierarchies.jpg.

      (3) 注册Service时添加Service Properties

      主要用于在查看找服务时过滤服务。

      <service ref="serviceBean" interface="com.apress.springosgi.FlightService">
            <service-properties>

                  <beans:entry key="version" value="2.0"/>
                  <beans:entry key="flight" value="ACMEAirlines"/>
                  <beans:entry key="aports" value-ref="airportsBean"/>
            </service-properties>
      </service>

      (3) 注册服务时指定Id

      指定了Id,则该服务可被注入至其他的Bean,该Id在这种情况下的类型是:org.osgi.fraemwork.

      ServiceRegistration.

      <service ref="serviceBean" id="flightServiceDM" interface="com.apress.springosgi.

            FlightService"/>

      (4) 注册服务时使用匿名Bean

      <service interface="com.apress.springosgi.FlightService">
           <bean:bean class="com.apress.springosgi.FlightServiceDAO">
           </bean>
      </service>

      (5) 注册服务时使用depneds-on属性

      指定该属性表明在注册该服务前,该服务的所有依赖已经满足。

      <service ref="serviceBean" interface="com.apress.springosgi.FlightService"
            depends-on="groundCrewBean"/>

      (6) 注册服务是使用属性:ranking

      该属性是一个Integer值,用于在查找服务时若有两个或多个服务时的限定条件;在这种条件下,OSGi Registry

      中心将返回已经注册的拥有最高rangking值得服务,而不会返回serviceId最小的服务。

      <osgi:service ref="helloWorldDAO" ranking="100"

                interface="com.apress.springosgi.ch3.service.HelloWorldService"/>

      (7) 注册服务时使用属性:context-class-loader

      该属性用于定义ClassLoader的可见性,默认情况下service元素的该属性默认值是:unmanaged, 指明只有类

      加载中可用的资源才可以被使用。

      该属性另外一个值是:service-provider, 当服务使用某特定的资源时,而该消费Bundle对这些资源却是不可见

      的;此时使用该属性,SpringDM将确保消费Bundle拥有提供服务的主Bundle的所有资源的访问能力。

      (8) 注册服务时指定引用Bean的scope属性

      默认情况下,OSGi服务引用的Bean创建时有一个global scope, 就是说所有的消费Bundle在使用该服务时用的

      是仅有的一个Bean实例;为了提供更细粒度的控制,SpringDM使用Factory模式提供了scope属性。

      <bean:bean id="serviceBean" scope="bundle" class="com.apress.springosgi.

            FlightServiceImpl"/>
      <service ref="serviceBean" interface="com.apress.springosgi.FlightService"/>

      在这种情况下,每个Client Bundle访问该服务时,将会获取一个新的实例,当Client Bundle停用时该实例将被

      销毁。

      (9) 注册服务时使用监听器

      指定在服务注册或取消注册时触发的事件。

      <service ref="serviceBean" interface="com.apress.springosgi.FlightService">
                <registration-listener ref="runwayBean"
                      registration-method="preTakeoff"
                      unregistration-method="postTakeoff">
      </service>

 

      <service ref="serviceBean" interface="com.apress.springosgi.FlightService">
            <registration-listener
                       registration-method="preTakeoff"
                       unregistration-method="postTakeoff">
                       <bean class="com.apress.springosgi.FlightServiceRunway"/>
            </registration-listener>
       </service>

 

       注册服务时监听器的方法签名:

       public void methodName(ServiceType serviceInstance, Map serviceProperties);
       public void methodName(ServiceType serviceInstance, Dictionary serviceProperties);

2.2 REFERENCING SERVICES:Simple service referral within Spring XML configuration

      (1)配置文件

      <beans:beans xmlns="http://www.springframework.org/schema/osgi"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xmlns:osgi="http://www.springframework.org/schema/beans"
               xsi:schemaLocation="http://www.springframework.org/schema/beans
               http://www.springframework.org/schema/beans/spring-beans.xsd
               http://www.springframework.org/schema/osgi
               http://www.springframework.org/schema/osgi/spring-osgi.xsd">
          <reference id="testService"

                    interface="com.manning.sdmia.springdm.service.TestService"/>
          <bean id="testBean" class="com.manning.sdmia.springdm.SimpleTestBean">
                 <property name="testService" ref="testService"/>
          </bean>

       </beans:beans>

       (2) 查找服务with Multiple Inteface

       <reference id="serviceBean">
              <interfaces>
                    <value>com.apress.springosgi.FlightService</value>
                    <value>com.apress.springosgi.InFlightOperations</value>
                    <value>com.apress.springosgi.GroundCrewOperations</value>
              </interfaces>
       </service>

       在这种情况下,serviceBean由支持声明了上述接口的BundleContext来创建。

       (3) 查找服务使用bean-name属性

       <reference id="lookedUpserviceBean" interface="com.apress.springosgi.Flight.
              Service" bean-name="serviceBean"/>

       在这种情况下,将创建一个代理,该代理根据实现了FlightService 接口且创建了serviceBean的服务来创建;

       这样会导致Bundle紧耦合。

       (4) 查找服务使用过滤器

      <reference id="serviceBean" interface="com.apress.springosgi.FlightService">
            filter="(flight=ACMEAirlines)"/>

      实例化serviceBean时将根据实现了FlightService接口且有一个属性flight值为ACMEAirlines的服务来实例化。

      <reference id="serviceBean" interface="com.apress.springosgi.FlightService">
            filter="(version=2.0)"/>

      实例化serviceBean时将根据实现了FlightService接口且有一个属性version值为2.0的服务来实例化;version

      =2.0与version=2或version=2.0.0是不同的过滤条件,如果更具该version=2.0找不到适合的服务将没有服务

      返回,没有默认服务。

      (5) 属性:rangking

      根据OSGi规范,SpringDM默认返回拥有最高rangking属性的service;如果有多个rangking属性相同的服务返

      回,则拥有最小serviceID的服务返回。

      (6) 属性:depends-on

      使用该属性,在查找服务时必须确保依赖的bean在Bundel上下文中。

      (7) 属性:context-class-loader

      该属性有三个值:client,service-provider,unmanaged,默认值是:client; 该client属性值可以确保在服务的

      调用过程中,类加载器可以看见调用Bundle类路径中所有类。

      (8) 属性:cardinality

      即指一个服务是强制的还是可选的。默认reference元素的该值是:1..1,指方根据引用的服务创建bean时该服

      务必须是可用的。其他可选值:0..1,1..N, 对osgi:list/set,默认值是0..N。

      (9) 属性:timeout

      该属性指定一个等待时间,该时间是SpringDM根据引用的服务创建bean的时间,默认值是:300 seconds。

      配置实例:

      <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:osgi="http://www.springframework.org/schema/osgi"
               osgi:default-timeout="5000"
               osgi:default-cardinality="0..X">
           <reference id="flightService" interface="com.apress.springosgi.FlightService"/>
           <reference id="nightlyFlightService" interface="com.apress.springosgi.NightlyFlightService"
                   timeout="1000"/>
           <list id="cargoFlightServices" interface="com.apress.springosgi.CargoFlightService"

                   cardinality="1..N"/>
       </beans:beans>

       (10) 元素:list/set

       这两个元素与reference元素相同,也有属性:interface,filter,bean-name,cardinality,context-class

       -loader. 下面区分这两个的 区别:

       Set返回的Object不可能相同,而List中元素有可能相同,这与Java Collection Framework中Set/List的

       概念一致。

       通过List/Set元素生成的Bean与reference元素生成的Bean是不同的,List元素生成的Bean类型是:java.

       util.list,而Set元素生成的Bean类型是:java.util.Set,可以使用comparator元素作为集合服务的排序策略:

       <list id="flightServices" interface"com.apress.springosgi.FlightService">

              <!--使用Java集合框架的默认排序策略-->
              <comparator><natural-ordering basis="services"/></comparator>
       </list>
       <set id="nightlyFlightServices" interface="com.apress.springosgi.FlightService">
              <comparator><natural-ordering basis="service-references"/></comparator>
       </set>

       comparator元素也可以改成comparator-ref属性,指向一个java.util.Comparator类型的类:

       <set id="flightServices" interface="com.apress.springosgi.FlightService"
              comparator-ref="flightComparator"/>
       <list id="nightlyFlightServices"
                      interface="com.apress.springosgi.NightlyFlightService">

              <!--嵌套匿名内部Bean-->
              <comparator>
                   <beans:bean class="nightlyFlightComparator"/>
              </comparator>
       </list>

       (11) 属性:greedy-proxying

       该属性确保可访问一组服务中所有底层的class和接口:

       <set id="flightServices" interface="com.apress.springosgi.FlightService" greedy-proxying

       ="true"/>

 

       for (Iterator iterator = services.iterator(); iterator.hasNext();) {
               FlightService service = (FlightService) iterator.next();
               service.runwayOperation();
               // If the service implements additional type, execute more logic
               if (service instanceof ACMEFlight) {
                    ((ACMEFlight)service).sendRunwayClearance();

               }

        }

        (12) Bunding 和 Unbinding事件:

        <reference id="flightService" interface="com.apress.springosgi.FlightService">
               <listener ref="flightListenerBean"/>
        </reference>

         flightListenerBean是实现了接口

         org.springframework.osgi.service.importer.OsgiServiceLifecycleListener的Bean。

         客制化定义Binding 和 Unbing事件:

         <reference id="flightService" interface="com.apress.springosgi.FlightService">
                <listener bind-method="onBind" unbind-method="onUnbind">
                       <beans:bean class="flightListenerBean"/>
                 </listner>
         </reference>

         查找OSGi服务是监听器方法签名:

         public void methodName(ServiceType serviceInstance, Map serviceProperties);
         public void methodName(ServiceType serviceInstance, Dictionary serviceProperties);
         public void methodName(ServiceType serviceInstance);

 

3. Annotation-based service referral

    Spring DM also provides annotation-based support for referencing and using services,service

    registration isn’t supported by this approach. For example:

    public class AnnotatedTestBean {
       private TestService testService;
       (...)
       @ServiceReference
       public void setTestService( TestService testService) {
             this.testService = testService;
       }
    }

    @ServiceReference注解根据set方法中的接口去查找一个TestService服务,然后注入至该类中;同时该注解

    也拥有属性:cardinality,contextClassLoader,filter,serviceBeanName,serviceTypes,timeOut.

    SpringDM实现基于注解的注入功能实现方式:

    (1)通过设置Spring DM’s extender-based 的配置属性:process.annotations

    (2)使用Spring’s bean post-processor 机制,需要在Spring配置文件中配置下面的Bean:

    ServiceReferenceInjectionBeanPostProcessor信息:

    <beans (...)>
    (...)
         <bean class="org.springframework.osgi.extensions.annotation

              .ServiceReferenceInjectionBeanPostProcessor"/>
    </beans>

 

    SpringDM Dependency management with annotations:

    We’ve discussed how mandatory dependencies configured in a Spring-powered bundle’s XML file

    cause the application context to be suspended until the dependencies are satisfied. Spring DM

    achieves this by preinstantiating service beans, then deciding whether or not they’re mandatory.

    But instantiating mandatory service references declared through annotations gets quite tricky

    because the actual bean class is required, and mandatory dependencies don’t cause the

    application context startup to be suspended. Instead, the application context is created as usual,

    but any subsequent calls to mandatory dependencies will block.

 

    Spring DM provides support for dependency management with annotations through the use of the

    ServiceReferenceDependencyBeanFactoryPostProcessor class, but this class is package-protected

    and can only be used through extender-based configuration. For this reason, we recommend that

    you use the extender-based configuration mechanism (后面的笔记中将会体现使用方式) if you want to

    use  annotation-based service injection.

4. RequireBundle:

    ...

    Require-Bundle: com.springsource.javax.servlet;version="2.5.0"

    ...

    该声明指定该Bundle需要一个Bundle:com.springsource.javax.servlet, 版本为大于等于2.5.0的。

    默认情况下,该Bundle有一个属性:visibility,默认值为private;可选值有:reexport;例如:

    Bundle B  使用了声明Require-Bundle: A,则BunldeA Export的Package只能在BundleB中使用;但如果

    Bundle b  使用了声明Require-Bundle:A;visibility:=reexport,那么这将允许消费Bundle B 的其他消费Bundle

    如:Bundle C使用了声明:Reuqire-Bundle: B,可以自动看见Bundle A Export的Package.

 

    该Header常见的使用是Split Package,见附件设计图:Split packages using a facade with Require

    -Bundle.jpg

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics