KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > springframework > context > support > AbstractApplicationContext


1 /*
2  * Copyright 2002-2007 the original author or authors.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17 package org.springframework.context.support;
18
19 import java.io.IOException JavaDoc;
20 import java.util.ArrayList JavaDoc;
21 import java.util.Collection JavaDoc;
22 import java.util.Collections JavaDoc;
23 import java.util.Date JavaDoc;
24 import java.util.Iterator JavaDoc;
25 import java.util.List JavaDoc;
26 import java.util.Locale JavaDoc;
27 import java.util.Map JavaDoc;
28
29 import org.apache.commons.logging.Log;
30 import org.apache.commons.logging.LogFactory;
31
32 import org.springframework.beans.BeansException;
33 import org.springframework.beans.factory.BeanFactory;
34 import org.springframework.beans.factory.DisposableBean;
35 import org.springframework.beans.factory.NoSuchBeanDefinitionException;
36 import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
37 import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
38 import org.springframework.beans.factory.config.BeanPostProcessor;
39 import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
40 import org.springframework.beans.support.ResourceEditorRegistrar;
41 import org.springframework.context.ApplicationContext;
42 import org.springframework.context.ApplicationContextAware;
43 import org.springframework.context.ApplicationEvent;
44 import org.springframework.context.ApplicationEventPublisherAware;
45 import org.springframework.context.ApplicationListener;
46 import org.springframework.context.ConfigurableApplicationContext;
47 import org.springframework.context.HierarchicalMessageSource;
48 import org.springframework.context.Lifecycle;
49 import org.springframework.context.MessageSource;
50 import org.springframework.context.MessageSourceAware;
51 import org.springframework.context.MessageSourceResolvable;
52 import org.springframework.context.NoSuchMessageException;
53 import org.springframework.context.ResourceLoaderAware;
54 import org.springframework.context.event.ApplicationEventMulticaster;
55 import org.springframework.context.event.ContextClosedEvent;
56 import org.springframework.context.event.ContextRefreshedEvent;
57 import org.springframework.context.event.SimpleApplicationEventMulticaster;
58 import org.springframework.core.OrderComparator;
59 import org.springframework.core.Ordered;
60 import org.springframework.core.io.DefaultResourceLoader;
61 import org.springframework.core.io.Resource;
62 import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
63 import org.springframework.core.io.support.ResourcePatternResolver;
64 import org.springframework.util.Assert;
65 import org.springframework.util.ObjectUtils;
66
67 /**
68  * Abstract implementation of the {@link org.springframework.context.ApplicationContext}
69  * interface. Doesn't mandate the type of storage used for configuration; simply
70  * implements common context functionality. Uses the Template Method design pattern,
71  * requiring concrete subclasses to implement abstract methods.
72  *
73  * <p>In contrast to a plain BeanFactory, an ApplicationContext is supposed
74  * to detect special beans defined in its internal bean factory:
75  * Therefore, this class automatically registers
76  * {@link org.springframework.beans.factory.config.BeanFactoryPostProcessor BeanFactoryPostProcessors},
77  * {@link org.springframework.beans.factory.config.BeanPostProcessor BeanPostProcessors}
78  * and {@link org.springframework.context.ApplicationListener ApplicationListeners}
79  * which are defined as beans in the context.
80  *
81  * <p>A {@link org.springframework.context.MessageSource} may also be supplied
82  * as a bean in the context, with the name "messageSource"; else, message
83  * resolution is delegated to the parent context. Furthermore, a multicaster
84  * for application events can be supplied as "applicationEventMulticaster" bean
85  * of type {@link org.springframework.context.event.ApplicationEventMulticaster}
86  * in the context; else, a default multicaster of type
87  * {@link org.springframework.context.event.SimpleApplicationEventMulticaster} will be used.
88  *
89  * <p>Implements resource loading through extending
90  * {@link org.springframework.core.io.DefaultResourceLoader}.
91  * Consequently treats non-URL resource paths as class path resources
92  * (supporting full class path resource names that include the package path,
93  * e.g. "mypackage/myresource.dat"), unless the {@link #getResourceByPath}
94  * method is overwritten in a subclass.
95  *
96  * @author Rod Johnson
97  * @author Juergen Hoeller
98  * @since January 21, 2001
99  * @see #refreshBeanFactory
100  * @see #getBeanFactory
101  * @see org.springframework.beans.factory.config.BeanFactoryPostProcessor
102  * @see org.springframework.beans.factory.config.BeanPostProcessor
103  * @see org.springframework.context.event.ApplicationEventMulticaster
104  * @see org.springframework.context.ApplicationListener
105  * @see org.springframework.context.MessageSource
106  */

