Global References To ApplicationContext(s) Unintrusively
June 6, 2005 – 19:58 | java, springSpring provides an out-of-box SingletonBeanFactoryLocator (or WebApplicationContextUtils in the case of a Web application) for code to globally reference bean factories and application contexts. The class takes a resource string (by default "classpath*:beanRefFactory.xml") and builds a bean factory from all the definition files on the classpath matching the resource string. Most of the time this suffices - straightforward and easy to use. However this locator-also-creates approach can be inconvenient in some cases, where I don't find myself having control over when and how to create the bean factories. This is where my "passive" AppContextCollector comes in.
The implementation itself is quite simple and straightforward.
-
package com.digizen.commons.spring;
-
-
import org.apache.log4j.Logger;
-
-
import java.lang.ref.WeakReference;
-
import java.util.HashMap;
-
import java.util.Iterator;
-
import java.util.Map;
-
-
import org.springframework.beans.BeansException;
-
import org.springframework.beans.factory.BeanInitializationException;
-
import org.springframework.beans.factory.InitializingBean;
-
import org.springframework.context.ApplicationContext;
-
import org.springframework.context.ApplicationContextAware;
-
-
import com.digizen.commons.util.ReferenceIteratorWrapper;
-
-
public class AppContextCollector implements ApplicationContextAware, InitializingBean {
-
-
private static final Logger LOG = Logger.getLogger(AppContextCollector.class);
-
-
private static Map<string , WeakReference<ApplicationContext>> contextMap_ =
-
new HashMap</string><string , WeakReference<ApplicationContext>>();
-
-
private String currentKey_;
-
private ApplicationContext currentContext_;
-
-
return contextMap_.get(key).get();
-
}
-
-
public static Iterator<applicationcontext> getContextIterator() {
-
return new ReferenceIteratorWrapper</applicationcontext><applicationcontext>(contextMap_.values().iterator());
-
}
-
-
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
-
currentContext_ = applicationContext;
-
}
-
-
return currentKey_;
-
}
-
-
currentKey_ = contextKey;
-
}
-
-
public void afterPropertiesSet() throws BeanInitializationException{
-
if (currentKey_ == null) {
-
throw new BeanInitializationException("Property 'contextKey' is required.");
-
}
-
-
contextMap_.put(currentKey_, new WeakReference</applicationcontext><applicationcontext>(currentContext_));
-
-
if (LOG.isDebugEnabled()) {
-
LOG.debug("ApplicationContext '" + currentKey_ + "' is collected.");
-
}
-
-
currentKey_ = null;
-
currentContext_ = null;
-
}
-
}
To collect an ApplicationContext and make it available globally through a key, declare a Spring bean in the definition file for that particular ApplicationContext:
-
<bean id="contextCollector"
-
class="com.digizen.commons.spring.AppContextCollector"
-
singleton="true">
-
<property name="contextKey"><value>mainContext</value></property>
-
</bean>
Anywhere in your code, you can then use:
-
AppContextCollector.getContext("mainContext");[/code]
-
-
To get the reference to the context instance.
-
-
Appendix: The <code>ReferenceIteratorWrapper</code> class(referenced in the above class) to avoid hanging onto any context references as they are supposed to be kept in weak references:
-
[code lang="java"]
-
package com.digizen.commons.util;
-
-
import java.lang.ref.Reference;
-
import java.util.Iterator;
-
-
public final class ReferenceIteratorWrapper<t> implements Iterator</t><t> {
-
-
private Iterator<? extends Reference<T>> iterator_;
-
-
public ReferenceIteratorWrapper(Iterator<? extends Reference<T>> iterator) {
-
iterator_ = iterator;
-
}
-
-
public boolean hasNext() {
-
return iterator_.hasNext();
-
}
-
-
public T next() {
-
return iterator_.next().get();
-
}
-
-
public T nextNotNull() {
-
while (iterator_.hasNext()) {
-
T t = iterator_.next().get();
-
if (t != null) {
-
return t;
-
}
-
}
-
return null;
-
}
-
-
public void remove() {
-
iterator_.remove();
-
}
-
}

4 Responses to “Global References To ApplicationContext(s) Unintrusively”
Great idea! I'm using Java 1.4, how would the non-generics version of ReferenceIteratorWrapper be?
Thanks,
Daniel Serodio
By Daniel Serodio on Jul 16, 2005
None of this really depends on generics. I guess to backport to 1.4, you just need to literally remove all the bracket pairs and whatever's between them, replace T with Object, and add type casting where necessary.
By Jing Xue on Jul 16, 2005
Thanks, I've been using your AppContextCollector successfully since then. Did you consider submitting it to Spring ?
By Daniel Serodio on May 4, 2006
Glad it helps. The Spring codebase is still pre-1.5 for the obvious compatibility reason. Also for it to fit into Spring, this class probably needs to implement the SingleFactoryLocator interface somehow.
By Jing Xue on May 4, 2006