У нас была похожая потребность в одном из наших старых приложений.Решением, которое мы придумали, был ResourceManager, который извлекал ресурсы (Logger, файлы конфигурации и т. Д.) С помощью (context) ClassLoader.
Обычно каждое приложение, развернутое как EAR, получает свой собственный ClassLoader, и библиотека может затем просто вызвать ResourceManager.getLogger (), чтобы получить Logger, связанный с текущим потоком / приложением.Таким образом, вам не нужно передавать его при каждом вызове метода в библиотеке (это требует, чтобы вы могли изменить библиотеку, хотя).
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);
}
}
Зарегистрировать регистратор в фазе инициализации EJB / WebApp (необходимо зарегистрироваться перед любым вызовом getLogger):
Logger logger = Logger.getLogger([Application Logger Name]);
ResourceManager.registerLogger(logger);
Получить регистратор в библиотеке (служебный метод):
private Logger getLogger()
{
return ResourceManager.getLogger();
}
Возвращает регистратор для приложения (EAR), связанного с текущим потоком.
Не ограничивается регистраторами, он также работает для других ресурсов, которыми вы хотите поделиться.
Ограничения:
не будут работать, если вы упаковываете несколько приложений / EJB для развернутого EAR
Необходимо использовать ResourceManager и Logging libraryна том же или более высоком ClassLoader, чем библиотека и приложение.Если есть возможность связать, то подход Александера будет чище.(мы используем java.util.logging, который по умолчанию находится на уровне сервера, поэтому его подход не работает)