107 public abstract class AbstractApplicationContext extends DefaultResourceLoader
108         implements ConfigurableApplicationContext, DisposableBean {
109
110     /**
111      * Name of the MessageSource bean in the factory.
112      * If none is supplied, message resolution is delegated to the parent.
113      * @see MessageSource
114      */

115     public static final String JavaDoc MESSAGE_SOURCE_BEAN_NAME = "messageSource";
116
117     /**
118      * Name of the ApplicationEventMulticaster bean in the factory.
119      * If none is supplied, a default SimpleApplicationEventMulticaster is used.
120      * @see org.springframework.context.event.ApplicationEventMulticaster
121      * @see org.springframework.context.event.SimpleApplicationEventMulticaster
122      */

123     public static final String JavaDoc APPLICATION_EVENT_MULTICASTER_BEAN_NAME = "applicationEventMulticaster";
124
125
126     static {
127         // Eagerly load the ContextClosedEvent class to avoid weird classloader issues
128
// on application shutdown in WebLogic 8.1. (Reported by Dustin Woods.)
129
ContextClosedEvent.class.getName();
130     }
131
132
133     /** Logger used by this class. Available to subclasses. */
134     protected final Log logger = LogFactory.getLog(getClass());
135
136     /** Parent context */
137     private ApplicationContext parent;
138
139     /** BeanFactoryPostProcessors to apply on refresh */
140     private final List JavaDoc beanFactoryPostProcessors = new ArrayList JavaDoc();
141
142     /** Display name */
143     private String JavaDoc displayName = ObjectUtils.identityToString(this);
144
145     /** System time in milliseconds when this context started */
146     private long startupDate;
147
148     /** Flag that indicates whether this context is currently active */
149     private boolean active = false;
150
151     /** Synchronization monitor for the "active" flag */
152     private final Object JavaDoc activeMonitor = new Object JavaDoc();
153
154     /** Synchronization monitor for the "refresh" and "destroy" */
155     private final Object JavaDoc startupShutdownMonitor = new Object JavaDoc();
156
157     /** Reference to the JVM shutdown hook, if registered */
158     private Thread JavaDoc shutdownHook;
159
160     /** ResourcePatternResolver used by this context */
161     private ResourcePatternResolver resourcePatternResolver;
162
163     /** MessageSource we delegate our implementation of this interface to */
164     private MessageSource messageSource;
165
166     /** Helper class used in event publishing */
167     private ApplicationEventMulticaster applicationEventMulticaster;
168
169
170     /**
171      * Create a new AbstractApplicationContext with no parent.
172      */

173     public AbstractApplicationContext() {
174         this(null);
175     }
176
177     /**
178      * Create a new AbstractApplicationContext with the given parent context.
179      * @param parent the parent context
180      */

181     public AbstractApplicationContext(ApplicationContext parent) {
182         this.parent = parent;
183         this.resourcePatternResolver = getResourcePatternResolver();
184     }
185
186
187     //---------------------------------------------------------------------
188
// Implementation of ApplicationContext interface
189
//---------------------------------------------------------------------
190

191     /**
192      * Return the parent context, or <code>null</code> if there is no parent
193      * (that is, this context is the root of the context hierarchy).
194      */

195     public ApplicationContext getParent() {
196         return this.parent;
197     }
198
199     /**
200      * Return this context's internal bean factory as AutowireCapableBeanFactory,
201      * if already available.
202      * @see #getBeanFactory()
203      */

204     public AutowireCapableBeanFactory getAutowireCapableBeanFactory() throws IllegalStateException JavaDoc {
205         return getBeanFactory();
206     }
207
208     /**
209      * Set a friendly name for this context.
210      * Typically done during initialization of concrete context implementations.
211      */

212     public void setDisplayName(String JavaDoc displayName) {
213         this.displayName = displayName;
214     }
215
216     /**
217      * Return a friendly name for this context.
218      */

219     public String JavaDoc getDisplayName() {
220         return this.displayName;
221     }
222
223     /**
224      * Return the timestamp (ms) when this context was first loaded.
225      */

226     public long getStartupDate() {
227         return this.startupDate;
228     }
229
230     /**
231      * Publish the given event to all listeners.
232      * <p>Note: Listeners get initialized after the MessageSource, to be able
233      * to access it within listener implementations. Thus, MessageSource
234      * implementations cannot publish events.
235      * @param event the event to publish (may be application-specific or a
236      * standard framework event)
237      */

238     public void publishEvent(ApplicationEvent event) {
239         Assert.notNull(event, "Event must not be null");
240         if (logger.isDebugEnabled()) {
241             logger.debug("Publishing event in context [" + ObjectUtils.identityToString(this) + "]: " + event);
242         }
243         getApplicationEventMulticaster().multicastEvent(event);
244         if (this.parent != null) {
245             this.parent.publishEvent(event);
246         }
247     }
248
249     /**
250      * Return the internal MessageSource used by the context.
251      * @return the internal MessageSource (never <code>null</code>)
252      * @throws IllegalStateException if the context has not been initialized yet
253      */

254     private ApplicationEventMulticaster getApplicationEventMulticaster() throws IllegalStateException JavaDoc {
255         if (this.applicationEventMulticaster == null) {
256             throw new IllegalStateException JavaDoc("ApplicationEventMulticaster not initialized - " +
257                     "call 'refresh' before multicasting events via the context: " + this);
258         }
259         return this.applicationEventMulticaster;
260     }
261
262
263     //---------------------------------------------------------------------
264
// Implementation of ConfigurableApplicationContext interface
265
//---------------------------------------------------------------------
266

267     public void setParent(ApplicationContext parent) {
268         this.parent = parent;
269     }
270
271     public void addBeanFactoryPostProcessor(BeanFactoryPostProcessor beanFactoryPostProcessor) {
272         this.beanFactoryPostProcessors.add(beanFactoryPostProcessor);
273     }
274
275     /**
276      * Return the list of BeanFactoryPostProcessors that will get applied
277      * to the internal BeanFactory.
278      * @see org.springframework.beans.factory.config.BeanFactoryPostProcessor
279      */

280     public List JavaDoc getBeanFactoryPostProcessors() {
281         return this.beanFactoryPostProcessors;
282     }
283
284
285     public void refresh() throws BeansException, IllegalStateException JavaDoc {
286         synchronized (this.startupShutdownMonitor) {
287             this.startupDate = System.currentTimeMillis();
288
289             if (logger.isInfoEnabled()) {
290                 logger.info("Refreshing " + this);
291             }
292
293             synchronized (this.activeMonitor) {
294                 this.active = true;
295             }
296
297             // Tell subclass to refresh the internal bean factory.
298
refreshBeanFactory();
299             ConfigurableListableBeanFactory beanFactory = getBeanFactory();
300
301             if (logger.isInfoEnabled()) {
302                 logger.info("Bean factory for application context [" + ObjectUtils.identityToString(this) +
303                         "]: " + ObjectUtils.identityToString(beanFactory));
304             }
305
306             // Tell the internal bean factory to use the context's class loader.
307
beanFactory.setBeanClassLoader(getClassLoader());
308
309             // Populate the bean factory with context-specific resource editors.
310
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this));
311
312             // Configure the bean factory with context semantics.
313
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
314             beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
315             beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
316             beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
317             beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
318
319             // Allows post-processing of the bean factory in context subclasses.
320
postProcessBeanFactory(beanFactory);
321
322             // Invoke factory processors registered with the context instance.
323
for (Iterator JavaDoc it = getBeanFactoryPostProcessors().iterator(); it.hasNext();) {
324                 BeanFactoryPostProcessor factoryProcessor = (BeanFactoryPostProcessor) it.next();
325                 factoryProcessor.postProcessBeanFactory(beanFactory);
326             }
327
328             if (logger.isDebugEnabled()) {
329                 logger.debug(getBeanDefinitionCount() + " beans defined in " + this);
330             }
331
332             try {
333                 // Invoke factory processors registered as beans in the context.
334
invokeBeanFactoryPostProcessors();
335
336                 // Register bean processors that intercept bean creation.
337
registerBeanPostProcessors();
338
339                 // Initialize message source for this context.
340
initMessageSource();
341
342                 // Initialize event multicaster for this context.
343
initApplicationEventMulticaster();
344
345                 // Initialize other special beans in specific context subclasses.
346
onRefresh();
347
348                 // Check for listener beans and register them.
349
registerListeners();
350
351                 // Instantiate singletons this late to allow them to access the message source.
352
beanFactory.preInstantiateSingletons();
353
354                 // Last step: publish corresponding event.
355
publishEvent(new ContextRefreshedEvent(this));
356             }
357
358             catch (BeansException ex) {
359                 // Destroy already created singletons to avoid dangling resources.
360
beanFactory.destroySingletons();
361                 throw ex;
362             }
363         }
364     }
365
366     /**
367      * Return the ResourcePatternResolver to use for resolving location patterns
368      * into Resource instances. Default is a
369      * {@link org.springframework.core.io.support.PathMatchingResourcePatternResolver},
370      * supporting Ant-style location patterns.
371      * <p>Can be overridden in subclasses, for extended resolution strategies,
372      * for example in a web environment.
373      * <p><b>Do not call this when needing to resolve a location pattern.</b>
374      * Call the context's <code>getResources</code> method instead, which
375      * will delegate to the ResourcePatternResolver.
376      * @return the ResourcePatternResolver for this context
377      * @see #getResources
378      * @see org.springframework.core.io.support.PathMatchingResourcePatternResolver
379      */

