2010-01-20 14 views
18

Me gustaría implementar una función de complemento dinámico en una aplicación Java. Idealmente:Implementación de complementos dinámicos en Java

  • La aplicación sería definir una interfaz Plugin con un método como getCapabilities().
  • Un complemento sería un JAR pluginX.jar que contiene una clase PluginXImpl implementando Plugin (y tal vez algunos otros).
  • El usuario pondría pluginX.jar en un directorio especial o establecería un parámetro de configuración apuntando a él. El usuario no debería necesariamente tener que incluir pluginX.jar en su classpath.
  • La aplicación encontraría PluginXImpl (tal vez a través del manifiesto JAR, tal vez por reflexión) y agregarlo a un registro.
  • El cliente puede obtener una instancia de PluginXImpl, por ejemplo, invocando un método como getPluginWithCapabilities("X"). El usuario no necesariamente debe saber el nombre del complemento.

Tengo la sensación de que podría hacer esto con peaberry, pero no puedo entender la documentación. He invertido algo de tiempo en aprender sobre Guice, por lo que mi respuesta preferida no sería "use Spring Dynamic Modules".

¿Alguien puede darme una idea simple de cómo hacer esto usando Guice/peaberry, OSGi, o simplemente Java?

+0

Peaberry y Spring DM son capas sobre OSGi. OSGi parece hacer lo que quiere (conceptualmente), pero lo hará de la manera 'OSGi-way' y no se asignará a su proceso exacto, por lo que una sugerencia es google para algunos tutoriales OSGi. – SteveD

+1

OSGi parece cien veces más complicado que peaberry. ¿Algún enlace a buenos tutoriales? –

Respuesta

17

Esto es realmente muy fácil usando llanura de Java significa:

Puesto que usted no desea que el usuario configure la ruta de clase antes de iniciar la aplicación, lo primero sería crear un URLClassLoader con una serie de direcciones URL a los archivos en su directorio de plugins Use File.listFiles para buscar todos los archivos jar de complementos y luego File.toURI(). ToURL() para obtener una URL para cada archivo. Debería pasar el cargador de clases del sistema (ClassLoader.getSystemClassLoader()) como principal a su URLClassLoader.

Si los archivos auxiliares contienen un archivo de configuración en META-INF/services como se describe en la documentación API para java.util.ServiceLoader, ahora puede usar ServiceLoader.load (Plugin.class, myUrlClassLoader) para obtener un cargador de servicio para su interfaz de Plugin e invoque iterator() en ella para obtener instancias de todas las implementaciones de Plugin configuradas.

Todavía tiene que proporcionar su propio envoltorio alrededor de esto para filtrar las capacidades del plugin, pero eso no debería ser demasiado problema, supongo.

+0

¿Podría explicar esto un poco más detallado? – stacker

+1

No, a menos que tenga una pregunta más detallada. – jarnbjo

+0

@jarnbjo: ¡Eso funciona totalmente! ¡Gracias! Todavía estaría interesado en ver una solución de peaberry u OSGi ... –

0

Disculpe si sabe esto, pero consulte el método forName de Class. Se utiliza al menos en JDBC para cargar dinámicamente el tiempo de ejecución de las clases de controlador específicas de DBMS por nombre de clase.

Entonces supongo que no sería difícil enumerar todos los archivos de clase/jar en un directorio, cargar cada uno de ellos y definir una interfaz para un método estático getCapabilities() (o cualquier nombre que elija) que devuelva sus capacidades/descripción en los términos y formatos que tengan sentido para su sistema.

+0

@ Bandi-T: he agregado algunos de los requisitos anteriores en respuesta. No quiero tener que usar algo como 'getPluginInstance (" org.example.PluginXImpl ")' o necesariamente tener el directorio de complementos en classpath. –

+0

@Chris Conway: Entonces lo siento, eso está más allá de mí, no estoy muy avanzado en Java. –

1

OSGI estaría bien si quiere reemplazar los complementos durante el tiempo de ejecución, p. para correcciones de errores en un entorno 24/7. Jugué un tiempo con OSGI pero me llevó demasiado tiempo, porque no era un requisito, y necesitas un plan b si eliminas un paquete.

Mi humilde solución fue, proporcionar un archivo de propiedades con los nombres de clase de las clases de descriptores de complementos y dejar que el servidor los llame para registrarlos (incluso consultar sus capacidades).

Esto es obvio subóptimo, pero no puedo esperar para leer la respuesta aceptada.

1

La mejor manera de implementar plug-ins con Guice es con Multibindings. La página enlazada entra en detalles sobre cómo usar los enlaces múltiples para alojar complementos.

+1

"Tenga en cuenta que este mecanismo no puede cargar o descargar complementos mientras el sistema se está ejecutando". Me parece que los Multibindings requieren que los JAR del plugin estén en el classpath y que el usuario especifique las clases del Módulo en un archivo de configuración. Tal vez pueda cargar dinámicamente los JAR en el directorio de complementos utilizando un ClassLoader, pero luego tendría que usar algo así como un cargador de servicios para encontrar los módulos automáticamente. –