Tuvimos una necesidad similar en una de nuestras aplicaciones anteriores. La solución que obtuvimos fue un ResourceManager que recuperaría recursos (Logger, Config files, etc.) por (context) ClassLoader.
Por lo general, cada aplicación implementada como un EAR obtiene su propio ClassLoader y la biblioteca puede simplemente llamar a ResourceManager.getLogger() para obtener el registrador asociado con el subproceso/aplicación actual. De esta forma, no necesita pasarlo con cada llamada a un método en la biblioteca (requiere que usted pueda cambiar la biblioteca).
import java.util.*;
import java.util.logging.*;
public class ResourceManager
{
private static final Map<ClassLoader, Map<String, Object>> resources =
Collections.synchronizedMap(new WeakHashMap<ClassLoader, Map<String, Object>>());
public static final String LOGGER = Logger.class.getName();
static
{
// adjust for log4j or other frameworks
final Logger logger = Logger.getLogger("logging.default");
logger.setLevel(Level.ALL);
logger.addHandler(new ConsoleHandler()
{
{
setOutputStream(System.out);
setLevel(Level.ALL);
}
});
registerResource(null, LOGGER, logger);
}
private static ClassLoader getApplicationScope()
{
return Thread.currentThread().getContextClassLoader();
}
public static void registerResource(final String name, final Object resource)
{
registerResource(getApplicationScope(), name, resource);
}
public static synchronized void registerResource(final ClassLoader scope, final String name, final Object resource)
{
Map<String, Object> hm = null;
hm = resources.get(scope);
if (hm == null)
{
hm = Collections.synchronizedMap(new HashMap<String, Object>());
resources.put(scope, hm);
}
hm.put(name, resource);
}
public static Object getResource(final String name)
{
for(ClassLoader scope = getApplicationScope();;scope = scope.getParent())
{
final Map<String, Object> hm = resources.get(scope);
if ((hm != null) && hm.containsKey(name))
{
return hm.get(name);
}
if (scope == null) break;
}
return null;
}
public static void registerLogger(final Logger logger)
{
registerResource(LOGGER, logger);
}
public static Logger getLogger()
{
return (Logger)getResource(LOGGER);
}
}
Registro Logger en la fase de inicio de EJB/aplicación web (tiene que ser registrada antes de cualquier llamada a getLogger):
Logger logger = Logger.getLogger([Application Logger Name]);
ResourceManager.registerLogger(logger);
Recuperar Logger en la biblioteca (método de utilidad):
private Logger getLogger()
{
return ResourceManager.getLogger();
}
Esto devolverá el registrador para la aplicación (EAR) que está asociada con el hilo actual.
No limitado a los registradores, también funciona para otros recursos que desee compartir.
Limitaciones:
no funcionará si empaquetar múltiples aplicaciones/EJB por EAR desplegado
ResourceManager y la biblioteca de registro deben estar incluidos en el mismo o un cargador de clases más alta que la biblioteca y aplicación. Si hay una opción para agrupar, el enfoque de Alexanders es más limpio. (usamos java.util.logging que es por defecto en el nivel del servidor por lo que su enfoque no funciona)
Como nota al margen, esta solución también se puede usar para compartir todo tipo de recursos, no solo los registradores. – Stefan
es posible que desee pegar secciones de código relevantes en su respuesta, en caso de que el enlace muera en el futuro. – rouble
Otra cosa a tener en cuenta acerca de este método es que se debe invocar a ResourceManager.registerLogger() antes de crear una instancia de la biblioteca. De lo contrario, los registradores de clase se establecerán utilizando el registrador predeterminado. Esto puede ser un factor decisivo para algunas implementaciones. – rouble