380     protected ResourcePatternResolver getResourcePatternResolver() {
381         return new PathMatchingResourcePatternResolver(this);
382     }
383
384     /**
385      * Modify the application context's internal bean factory after its standard
386      * initialization. All bean definitions will have been loaded, but no beans
387      * will have been instantiated yet. This allows for registering special
388      * BeanPostProcessors etc in certain ApplicationContext implementations.
389      * @param beanFactory the bean factory used by the application context
390      * @throws org.springframework.beans.BeansException in case of errors
391      */

392     protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
393     }
394
395     /**
396      * Instantiate and invoke all registered BeanFactoryPostProcessor beans,
397      * respecting explicit order if given.
398      * Must be called before singleton instantiation.
399      */

400     private void invokeBeanFactoryPostProcessors() {
401         // Do not initialize FactoryBeans here: We need to leave all regular beans
402
// uninitialized to let the bean factory post-processors apply to them!
403
String JavaDoc[] factoryProcessorNames = getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);
404
405         // Separate between BeanFactoryPostProcessor that implement the Ordered
406
// interface and those that do not.
407
List JavaDoc orderedFactoryProcessors = new ArrayList JavaDoc();
408         List JavaDoc nonOrderedFactoryProcessorNames = new ArrayList JavaDoc();
409         for (int i = 0; i < factoryProcessorNames.length; i++) {
410             if (isTypeMatch(factoryProcessorNames[i], Ordered.class)) {
411                 orderedFactoryProcessors.add(getBean(factoryProcessorNames[i]));
412             }
413             else {
414                 nonOrderedFactoryProcessorNames.add(factoryProcessorNames[i]);
415             }
416         }
417
418         // First, invoke the BeanFactoryPostProcessors that implement Ordered.
419
Collections.sort(orderedFactoryProcessors, new OrderComparator());
420         for (Iterator JavaDoc it = orderedFactoryProcessors.iterator(); it.hasNext();) {
421             BeanFactoryPostProcessor factoryProcessor = (BeanFactoryPostProcessor) it.next();
422             factoryProcessor.postProcessBeanFactory(getBeanFactory());
423         }
424         // Second, invoke all other BeanFactoryPostProcessors, one by one.
425
for (Iterator JavaDoc it = nonOrderedFactoryProcessorNames.iterator(); it.hasNext();) {
426             String JavaDoc factoryProcessorName = (String JavaDoc) it.next();
427             ((BeanFactoryPostProcessor) getBean(factoryProcessorName)).postProcessBeanFactory(getBeanFactory());
428         }
429     }
430
431     /**
432      * Instantiate and invoke all registered BeanPostProcessor beans,
433      * respecting explicit order if given.
434      * <p>Must be called before any instantiation of application beans.
435      */

