java - injection - inyeccion de dependencias swift
Inyección de dependencia en entornos OSGI (6)
Enfoque global
La forma más sencilla de tener inyección de dependencia con Apache Sling, y la que se utiliza en toda la base de código, es usar maven-scr-plugin .
Puede anotar sus clases de Java y luego, en tiempo de compilación, invocar el plugin SCR, ya sea como un plugin de Maven o como una tarea Ant.
Por ejemplo, para registrar un servlet puede hacer lo siguiente:
@Component // signal that it''s OSGI-managed
@Service(Servlet.class) // register as a Servlet service
public class SampleServlet implements Servlet {
@Reference SlingRepository repository; // get a reference to the repository
}
Respuestas específicas
¿Cómo se comparan los servicios declarativos con la DI "tradicional" como Guice o Spring? ¿Resuelven el mismo problema o están orientados a diferentes problemas?
Resuelven el mismo problema: inyección de dependencia. Sin embargo (ver más abajo) también están diseñados para tener en cuenta los sistemas dinámicos donde los servicios pueden aparecer o desaparecer en cualquier momento.
Todas las soluciones específicas de OSGI que he visto hasta ahora carecen del concepto de alcances para DI. Por ejemplo, Guice + guice-servlet ha solicitado dependencias con ámbito que hace que escribir aplicaciones web sea realmente limpio y fácil. ¿Acabo de perder eso en los documentos o estas preocupaciones no están cubiertas por ninguno de estos marcos?
No he visto ningún enfoque en el mundo SCR para agregar servicios con ámbito de sesión o de ámbito de solicitud. Sin embargo, SCR es un enfoque genérico, y el alcance se puede manejar en una capa más específica.
Como está usando Sling, creo que habrá poca necesidad de enlaces de sesión o de ámbito de solicitud, ya que Sling tiene objetos incorporados para cada solicitud que se crean de forma apropiada para el usuario actual.
Un buen ejemplo es la sesión de JCR. Se construye automáticamente con los privilegios correctos y en la práctica es un DAO con ámbito de solicitud. Lo mismo ocurre con Sling resourceResolver.
Si encuentra que necesita trabajo por usuario, el enfoque más simple es contar con servicios que reciban una Session
JCR o un Sling ResourceResolver
y los utilice para realizar el trabajo que necesita. Los resultados se ajustarán automáticamente para los privilegios del usuario actual sin ningún esfuerzo adicional.
¿Los DI de JSR 330 y OSGI tienen dos mundos diferentes? iPOJO, por ejemplo, trae sus propias anotaciones y las anotaciones de Felix SCR parecen ser un mundo completamente diferente.
Sí, son diferentes. Debe tener en cuenta que aunque Spring y Guice son más convencionales, los servicios OSGi son más complejos y admiten más casos de uso. En los paquetes de OSGi (e implícitamente los servicios) son gratuitos y gratuitos en cualquier momento.
Esto significa que cuando tiene un componente que depende de un servicio que simplemente no está disponible, su componente se desactiva. O cuando recibe una lista de componentes (por ejemplo, implementaciones de Servlet) y uno de ellos está desactivado, se lo notifica. Que yo sepa, ni Spring ni Guice apoyan esto ya que sus cables son estáticos.
Esa es una gran cantidad de flexibilidad que te ofrece OSGi.
¿Alguien tiene experiencia en la construcción de sistemas basados en OSGI y DI? Tal vez incluso un código de muestra en github?
Hay una gran cantidad de muestras en el repositorio Sling Samples SVN . Deberías encontrar la mayor parte de lo que necesitas allí.
¿Alguien usa diferentes tecnologías como Guice e iPOJO juntas o es solo una idea loca?
Si tiene marcos que están configurados con anotaciones JSR 330, tiene sentido configurarlos en tiempo de ejecución utilizando Guice o Spring o lo que sea que funcione para usted. Sin embargo, como ha señalado Neil Bartlett, esto no funcionará en paquetes cruzados.
Primero algunos antecedentes:
Estoy trabajando en un código de prototipo de webapp basado en Apache Sling que está basado en OSGI y se ejecuta en Apache Felix. Todavía soy relativamente nuevo en OSGI aunque creo que ya comprendí la mayoría de los conceptos. Sin embargo, lo que me desconcierta es que no he podido encontrar un marco de inyección de dependencia (DI) "completo". He empleado con éxito el DI rudimentario usando los Servicios declarativos (DS). Pero entiendo que los DS se utilizan para hacer referencia, ¿cómo puedo poner esto? - OSGI registró servicios y componentes juntos. Y para eso funciona bien, pero yo personalmente uso marcos DI como Guice para conectar gráficos de objetos completos y poner objetos en los ámbitos correctos (por ejemplo, piense en @RequestScoped
o @SessionScoped
). Sin embargo, ninguno de los marcos específicos de OSGI que he analizado parece apoyar este concepto.
Empecé a leer acerca de los modelos OSGI y iPOJO pero estos marcos parecen estar más preocupados por cablear los servicios OSGI juntos que por proporcionar una solución DI completa. Tengo que admitir que aún no he hecho ninguna muestra, por lo que mi impresión podría ser incorrecta.
Siendo una extensión de Guice, he experimentado con Peaberry , sin embargo, encontré la documentación muy difícil de encontrar, y aunque obtuve un funcionamiento DI básico, una gran cantidad de funciones avanzadas de guice-servlet (inyección automática en filtros, servlets, etc.) no funcionó. t trabajo en absoluto.
Entonces, mis preguntas son las siguientes:
- ¿Cómo se comparan los servicios declarativos con la DI "tradicional" como Guice o Spring? ¿Resuelven el mismo problema o están orientados a diferentes problemas?
- Todas las soluciones específicas de OSGI que he visto hasta ahora carecen del concepto de alcances para DI. Por ejemplo, Guice + guice-servlet ha solicitado dependencias con ámbito que hace que escribir aplicaciones web sea realmente limpio y fácil. ¿Acabo de perder eso en los documentos o estas preocupaciones no están cubiertas por ninguno de estos marcos?
- ¿Los DI de JSR 330 y OSGI tienen dos mundos diferentes? iPOJO, por ejemplo, trae sus propias anotaciones y las anotaciones de Felix SCR parecen ser un mundo completamente diferente.
- ¿Alguien tiene experiencia en la construcción de sistemas basados en OSGI y DI? Tal vez incluso un código de muestra en github?
- ¿Alguien usa diferentes tecnologías como Guice e iPOJO juntas o es solo una idea loca?
Perdón por la pregunta bastante larga.
Cualquier comentario es muy apreciado.
Actualizaciones
La inyección de ámbito: la inyección de ámbito es un mecanismo útil para inyectar automáticamente objetos de un ciclo de vida específico. Piense, por ejemplo, que parte de su código se basa en un objeto de sesión de Hibernate que se crea como parte de un filtro de servlet. Al marcar una dependencia, el contenedor reconstruirá automáticamente el gráfico del objeto. Tal vez solo hay diferentes enfoques para eso?
JSR 330 vs DS : de todas sus excelentes respuestas veo que estas son dos cosas diferentes. Eso plantea la pregunta, ¿cómo lidiar con bibliotecas y marcos de terceros que usan anotaciones JSR 330 cuando se usan en un contexto OSGI? ¿Cuál es un buen enfoque? ¿Ejecutando un contenedor JSR 330 dentro del paquete?
Aprecio todas tus respuestas, ¡has sido muy útil!
Estoy usando osgi y DI para mi proyecto actual. Escogí el modelo de geminis porque es la segunda versión de los MÓDULOS DINÁMICOS DE PRIMAVERA . En base a esta información, sugiero que lean los Módulos de Spring Dynamic en acción . Este libro te ayudará a entender algunas partes y puntos sobre cómo construir arquitectura y por qué es bueno :)
Me encontré con un problema de arquitectura similar aquí, como Robert mencionó anteriormente en su respuesta:
Si encuentra que necesita trabajo por usuario, el enfoque más simple es contar con servicios que reciban una sesión JCR o un Sling ResourceResolver y los utilice para realizar el trabajo que necesita. Los resultados se ajustarán automáticamente para los privilegios del usuario actual sin ningún esfuerzo adicional.
Extrapolando de esto (y de lo que estoy actualmente codificando), un enfoque sería agregar @param resourceResolver
a cualquier método @Service
para que pueda pasar el objeto del ámbito de solicitud apropiado para usar en la cadena de ejecución.
Específicamente, tenemos una capa XXXXService
/ XXXXDao
, llamada desde XXXXServlet
/ XXXXViewHelper
/ JSP equivalentes. Para gestionar todos estos componentes a través de las anotaciones OSGI @Service
, podemos conectar fácilmente toda la pila.
La desventaja aquí es que debe ensuciar su diseño de interfaz con ResourceResolver
o params de Sessions
.
Inicialmente tratamos de inyectar ResourceResolverFactory
en la capa DAO, de modo que pudiéramos acceder fácilmente a la sesión a voluntad desde la fábrica. Sin embargo, estamos interactuando con la sesión en varios puntos de la jerarquía y varias veces por solicitud. Esto dio lugar a excepciones cerradas por sesión.
¿Hay alguna forma de obtener ese ResourceResolver
por solicitud de manera confiable sin tener que pasarlo a cada método de servicio?
Con la inyección de ámbito de solicitud en las capas de servicio, en su lugar, simplemente podría pasar el ResourceResolver como un argumento de constructor y usar una variable de instancia en su lugar. Por supuesto, la desventaja aquí es que tendrías que pensar en el código de servicio del alcance de la solicitud frente al prototipo y separarlo según corresponda.
Esto parece ser un problema común en el que desea separar las preocupaciones en el código de servicio / dao, dejando las interacciones de JCR en el DAO, análoga a Hibernate, ¿cómo puede llegar fácilmente a la Session
por solicitud para realizar operaciones de repositorio?
Me gustaría agregar un poco más de información a la excelente respuesta de Robert, particularmente con respecto a JSR330 y DS.
Los servicios declarativos, Blueprint, iPOJO y los demás "modelos de componentes" OSGi están destinados principalmente a la inyección de servicios OSGi. Estos son un poco más difíciles de manejar que las dependencias regulares porque pueden aparecer y desaparecer en cualquier momento, incluso en respuesta a eventos externos (por ejemplo, la red desconectada) o acciones del usuario (por ejemplo, paquete eliminado). Por lo tanto, todos estos modelos de componentes proporcionan una capa de ciclo de vida adicional sobre los marcos de inyección de dependencia pura.
Esta es la razón principal por la que las anotaciones DS son diferentes de las JSR330 ... las JSR330 no proporcionan suficiente semántica para lidiar con el ciclo de vida. Por ejemplo, no dicen nada sobre:
- ¿Cuándo debería inyectarse la dependencia?
- ¿Qué deberíamos hacer cuando la dependencia no está disponible actualmente (es decir, es opcional u obligatoria)?
- ¿Qué deberíamos hacer cuando un servicio que estamos usando desaparece?
- ¿Podemos cambiar dinámicamente de una instancia de un servicio a otra?
- etc ...
Desafortunadamente, debido a que los modelos de componentes se centran principalmente en los servicios, es decir, los vínculos entre los paquetes, son comparativamente espartanos con respecto al cableado de las dependencias dentro del paquete (aunque Blueprint ofrece algo de soporte para esto).
No debería haber problemas al usar un marco DI existente para cablear las dependencias dentro del paquete. Por ejemplo, tuve un cliente que usó Guice para cablear los componentes internos de algunos componentes de los Servicios Declarativos. Sin embargo, tiendo a cuestionar el valor de hacer esto, porque si necesita DI dentro de su paquete, sugiere que su paquete puede ser demasiado grande e incoherente.
Tenga en cuenta que es muy importante NO utilizar un marco DI tradicional para cablear componentes entre haces. Si el marco DI necesita acceder a una clase de otro paquete, ese otro paquete debe exponer sus detalles de implementación, lo que rompe la encapsulación que buscamos en OSGi.
Puedo recomendar Bnd y si también usa Eclipse IDE sepcially Bndtools. Con eso puedes evitar describir DS en XML y usar anotaciones en su lugar. Hay una anotación de Reference
especial para DI. Este también tiene un filtro donde puede hacer referencia solo a un subconjunto especial de servicios.
Tengo experiencia en la construcción de aplicaciones usando Aries Blueprint. Tiene algunas características muy agradables con respecto a los servicios OSGi y el soporte de administración de configuración.
Si busca algunos ejemplos geniales, eche un vistazo al código de Apache Karaf que utiliza un plano para todo su cableado. Ver http://svn.apache.org/repos/asf/karaf/
También tengo algunos tutortials para Blueprint y Apache Karaf en mi sitio web: http://www.liquid-reality.de/display/liquid/Karaf+Tutorials
En su entorno con el felix incorporado, será un poco diferente ya que no tiene las funciones de administración de Karaf, pero solo necesita instalar los mismos paquetes y debería funcionar bien.