2011-02-09 23 views
5

Me gustaría saber qué se consideran las mejores prácticas o patrones para desacoplar el código de la aplicación del código de la infraestructura, específicamente con respecto a OSGi.Mejor práctica de acoplamiento suelto OSGi

Voy a utilizar el servicio example from the Felix SCR pages

El ejemplo es un comparador

package sample.service; 
import java.util.Comparator; 
public class SampleComparator implements Comparator 
{ 
    public int compare(Object o1, Object o2) 
    { 
     return o1.equals(o2) ? 0 : -1; 
    } 
} 

El código anterior no contiene cañerías marco, que está enfocado y conciso. Hacer que esté disponible para la aplicación, cuando se usa OSGi, implica registrarlo en un registro de servicio. Una forma, como se describe en las páginas de Felix vinculadas, es mediante el uso de Service Component Runtime.

// OSGI-INF/sample.xml 
<?xml version="1.0" encoding="UTF-8"?> 
<component name="sample.component" immediate="true"> 
    <implementation class="sample.service.SampleComparator" /> 
    <property name="service.description" value="Sample Comparator Service" /> 
    <property name="service.vendor" value="Apache Software Foundation" /> 
    <service> 
    <provide interface="java.util.Comparator" /> 
    </service> 
</component> 

y

Service-Component: OSGI-INF/sample.xml 

Todo agradable y encantador, mi implementación del servicio no tiene acoplamiento en absoluto a OSGi.

Ahora quiero utilizar el servicio ...

package sample.consumer; 
import java.util.Comparator; 
public class Consumer { 
    public void doCompare(Object o1, Object o2) { 
     Comparator c = ...; 
    } 
} 

El uso de la estrategia de búsqueda SCR tengo que añadir métodos marco de sólo:

protected void activate(ComponentContext context) { 
    Comparator c = (Comparator) context.locateService("sample.component"); 
} 

uso de la estrategia de eventos SCR también tengo que añadir métodos marco de sólo:

protected void bindComparator(Comparator c) { 
    this.c = c; 
} 

protected void unbindComparator(Comparator c) { 
    this.c = null; 
} 

Ni son terriblemente onerosa, aunque creo que es probable que terminarías wi La cantidad justa de este tipo de código se duplica en las clases, lo que hace que sea más ruidoso filtrar.

Una posible solución que puedo ver sería utilizar una clase específica OSGi para mediar entre el consumidor, a través de medios más tradicionales, y el marco.

package sample.internal; 
public class OsgiDependencyInjector { 
    private Consumer consumer; 
    protected void bindComparator(Comparator c) { 
     this.consumer.setComparator(c); 
    } 

    protected void unbindComparator(Comparator c) { 
     this.consumer.setComparator(null); 
    } 
} 

Aunque no estoy seguro de cómo lo arreglaría en la configuración de SCR.

Existe también org.apache.felix.scr.annotations, aunque eso significa que todo, sólo funcionará si usted está construyendo con el experto-SCR-plugin. No está tan mal realmente y, AFAICT, no imponen ninguna implicación en el tiempo de ejecución.

Así que, ahora que usted ha leído todo esto, ¿qué sugieres es la mejor manera de consumir OSGi servicios prestados sin 'contaminar' código de la aplicación con el código de la arquitectura?

Respuesta

3

1) No creo que los métodos de enlace estén contaminando tu código, solo son setters de bean (también puedes llamarlos setXXX para que sean más tradicionales). También los necesitarás para pruebas unitarias.

2) Si usa bnd (que está en maven, ant, bndtools, eclipse plugin, etc.) entonces también puede usar las anotaciones de la bnd. Bnd creará automáticamente el xml (siempre horrible) para usted.

package sample.service; 
import java.util.Comparator; 
import aQute.bnd.annotations.component.*; 

@Component 
public class SampleComparator implements Comparator { 
    public int compare(Object o1, Object o2) { 
     return o1.equals(o2) ? 0 : -1; 
    } 
} 

@Component 
class Consumer { 
    Comparator comparator; 

    public void doCompare(Object o1, Object o2) { 
     if (comparator.compare(o1,o2)) 
     .... 
    } 

    @Reference 
    protected setComparator(Comparator c) { 
     comparator = c; 
    } 
} 

En su manifiesto, sólo tiene que añadir:

Service-Component: * 

Este será recogido por el BND. Entonces no hay código OSGi en su código de dominio. Es posible que le sorprenda que no haya un método no establecido, pero el valor predeterminado para bnd es el enlace estático. Entonces se llama al método set antes de que se active y se desactiva antes de que se llame el desarmado. Siempre que su objeto de Consumo sea un μservicio también, está a salvo. Mira bndtools, la página de inicio bnd, y mi blogs para obtener más información sobre μservices.

PS. Su muestra es un código no válido porque o1 responderá tanto a mayor como menor que o2 si o1! = O2, esto no está permitido por el contrato del Comparador y hará que los géneros sean inestables.

2

Te escribiré cómo lo hacemos en mi proyecto. Como contenedor OSGi, usamos Fuse ESB, aunque en algún lugar dentro de Apache Karaf se puede encontrar. Para no contaminar nuestro código usamos Spring DM (http://www.springsource.org/osgi), lo que facilita enormemente la interacción con el contenedor OSGi. Está probado "contra Equinox 3.2.x, Felix 1.0.3+ y Knopflerfish 2.1.x como parte de nuestro proceso de integración continua" (la última versión).

ventajas de este enfoque:

  • toda la configuración "osgi" en archivos XML - código no contaminado
  • capacidad de trabajar con diferentes implementaciones de contenedor OSGi

¿Cómo se ve?

  • servicio de publicación en el registro de OSGi:

< osgi: Servicio id = "alguna-id" ref = "grano-implementación de servicio a exponer" interface = "interface- de-su-servicio" />

  • la importación de servicios de OSGi registro:

< osgi: id de referencia = interfaz "grano-id" = "interfaz de servicio expuesto" />

Por otra parte, para crear paquetes OSGi válidos que utilizamos maven-haz-plugin .

1

La ventaja de las anotaciones de Felix en comparación con las de aQute.bnd.annotations.component parece ser que los métodos de vinculación y desvinculación se crean automáticamente con el plugin de felix scr (puede anotar un campo privado). La desventaja del plugin de felix es que actúa sobre las fuentes de Java y, por lo tanto, no funciona para archivos de clase creados en otros lenguajes (como scala).