436     private void registerBeanPostProcessors() {
437         String JavaDoc[] processorNames = getBeanNamesForType(BeanPostProcessor.class, true, false);
438
439         // Register BeanPostProcessorChecker that logs an info message when
440
// a bean is created during BeanPostProcessor instantiation, i.e. when
441
// a bean is not eligible for getting processed by all BeanPostProcessors.
442
int beanProcessorTargetCount = getBeanFactory().getBeanPostProcessorCount() + 1 + processorNames.length;
443         getBeanFactory().addBeanPostProcessor(new BeanPostProcessorChecker(beanProcessorTargetCount));
444
445         // Separate between BeanPostProcessor that implement the Ordered
446
// interface and those that do not.
447
List JavaDoc orderedProcessors = new ArrayList JavaDoc();
448         List JavaDoc nonOrderedProcessorNames = new ArrayList JavaDoc();
449         for (int i = 0; i < processorNames.length; i++) {
450             if (isTypeMatch(processorNames[i], Ordered.class)) {
451                 orderedProcessors.add(getBean(processorNames[i]));
452             }
453             else {
454                 nonOrderedProcessorNames.add(processorNames[i]);
455             }
456         }
457
458         // First, register the BeanPostProcessors that implement Ordered.
459
Collections.sort(orderedProcessors, new OrderComparator());
460         for (Iterator JavaDoc it = orderedProcessors.iterator(); it.hasNext();) {
461             getBeanFactory().addBeanPostProcessor((BeanPostProcessor) it.next());
462         }
463         // Second, register all other BeanPostProcessors, one by one.
464
for (Iterator JavaDoc it = nonOrderedProcessorNames.iterator(); it.hasNext();) {
465             String JavaDoc processorName = (String JavaDoc) it.next();
466             getBeanFactory().addBeanPostProcessor((BeanPostProcessor) getBean(processorName));
467         }
468     }
469
470     /**
471      * Initialize the MessageSource.
472      * Use parent's if none defined in this context.
473      */

