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