Mamy podobną potrzebę w jednej z naszych starszych aplikacji. Rozwiązaniem, które wymyśliliśmy, był ResourceManager, który pobierał zasoby (Logger, Config files etc) według (context) ClassLoader.
Zwykle każda aplikacja wdrożona jako EAR otrzymuje własną klasę ClassLoader, a biblioteka może wtedy wywołać ResourceManager.getLogger() w celu uzyskania Loggera powiązanego z bieżącym wątkiem/aplikacją. W ten sposób nie musisz go przekazywać przy każdym wywołaniu metody w bibliotece (wymaga to zmiany biblioteki).
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);
}
}
Rejestracja Rejestrator w fazie init EJB/aplikacji sieci Web (musi być rejestrowane przed każdym wywołaniu getLogger):
Logger logger = Logger.getLogger([Application Logger Name]);
ResourceManager.registerLogger(logger);
Retrieve rejestratora w bibliotece (metoda Narzędzie)
private Logger getLogger()
{
return ResourceManager.getLogger();
}
Spowoduje to zwrócenie programu rejestrującego dla aplikacji (EAR) powiązanej z bieżącym wątkiem.
Nie ogranicza się tylko do Loggers działa również dla innych zasobów, które chcesz udostępnić.
Ograniczenia:
przyzwyczajenie praca, jeśli pakiet wielu aplikacji/EJBs za wdrożonej EAR
ResourceManager i biblioteki rejestrowania muszą być na tym samym lub wyższym ClassLoader niż biblioteki i aplikacji. Jeśli istnieje opcja łączenia, to podejście Alexandersa jest czystsze. (używamy java.util.logging, który jest domyślnie na poziomie serwera, więc jego podejście nie działa)
Na marginesie tego rozwiązania można również używać do dzielenia się wszelkimi zasobami, a nie tylko rejestratorami. – Stefan
możesz wkleić odpowiednie sekcje kodu w swojej odpowiedzi, na wypadek gdyby link umarł w przyszłości. – rouble
Inną rzeczą, na którą warto zwrócić uwagę na temat tej metody, jest to, że ResourceManager.registerLogger() musi zostać wywołany przed utworzeniem instancji biblioteki. W przeciwnym razie rejestratory klas zostaną ustawione przy użyciu domyślnego programu rejestrującego. Może to być przełom w przypadku niektórych implementacji. – rouble