474     private void initMessageSource() {
475         if (containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) {
476             this.messageSource = (MessageSource) getBean(MESSAGE_SOURCE_BEAN_NAME, MessageSource.class);
477             // Make MessageSource aware of parent MessageSource.
478
if (this.parent != null && this.messageSource instanceof HierarchicalMessageSource) {
479                 HierarchicalMessageSource hms = (HierarchicalMessageSource) this.messageSource;
480                 if (hms.getParentMessageSource() == null) {
481                     // Only set parent context as parent MessageSource if no parent MessageSource
482
// registered already.
483
hms.setParentMessageSource(getInternalParentMessageSource());
484                 }
485             }
486             if (logger.isDebugEnabled()) {
487                 logger.debug("Using MessageSource [" + this.messageSource + "]");
488             }
489         }
490         else {
491             // Use empty MessageSource to be able to accept getMessage calls.
492
DelegatingMessageSource dms = new DelegatingMessageSource();
493             dms.setParentMessageSource(getInternalParentMessageSource());
494             this.messageSource = dms;
495             if (logger.isDebugEnabled()) {
496                 logger.debug("Unable to locate MessageSource with name '" + MESSAGE_SOURCE_BEAN_NAME +
497                         "': using default [" + this.messageSource + "]");
498             }
499         }
500     }
501
502     /**
503      * Initialize the ApplicationEventMulticaster.
504      * Uses SimpleApplicationEventMulticaster if none defined in the context.
505      * @see org.springframework.context.event.SimpleApplicationEventMulticaster
506      */

