1 /*
2 * Copyright 2002-2008 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;
20 import java.util.ArrayList;
21 import java.util.Collection;
22 import java.util.Collections;
23 import java.util.Date;
24 import java.util.Iterator;
25 import java.util.LinkedHashMap;
26 import java.util.LinkedHashSet;
27 import java.util.List;
28 import java.util.Locale;
29 import java.util.Map;
30
31 import org.apache.commons.logging.Log;
32 import org.apache.commons.logging.LogFactory;
33 import org.springframework.beans.BeanUtils;
34 import org.springframework.beans.BeansException;
35 import org.springframework.beans.factory.BeanFactory;
36 import org.springframework.beans.factory.BeanFactoryAware;
37 import org.springframework.beans.factory.DisposableBean;
38 import org.springframework.beans.factory.NoSuchBeanDefinitionException;
39 import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
40 import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
41 import org.springframework.beans.factory.config.BeanPostProcessor;
42 import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
43 import org.springframework.beans.support.ResourceEditorRegistrar;
44 import org.springframework.context.ApplicationContext;
45 import org.springframework.context.ApplicationContextAware;
46 import org.springframework.context.ApplicationEvent;
47 import org.springframework.context.ApplicationEventPublisher;
48 import org.springframework.context.ApplicationEventPublisherAware;
49 import org.springframework.context.ApplicationListener;
50 import org.springframework.context.ConfigurableApplicationContext;
51 import org.springframework.context.HierarchicalMessageSource;
52 import org.springframework.context.Lifecycle;
53 import org.springframework.context.MessageSource;
54 import org.springframework.context.MessageSourceAware;
55 import org.springframework.context.MessageSourceResolvable;
56 import org.springframework.context.NoSuchMessageException;
57 import org.springframework.context.ResourceLoaderAware;
58 import org.springframework.context.event.ApplicationEventMulticaster;
59 import org.springframework.context.event.ContextClosedEvent;
60 import org.springframework.context.event.ContextRefreshedEvent;
61 import org.springframework.context.event.ContextStartedEvent;
62 import org.springframework.context.event.ContextStoppedEvent;
63 import org.springframework.context.event.SimpleApplicationEventMulticaster;
64 import org.springframework.core.JdkVersion;
65 import org.springframework.core.OrderComparator;
66 import org.springframework.core.Ordered;
67 import org.springframework.core.PriorityOrdered;
68 import org.springframework.core.io.DefaultResourceLoader;
69 import org.springframework.core.io.Resource;
70 import org.springframework.core.io.ResourceLoader;
71 import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
72 import org.springframework.core.io.support.ResourcePatternResolver;
73 import org.springframework.util.Assert;
74 import org.springframework.util.ClassUtils;
75 import org.springframework.util.ObjectUtils;
76
77 /**
78 * Abstract implementation of the {@link org.springframework.context.ApplicationContext}
79 * interface. Doesn't mandate the type of storage used for configuration; simply
80 * implements common context functionality. Uses the Template Method design pattern,
81 * requiring concrete subclasses to implement abstract methods.
82 *
83 * <p>In contrast to a plain BeanFactory, an ApplicationContext is supposed
84 * to detect special beans defined in its internal bean factory:
85 * Therefore, this class automatically registers
86 * {@link org.springframework.beans.factory.config.BeanFactoryPostProcessor BeanFactoryPostProcessors},
87 * {@link org.springframework.beans.factory.config.BeanPostProcessor BeanPostProcessors}
88 * and {@link org.springframework.context.ApplicationListener ApplicationListeners}
89 * which are defined as beans in the context.
90 *
91 * <p>A {@link org.springframework.context.MessageSource} may also be supplied
92 * as a bean in the context, with the name "messageSource"; otherwise, message
93 * resolution is delegated to the parent context. Furthermore, a multicaster
94 * for application events can be supplied as "applicationEventMulticaster" bean
95 * of type {@link org.springframework.context.event.ApplicationEventMulticaster}
96 * in the context; otherwise, a default multicaster of type
97 * {@link org.springframework.context.event.SimpleApplicationEventMulticaster} will be used.
98 *
99 * <p>Implements resource loading through extending
100 * {@link org.springframework.core.io.DefaultResourceLoader}.
101 * Consequently treats non-URL resource paths as class path resources
102 * (supporting full class path resource names that include the package path,
103 * e.g. "mypackage/myresource.dat"), unless the {@link #getResourceByPath}
104 * method is overwritten in a subclass.
105 *
106 * @author Rod Johnson
107 * @author Juergen Hoeller
108 * @author Mark Fisher
109 * @since January 21, 2001
110 * @see #refreshBeanFactory
111 * @see #getBeanFactory
112 * @see org.springframework.beans.factory.config.BeanFactoryPostProcessor
113 * @see org.springframework.beans.factory.config.BeanPostProcessor
114 * @see org.springframework.context.event.ApplicationEventMulticaster
115 * @see org.springframework.context.ApplicationListener
116 * @see org.springframework.context.MessageSource
117 */
118 public abstract class AbstractApplicationContext extends DefaultResourceLoader
119 implements ConfigurableApplicationContext, DisposableBean {
120
121 /**
122 * Name of the MessageSource bean in the factory.
123 * If none is supplied, message resolution is delegated to the parent.
124 * @see MessageSource
125 */
126 public static final String MESSAGE_SOURCE_BEAN_NAME = "messageSource";
127
128 /**
129 * Name of the ApplicationEventMulticaster bean in the factory.
130 * If none is supplied, a default SimpleApplicationEventMulticaster is used.
131 * @see org.springframework.context.event.ApplicationEventMulticaster
132 * @see org.springframework.context.event.SimpleApplicationEventMulticaster
133 */
134 public static final String APPLICATION_EVENT_MULTICASTER_BEAN_NAME = "applicationEventMulticaster";
135
136
137 static {
138 // Eagerly load the ContextClosedEvent class to avoid weird classloader issues
139 // on application shutdown in WebLogic 8.1. (Reported by Dustin Woods.)
140 ContextClosedEvent.class.getName();
141 }
142
143
144 /** Logger used by this class. Available to subclasses. */
145 protected final Log logger = LogFactory.getLog(getClass());
146
147 /** Unique id for this context, if any */
148 private String id = ObjectUtils.identityToString(this);
149
150 /** Parent context */
151 private ApplicationContext parent;
152
153 /** BeanFactoryPostProcessors to apply on refresh */
154 private final List beanFactoryPostProcessors = new ArrayList();
155
156 /** Display name */
157 private String displayName;
158
159 /** System time in milliseconds when this context started */
160 private long startupDate;
161
162 /** Flag that indicates whether this context is currently active */
163 private boolean active = false;
164
165 /** Synchronization monitor for the "active" flag */
166 private final Object activeMonitor = new Object();
167
168 /** Synchronization monitor for the "refresh" and "destroy" */
169 private final Object startupShutdownMonitor = new Object();
170
171 /** Reference to the JVM shutdown hook, if registered */
172 private Thread shutdownHook;
173
174 /** ResourcePatternResolver used by this context */
175 private ResourcePatternResolver resourcePatternResolver;
176
177 /** MessageSource we delegate our implementation of this interface to */
178 private MessageSource messageSource;
179
180 /** Helper class used in event publishing */
181 private ApplicationEventMulticaster applicationEventMulticaster;
182
183 /** Statically specified listeners */
184 private List applicationListeners = new ArrayList();
185
186
187 /**
188 * Create a new AbstractApplicationContext with no parent.
189 */
190 public AbstractApplicationContext() {
191 this(null);
192 }
193
194 /**
195 * Create a new AbstractApplicationContext with the given parent context.
196 * @param parent the parent context
197 */
198 public AbstractApplicationContext(ApplicationContext parent) {
199 this.parent = parent;
200 this.resourcePatternResolver = getResourcePatternResolver();
201 }
202
203
204 //---------------------------------------------------------------------
205 // Implementation of ApplicationContext interface
206 //---------------------------------------------------------------------
207
208 /**
209 * Set the unique id of this application context.
210 * <p>Default is the object id of the context instance, or the name
211 * of the context bean if the context is itself defined as a bean.
212 * @param id the unique id of the context
213 */
214 public void setId(String id) {
215 this.id = id;
216 }
217
218 public String getId() {
219 return this.id;
220 }
221
222 /**
223 * Return the parent context, or <code>null</code> if there is no parent
224 * (that is, this context is the root of the context hierarchy).
225 */
226 public ApplicationContext getParent() {
227 return this.parent;
228 }
229
230 /**
231 * Return this context's internal bean factory as AutowireCapableBeanFactory,
232 * if already available.
233 * @see #getBeanFactory()
234 */
235 public AutowireCapableBeanFactory getAutowireCapableBeanFactory() throws IllegalStateException {
236 return getBeanFactory();
237 }
238
239 /**
240 * Set a friendly name for this context.
241 * Typically done during initialization of concrete context implementations.
242 */
243 public void setDisplayName(String displayName) {
244 this.displayName = displayName;
245 }
246
247 /**
248 * Return a friendly name for this context.
249 */
250 public String getDisplayName() {
251 return (this.displayName != null ? this.displayName : getId());
252 }
253
254 /**
255 * Return the timestamp (ms) when this context was first loaded.
256 */
257 public long getStartupDate() {
258 return this.startupDate;
259 }
260
261 /**
262 * Publish the given event to all listeners.
263 * <p>Note: Listeners get initialized after the MessageSource, to be able
264 * to access it within listener implementations. Thus, MessageSource
265 * implementations cannot publish events.
266 * @param event the event to publish (may be application-specific or a
267 * standard framework event)
268 */
269 public void publishEvent(ApplicationEvent event) {
270 Assert.notNull(event, "Event must not be null");
271 if (logger.isTraceEnabled()) {
272 logger.trace("Publishing event in context [" + getId() + "]: " + event);
273 }
274 getApplicationEventMulticaster().multicastEvent(event);
275 if (this.parent != null) {
276 this.parent.publishEvent(event);
277 }
278 }
279
280 /**
281 * Return the internal MessageSource used by the context.
282 * @return the internal MessageSource (never <code>null</code>)
283 * @throws IllegalStateException if the context has not been initialized yet
284 */
285 private ApplicationEventMulticaster getApplicationEventMulticaster() throws IllegalStateException {
286 if (this.applicationEventMulticaster == null) {
287 throw new IllegalStateException("ApplicationEventMulticaster not initialized - " +
288 "call 'refresh' before multicasting events via the context: " + this);
289 }
290 return this.applicationEventMulticaster;
291 }
292
293 /**
294 * Return the ResourcePatternResolver to use for resolving location patterns
295 * into Resource instances. Default is a
296 * {@link org.springframework.core.io.support.PathMatchingResourcePatternResolver},
297 * supporting Ant-style location patterns.
298 * <p>Can be overridden in subclasses, for extended resolution strategies,
299 * for example in a web environment.
300 * <p><b>Do not call this when needing to resolve a location pattern.</b>
301 * Call the context's <code>getResources</code> method instead, which
302 * will delegate to the ResourcePatternResolver.
303 * @return the ResourcePatternResolver for this context
304 * @see #getResources
305 * @see org.springframework.core.io.support.PathMatchingResourcePatternResolver
306 */
307 protected ResourcePatternResolver getResourcePatternResolver() {
308 return new PathMatchingResourcePatternResolver(this);
309 }
310
311
312 //---------------------------------------------------------------------
313 // Implementation of ConfigurableApplicationContext interface
314 //---------------------------------------------------------------------
315
316 public void setParent(ApplicationContext parent) {
317 this.parent = parent;
318 }
319
320 public void addBeanFactoryPostProcessor(BeanFactoryPostProcessor beanFactoryPostProcessor) {
321 this.beanFactoryPostProcessors.add(beanFactoryPostProcessor);
322 }
323
324 /**
325 * Return the list of BeanFactoryPostProcessors that will get applied
326 * to the internal BeanFactory.
327 * @see org.springframework.beans.factory.config.BeanFactoryPostProcessor
328 */
329 public List getBeanFactoryPostProcessors() {
330 return this.beanFactoryPostProcessors;
331 }
332
333 public void addApplicationListener(ApplicationListener listener) {
334 this.applicationListeners.add(listener);
335 }
336
337 /**
338 * Return the list of statically specified ApplicationListeners.
339 * @see org.springframework.context.ApplicationListener
340 */
341 public List getApplicationListeners() {
342 return this.applicationListeners;
343 }
344
345
346 public void refresh() throws BeansException, IllegalStateException {
347 synchronized (this.startupShutdownMonitor) {
348 // Prepare this context for refreshing.
349 prepareRefresh();
350
351 // Tell the subclass to refresh the internal bean factory.
352 ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
353
354 // Prepare the bean factory for use in this context.
355 prepareBeanFactory(beanFactory);
356
357 try {
358 // Allows post-processing of the bean factory in context subclasses.
359 postProcessBeanFactory(beanFactory);
360
361 // Invoke factory processors registered as beans in the context.
362 invokeBeanFactoryPostProcessors(beanFactory);
363
364 // Register bean processors that intercept bean creation.
365 registerBeanPostProcessors(beanFactory);
366
367 // Initialize message source for this context.
368 initMessageSource();
369
370 // Initialize event multicaster for this context.
371 initApplicationEventMulticaster();
372
373 // Initialize other special beans in specific context subclasses.
374 onRefresh();
375
376 // Check for listener beans and register them.
377 registerListeners();
378
379 // Instantiate all remaining (non-lazy-init) singletons.
380 finishBeanFactoryInitialization(beanFactory);
381
382 // Last step: publish corresponding event.
383 finishRefresh();
384 }
385
386 catch (BeansException ex) {
387 // Destroy already created singletons to avoid dangling resources.
388 beanFactory.destroySingletons();
389
390 // Reset 'active' flag.
391 cancelRefresh(ex);
392
393 // Propagate exception to caller.
394 throw ex;
395 }
396 }
397 }
398
399 /**
400 * Prepare this context for refreshing, setting its startup date and
401 * active flag.
402 */
403 protected void prepareRefresh() {
404 this.startupDate = System.currentTimeMillis();
405
406 synchronized (this.activeMonitor) {
407 this.active = true;
408 }
409
410 if (logger.isInfoEnabled()) {
411 logger.info("Refreshing " + this);
412 }
413 }
414
415 /**
416 * Tell the subclass to refresh the internal bean factory.
417 * @return the fresh BeanFactory instance
418 * @see #refreshBeanFactory()
419 * @see #getBeanFactory()
420 */
421 protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
422 refreshBeanFactory();
423 ConfigurableListableBeanFactory beanFactory = getBeanFactory();
424
425 if (logger.isInfoEnabled()) {
426 logger.info("Bean factory for application context [" + getId() + "]: " +
427 ObjectUtils.identityToString(beanFactory));
428 }
429 if (logger.isDebugEnabled()) {
430 logger.debug(beanFactory.getBeanDefinitionCount() + " beans defined in " + this);
431 }
432
433 return beanFactory;
434 }
435
436 /**
437 * Configure the factory's standard context characteristics,
438 * such as the context's ClassLoader and post-processors.
439 * @param beanFactory the BeanFactory to configure
440 */
441 protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
442 // Tell the internal bean factory to use the context's class loader.
443 beanFactory.setBeanClassLoader(getClassLoader());
444
445 // Populate the bean factory with context-specific resource editors.
446 beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this));
447
448 // Configure the bean factory with context callbacks.
449 beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
450 beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
451 beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
452 beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
453 beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
454
455 // BeanFactory interface not registered as resolvable type in a plain factory.
456 // MessageSource registered (and found for autowiring) as a bean.
457 beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
458 beanFactory.registerResolvableDependency(ResourceLoader.class, this);
459 beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
460 beanFactory.registerResolvableDependency(ApplicationContext.class, this);
461
462 // Detect a LoadTimeWeaver and prepare for weaving, if found.
463 if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME) && JdkVersion.isAtLeastJava15()) {
464 // Register the (JDK 1.5 specific) LoadTimeWeaverAwareProcessor.
465 try {
466 Class ltwapClass = ClassUtils.forName(
467 "org.springframework.context.weaving.LoadTimeWeaverAwareProcessor",
468 AbstractApplicationContext.class.getClassLoader());
469 BeanPostProcessor ltwap = (BeanPostProcessor) BeanUtils.instantiateClass(ltwapClass);
470 ((BeanFactoryAware) ltwap).setBeanFactory(beanFactory);
471 beanFactory.addBeanPostProcessor(ltwap);
472 }
473 catch (ClassNotFoundException ex) {
474 throw new IllegalStateException("Spring's LoadTimeWeaverAwareProcessor class is not available");
475 }
476 // Set a temporary ClassLoader for type matching.
477 beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
478 }
479 }
480
481 /**
482 * Modify the application context's internal bean factory after its standard
483 * initialization. All bean definitions will have been loaded, but no beans
484 * will have been instantiated yet. This allows for registering special
485 * BeanPostProcessors etc in certain ApplicationContext implementations.
486 * @param beanFactory the bean factory used by the application context
487 */
488 protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
489 }
490
491 /**
492 * Instantiate and invoke all registered BeanFactoryPostProcessor beans,
493 * respecting explicit order if given.
494 * <p>Must be called before singleton instantiation.
495 */
496 protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
497 // Invoke factory processors registered with the context instance.
498 for (Iterator it = getBeanFactoryPostProcessors().iterator(); it.hasNext();) {
499 BeanFactoryPostProcessor factoryProcessor = (BeanFactoryPostProcessor) it.next();
500 factoryProcessor.postProcessBeanFactory(beanFactory);
501 }
502
503 // Do not initialize FactoryBeans here: We need to leave all regular beans
504 // uninitialized to let the bean factory post-processors apply to them!
505 String[] postProcessorNames =
506 beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);
507
508 // Separate between BeanFactoryPostProcessors that implement PriorityOrdered,
509 // Ordered, and the rest.
510 List priorityOrderedPostProcessors = new ArrayList();
511 List orderedPostProcessorNames = new ArrayList();
512 List nonOrderedPostProcessorNames = new ArrayList();
513 for (int i = 0; i < postProcessorNames.length; i++) {
514 if (isTypeMatch(postProcessorNames[i], PriorityOrdered.class)) {
515 priorityOrderedPostProcessors.add(beanFactory.getBean(postProcessorNames[i]));
516 }
517 else if (isTypeMatch(postProcessorNames[i], Ordered.class)) {
518 orderedPostProcessorNames.add(postProcessorNames[i]);
519 }
520 else {
521 nonOrderedPostProcessorNames.add(postProcessorNames[i]);
522 }
523 }
524
525 // First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.
526 Collections.sort(priorityOrderedPostProcessors, new OrderComparator());
527 invokeBeanFactoryPostProcessors(beanFactory, priorityOrderedPostProcessors);
528
529 // Next, invoke the BeanFactoryPostProcessors that implement Ordered.
530 List orderedPostProcessors = new ArrayList();
531 for (Iterator it = orderedPostProcessorNames.iterator(); it.hasNext();) {
532 String postProcessorName = (String) it.next();
533 orderedPostProcessors.add(getBean(postProcessorName));
534 }
535 Collections.sort(orderedPostProcessors, new OrderComparator());
536 invokeBeanFactoryPostProcessors(beanFactory, orderedPostProcessors);
537
538 // Finally, invoke all other BeanFactoryPostProcessors.
539 List nonOrderedPostProcessors = new ArrayList();
540 for (Iterator it = nonOrderedPostProcessorNames.iterator(); it.hasNext();) {
541 String postProcessorName = (String) it.next();
542 nonOrderedPostProcessors.add(getBean(postProcessorName));
543 }
544 invokeBeanFactoryPostProcessors(beanFactory, nonOrderedPostProcessors);
545 }
546
547 /**
548 * Invoke the given BeanFactoryPostProcessor beans.
549 */
550 private void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory, List postProcessors) {
551 for (Iterator it = postProcessors.iterator(); it.hasNext();) {
552 BeanFactoryPostProcessor postProcessor = (BeanFactoryPostProcessor) it.next();
553 postProcessor.postProcessBeanFactory(beanFactory);
554 }
555 }
556
557 /**
558 * Instantiate and invoke all registered BeanPostProcessor beans,
559 * respecting explicit order if given.
560 * <p>Must be called before any instantiation of application beans.
561 */
562 protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
563 String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);
564
565 // Register BeanPostProcessorChecker that logs an info message when
566 // a bean is created during BeanPostProcessor instantiation, i.e. when
567 // a bean is not eligible for getting processed by all BeanPostProcessors.
568 int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
569 beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));
570
571 // Separate between BeanPostProcessors that implement PriorityOrdered,
572 // Ordered, and the rest.
573 List priorityOrderedPostProcessors = new ArrayList();
574 List orderedPostProcessorNames = new ArrayList();
575 List nonOrderedPostProcessorNames = new ArrayList();
576 for (int i = 0; i < postProcessorNames.length; i++) {
577 if (isTypeMatch(postProcessorNames[i], PriorityOrdered.class)) {
578 priorityOrderedPostProcessors.add(beanFactory.getBean(postProcessorNames[i]));
579 }
580 else if (isTypeMatch(postProcessorNames[i], Ordered.class)) {
581 orderedPostProcessorNames.add(postProcessorNames[i]);
582 }
583 else {
584 nonOrderedPostProcessorNames.add(postProcessorNames[i]);
585 }
586 }
587
588 // First, register the BeanPostProcessors that implement PriorityOrdered.
589 Collections.sort(priorityOrderedPostProcessors, new OrderComparator());
590 registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);
591
592 // Next, register the BeanPostProcessors that implement Ordered.
593 List orderedPostProcessors = new ArrayList();
594 for (Iterator it = orderedPostProcessorNames.iterator(); it.hasNext();) {
595 String postProcessorName = (String) it.next();
596 orderedPostProcessors.add(getBean(postProcessorName));
597 }
598 Collections.sort(orderedPostProcessors, new OrderComparator());
599 registerBeanPostProcessors(beanFactory, orderedPostProcessors);
600
601 // Finally, register all other BeanPostProcessors.
602 List nonOrderedPostProcessors = new ArrayList();
603 for (Iterator it = nonOrderedPostProcessorNames.iterator(); it.hasNext();) {
604 String postProcessorName = (String) it.next();
605 nonOrderedPostProcessors.add(getBean(postProcessorName));
606 }
607 registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);
608 }
609
610 /**
611 * Register the given BeanPostProcessor beans.
612 */
613 private void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory, List postProcessors) {
614 for (Iterator it = postProcessors.iterator(); it.hasNext();) {
615 BeanPostProcessor postProcessor = (BeanPostProcessor) it.next();
616 beanFactory.addBeanPostProcessor(postProcessor);
617 }
618 }
619
620 /**
621 * Initialize the MessageSource.
622 * Use parent's if none defined in this context.
623 */
624 protected void initMessageSource() {
625 ConfigurableListableBeanFactory beanFactory = getBeanFactory();
626 if (beanFactory.containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) {
627 this.messageSource = (MessageSource) beanFactory.getBean(MESSAGE_SOURCE_BEAN_NAME, MessageSource.class);
628 // Make MessageSource aware of parent MessageSource.
629 if (this.parent != null && this.messageSource instanceof HierarchicalMessageSource) {
630 HierarchicalMessageSource hms = (HierarchicalMessageSource) this.messageSource;
631 if (hms.getParentMessageSource() == null) {
632 // Only set parent context as parent MessageSource if no parent MessageSource
633 // registered already.
634 hms.setParentMessageSource(getInternalParentMessageSource());
635 }
636 }
637 if (logger.isDebugEnabled()) {
638 logger.debug("Using MessageSource [" + this.messageSource + "]");
639 }
640 }
641 else {
642 // Use empty MessageSource to be able to accept getMessage calls.
643 DelegatingMessageSource dms = new DelegatingMessageSource();
644 dms.setParentMessageSource(getInternalParentMessageSource());
645 this.messageSource = dms;
646 beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.messageSource);
647 if (logger.isDebugEnabled()) {
648 logger.debug("Unable to locate MessageSource with name '" + MESSAGE_SOURCE_BEAN_NAME +
649 "': using default [" + this.messageSource + "]");
650 }
651 }
652 }
653
654 /**
655 * Initialize the ApplicationEventMulticaster.
656 * Uses SimpleApplicationEventMulticaster if none defined in the context.
657 * @see org.springframework.context.event.SimpleApplicationEventMulticaster
658 */
659 protected void initApplicationEventMulticaster() {
660 ConfigurableListableBeanFactory beanFactory = getBeanFactory();
661 if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
662 this.applicationEventMulticaster = (ApplicationEventMulticaster)
663 beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
664 if (logger.isDebugEnabled()) {
665 logger.debug("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
666 }
667 }
668 else {
669 this.applicationEventMulticaster = new SimpleApplicationEventMulticaster();
670 beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
671 if (logger.isDebugEnabled()) {
672 logger.debug("Unable to locate ApplicationEventMulticaster with name '" +
673 APPLICATION_EVENT_MULTICASTER_BEAN_NAME +
674 "': using default [" + this.applicationEventMulticaster + "]");
675 }
676 }
677 }
678
679 /**
680 * Template method which can be overridden to add context-specific refresh work.
681 * Called on initialization of special beans, before instantiation of singletons.
682 * <p>This implementation is empty.
683 * @throws BeansException in case of errors
684 * @see #refresh()
685 */
686 protected void onRefresh() throws BeansException {
687 // For subclasses: do nothing by default.
688 }
689
690 /**
691 * Add beans that implement ApplicationListener as listeners.
692 * Doesn't affect other listeners, which can be added without being beans.
693 */
694 protected void registerListeners() {
695 // Register statically specified listeners first.
696 for (Iterator it = getApplicationListeners().iterator(); it.hasNext();) {
697 addListener((ApplicationListener) it.next());
698 }
699 // Do not initialize FactoryBeans here: We need to leave all regular beans
700 // uninitialized to let post-processors apply to them!
701 Collection listenerBeans = getBeansOfType(ApplicationListener.class, true, false).values();
702 for (Iterator it = listenerBeans.iterator(); it.hasNext();) {
703 addListener((ApplicationListener) it.next());
704 }
705 }
706
707 /**
708 * Subclasses can invoke this method to register a listener.
709 * Any beans in the context that are listeners are automatically added.
710 * @param listener the listener to register
711 */
712 protected void addListener(ApplicationListener listener) {
713 getApplicationEventMulticaster().addApplicationListener(listener);
714 }
715
716 /**
717 * Finish the initialization of this context's bean factory,
718 * initializing all remaining singleton beans.
719 */
720 protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
721 // Stop using the temporary ClassLoader for type matching.
722 beanFactory.setTempClassLoader(null);
723
724 // Allow for caching all bean definition metadata, not expecting further changes.
725 beanFactory.freezeConfiguration();
726
727 // Instantiate all remaining (non-lazy-init) singletons.
728 beanFactory.preInstantiateSingletons();
729 }
730
731 /**
732 * Finish the refresh of this context, publishing the
733 * {@link org.springframework.context.event.ContextRefreshedEvent}.
734 */
735 protected void finishRefresh() {
736 publishEvent(new ContextRefreshedEvent(this));
737 }
738
739 /**
740 * Cancel this context's refresh attempt, resetting the <code>active</code> flag
741 * after an exception got thrown.
742 * @param ex the exception that led to the cancellation
743 */
744 protected void cancelRefresh(BeansException ex) {
745 synchronized (this.activeMonitor) {
746 this.active = false;
747 }
748 }
749
750
751 /**
752 * Register a shutdown hook with the JVM runtime, closing this context
753 * on JVM shutdown unless it has already been closed at that time.
754 * <p>Delegates to <code>doClose()</code> for the actual closing procedure.
755 * @see java.lang.Runtime#addShutdownHook
756 * @see #close()
757 * @see #doClose()
758 */
759 public void registerShutdownHook() {
760 if (this.shutdownHook == null) {
761 // No shutdown hook registered yet.
762 this.shutdownHook = new Thread() {
763 public void run() {
764 doClose();
765 }
766 };
767 Runtime.getRuntime().addShutdownHook(this.shutdownHook);
768 }
769 }
770
771 /**
772 * DisposableBean callback for destruction of this instance.
773 * Only called when the ApplicationContext itself is running
774 * as a bean in another BeanFactory or ApplicationContext,
775 * which is rather unusual.
776 * <p>The <code>close</code> method is the native way to
777 * shut down an ApplicationContext.
778 * @see #close()
779 * @see org.springframework.beans.factory.access.SingletonBeanFactoryLocator
780 */
781 public void destroy() {
782 close();
783 }
784
785 /**
786 * Close this application context, destroying all beans in its bean factory.
787 * <p>Delegates to <code>doClose()</code> for the actual closing procedure.
788 * Also removes a JVM shutdown hook, if registered, as it's not needed anymore.
789 * @see #doClose()
790 * @see #registerShutdownHook()
791 */
792 public void close() {
793 synchronized (this.startupShutdownMonitor) {
794 doClose();
795 // If we registered a JVM shutdown hook, we don't need it anymore now:
796 // We've already explicitly closed the context.
797 if (this.shutdownHook != null) {
798 Runtime.getRuntime().removeShutdownHook(this.shutdownHook);
799 }
800 }
801 }
802
803 /**
804 * Actually performs context closing: publishes a ContextClosedEvent and
805 * destroys the singletons in the bean factory of this application context.
806 * <p>Called by both <code>close()</code> and a JVM shutdown hook, if any.
807 * @see org.springframework.context.event.ContextClosedEvent
808 * @see org.springframework.beans.factory.config.ConfigurableBeanFactory#destroySingletons()
809 * @see #close()
810 * @see #registerShutdownHook()
811 */
812 protected void doClose() {
813 if (isActive()) {
814 if (logger.isInfoEnabled()) {
815 logger.info("Closing " + this);
816 }
817 try {
818 // Publish shutdown event.
819 publishEvent(new ContextClosedEvent(this));
820 }
821 catch (Throwable ex) {
822 logger.error("Exception thrown from ApplicationListener handling ContextClosedEvent", ex);
823 }
824 // Stop all Lifecycle beans, to avoid delays during individual destruction.
825 Map lifecycleBeans = getLifecycleBeans();
826 for (Iterator it = new LinkedHashSet(lifecycleBeans.keySet()).iterator(); it.hasNext();) {
827 String beanName = (String) it.next();
828 doStop(lifecycleBeans, beanName);
829 }
830 // Destroy all cached singletons in the context's BeanFactory.
831 destroyBeans();
832 // Close the state of this context itself.
833 closeBeanFactory();
834 onClose();
835 synchronized (this.activeMonitor) {
836 this.active = false;
837 }
838 }
839 }
840
841 /**
842 * Template method for destroying all beans that this context manages.
843 * The default implementation destroy all cached singletons in this context,
844 * invoking <code>DisposableBean.destroy()</code> and/or the specified
845 * "destroy-method".
846 * <p>Can be overridden to add context-specific bean destruction steps
847 * right before or right after standard singleton destruction,
848 * while the context's BeanFactory is still active.
849 * @see #getBeanFactory()
850 * @see org.springframework.beans.factory.config.ConfigurableBeanFactory#destroySingletons()
851 */
852 protected void destroyBeans() {
853 getBeanFactory().destroySingletons();
854 }
855
856 /**
857 * Template method which can be overridden to add context-specific shutdown work.
858 * The default implementation is empty.
859 * <p>Called at the end of {@link #doClose}'s shutdown procedure, after
860 * this context's BeanFactory has been closed. If custom shutdown logic
861 * needs to execute while the BeanFactory is still active, override
862 * the {@link #destroyBeans()} method instead.
863 */
864 protected void onClose() {
865 // For subclasses: do nothing by default.
866 }
867
868 public boolean isActive() {
869 synchronized (this.activeMonitor) {
870 return this.active;
871 }
872 }
873
874
875 //---------------------------------------------------------------------
876 // Implementation of BeanFactory interface
877 //---------------------------------------------------------------------
878
879 public Object getBean(String name) throws BeansException {
880 return getBeanFactory().getBean(name);
881 }
882
883 public Object getBean(String name, Class requiredType) throws BeansException {
884 return getBeanFactory().getBean(name, requiredType);
885 }
886
887 public Object getBean(String name, Object[] args) throws BeansException {
888 return getBeanFactory().getBean(name, args);
889 }
890
891 public boolean containsBean(String name) {
892 return getBeanFactory().containsBean(name);
893 }
894
895 public boolean isSingleton(String name) throws NoSuchBeanDefinitionException {
896 return getBeanFactory().isSingleton(name);
897 }
898
899 public boolean isPrototype(String name) throws NoSuchBeanDefinitionException {
900 return getBeanFactory().isPrototype(name);
901 }
902
903 public boolean isTypeMatch(String name, Class targetType) throws NoSuchBeanDefinitionException {
904 return getBeanFactory().isTypeMatch(name, targetType);
905 }
906
907 public Class getType(String name) throws NoSuchBeanDefinitionException {
908 return getBeanFactory().getType(name);
909 }
910
911 public String[] getAliases(String name) {
912 return getBeanFactory().getAliases(name);
913 }
914
915
916 //---------------------------------------------------------------------
917 // Implementation of ListableBeanFactory interface
918 //---------------------------------------------------------------------
919
920 public boolean containsBeanDefinition(String name) {
921 return getBeanFactory().containsBeanDefinition(name);
922 }
923
924 public int getBeanDefinitionCount() {
925 return getBeanFactory().getBeanDefinitionCount();
926 }
927
928 public String[] getBeanDefinitionNames() {
929 return getBeanFactory().getBeanDefinitionNames();
930 }
931
932 public String[] getBeanNamesForType(Class type) {
933 return getBeanFactory().getBeanNamesForType(type);
934 }
935
936 public String[] getBeanNamesForType(Class type, boolean includePrototypes, boolean allowEagerInit) {
937 return getBeanFactory().getBeanNamesForType(type, includePrototypes, allowEagerInit);
938 }
939
940 public Map getBeansOfType(Class type) throws BeansException {
941 return getBeanFactory().getBeansOfType(type);
942 }
943
944 public Map getBeansOfType(Class type, boolean includePrototypes, boolean allowEagerInit)
945 throws BeansException {
946
947 return getBeanFactory().getBeansOfType(type, includePrototypes, allowEagerInit);
948 }
949
950
951 //---------------------------------------------------------------------
952 // Implementation of HierarchicalBeanFactory interface
953 //---------------------------------------------------------------------
954
955 public BeanFactory getParentBeanFactory() {
956 return getParent();
957 }
958
959 public boolean containsLocalBean(String name) {
960 return getBeanFactory().containsLocalBean(name);
961 }
962
963 /**
964 * Return the internal bean factory of the parent context if it implements
965 * ConfigurableApplicationContext; else, return the parent context itself.
966 * @see org.springframework.context.ConfigurableApplicationContext#getBeanFactory
967 */
968 protected BeanFactory getInternalParentBeanFactory() {
969 return (getParent() instanceof ConfigurableApplicationContext) ?
970 ((ConfigurableApplicationContext) getParent()).getBeanFactory() : (BeanFactory) getParent();
971 }
972
973
974 //---------------------------------------------------------------------
975 // Implementation of MessageSource interface
976 //---------------------------------------------------------------------
977
978 public String getMessage(String code, Object args[], String defaultMessage, Locale locale) {
979 return getMessageSource().getMessage(code, args, defaultMessage, locale);
980 }
981
982 public String getMessage(String code, Object args[], Locale locale) throws NoSuchMessageException {
983 return getMessageSource().getMessage(code, args, locale);
984 }
985
986 public String getMessage(MessageSourceResolvable resolvable, Locale locale) throws NoSuchMessageException {
987 return getMessageSource().getMessage(resolvable, locale);
988 }
989
990 /**
991 * Return the internal MessageSource used by the context.
992 * @return the internal MessageSource (never <code>null</code>)
993 * @throws IllegalStateException if the context has not been initialized yet
994 */
995 private MessageSource getMessageSource() throws IllegalStateException {
996 if (this.messageSource == null) {
997 throw new IllegalStateException("MessageSource not initialized - " +
998 "call 'refresh' before accessing messages via the context: " + this);
999 }
1000 return this.messageSource;
1001 }
1002
1003 /**
1004 * Return the internal message source of the parent context if it is an
1005 * AbstractApplicationContext too; else, return the parent context itself.
1006 */
1007 protected MessageSource getInternalParentMessageSource() {
1008 return (getParent() instanceof AbstractApplicationContext) ?
1009 ((AbstractApplicationContext) getParent()).messageSource : getParent();
1010 }
1011
1012
1013 //---------------------------------------------------------------------
1014 // Implementation of ResourcePatternResolver interface
1015 //---------------------------------------------------------------------
1016
1017 public Resource[] getResources(String locationPattern) throws IOException {
1018 return this.resourcePatternResolver.getResources(locationPattern);
1019 }
1020
1021
1022 //---------------------------------------------------------------------
1023 // Implementation of Lifecycle interface
1024 //---------------------------------------------------------------------
1025
1026 public void start() {
1027 Map lifecycleBeans = getLifecycleBeans();
1028 for (Iterator it = new LinkedHashSet(lifecycleBeans.keySet()).iterator(); it.hasNext();) {
1029 String beanName = (String) it.next();
1030 doStart(lifecycleBeans, beanName);
1031 }
1032 publishEvent(new ContextStartedEvent(this));
1033 }
1034
1035 public void stop() {
1036 Map lifecycleBeans = getLifecycleBeans();
1037 for (Iterator it = new LinkedHashSet(lifecycleBeans.keySet()).iterator(); it.hasNext();) {
1038 String beanName = (String) it.next();
1039 doStop(lifecycleBeans, beanName);
1040 }
1041 publishEvent(new ContextStoppedEvent(this));
1042 }
1043
1044 public boolean isRunning() {
1045 Iterator it = getLifecycleBeans().values().iterator();
1046 while (it.hasNext()) {
1047 Lifecycle lifecycle = (Lifecycle) it.next();
1048 if (!lifecycle.isRunning()) {
1049 return false;
1050 }
1051 }
1052 return true;
1053 }
1054
1055 /**
1056 * Return a Map of all singleton beans that implement the
1057 * Lifecycle interface in this context.
1058 * @return Map of Lifecycle beans with bean name as key
1059 */
1060 private Map getLifecycleBeans() {
1061 ConfigurableListableBeanFactory beanFactory = getBeanFactory();
1062 String[] beanNames = beanFactory.getSingletonNames();
1063 Map beans = new LinkedHashMap();
1064 for (int i = 0; i < beanNames.length; i++) {
1065 Object bean = beanFactory.getSingleton(beanNames[i]);
1066 if (bean instanceof Lifecycle) {
1067 beans.put(beanNames[i], bean);
1068 }
1069 }
1070 return beans;
1071 }
1072
1073 /**
1074 * Start the specified bean as part of the given set of Lifecycle beans,
1075 * making sure that any beans that it depends on are started first.
1076 * @param lifecycleBeans Map with bean name as key and Lifecycle instance as value
1077 * @param beanName the name of the bean to start
1078 */
1079 private void doStart(Map lifecycleBeans, String beanName) {
1080 Lifecycle bean = (Lifecycle) lifecycleBeans.get(beanName);
1081 if (bean != null) {
1082 String[] dependenciesForBean = getBeanFactory().getDependenciesForBean(beanName);
1083 for (int i = 0; i < dependenciesForBean.length; i++) {
1084 doStart(lifecycleBeans, dependenciesForBean[i]);
1085 }
1086 if (!bean.isRunning()) {
1087 bean.start();
1088 }
1089 lifecycleBeans.remove(beanName);
1090 }
1091 }
1092
1093 /**
1094 * Stop the specified bean as part of the given set of Lifecycle beans,
1095 * making sure that any beans that depends on it are stopped first.
1096 * @param lifecycleBeans Map with bean name as key and Lifecycle instance as value
1097 * @param beanName the name of the bean to stop
1098 */
1099 private void doStop(Map lifecycleBeans, String beanName) {
1100 Lifecycle bean = (Lifecycle) lifecycleBeans.get(beanName);
1101 if (bean != null) {
1102 String[] dependentBeans = getBeanFactory().getDependentBeans(beanName);
1103 for (int i = 0; i < dependentBeans.length; i++) {
1104 doStop(lifecycleBeans, dependentBeans[i]);
1105 }
1106 if (bean.isRunning()) {
1107 bean.stop();
1108 }
1109 lifecycleBeans.remove(beanName);
1110 }
1111 }
1112
1113
1114 //---------------------------------------------------------------------
1115 // Abstract methods that must be implemented by subclasses
1116 //---------------------------------------------------------------------
1117
1118 /**
1119 * Subclasses must implement this method to perform the actual configuration load.
1120 * The method is invoked by {@link #refresh()} before any other initialization work.
1121 * <p>A subclass will either create a new bean factory and hold a reference to it,
1122 * or return a single BeanFactory instance that it holds. In the latter case, it will
1123 * usually throw an IllegalStateException if refreshing the context more than once.
1124 * @throws BeansException if initialization of the bean factory failed
1125 * @throws IllegalStateException if already initialized and multiple refresh
1126 * attempts are not supported
1127 */
1128 protected abstract void refreshBeanFactory() throws BeansException, IllegalStateException;
1129
1130 /**
1131 * Subclasses must implement this method to release their internal bean factory.
1132 * This method gets invoked by {@link #close()} after all other shutdown work.
1133 * <p>Should never throw an exception but rather log shutdown failures.
1134 */
1135 protected abstract void closeBeanFactory();
1136
1137 /**
1138 * Subclasses must return their internal bean factory here. They should implement the
1139 * lookup efficiently, so that it can be called repeatedly without a performance penalty.
1140 * <p>Note: Subclasses should check whether the context is still active before
1141 * returning the internal bean factory. The internal factory should generally be
1142 * considered unavailable once the context has been closed.
1143 * @return this application context's internal bean factory (never <code>null</code>)
1144 * @throws IllegalStateException if the context does not hold an internal bean factory yet
1145 * (usually if {@link #refresh()} has never been called) or if the context has been
1146 * closed already
1147 * @see #refreshBeanFactory()
1148 * @see #closeBeanFactory()
1149 */
1150 public abstract ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException;
1151
1152
1153 /**
1154 * Return information about this context.
1155 */
1156 public String toString() {
1157 StringBuffer sb = new StringBuffer(getId());
1158 sb.append(": display name [").append(getDisplayName());
1159 sb.append("]; startup date [").append(new Date(getStartupDate()));
1160 sb.append("]; ");
1161 ApplicationContext parent = getParent();
1162 if (parent == null) {
1163 sb.append("root of context hierarchy");
1164 }
1165 else {
1166 sb.append("parent: ").append(parent.getId());
1167 }
1168 return sb.toString();
1169 }
1170
1171
1172 /**
1173 * BeanPostProcessor that logs an info message when a bean is created during
1174 * BeanPostProcessor instantiation, i.e. when a bean is not eligible for
1175 * getting processed by all BeanPostProcessors.
1176 */
1177 private class BeanPostProcessorChecker implements BeanPostProcessor {
1178
1179 private final ConfigurableListableBeanFactory beanFactory;
1180
1181 private final int beanPostProcessorTargetCount;
1182
1183 public BeanPostProcessorChecker(ConfigurableListableBeanFactory beanFactory, int beanPostProcessorTargetCount) {
1184 this.beanFactory = beanFactory;
1185 this.beanPostProcessorTargetCount = beanPostProcessorTargetCount;
1186 }
1187
1188 public Object postProcessBeforeInitialization(Object bean, String beanName) {
1189 return bean;
1190 }
1191
1192 public Object postProcessAfterInitialization(Object bean, String beanName) {
1193 if (!(bean instanceof BeanPostProcessor) &&
1194 this.beanFactory.getBeanPostProcessorCount() < this.beanPostProcessorTargetCount) {
1195 if (logger.isInfoEnabled()) {
1196 logger.info("Bean '" + beanName + "' is not eligible for getting processed by all " +
1197 "BeanPostProcessors (for example: not eligible for auto-proxying)");
1198 }
1199 }
1200 return bean;
1201 }
1202 }
1203
1204 }