हमें हमारे पुराने अनुप्रयोगों में से एक में समान आवश्यकता थी। जिस समाधान के साथ हम आए थे वह एक संसाधन प्रबंधक था जो संसाधन (लॉगर, कॉन्फ़िगरेशन इत्यादि) को (संदर्भ) क्लासलोडर द्वारा पुनर्प्राप्त करेगा।
आमतौर पर ईएआर के रूप में तैनात हर एप्लिकेशन को अपना स्वयं का क्लासलोडर मिलता है और लाइब्रेरी केवल मौजूदा थ्रेड/एप्लिकेशन से जुड़े लॉगर को प्राप्त करने के लिए ResourceManager.getLogger() को कॉल कर सकती है। इस तरह आपको लाइब्रेरी में प्रत्येक विधि कॉल के साथ इसे पास करने की आवश्यकता नहीं है (इसके लिए आवश्यक है कि आप लाइब्रेरी को बदल सकें)।
Logger logger = Logger.getLogger([Application Logger Name]);
ResourceManager.registerLogger(logger);
पुस्तकालय में लॉगर पुनः प्राप्त (उपयोगिता विधि):
private Logger getLogger()
{
return ResourceManager.getLogger();
}
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 की init चरण में लॉगर (getLogger के लिए किसी भी कॉल करने से पहले पंजीकृत होना आवश्यक है)
यह वर्तमान थ्रेड से जुड़े एप्लिकेशन (ईएआर) के लिए लॉगर वापस करेगा।
लॉगर्स तक सीमित नहीं है यह अन्य संसाधनों के लिए भी काम करता है जिन्हें आप साझा करना चाहते हैं।
सीमाएं:
अभ्यस्त काम अगर आप तैनात EAR
संसाधनप्रबंधक और लॉगिंग पुस्तकालय प्रति एक से अधिक आवेदन/EJBs पैकेज एक ही या पुस्तकालय और आवेदन की तुलना में अधिक classloader पर होने की जरूरत है। यदि बंडल करने का कोई विकल्प है तो अलेक्जेंडर्स दृष्टिकोण क्लीनर है। (हम java.util.logging का उपयोग करते हैं जो सर्वर स्तर पर डिफ़ॉल्ट रूप से होता है, इसलिए उसका दृष्टिकोण काम नहीं करता है)
एक साइड नोट के रूप में इस समाधान का उपयोग सभी प्रकार के संसाधनों को साझा करने के लिए भी किया जा सकता है, न केवल लॉगर्स। – Stefan
यदि भविष्य में लिंक मर जाता है, तो आप अपने उत्तर में कोड के प्रासंगिक अनुभाग पेस्ट करना चाहेंगे। – rouble
इस विधि के बारे में ध्यान देने योग्य एक अन्य बात यह है कि लाइब्रेरी तत्काल होने से पहले ResourceManager.registerLogger() को कॉल किया जाना चाहिए। अन्यथा, क्लास लॉगर्स डिफ़ॉल्ट लॉगर का उपयोग करके सेट किए जाएंगे। यह कुछ कार्यान्वयन के लिए एक सौदा ब्रेकर हो सकता है। – rouble