507     private void initApplicationEventMulticaster() {
508         if (containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
509             this.applicationEventMulticaster = (ApplicationEventMulticaster)
510                     getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
511             if (logger.isDebugEnabled()) {
512                 logger.debug("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
513             }
514         }
515         else {
516             this.applicationEventMulticaster = new SimpleApplicationEventMulticaster();
517             if (logger.isDebugEnabled()) {
518                 logger.debug("Unable to locate ApplicationEventMulticaster with name '" +
519                         APPLICATION_EVENT_MULTICASTER_BEAN_NAME +
520                         "': using default [" + this.applicationEventMulticaster + "]");
521             }
522         }
523     }
524
525     /**
526      * Template method which can be overridden to add context-specific refresh work.
527      * Called on initialization of special beans, before instantiation of singletons.
528      * @throws BeansException in case of errors during refresh
529      * @see #refresh
530      */

531     protected void onRefresh() throws BeansException {
532         // For subclasses: do nothing by default.
533
}
534
535     /**
536      * Add beans that implement ApplicationListener as listeners.
537      * Doesn't affect other listeners, which can be added without being beans.
538      */

539     private void registerListeners() {
540         // Do not initialize FactoryBeans here: We need to leave all regular beans
541
// uninitialized to let post-processors apply to them!
542
Collection JavaDoc listeners = getBeansOfType(ApplicationListener.class, true, false).values();
543         for (Iterator JavaDoc it = listeners.iterator(); it.hasNext();) {
544             addListener((ApplicationListener) it.next());
545         }
546     }
547
548     /**
549      * Subclasses can invoke this method to register a listener.
550      * Any beans in the context that are listeners are automatically added.
551      * @param listener the listener to register
552      */

553     protected void addListener(ApplicationListener listener) {
554         getApplicationEventMulticaster().addApplicationListener(listener);
555     }
556
557
558     /**
559      * Register a shutdown hook with the JVM runtime, closing this context
560      * on JVM shutdown unless it has already been closed at that time.
561      * <p>Delegates to <code>doClose()</code> for the actual closing procedure.
562      * @see java.lang.Runtime#addShutdownHook
563      * @see #close()
564      * @see #doClose()
565      */

566     public void registerShutdownHook() {
567         if (this.shutdownHook == null) {
568             // No shutdown hook registered yet.
569
this.shutdownHook = new Thread JavaDoc() {
570                 public void run() {
571                     doClose();
572                 }
573             };
574             Runtime.getRuntime().addShutdownHook(this.shutdownHook);
575         }
576     }
577
578     /**
579      * DisposableBean callback for destruction of this instance.
580      * Only called when the ApplicationContext itself is running
581      * as a bean in another BeanFactory or ApplicationContext,
582      * which is rather unusual.
583      * <p>The <code>close</code> method is the native way to
584      * shut down an ApplicationContext.
585      * @see #close()
586      * @see org.springframework.beans.factory.access.SingletonBeanFactoryLocator
587      */

588     public void destroy() {
589         close();
590     }
591
592     /**
593      * Close this application context, destroying all beans in its bean factory.
594      * <p>Delegates to <code>doClose()</code> for the actual closing procedure.
595      * Also removes a JVM shutdown hook, if registered, as it's not needed anymore.
596      * @see #doClose()
597      * @see #registerShutdownHook()
598      */

599     public void close() {
600         synchronized (this.startupShutdownMonitor) {
601             doClose();
602             // If we registered a JVM shutdown hook, we don't need it anymore now:
603
// We've already explicitly closed the context.
604
if (this.shutdownHook != null) {
605                 Runtime.getRuntime().removeShutdownHook(this.shutdownHook);
606             }
607         }
608     }
609
610     /**
611      * Actually performs context closing: publishes a ContextClosedEvent and
612      * destroys the singletons in the bean factory of this application context.
613      * <p>Called by both <code>close()</code> and a JVM shutdown hook, if any.
614      * @see org.springframework.context.event.ContextClosedEvent
615      * @see org.springframework.beans.factory.config.ConfigurableBeanFactory#destroySingletons()
616      * @see #close()
617      * @see #registerShutdownHook()
618      */

619     protected void doClose() {
620         if (isActive()) {
621             if (logger.isInfoEnabled()) {
622                 logger.info("Closing " + this);
623             }
624             try {
625                 // Publish shutdown event.
626
publishEvent(new ContextClosedEvent(this));
627             }
628             catch (Throwable JavaDoc ex) {
629                 logger.error("Exception thrown from ApplicationListener handling ContextClosedEvent", ex);
630             }
631             // Stop all Lifecycle beans, to avoid delays during individual destruction.
632
stop();
633             // Destroy all cached singletons in the context's BeanFactory.
634
destroyBeans();
635             // Close the state of this context itself.
636
closeBeanFactory();
637             onClose();
638             synchronized (this.activeMonitor) {
639                 this.active = false;
640             }
641         }
642     }
643
644     /**
645      * Template method for destroying all beans that this context manages.
646      * The default implementation destroy all cached singletons in this context,
647      * invoking <code>DisposableBean.destroy()</code> and/or the specified
648      * "destroy-method".
649      * <p>Can be overridden to add context-specific bean destruction steps
650      * right before or right after standard singleton destruction,
651      * while the context's BeanFactory is still active.
652      * @see #getBeanFactory()
653      * @see org.springframework.beans.factory.config.ConfigurableBeanFactory#destroySingletons()
654      */

655     protected void destroyBeans() {
656         getBeanFactory().destroySingletons();
657     }
658
659     /**
660      * Template method which can be overridden to add context-specific shutdown work.
661      * The default implementation is empty.
662      * <p>Called at the end of {@link #doClose}'s shutdown procedure, after
663      * this context's BeanFactory has been closed. If custom shutdown logic
664      * needs to execute while the BeanFactory is still active, override
665      * the {@link #destroyBeans()} method instead.
666      */

667     protected void onClose() {
668         // For subclasses: do nothing by default.
669
}
670
671     public boolean isActive() {
672         synchronized (this.activeMonitor) {
673             return this.active;
674         }
675     }
676
677
678     //---------------------------------------------------------------------
679
// Implementation of BeanFactory interface
680
//---------------------------------------------------------------------
681

682     public Object JavaDoc getBean(String JavaDoc name) throws BeansException {
683         return getBeanFactory().getBean(name);
684     }
685
686     public Object JavaDoc getBean(String JavaDoc name, Class JavaDoc requiredType) throws BeansException {
687         return getBeanFactory().getBean(name, requiredType);
688     }
689
690     public boolean containsBean(String JavaDoc name) {
691         return getBeanFactory().containsBean(name);
692     }
693
694     public boolean isSingleton(String JavaDoc name) throws NoSuchBeanDefinitionException {
695         return getBeanFactory().isSingleton(name);
696     }
697
698     public boolean isPrototype(String JavaDoc name) throws NoSuchBeanDefinitionException {
699         return getBeanFactory().isPrototype(name);
700     }
701
702     public boolean isTypeMatch(String JavaDoc name, Class JavaDoc targetType) throws NoSuchBeanDefinitionException {
703         return getBeanFactory().isTypeMatch(name, targetType);
704     }
705
706     public Class JavaDoc getType(String JavaDoc name) throws NoSuchBeanDefinitionException {
707         return getBeanFactory().getType(name);
708     }
709
710     public String JavaDoc[] getAliases(String JavaDoc name) {
711         return getBeanFactory().getAliases(name);
712     }
713
714
715     //---------------------------------------------------------------------
716
// Implementation of ListableBeanFactory interface
717
//---------------------------------------------------------------------
718

719     public boolean containsBeanDefinition(String JavaDoc name) {
720         return getBeanFactory().containsBeanDefinition(name);
721     }
722
723     public int getBeanDefinitionCount() {
724         return getBeanFactory().getBeanDefinitionCount();
725     }
726
727     public String JavaDoc[] getBeanDefinitionNames() {
728         return getBeanFactory().getBeanDefinitionNames();
729     }
730
731     public String JavaDoc[] getBeanNamesForType(Class JavaDoc type) {
732         return getBeanFactory().getBeanNamesForType(type);
733     }
734
735     public String JavaDoc[] getBeanNamesForType(Class JavaDoc type, boolean includePrototypes, boolean allowEagerInit) {
736         return getBeanFactory().getBeanNamesForType(type, includePrototypes, allowEagerInit);
737     }
738
739     public Map JavaDoc getBeansOfType(Class JavaDoc type) throws BeansException {
740         return getBeanFactory().getBeansOfType(type);
741     }
742
743     public Map JavaDoc getBeansOfType(Class JavaDoc type, boolean includePrototypes, boolean allowEagerInit)
744             throws BeansException {
745
746         return getBeanFactory().getBeansOfType(type, includePrototypes, allowEagerInit);
747     }
748
749
750     //---------------------------------------------------------------------
751
// Implementation of HierarchicalBeanFactory interface
752
//---------------------------------------------------------------------
753

754     public BeanFactory getParentBeanFactory() {
755         return getParent();
756     }
757
758     public boolean containsLocalBean(String JavaDoc name) {
759         return getBeanFactory().containsLocalBean(name);
760     }
761
762     /**
763      * Return the internal bean factory of the parent context if it implements
764      * ConfigurableApplicationContext; else, return the parent context itself.
765      * @see org.springframework.context.ConfigurableApplicationContext#getBeanFactory
766      */

767     protected BeanFactory getInternalParentBeanFactory() {
768         return (getParent() instanceof ConfigurableApplicationContext) ?
769                 ((ConfigurableApplicationContext) getParent()).getBeanFactory() : (BeanFactory) getParent();
770     }
771
772
773     //---------------------------------------------------------------------
774
// Implementation of MessageSource interface
775
//---------------------------------------------------------------------
776

777     public String JavaDoc getMessage(String JavaDoc code, Object JavaDoc args[], String JavaDoc defaultMessage, Locale JavaDoc locale) {
778         return getMessageSource().getMessage(code, args, defaultMessage, locale);
779     }
780
781     public String JavaDoc getMessage(String JavaDoc code, Object JavaDoc args[], Locale JavaDoc locale) throws NoSuchMessageException {
782         return getMessageSource().getMessage(code, args, locale);
783     }
784
785     public String JavaDoc getMessage(MessageSourceResolvable resolvable, Locale JavaDoc locale) throws NoSuchMessageException {
786         return getMessageSource().getMessage(resolvable, locale);
787     }
788
789     /**
790      * Return the internal MessageSource used by the context.
791      * @return the internal MessageSource (never <code>null</code>)
792      * @throws IllegalStateException if the context has not been initialized yet
793      */

794     private MessageSource getMessageSource() throws IllegalStateException JavaDoc {
795         if (this.messageSource == null) {
796             throw new IllegalStateException JavaDoc("MessageSource not initialized - " +
797                     "call 'refresh' before accessing messages via the context: " + this);
798         }
799         return this.messageSource;
800     }
801
802     /**
803      * Return the internal message source of the parent context if it is an
804      * AbstractApplicationContext too; else, return the parent context itself.
805      */

806     protected MessageSource getInternalParentMessageSource() {
807         return (getParent() instanceof AbstractApplicationContext) ?
808             ((AbstractApplicationContext) getParent()).messageSource : getParent();
809     }
810
811
812     //---------------------------------------------------------------------
813
// Implementation of ResourcePatternResolver interface
814
//---------------------------------------------------------------------
815

816     public Resource[] getResources(String JavaDoc locationPattern) throws IOException JavaDoc {
817         return this.resourcePatternResolver.getResources(locationPattern);
818     }
819
820
821     //---------------------------------------------------------------------
822
// Implementation of Lifecycle interface
823
//---------------------------------------------------------------------
824

825     public void start() {
826         Iterator JavaDoc it = getLifecycleBeans().iterator();
827         while (it.hasNext()) {
828             Lifecycle lifecycle = (Lifecycle) it.next();
829             if (!lifecycle.isRunning()) {
830                 lifecycle.start();
831             }
832         }
833     }
834
835     public void stop() {
836         Iterator JavaDoc it = getLifecycleBeans().iterator();
837         while (it.hasNext()) {
838             Lifecycle lifecycle = (Lifecycle) it.next();
839             if (lifecycle.isRunning()) {
840                 lifecycle.stop();
841             }
842         }
843     }
844
845     public boolean isRunning() {
846         Iterator JavaDoc it = getLifecycleBeans().iterator();
847         while (it.hasNext()) {
848             Lifecycle lifecycle = (Lifecycle) it.next();
849             if (!lifecycle.isRunning()) {
850                 return false;
851             }
852         }
853         return true;
854     }
855
856     /**
857      * Return a Collection of all singleton beans that implement the
858      * Lifecycle interface in this context.
859      * @return Collection of Lifecycle beans
860      */

861     protected Collection JavaDoc getLifecycleBeans() {
862         ConfigurableListableBeanFactory beanFactory = getBeanFactory();
863         String JavaDoc[] beanNames = beanFactory.getBeanNamesForType(Lifecycle.class, false, false);
864         Collection JavaDoc beans = new ArrayList JavaDoc(beanNames.length);
865         for (int i = 0; i < beanNames.length; i++) {
866             Object JavaDoc bean = beanFactory.getSingleton(beanNames[i]);
867             if (bean != null) {
868                 beans.add(bean);
869             }
870         }
871         return beans;
872     }
873
874
875     //---------------------------------------------------------------------
876
// Abstract methods that must be implemented by subclasses
877
//---------------------------------------------------------------------
878

879     /**
880      * Subclasses must implement this method to perform the actual configuration load.
881      * The method is invoked by {@link #refresh()} before any other initialization work.
882      * <p>A subclass will either create a new bean factory and hold a reference to it,
883      * or return a single BeanFactory instance that it holds. In the latter case, it will
884      * usually throw an IllegalStateException if refreshing the context more than once.
885      * @throws BeansException if initialization of the bean factory failed
886      * @throws IllegalStateException if already initialized and multiple refresh
887      * attempts are not supported
888      */

889     protected abstract void refreshBeanFactory() throws BeansException, IllegalStateException JavaDoc;
890
891     /**
892      * Subclasses must implement this method to release their internal bean factory.
893      * This method gets invoked by {@link #close()} after all other shutdown work.
894      * <p>Should never throw an exception but rather log shutdown failures.
895      */

896     protected abstract void closeBeanFactory();
897
898     /**
899      * Subclasses must return their internal bean factory here. They should implement the
900      * lookup efficiently, so that it can be called repeatedly without a performance penalty.
901      * <p>Note: Subclasses should check whether the context is still active before
902      * returning the internal bean factory. The internal factory should generally be
903      * considered unavailable once the context has been closed.
904      * @return this application context's internal bean factory (never <code>null</code>)
905      * @throws IllegalStateException if the context does not hold an internal bean factory yet
906      * (usually if {@link #refresh()} has never been called) or if the context has been
907      * closed already
908      * @see #refreshBeanFactory()
909      * @see #closeBeanFactory()
910      */

911     public abstract ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException JavaDoc;
912
913
914     /**
915      * Return information about this context.
916      */

917     public String JavaDoc toString() {
918         StringBuffer JavaDoc sb = new StringBuffer JavaDoc(ObjectUtils.identityToString(this));
919         sb.append(": display name [").append(getDisplayName());
920         sb.append("]; startup date [").append(new Date JavaDoc(getStartupDate()));
921         sb.append("]; ");
922         ApplicationContext parent = getParent();
923         if (parent == null) {
924             sb.append("root of context hierarchy");
925         }
926         else {
927             sb.append("parent: ").append(ObjectUtils.identityToString(parent));
928         }
929         return sb.toString();
930     }
931
932
933     /**
934      * BeanPostProcessor that logs an info message when a bean is created during
935      * BeanPostProcessor instantiation, i.e. when a bean is not eligible for
936      * getting processed by all BeanPostProcessors.
937      */

938     private class BeanPostProcessorChecker implements BeanPostProcessor {
939
940         private final int beanPostProcessorTargetCount;
941
942         public BeanPostProcessorChecker(int beanPostProcessorTargetCount) {
943             this.beanPostProcessorTargetCount = beanPostProcessorTargetCount;
944         }
945
946         public Object JavaDoc postProcessBeforeInitialization(Object JavaDoc bean, String JavaDoc beanName) {
947             return bean;
948         }
949
950         public Object JavaDoc postProcessAfterInitialization(Object JavaDoc bean, String JavaDoc beanName) {
951             if (getBeanFactory().getBeanPostProcessorCount() < this.beanPostProcessorTargetCount) {
952                 if (logger.isInfoEnabled()) {
953                     logger.info("Bean '" + beanName + "' is not eligible for getting processed by all " +
954                             "BeanPostProcessors (for example: not eligible for auto-proxying)");
955                 }
956             }
957             return bean;
958         }
959     }
960
961 }
962
Popular Tags