¿Cómo descubro las clases en tiempo de ejecución en el classpath que implementa una interfaz definida?¿Hay algo similar a ServiceLoader en Java 1.5?
ServiceLoader se adapta bien (creo que no lo he usado), pero necesito hacerlo en Java 1.5.
¿Cómo descubro las clases en tiempo de ejecución en el classpath que implementa una interfaz definida?¿Hay algo similar a ServiceLoader en Java 1.5?
ServiceLoader se adapta bien (creo que no lo he usado), pero necesito hacerlo en Java 1.5.
No hay nada incorporado en Java 1.5 para esto. Lo implementé yo mismo; no es muy complicado. Sin embargo, cuando actualicemos a Java 6, tendré que reemplazar las llamadas a mi implementación con llamadas al ServiceLoader
. Podría haber definido un pequeño puente entre la aplicación y el cargador, pero solo lo uso en algunos lugares, y el contenedor podría ser un buen candidato para un ServiceLoader.
Esta es la idea central:
public <S> Iterable<S> load(Class<S> ifc) throws Exception {
ClassLoader ldr = Thread.currentThread().getContextClassLoader();
Enumeration<URL> e = ldr.getResources("META-INF/services/" + ifc.getName());
Collection<S> services = new ArrayList<S>();
while (e.hasMoreElements()) {
URL url = e.nextElement();
InputStream is = url.openStream();
try {
BufferedReader r = new BufferedReader(new InputStreamReader(is, "UTF-8"));
while (true) {
String line = r.readLine();
if (line == null)
break;
int comment = line.indexOf('#');
if (comment >= 0)
line = line.substring(0, comment);
String name = line.trim();
if (name.length() == 0)
continue;
Class<?> clz = Class.forName(name, true, ldr);
Class<? extends S> impl = clz.asSubclass(ifc);
Constructor<? extends S> ctor = impl.getConstructor();
S svc = ctor.newInstance();
services.add(svc);
}
}
finally {
is.close();
}
}
return services;
}
mejor manejo de excepciones se deja como ejercicio para el lector. Además, el método podría parametrizarse para aceptar un ClassLoader de la elección de la persona que llama.
No hay una manera confiable de saber qué clases están en la ruta de clase. De acuerdo con su documentation, ServiceLoader se basa en archivos externos para indicarle qué clases cargar; es posible que desee hacer lo mismo. La idea básica es tener un archivo con el nombre de la (s) clase (s) a cargar, y luego usar el reflejo para crear una instancia de ellos/ellos.
ServiceLoader es bastante básico, y ha estado en uso (informalmente) dentro del JDK desde 1.3. ServiceLoader finalmente lo convirtió en un ciudadano de primera clase. Simplemente busca un archivo de recursos con el nombre de su interfaz, que básicamente se incluye en el directorio META-INF de un archivo jar de la biblioteca.
Ese archivo contiene el nombre de la clase a cargar.
Por lo tanto, tendría un archivo llamado:
META-INF/services/com.example.your.interface
y en su interior hay una sola línea: com.you.your.interfaceImpl .
En lugar de ServiceLoader, me gusta Netbeans Lookup. Funciona con 1.5 (y tal vez 1.4).
Fuera de la caja, hace exactamente lo mismo que ServiceLoader, y es trivial de usar. Pero ofrece mucha más flexibilidad.
Aquí hay un enlace: http://openide.netbeans.org/lookup/
Aquí está un artículo sobre ServiceLoader, pero menciones Netbeans de búsqueda en la parte inferior: http://weblogs.java.net/blog/timboudreau/archive/2008/08/simple_dependen.html
ha pensado en utilizar un framework OSGi?
javax.imageio.spi.ServiceRegistry
es el equivalente con las versiones anteriores de Java. Está disponible desde Java 1.4.
No parece una clase de utilidad general, pero lo es. Incluso es un poco más poderoso que ServiceLoader
, ya que permite cierto control sobre el orden de los proveedores devueltos y el acceso directo al registro.
Ver http://docs.oracle.com/javase/7/docs/api/index.html?javax/imageio/spi/ServiceRegistry.html
Desafortunadamente,
No hay nada construido en Java 1.5 para este ...
es sólo una parte de la verdad.
No es estándar sun.misc.Service
alrededor.
http://www.docjar.com/docs/api/sun/misc/Service.html
ten cuidado, que no es una parte de la API de J2SE estándar! Es una parte no estándar de Sun JDK. Así que no puede confiar si usa, digamos, JRockit
.
Esta es una pregunta anterior, pero la otra opción es usar Anotaciones de nivel de paquete. Ver mi respuesta para: Find Java classes implementing an interface
Las anotaciones a nivel de paquete son anotaciones que están en las clases package-info.java.
JAXB utiliza esto en lugar de Service Loaders. También creo que es más flexible que el cargador de servicios.