0001: /*
0002: * Copyright 2002-2007 the original author or authors.
0003: *
0004: * Licensed under the Apache License, Version 2.0 (the "License");
0005: * you may not use this file except in compliance with the License.
0006: * You may obtain a copy of the License at
0007: *
0008: * http://www.apache.org/licenses/LICENSE-2.0
0009: *
0010: * Unless required by applicable law or agreed to in writing, software
0011: * distributed under the License is distributed on an "AS IS" BASIS,
0012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0013: * See the License for the specific language governing permissions and
0014: * limitations under the License.
0015: */
0016:
0017: package org.springframework.context.support;
0018:
0019: import java.io.IOException;
0020: import java.util.ArrayList;
0021: import java.util.Collection;
0022: import java.util.Collections;
0023: import java.util.Date;
0024: import java.util.Iterator;
0025: import java.util.List;
0026: import java.util.Locale;
0027: import java.util.Map;
0028:
0029: import org.apache.commons.logging.Log;
0030: import org.apache.commons.logging.LogFactory;
0031:
0032: import org.springframework.beans.BeansException;
0033: import org.springframework.beans.factory.BeanFactory;
0034: import org.springframework.beans.factory.DisposableBean;
0035: import org.springframework.beans.factory.NoSuchBeanDefinitionException;
0036: import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
0037: import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
0038: import org.springframework.beans.factory.config.BeanPostProcessor;
0039: import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
0040: import org.springframework.beans.support.ResourceEditorRegistrar;
0041: import org.springframework.context.ApplicationContext;
0042: import org.springframework.context.ApplicationContextAware;
0043: import org.springframework.context.ApplicationEvent;
0044: import org.springframework.context.ApplicationEventPublisherAware;
0045: import org.springframework.context.ApplicationListener;
0046: import org.springframework.context.ConfigurableApplicationContext;
0047: import org.springframework.context.HierarchicalMessageSource;
0048: import org.springframework.context.Lifecycle;
0049: import org.springframework.context.MessageSource;
0050: import org.springframework.context.MessageSourceAware;
0051: import org.springframework.context.MessageSourceResolvable;
0052: import org.springframework.context.NoSuchMessageException;
0053: import org.springframework.context.ResourceLoaderAware;
0054: import org.springframework.context.event.ApplicationEventMulticaster;
0055: import org.springframework.context.event.ContextClosedEvent;
0056: import org.springframework.context.event.ContextRefreshedEvent;
0057: import org.springframework.context.event.SimpleApplicationEventMulticaster;
0058: import org.springframework.core.OrderComparator;
0059: import org.springframework.core.Ordered;
0060: import org.springframework.core.io.DefaultResourceLoader;
0061: import org.springframework.core.io.Resource;
0062: import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
0063: import org.springframework.core.io.support.ResourcePatternResolver;
0064: import org.springframework.util.Assert;
0065: import org.springframework.util.ObjectUtils;
0066:
0067: /**
0068: * Abstract implementation of the {@link org.springframework.context.ApplicationContext}
0069: * interface. Doesn't mandate the type of storage used for configuration; simply
0070: * implements common context functionality. Uses the Template Method design pattern,
0071: * requiring concrete subclasses to implement abstract methods.
0072: *
0073: * <p>In contrast to a plain BeanFactory, an ApplicationContext is supposed
0074: * to detect special beans defined in its internal bean factory:
0075: * Therefore, this class automatically registers
0076: * {@link org.springframework.beans.factory.config.BeanFactoryPostProcessor BeanFactoryPostProcessors},
0077: * {@link org.springframework.beans.factory.config.BeanPostProcessor BeanPostProcessors}
0078: * and {@link org.springframework.context.ApplicationListener ApplicationListeners}
0079: * which are defined as beans in the context.
0080: *
0081: * <p>A {@link org.springframework.context.MessageSource} may also be supplied
0082: * as a bean in the context, with the name "messageSource"; else, message
0083: * resolution is delegated to the parent context. Furthermore, a multicaster
0084: * for application events can be supplied as "applicationEventMulticaster" bean
0085: * of type {@link org.springframework.context.event.ApplicationEventMulticaster}
0086: * in the context; else, a default multicaster of type
0087: * {@link org.springframework.context.event.SimpleApplicationEventMulticaster} will be used.
0088: *
0089: * <p>Implements resource loading through extending
0090: * {@link org.springframework.core.io.DefaultResourceLoader}.
0091: * Consequently treats non-URL resource paths as class path resources
0092: * (supporting full class path resource names that include the package path,
0093: * e.g. "mypackage/myresource.dat"), unless the {@link #getResourceByPath}
0094: * method is overwritten in a subclass.
0095: *
0096: * @author Rod Johnson
0097: * @author Juergen Hoeller
0098: * @since January 21, 2001
0099: * @see #refreshBeanFactory
0100: * @see #getBeanFactory
0101: * @see org.springframework.beans.factory.config.BeanFactoryPostProcessor
0102: * @see org.springframework.beans.factory.config.BeanPostProcessor
0103: * @see org.springframework.context.event.ApplicationEventMulticaster
0104: * @see org.springframework.context.ApplicationListener
0105: * @see org.springframework.context.MessageSource
0106: */
0107: public abstract class AbstractApplicationContext extends
0108: DefaultResourceLoader implements
0109: ConfigurableApplicationContext, DisposableBean {
0110:
0111: /**
0112: * Name of the MessageSource bean in the factory.
0113: * If none is supplied, message resolution is delegated to the parent.
0114: * @see MessageSource
0115: */
0116: public static final String MESSAGE_SOURCE_BEAN_NAME = "messageSource";
0117:
0118: /**
0119: * Name of the ApplicationEventMulticaster bean in the factory.
0120: * If none is supplied, a default SimpleApplicationEventMulticaster is used.
0121: * @see org.springframework.context.event.ApplicationEventMulticaster
0122: * @see org.springframework.context.event.SimpleApplicationEventMulticaster
0123: */
0124: public static final String APPLICATION_EVENT_MULTICASTER_BEAN_NAME = "applicationEventMulticaster";
0125:
0126: static {
0127: // Eagerly load the ContextClosedEvent class to avoid weird classloader issues
0128: // on application shutdown in WebLogic 8.1. (Reported by Dustin Woods.)
0129: ContextClosedEvent.class.getName();
0130: }
0131:
0132: /** Logger used by this class. Available to subclasses. */
0133: protected final Log logger = LogFactory.getLog(getClass());
0134:
0135: /** Parent context */
0136: private ApplicationContext parent;
0137:
0138: /** BeanFactoryPostProcessors to apply on refresh */
0139: private final List beanFactoryPostProcessors = new ArrayList();
0140:
0141: /** Display name */
0142: private String displayName = ObjectUtils.identityToString(this );
0143:
0144: /** System time in milliseconds when this context started */
0145: private long startupDate;
0146:
0147: /** Flag that indicates whether this context is currently active */
0148: private boolean active = false;
0149:
0150: /** Synchronization monitor for the "active" flag */
0151: private final Object activeMonitor = new Object();
0152:
0153: /** Synchronization monitor for the "refresh" and "destroy" */
0154: private final Object startupShutdownMonitor = new Object();
0155:
0156: /** Reference to the JVM shutdown hook, if registered */
0157: private Thread shutdownHook;
0158:
0159: /** ResourcePatternResolver used by this context */
0160: private ResourcePatternResolver resourcePatternResolver;
0161:
0162: /** MessageSource we delegate our implementation of this interface to */
0163: private MessageSource messageSource;
0164:
0165: /** Helper class used in event publishing */
0166: private ApplicationEventMulticaster applicationEventMulticaster;
0167:
0168: /** Statically specified listeners */
0169: private List applicationListeners = new ArrayList();
0170:
0171: /**
0172: * Create a new AbstractApplicationContext with no parent.
0173: */
0174: public AbstractApplicationContext() {
0175: this (null);
0176: }
0177:
0178: /**
0179: * Create a new AbstractApplicationContext with the given parent context.
0180: * @param parent the parent context
0181: */
0182: public AbstractApplicationContext(ApplicationContext parent) {
0183: this .parent = parent;
0184: this .resourcePatternResolver = getResourcePatternResolver();
0185: }
0186:
0187: //---------------------------------------------------------------------
0188: // Implementation of ApplicationContext interface
0189: //---------------------------------------------------------------------
0190:
0191: /**
0192: * Return the parent context, or <code>null</code> if there is no parent
0193: * (that is, this context is the root of the context hierarchy).
0194: */
0195: public ApplicationContext getParent() {
0196: return this .parent;
0197: }
0198:
0199: /**
0200: * Return this context's internal bean factory as AutowireCapableBeanFactory,
0201: * if already available.
0202: * @see #getBeanFactory()
0203: */
0204: public AutowireCapableBeanFactory getAutowireCapableBeanFactory()
0205: throws IllegalStateException {
0206: return getBeanFactory();
0207: }
0208:
0209: /**
0210: * Set a friendly name for this context.
0211: * Typically done during initialization of concrete context implementations.
0212: */
0213: public void setDisplayName(String displayName) {
0214: this .displayName = displayName;
0215: }
0216:
0217: /**
0218: * Return a friendly name for this context.
0219: */
0220: public String getDisplayName() {
0221: return this .displayName;
0222: }
0223:
0224: /**
0225: * Return the timestamp (ms) when this context was first loaded.
0226: */
0227: public long getStartupDate() {
0228: return this .startupDate;
0229: }
0230:
0231: /**
0232: * Publish the given event to all listeners.
0233: * <p>Note: Listeners get initialized after the MessageSource, to be able
0234: * to access it within listener implementations. Thus, MessageSource
0235: * implementations cannot publish events.
0236: * @param event the event to publish (may be application-specific or a
0237: * standard framework event)
0238: */
0239: public void publishEvent(ApplicationEvent event) {
0240: Assert.notNull(event, "Event must not be null");
0241: if (logger.isDebugEnabled()) {
0242: logger.debug("Publishing event in context ["
0243: + ObjectUtils.identityToString(this ) + "]: "
0244: + event);
0245: }
0246: getApplicationEventMulticaster().multicastEvent(event);
0247: if (this .parent != null) {
0248: this .parent.publishEvent(event);
0249: }
0250: }
0251:
0252: /**
0253: * Return the internal MessageSource used by the context.
0254: * @return the internal MessageSource (never <code>null</code>)
0255: * @throws IllegalStateException if the context has not been initialized yet
0256: */
0257: private ApplicationEventMulticaster getApplicationEventMulticaster()
0258: throws IllegalStateException {
0259: if (this .applicationEventMulticaster == null) {
0260: throw new IllegalStateException(
0261: "ApplicationEventMulticaster not initialized - "
0262: + "call 'refresh' before multicasting events via the context: "
0263: + this );
0264: }
0265: return this .applicationEventMulticaster;
0266: }
0267:
0268: /**
0269: * Return the ResourcePatternResolver to use for resolving location patterns
0270: * into Resource instances. Default is a
0271: * {@link org.springframework.core.io.support.PathMatchingResourcePatternResolver},
0272: * supporting Ant-style location patterns.
0273: * <p>Can be overridden in subclasses, for extended resolution strategies,
0274: * for example in a web environment.
0275: * <p><b>Do not call this when needing to resolve a location pattern.</b>
0276: * Call the context's <code>getResources</code> method instead, which
0277: * will delegate to the ResourcePatternResolver.
0278: * @return the ResourcePatternResolver for this context
0279: * @see #getResources
0280: * @see org.springframework.core.io.support.PathMatchingResourcePatternResolver
0281: */
0282: protected ResourcePatternResolver getResourcePatternResolver() {
0283: return new PathMatchingResourcePatternResolver(this );
0284: }
0285:
0286: //---------------------------------------------------------------------
0287: // Implementation of ConfigurableApplicationContext interface
0288: //---------------------------------------------------------------------
0289:
0290: public void setParent(ApplicationContext parent) {
0291: this .parent = parent;
0292: }
0293:
0294: public void addBeanFactoryPostProcessor(
0295: BeanFactoryPostProcessor beanFactoryPostProcessor) {
0296: this .beanFactoryPostProcessors.add(beanFactoryPostProcessor);
0297: }
0298:
0299: /**
0300: * Return the list of BeanFactoryPostProcessors that will get applied
0301: * to the internal BeanFactory.
0302: * @see org.springframework.beans.factory.config.BeanFactoryPostProcessor
0303: */
0304: public List getBeanFactoryPostProcessors() {
0305: return this .beanFactoryPostProcessors;
0306: }
0307:
0308: public void addApplicationListener(ApplicationListener listener) {
0309: this .applicationListeners.add(listener);
0310: }
0311:
0312: /**
0313: * Return the list of statically specified ApplicationListeners.
0314: * @see org.springframework.context.ApplicationListener
0315: */
0316: public List getApplicationListeners() {
0317: return this .applicationListeners;
0318: }
0319:
0320: public void refresh() throws BeansException, IllegalStateException {
0321: synchronized (this .startupShutdownMonitor) {
0322: // Prepare this context for refreshing.
0323: prepareRefresh();
0324:
0325: // Tell the subclass to refresh the internal bean factory.
0326: ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
0327:
0328: // Prepare the bean factory for use in this context.
0329: prepareBeanFactory(beanFactory);
0330:
0331: try {
0332: // Allows post-processing of the bean factory in context subclasses.
0333: postProcessBeanFactory(beanFactory);
0334:
0335: // Invoke factory processors registered as beans in the context.
0336: invokeBeanFactoryPostProcessors(beanFactory);
0337:
0338: // Register bean processors that intercept bean creation.
0339: registerBeanPostProcessors(beanFactory);
0340:
0341: // Initialize message source for this context.
0342: initMessageSource();
0343:
0344: // Initialize event multicaster for this context.
0345: initApplicationEventMulticaster();
0346:
0347: // Initialize other special beans in specific context subclasses.
0348: onRefresh();
0349:
0350: // Check for listener beans and register them.
0351: registerListeners();
0352:
0353: // Instantiate singletons this late to allow them to access the message source.
0354: beanFactory.preInstantiateSingletons();
0355:
0356: // Last step: publish corresponding event.
0357: publishEvent(new ContextRefreshedEvent(this ));
0358: }
0359:
0360: catch (BeansException ex) {
0361: // Destroy already created singletons to avoid dangling resources.
0362: beanFactory.destroySingletons();
0363: throw ex;
0364: }
0365: }
0366: }
0367:
0368: /**
0369: * Prepare this context for refreshing, setting its startup date and
0370: * active flag.
0371: */
0372: protected void prepareRefresh() {
0373: this .startupDate = System.currentTimeMillis();
0374:
0375: synchronized (this .activeMonitor) {
0376: this .active = true;
0377: }
0378:
0379: if (logger.isInfoEnabled()) {
0380: logger.info("Refreshing " + this );
0381: }
0382: }
0383:
0384: /**
0385: * Tell the subclass to refresh the internal bean factory.
0386: * @return the fresh BeanFactory instance
0387: * @see #refreshBeanFactory()
0388: * @see #getBeanFactory()
0389: */
0390: protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
0391: refreshBeanFactory();
0392: ConfigurableListableBeanFactory beanFactory = getBeanFactory();
0393:
0394: if (logger.isInfoEnabled()) {
0395: logger.info("Bean factory for application context ["
0396: + ObjectUtils.identityToString(this ) + "]: "
0397: + ObjectUtils.identityToString(beanFactory));
0398: }
0399: if (logger.isDebugEnabled()) {
0400: logger.debug(beanFactory.getBeanDefinitionCount()
0401: + " beans defined in " + this );
0402: }
0403:
0404: return beanFactory;
0405: }
0406:
0407: /**
0408: * Configure the factory's standard context characteristics,
0409: * such as the context's ClassLoader and post-processors.
0410: * @param beanFactory the BeanFactory to configure
0411: */
0412: protected void prepareBeanFactory(
0413: ConfigurableListableBeanFactory beanFactory) {
0414: // Tell the internal bean factory to use the context's class loader.
0415: beanFactory.setBeanClassLoader(getClassLoader());
0416:
0417: // Populate the bean factory with context-specific resource editors.
0418: beanFactory
0419: .addPropertyEditorRegistrar(new ResourceEditorRegistrar(
0420: this ));
0421:
0422: // Configure the bean factory with context semantics.
0423: beanFactory
0424: .addBeanPostProcessor(new ApplicationContextAwareProcessor(
0425: this ));
0426: beanFactory
0427: .ignoreDependencyInterface(ResourceLoaderAware.class);
0428: beanFactory
0429: .ignoreDependencyInterface(ApplicationEventPublisherAware.class);
0430: beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
0431: beanFactory
0432: .ignoreDependencyInterface(ApplicationContextAware.class);
0433: }
0434:
0435: /**
0436: * Modify the application context's internal bean factory after its standard
0437: * initialization. All bean definitions will have been loaded, but no beans
0438: * will have been instantiated yet. This allows for registering special
0439: * BeanPostProcessors etc in certain ApplicationContext implementations.
0440: * @param beanFactory the bean factory used by the application context
0441: */
0442: protected void postProcessBeanFactory(
0443: ConfigurableListableBeanFactory beanFactory) {
0444: }
0445:
0446: /**
0447: * Instantiate and invoke all registered BeanFactoryPostProcessor beans,
0448: * respecting explicit order if given.
0449: * Must be called before singleton instantiation.
0450: */
0451: protected void invokeBeanFactoryPostProcessors(
0452: ConfigurableListableBeanFactory beanFactory) {
0453: // Invoke factory processors registered with the context instance.
0454: for (Iterator it = getBeanFactoryPostProcessors().iterator(); it
0455: .hasNext();) {
0456: BeanFactoryPostProcessor factoryProcessor = (BeanFactoryPostProcessor) it
0457: .next();
0458: factoryProcessor.postProcessBeanFactory(beanFactory);
0459: }
0460:
0461: // Do not initialize FactoryBeans here: We need to leave all regular beans
0462: // uninitialized to let the bean factory post-processors apply to them!
0463: String[] factoryProcessorNames = beanFactory
0464: .getBeanNamesForType(BeanFactoryPostProcessor.class,
0465: true, false);
0466:
0467: // Separate between BeanFactoryPostProcessors that implement the Ordered
0468: // interface and those that do not.
0469: List orderedFactoryProcessors = new ArrayList();
0470: List nonOrderedFactoryProcessorNames = new ArrayList();
0471: for (int i = 0; i < factoryProcessorNames.length; i++) {
0472: if (isTypeMatch(factoryProcessorNames[i], Ordered.class)) {
0473: orderedFactoryProcessors.add(beanFactory
0474: .getBean(factoryProcessorNames[i]));
0475: } else {
0476: nonOrderedFactoryProcessorNames
0477: .add(factoryProcessorNames[i]);
0478: }
0479: }
0480:
0481: // First, invoke the BeanFactoryPostProcessors that implement Ordered.
0482: Collections.sort(orderedFactoryProcessors,
0483: new OrderComparator());
0484: for (Iterator it = orderedFactoryProcessors.iterator(); it
0485: .hasNext();) {
0486: BeanFactoryPostProcessor factoryProcessor = (BeanFactoryPostProcessor) it
0487: .next();
0488: factoryProcessor.postProcessBeanFactory(beanFactory);
0489: }
0490: // Second, invoke all other BeanFactoryPostProcessors, one by one.
0491: for (Iterator it = nonOrderedFactoryProcessorNames.iterator(); it
0492: .hasNext();) {
0493: String factoryProcessorName = (String) it.next();
0494: ((BeanFactoryPostProcessor) getBean(factoryProcessorName))
0495: .postProcessBeanFactory(beanFactory);
0496: }
0497: }
0498:
0499: /**
0500: * Instantiate and invoke all registered BeanPostProcessor beans,
0501: * respecting explicit order if given.
0502: * <p>Must be called before any instantiation of application beans.
0503: */
0504: protected void registerBeanPostProcessors(
0505: ConfigurableListableBeanFactory beanFactory) {
0506: String[] processorNames = beanFactory.getBeanNamesForType(
0507: BeanPostProcessor.class, true, false);
0508:
0509: // Register BeanPostProcessorChecker that logs an info message when
0510: // a bean is created during BeanPostProcessor instantiation, i.e. when
0511: // a bean is not eligible for getting processed by all BeanPostProcessors.
0512: int beanProcessorTargetCount = beanFactory
0513: .getBeanPostProcessorCount()
0514: + 1 + processorNames.length;
0515: beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(
0516: beanFactory, beanProcessorTargetCount));
0517:
0518: // Separate between BeanPostProcessors that implement the Ordered
0519: // interface and those that do not.
0520: List orderedProcessors = new ArrayList();
0521: List nonOrderedProcessorNames = new ArrayList();
0522: for (int i = 0; i < processorNames.length; i++) {
0523: if (isTypeMatch(processorNames[i], Ordered.class)) {
0524: orderedProcessors.add(getBean(processorNames[i]));
0525: } else {
0526: nonOrderedProcessorNames.add(processorNames[i]);
0527: }
0528: }
0529:
0530: // First, register the BeanPostProcessors that implement Ordered.
0531: Collections.sort(orderedProcessors, new OrderComparator());
0532: for (Iterator it = orderedProcessors.iterator(); it.hasNext();) {
0533: beanFactory.addBeanPostProcessor((BeanPostProcessor) it
0534: .next());
0535: }
0536: // Second, register all other BeanPostProcessors, one by one.
0537: for (Iterator it = nonOrderedProcessorNames.iterator(); it
0538: .hasNext();) {
0539: String processorName = (String) it.next();
0540: beanFactory
0541: .addBeanPostProcessor((BeanPostProcessor) getBean(processorName));
0542: }
0543: }
0544:
0545: /**
0546: * Initialize the MessageSource.
0547: * Use parent's if none defined in this context.
0548: */
0549: protected void initMessageSource() {
0550: if (containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) {
0551: this .messageSource = (MessageSource) getBean(
0552: MESSAGE_SOURCE_BEAN_NAME, MessageSource.class);
0553: // Make MessageSource aware of parent MessageSource.
0554: if (this .parent != null
0555: && this .messageSource instanceof HierarchicalMessageSource) {
0556: HierarchicalMessageSource hms = (HierarchicalMessageSource) this .messageSource;
0557: if (hms.getParentMessageSource() == null) {
0558: // Only set parent context as parent MessageSource if no parent MessageSource
0559: // registered already.
0560: hms
0561: .setParentMessageSource(getInternalParentMessageSource());
0562: }
0563: }
0564: if (logger.isDebugEnabled()) {
0565: logger.debug("Using MessageSource ["
0566: + this .messageSource + "]");
0567: }
0568: } else {
0569: // Use empty MessageSource to be able to accept getMessage calls.
0570: DelegatingMessageSource dms = new DelegatingMessageSource();
0571: dms
0572: .setParentMessageSource(getInternalParentMessageSource());
0573: this .messageSource = dms;
0574: if (logger.isDebugEnabled()) {
0575: logger
0576: .debug("Unable to locate MessageSource with name '"
0577: + MESSAGE_SOURCE_BEAN_NAME
0578: + "': using default ["
0579: + this .messageSource + "]");
0580: }
0581: }
0582: }
0583:
0584: /**
0585: * Initialize the ApplicationEventMulticaster.
0586: * Uses SimpleApplicationEventMulticaster if none defined in the context.
0587: * @see org.springframework.context.event.SimpleApplicationEventMulticaster
0588: */
0589: protected void initApplicationEventMulticaster() {
0590: if (containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
0591: this .applicationEventMulticaster = (ApplicationEventMulticaster) getBean(
0592: APPLICATION_EVENT_MULTICASTER_BEAN_NAME,
0593: ApplicationEventMulticaster.class);
0594: if (logger.isDebugEnabled()) {
0595: logger.debug("Using ApplicationEventMulticaster ["
0596: + this .applicationEventMulticaster + "]");
0597: }
0598: } else {
0599: this .applicationEventMulticaster = new SimpleApplicationEventMulticaster();
0600: if (logger.isDebugEnabled()) {
0601: logger
0602: .debug("Unable to locate ApplicationEventMulticaster with name '"
0603: + APPLICATION_EVENT_MULTICASTER_BEAN_NAME
0604: + "': using default ["
0605: + this .applicationEventMulticaster
0606: + "]");
0607: }
0608: }
0609: }
0610:
0611: /**
0612: * Template method which can be overridden to add context-specific refresh work.
0613: * Called on initialization of special beans, before instantiation of singletons.
0614: * <p>This implementation is empty.
0615: * @throws BeansException in case of errors
0616: * @see #refresh()
0617: */
0618: protected void onRefresh() throws BeansException {
0619: // For subclasses: do nothing by default.
0620: }
0621:
0622: /**
0623: * Add beans that implement ApplicationListener as listeners.
0624: * Doesn't affect other listeners, which can be added without being beans.
0625: */
0626: protected void registerListeners() {
0627: // Register statically specified listeners first.
0628: for (Iterator it = getApplicationListeners().iterator(); it
0629: .hasNext();) {
0630: addListener((ApplicationListener) it.next());
0631: }
0632: // Do not initialize FactoryBeans here: We need to leave all regular beans
0633: // uninitialized to let post-processors apply to them!
0634: Collection listenerBeans = getBeansOfType(
0635: ApplicationListener.class, true, false).values();
0636: for (Iterator it = listenerBeans.iterator(); it.hasNext();) {
0637: addListener((ApplicationListener) it.next());
0638: }
0639: }
0640:
0641: /**
0642: * Subclasses can invoke this method to register a listener.
0643: * Any beans in the context that are listeners are automatically added.
0644: * @param listener the listener to register
0645: */
0646: protected void addListener(ApplicationListener listener) {
0647: getApplicationEventMulticaster().addApplicationListener(
0648: listener);
0649: }
0650:
0651: /**
0652: * Register a shutdown hook with the JVM runtime, closing this context
0653: * on JVM shutdown unless it has already been closed at that time.
0654: * <p>Delegates to <code>doClose()</code> for the actual closing procedure.
0655: * @see java.lang.Runtime#addShutdownHook
0656: * @see #close()
0657: * @see #doClose()
0658: */
0659: public void registerShutdownHook() {
0660: if (this .shutdownHook == null) {
0661: // No shutdown hook registered yet.
0662: this .shutdownHook = new Thread() {
0663: public void run() {
0664: doClose();
0665: }
0666: };
0667: Runtime.getRuntime().addShutdownHook(this .shutdownHook);
0668: }
0669: }
0670:
0671: /**
0672: * DisposableBean callback for destruction of this instance.
0673: * Only called when the ApplicationContext itself is running
0674: * as a bean in another BeanFactory or ApplicationContext,
0675: * which is rather unusual.
0676: * <p>The <code>close</code> method is the native way to
0677: * shut down an ApplicationContext.
0678: * @see #close()
0679: * @see org.springframework.beans.factory.access.SingletonBeanFactoryLocator
0680: */
0681: public void destroy() {
0682: close();
0683: }
0684:
0685: /**
0686: * Close this application context, destroying all beans in its bean factory.
0687: * <p>Delegates to <code>doClose()</code> for the actual closing procedure.
0688: * Also removes a JVM shutdown hook, if registered, as it's not needed anymore.
0689: * @see #doClose()
0690: * @see #registerShutdownHook()
0691: */
0692: public void close() {
0693: synchronized (this .startupShutdownMonitor) {
0694: doClose();
0695: // If we registered a JVM shutdown hook, we don't need it anymore now:
0696: // We've already explicitly closed the context.
0697: if (this .shutdownHook != null) {
0698: Runtime.getRuntime().removeShutdownHook(
0699: this .shutdownHook);
0700: }
0701: }
0702: }
0703:
0704: /**
0705: * Actually performs context closing: publishes a ContextClosedEvent and
0706: * destroys the singletons in the bean factory of this application context.
0707: * <p>Called by both <code>close()</code> and a JVM shutdown hook, if any.
0708: * @see org.springframework.context.event.ContextClosedEvent
0709: * @see org.springframework.beans.factory.config.ConfigurableBeanFactory#destroySingletons()
0710: * @see #close()
0711: * @see #registerShutdownHook()
0712: */
0713: protected void doClose() {
0714: if (isActive()) {
0715: if (logger.isInfoEnabled()) {
0716: logger.info("Closing " + this );
0717: }
0718: try {
0719: // Publish shutdown event.
0720: publishEvent(new ContextClosedEvent(this ));
0721: } catch (Throwable ex) {
0722: logger
0723: .error(
0724: "Exception thrown from ApplicationListener handling ContextClosedEvent",
0725: ex);
0726: }
0727: // Stop all Lifecycle beans, to avoid delays during individual destruction.
0728: stop();
0729: // Destroy all cached singletons in the context's BeanFactory.
0730: destroyBeans();
0731: // Close the state of this context itself.
0732: closeBeanFactory();
0733: onClose();
0734: synchronized (this .activeMonitor) {
0735: this .active = false;
0736: }
0737: }
0738: }
0739:
0740: /**
0741: * Template method for destroying all beans that this context manages.
0742: * The default implementation destroy all cached singletons in this context,
0743: * invoking <code>DisposableBean.destroy()</code> and/or the specified
0744: * "destroy-method".
0745: * <p>Can be overridden to add context-specific bean destruction steps
0746: * right before or right after standard singleton destruction,
0747: * while the context's BeanFactory is still active.
0748: * @see #getBeanFactory()
0749: * @see org.springframework.beans.factory.config.ConfigurableBeanFactory#destroySingletons()
0750: */
0751: protected void destroyBeans() {
0752: getBeanFactory().destroySingletons();
0753: }
0754:
0755: /**
0756: * Template method which can be overridden to add context-specific shutdown work.
0757: * The default implementation is empty.
0758: * <p>Called at the end of {@link #doClose}'s shutdown procedure, after
0759: * this context's BeanFactory has been closed. If custom shutdown logic
0760: * needs to execute while the BeanFactory is still active, override
0761: * the {@link #destroyBeans()} method instead.
0762: */
0763: protected void onClose() {
0764: // For subclasses: do nothing by default.
0765: }
0766:
0767: public boolean isActive() {
0768: synchronized (this .activeMonitor) {
0769: return this .active;
0770: }
0771: }
0772:
0773: //---------------------------------------------------------------------
0774: // Implementation of BeanFactory interface
0775: //---------------------------------------------------------------------
0776:
0777: public Object getBean(String name) throws BeansException {
0778: return getBeanFactory().getBean(name);
0779: }
0780:
0781: public Object getBean(String name, Class requiredType)
0782: throws BeansException {
0783: return getBeanFactory().getBean(name, requiredType);
0784: }
0785:
0786: public boolean containsBean(String name) {
0787: return getBeanFactory().containsBean(name);
0788: }
0789:
0790: public boolean isSingleton(String name)
0791: throws NoSuchBeanDefinitionException {
0792: return getBeanFactory().isSingleton(name);
0793: }
0794:
0795: public boolean isPrototype(String name)
0796: throws NoSuchBeanDefinitionException {
0797: return getBeanFactory().isPrototype(name);
0798: }
0799:
0800: public boolean isTypeMatch(String name, Class targetType)
0801: throws NoSuchBeanDefinitionException {
0802: return getBeanFactory().isTypeMatch(name, targetType);
0803: }
0804:
0805: public Class getType(String name)
0806: throws NoSuchBeanDefinitionException {
0807: return getBeanFactory().getType(name);
0808: }
0809:
0810: public String[] getAliases(String name) {
0811: return getBeanFactory().getAliases(name);
0812: }
0813:
0814: //---------------------------------------------------------------------
0815: // Implementation of ListableBeanFactory interface
0816: //---------------------------------------------------------------------
0817:
0818: public boolean containsBeanDefinition(String name) {
0819: return getBeanFactory().containsBeanDefinition(name);
0820: }
0821:
0822: public int getBeanDefinitionCount() {
0823: return getBeanFactory().getBeanDefinitionCount();
0824: }
0825:
0826: public String[] getBeanDefinitionNames() {
0827: return getBeanFactory().getBeanDefinitionNames();
0828: }
0829:
0830: public String[] getBeanNamesForType(Class type) {
0831: return getBeanFactory().getBeanNamesForType(type);
0832: }
0833:
0834: public String[] getBeanNamesForType(Class type,
0835: boolean includePrototypes, boolean allowEagerInit) {
0836: return getBeanFactory().getBeanNamesForType(type,
0837: includePrototypes, allowEagerInit);
0838: }
0839:
0840: public Map getBeansOfType(Class type) throws BeansException {
0841: return getBeanFactory().getBeansOfType(type);
0842: }
0843:
0844: public Map getBeansOfType(Class type, boolean includePrototypes,
0845: boolean allowEagerInit) throws BeansException {
0846:
0847: return getBeanFactory().getBeansOfType(type, includePrototypes,
0848: allowEagerInit);
0849: }
0850:
0851: //---------------------------------------------------------------------
0852: // Implementation of HierarchicalBeanFactory interface
0853: //---------------------------------------------------------------------
0854:
0855: public BeanFactory getParentBeanFactory() {
0856: return getParent();
0857: }
0858:
0859: public boolean containsLocalBean(String name) {
0860: return getBeanFactory().containsLocalBean(name);
0861: }
0862:
0863: /**
0864: * Return the internal bean factory of the parent context if it implements
0865: * ConfigurableApplicationContext; else, return the parent context itself.
0866: * @see org.springframework.context.ConfigurableApplicationContext#getBeanFactory
0867: */
0868: protected BeanFactory getInternalParentBeanFactory() {
0869: return (getParent() instanceof ConfigurableApplicationContext) ? ((ConfigurableApplicationContext) getParent())
0870: .getBeanFactory()
0871: : (BeanFactory) getParent();
0872: }
0873:
0874: //---------------------------------------------------------------------
0875: // Implementation of MessageSource interface
0876: //---------------------------------------------------------------------
0877:
0878: public String getMessage(String code, Object args[],
0879: String defaultMessage, Locale locale) {
0880: return getMessageSource().getMessage(code, args,
0881: defaultMessage, locale);
0882: }
0883:
0884: public String getMessage(String code, Object args[], Locale locale)
0885: throws NoSuchMessageException {
0886: return getMessageSource().getMessage(code, args, locale);
0887: }
0888:
0889: public String getMessage(MessageSourceResolvable resolvable,
0890: Locale locale) throws NoSuchMessageException {
0891: return getMessageSource().getMessage(resolvable, locale);
0892: }
0893:
0894: /**
0895: * Return the internal MessageSource used by the context.
0896: * @return the internal MessageSource (never <code>null</code>)
0897: * @throws IllegalStateException if the context has not been initialized yet
0898: */
0899: private MessageSource getMessageSource()
0900: throws IllegalStateException {
0901: if (this .messageSource == null) {
0902: throw new IllegalStateException(
0903: "MessageSource not initialized - "
0904: + "call 'refresh' before accessing messages via the context: "
0905: + this );
0906: }
0907: return this .messageSource;
0908: }
0909:
0910: /**
0911: * Return the internal message source of the parent context if it is an
0912: * AbstractApplicationContext too; else, return the parent context itself.
0913: */
0914: protected MessageSource getInternalParentMessageSource() {
0915: return (getParent() instanceof AbstractApplicationContext) ? ((AbstractApplicationContext) getParent()).messageSource
0916: : getParent();
0917: }
0918:
0919: //---------------------------------------------------------------------
0920: // Implementation of ResourcePatternResolver interface
0921: //---------------------------------------------------------------------
0922:
0923: public Resource[] getResources(String locationPattern)
0924: throws IOException {
0925: return this .resourcePatternResolver
0926: .getResources(locationPattern);
0927: }
0928:
0929: //---------------------------------------------------------------------
0930: // Implementation of Lifecycle interface
0931: //---------------------------------------------------------------------
0932:
0933: public void start() {
0934: Iterator it = getLifecycleBeans().iterator();
0935: while (it.hasNext()) {
0936: Lifecycle lifecycle = (Lifecycle) it.next();
0937: if (!lifecycle.isRunning()) {
0938: lifecycle.start();
0939: }
0940: }
0941: }
0942:
0943: public void stop() {
0944: Iterator it = getLifecycleBeans().iterator();
0945: while (it.hasNext()) {
0946: Lifecycle lifecycle = (Lifecycle) it.next();
0947: if (lifecycle.isRunning()) {
0948: lifecycle.stop();
0949: }
0950: }
0951: }
0952:
0953: public boolean isRunning() {
0954: Iterator it = getLifecycleBeans().iterator();
0955: while (it.hasNext()) {
0956: Lifecycle lifecycle = (Lifecycle) it.next();
0957: if (!lifecycle.isRunning()) {
0958: return false;
0959: }
0960: }
0961: return true;
0962: }
0963:
0964: /**
0965: * Return a Collection of all singleton beans that implement the
0966: * Lifecycle interface in this context.
0967: * @return Collection of Lifecycle beans
0968: */
0969: protected Collection getLifecycleBeans() {
0970: ConfigurableListableBeanFactory beanFactory = getBeanFactory();
0971: String[] beanNames = beanFactory.getBeanNamesForType(
0972: Lifecycle.class, false, false);
0973: Collection beans = new ArrayList(beanNames.length);
0974: for (int i = 0; i < beanNames.length; i++) {
0975: Object bean = beanFactory.getSingleton(beanNames[i]);
0976: if (bean != null) {
0977: beans.add(bean);
0978: }
0979: }
0980: return beans;
0981: }
0982:
0983: //---------------------------------------------------------------------
0984: // Abstract methods that must be implemented by subclasses
0985: //---------------------------------------------------------------------
0986:
0987: /**
0988: * Subclasses must implement this method to perform the actual configuration load.
0989: * The method is invoked by {@link #refresh()} before any other initialization work.
0990: * <p>A subclass will either create a new bean factory and hold a reference to it,
0991: * or return a single BeanFactory instance that it holds. In the latter case, it will
0992: * usually throw an IllegalStateException if refreshing the context more than once.
0993: * @throws BeansException if initialization of the bean factory failed
0994: * @throws IllegalStateException if already initialized and multiple refresh
0995: * attempts are not supported
0996: */
0997: protected abstract void refreshBeanFactory() throws BeansException,
0998: IllegalStateException;
0999:
1000: /**
1001: * Subclasses must implement this method to release their internal bean factory.
1002: * This method gets invoked by {@link #close()} after all other shutdown work.
1003: * <p>Should never throw an exception but rather log shutdown failures.
1004: */
1005: protected abstract void closeBeanFactory();
1006:
1007: /**
1008: * Subclasses must return their internal bean factory here. They should implement the
1009: * lookup efficiently, so that it can be called repeatedly without a performance penalty.
1010: * <p>Note: Subclasses should check whether the context is still active before
1011: * returning the internal bean factory. The internal factory should generally be
1012: * considered unavailable once the context has been closed.
1013: * @return this application context's internal bean factory (never <code>null</code>)
1014: * @throws IllegalStateException if the context does not hold an internal bean factory yet
1015: * (usually if {@link #refresh()} has never been called) or if the context has been
1016: * closed already
1017: * @see #refreshBeanFactory()
1018: * @see #closeBeanFactory()
1019: */
1020: public abstract ConfigurableListableBeanFactory getBeanFactory()
1021: throws IllegalStateException;
1022:
1023: /**
1024: * Return information about this context.
1025: */
1026: public String toString() {
1027: StringBuffer sb = new StringBuffer(ObjectUtils
1028: .identityToString(this ));
1029: sb.append(": display name [").append(getDisplayName());
1030: sb.append("]; startup date [").append(
1031: new Date(getStartupDate()));
1032: sb.append("]; ");
1033: ApplicationContext parent = getParent();
1034: if (parent == null) {
1035: sb.append("root of context hierarchy");
1036: } else {
1037: sb.append("parent: ").append(
1038: ObjectUtils.identityToString(parent));
1039: }
1040: return sb.toString();
1041: }
1042:
1043: /**
1044: * BeanPostProcessor that logs an info message when a bean is created during
1045: * BeanPostProcessor instantiation, i.e. when a bean is not eligible for
1046: * getting processed by all BeanPostProcessors.
1047: */
1048: private class BeanPostProcessorChecker implements BeanPostProcessor {
1049:
1050: private final ConfigurableListableBeanFactory beanFactory;
1051:
1052: private final int beanPostProcessorTargetCount;
1053:
1054: public BeanPostProcessorChecker(
1055: ConfigurableListableBeanFactory beanFactory,
1056: int beanPostProcessorTargetCount) {
1057: this .beanFactory = beanFactory;
1058: this .beanPostProcessorTargetCount = beanPostProcessorTargetCount;
1059: }
1060:
1061: public Object postProcessBeforeInitialization(Object bean,
1062: String beanName) {
1063: return bean;
1064: }
1065:
1066: public Object postProcessAfterInitialization(Object bean,
1067: String beanName) {
1068: if (this .beanFactory.getBeanPostProcessorCount() < this .beanPostProcessorTargetCount) {
1069: if (logger.isInfoEnabled()) {
1070: logger
1071: .info("Bean '"
1072: + beanName
1073: + "' is not eligible for getting processed by all "
1074: + "BeanPostProcessors (for example: not eligible for auto-proxying)");
1075: }
1076: }
1077: return bean;
1078: }
1079: }
1080:
1081: }
|