1. /*
  2. * Copyright 2002-2004 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. package org.springframework.context.support;
  17. import java.io.InputStream;
  18. import java.util.ArrayList;
  19. import java.util.Arrays;
  20. import java.util.Collection;
  21. import java.util.Collections;
  22. import java.util.Date;
  23. import java.util.Iterator;
  24. import java.util.List;
  25. import java.util.Locale;
  26. import java.util.Map;
  27. import org.apache.commons.logging.Log;
  28. import org.apache.commons.logging.LogFactory;
  29. import org.springframework.beans.BeansException;
  30. import org.springframework.beans.factory.BeanFactory;
  31. import org.springframework.beans.factory.NoSuchBeanDefinitionException;
  32. import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
  33. import org.springframework.beans.factory.config.BeanPostProcessor;
  34. import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
  35. import org.springframework.beans.propertyeditors.InputStreamEditor;
  36. import org.springframework.context.ApplicationContext;
  37. import org.springframework.context.ApplicationEvent;
  38. import org.springframework.context.ApplicationListener;
  39. import org.springframework.context.ConfigurableApplicationContext;
  40. import org.springframework.context.HierarchicalMessageSource;
  41. import org.springframework.context.MessageSource;
  42. import org.springframework.context.MessageSourceResolvable;
  43. import org.springframework.context.NoSuchMessageException;
  44. import org.springframework.context.event.ApplicationEventMulticaster;
  45. import org.springframework.context.event.ApplicationEventMulticasterImpl;
  46. import org.springframework.context.event.ContextClosedEvent;
  47. import org.springframework.context.event.ContextRefreshedEvent;
  48. import org.springframework.core.OrderComparator;
  49. import org.springframework.core.io.DefaultResourceLoader;
  50. import org.springframework.core.io.Resource;
  51. import org.springframework.core.io.ResourceEditor;
  52. import org.springframework.core.io.ResourceLoader;
  53. /**
  54. * Partial implementation of ApplicationContext. Doesn't mandate the type
  55. * of storage used for configuration, but implements common functionality.
  56. * Uses the Template Method design pattern, requiring concrete subclasses
  57. * to implement abstract methods.
  58. *
  59. * <p>In contrast to a plain bean factory, an ApplicationContext is supposed
  60. * to detect special beans defined in its bean factory: Therefore, this class
  61. * automatically registers BeanFactoryPostProcessors, BeanPostProcessors
  62. * and ApplicationListeners that are defined as beans in the context.
  63. *
  64. * <p>A MessageSource may be also supplied as a bean in the context, with
  65. * the name "messageSource". Else, message resolution is delegated to the
  66. * parent context.
  67. *
  68. * <p>Implements resource loading through extending DefaultResourceLoader.
  69. * Therefore, treats resource paths as class path resources. Only supports
  70. * full classpath resource names that include the package path, like
  71. * "mypackage/myresource.dat".
  72. *
  73. * @author Rod Johnson
  74. * @author Juergen Hoeller
  75. * @since January 21, 2001
  76. * @version $Revision: 1.43 $
  77. * @see #refreshBeanFactory
  78. * @see #getBeanFactory
  79. * @see #MESSAGE_SOURCE_BEAN_NAME
  80. */
  81. public abstract class AbstractApplicationContext extends DefaultResourceLoader
  82. implements ConfigurableApplicationContext {
  83. /**
  84. * Name of the MessageSource bean in the factory.
  85. * If none is supplied, message resolution is delegated to the parent.
  86. * @see MessageSource
  87. */
  88. public static final String MESSAGE_SOURCE_BEAN_NAME = "messageSource";
  89. //---------------------------------------------------------------------
  90. // Instance data
  91. //---------------------------------------------------------------------
  92. /** Logger used by this class. Available to subclasses. */
  93. protected final Log logger = LogFactory.getLog(getClass());
  94. /** Parent context */
  95. private ApplicationContext parent;
  96. /** BeanFactoryPostProcessors to apply on refresh */
  97. private final List beanFactoryPostProcessors = new ArrayList();
  98. /** Display name */
  99. private String displayName = getClass().getName() + ";hashCode=" + hashCode();
  100. /** System time in milliseconds when this context started */
  101. private long startupTime;
  102. /** MessageSource we delegate our implementation of this interface to */
  103. private MessageSource messageSource;
  104. /** Helper class used in event publishing */
  105. private final ApplicationEventMulticaster applicationEventMulticaster = new ApplicationEventMulticasterImpl();
  106. //---------------------------------------------------------------------
  107. // Constructors
  108. //---------------------------------------------------------------------
  109. /**
  110. * Create a new AbstractApplicationContext with no parent.
  111. */
  112. public AbstractApplicationContext() {
  113. }
  114. /**
  115. * Create a new AbstractApplicationContext with the given parent context.
  116. * @param parent the parent context
  117. */
  118. public AbstractApplicationContext(ApplicationContext parent) {
  119. this.parent = parent;
  120. }
  121. //---------------------------------------------------------------------
  122. // Implementation of ApplicationContext
  123. //---------------------------------------------------------------------
  124. /**
  125. * Return the parent context, or null if there is no parent
  126. * (that is, this context is the root of the context hierarchy).
  127. */
  128. public ApplicationContext getParent() {
  129. return parent;
  130. }
  131. /**
  132. * Set a friendly name for this context.
  133. * Typically done during initialization of concrete context implementations.
  134. */
  135. protected void setDisplayName(String displayName) {
  136. this.displayName = displayName;
  137. }
  138. /**
  139. * Return a friendly name for this context.
  140. */
  141. public String getDisplayName() {
  142. return displayName;
  143. }
  144. /**
  145. * Return the timestamp (ms) when this context was first loaded.
  146. */
  147. public long getStartupDate() {
  148. return startupTime;
  149. }
  150. /**
  151. * Publish the given event to all listeners.
  152. * <p>Note: Listeners get initialized after the MessageSource, to be able
  153. * to access it within listener implementations. Thus, MessageSource
  154. * implementation cannot publish events.
  155. * @param event event to publish (may be application-specific or a
  156. * standard framework event)
  157. */
  158. public void publishEvent(ApplicationEvent event) {
  159. if (logger.isDebugEnabled()) {
  160. logger.debug("Publishing event in context [" + getDisplayName() + "]: " + event.toString());
  161. }
  162. this.applicationEventMulticaster.onApplicationEvent(event);
  163. if (this.parent != null) {
  164. this.parent.publishEvent(event);
  165. }
  166. }
  167. //---------------------------------------------------------------------
  168. // Implementation of ConfigurableApplicationContext
  169. //---------------------------------------------------------------------
  170. public void setParent(ApplicationContext parent) {
  171. this.parent = parent;
  172. }
  173. public void addBeanFactoryPostProcessor(BeanFactoryPostProcessor beanFactoryPostProcessor) {
  174. this.beanFactoryPostProcessors.add(beanFactoryPostProcessor);
  175. }
  176. /**
  177. * Return the list of BeanPostProcessors that will get applied
  178. * to beans created with this factory.
  179. */
  180. public List getBeanFactoryPostProcessors() {
  181. return beanFactoryPostProcessors;
  182. }
  183. /**
  184. * Load or reload configuration.
  185. * @throws org.springframework.context.ApplicationContextException if the
  186. * configuration was invalid or couldn't be found, or if configuration
  187. * has already been loaded and reloading is forbidden
  188. * @throws BeansException if the bean factory could not be initialized
  189. */
  190. public void refresh() throws BeansException {
  191. this.startupTime = System.currentTimeMillis();
  192. // tell subclass to refresh the internal bean factory
  193. refreshBeanFactory();
  194. ConfigurableListableBeanFactory beanFactory = getBeanFactory();
  195. // configure the bean factory with context semantics
  196. beanFactory.registerCustomEditor(Resource.class, new ResourceEditor(this));
  197. beanFactory.registerCustomEditor(InputStream.class, new InputStreamEditor(new ResourceEditor(this)));
  198. beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
  199. beanFactory.ignoreDependencyType(ResourceLoader.class);
  200. beanFactory.ignoreDependencyType(ApplicationContext.class);
  201. // allows post-processing of the bean factory in context subclasses
  202. postProcessBeanFactory(beanFactory);
  203. // invoke factory processors registered with the context instance
  204. for (Iterator it = getBeanFactoryPostProcessors().iterator(); it.hasNext();) {
  205. BeanFactoryPostProcessor factoryProcessor = (BeanFactoryPostProcessor) it.next();
  206. factoryProcessor.postProcessBeanFactory(beanFactory);
  207. }
  208. if (getBeanDefinitionCount() == 0) {
  209. logger.warn("No beans defined in ApplicationContext [" + getDisplayName() + "]");
  210. }
  211. else {
  212. logger.info(getBeanDefinitionCount() + " beans defined in ApplicationContext [" + getDisplayName() + "]");
  213. }
  214. // invoke factory processors registered as beans in the context
  215. invokeBeanFactoryPostProcessors();
  216. // register bean processor that intercept bean creation
  217. registerBeanPostProcessors();
  218. // initialize message source for this context
  219. initMessageSource();
  220. // initialize other special beans in specific context subclasses
  221. onRefresh();
  222. // check for listener beans and register them
  223. refreshListeners();
  224. // instantiate singletons this late to allow them to access the message source
  225. beanFactory.preInstantiateSingletons();
  226. // last step: publish corresponding event
  227. publishEvent(new ContextRefreshedEvent(this));
  228. }
  229. /**
  230. * Modify the application context's internal bean factory after its standard
  231. * initialization. All bean definitions will have been loaded, but no beans
  232. * will have been instantiated yet. This allows for registering special
  233. * BeanPostProcessors etc in certain ApplicationContext implementations.
  234. * @param beanFactory the bean factory used by the application context
  235. * @throws org.springframework.beans.BeansException in case of errors
  236. */
  237. protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
  238. }
  239. /**
  240. * Instantiate and invoke all registered BeanFactoryPostProcessor beans,
  241. * respecting explicit order if given.
  242. * Must be called before singleton instantiation.
  243. */
  244. private void invokeBeanFactoryPostProcessors() throws BeansException {
  245. String[] beanNames = getBeanDefinitionNames(BeanFactoryPostProcessor.class);
  246. BeanFactoryPostProcessor[] factoryProcessors = new BeanFactoryPostProcessor[beanNames.length];
  247. for (int i = 0; i < beanNames.length; i++) {
  248. factoryProcessors[i] = (BeanFactoryPostProcessor) getBean(beanNames[i]);
  249. }
  250. Arrays.sort(factoryProcessors, new OrderComparator());
  251. for (int i = 0; i < factoryProcessors.length; i++) {
  252. BeanFactoryPostProcessor factoryProcessor = factoryProcessors[i];
  253. factoryProcessor.postProcessBeanFactory(getBeanFactory());
  254. }
  255. }
  256. /**
  257. * Instantiate and invoke all registered BeanPostProcessor beans,
  258. * respecting explicit order if given.
  259. * <p>Must be called before any instantiation of application beans.
  260. */
  261. private void registerBeanPostProcessors() throws BeansException {
  262. String[] beanNames = getBeanDefinitionNames(BeanPostProcessor.class);
  263. if (beanNames.length > 0) {
  264. List beanProcessors = new ArrayList();
  265. for (int i = 0; i < beanNames.length; i++) {
  266. beanProcessors.add(getBean(beanNames[i]));
  267. }
  268. Collections.sort(beanProcessors, new OrderComparator());
  269. for (Iterator it = beanProcessors.iterator(); it.hasNext();) {
  270. getBeanFactory().addBeanPostProcessor((BeanPostProcessor) it.next());
  271. }
  272. }
  273. }
  274. /**
  275. * Initialize the MessageSource.
  276. * Use parent's if none defined in this context.
  277. */
  278. private void initMessageSource() throws BeansException {
  279. try {
  280. this.messageSource = (MessageSource) getBean(MESSAGE_SOURCE_BEAN_NAME);
  281. // set parent message source if applicable,
  282. // and if the message source is defined in this context, not in a parent
  283. if (this.parent != null && (this.messageSource instanceof HierarchicalMessageSource) &&
  284. Arrays.asList(getBeanDefinitionNames()).contains(MESSAGE_SOURCE_BEAN_NAME)) {
  285. ((HierarchicalMessageSource) this.messageSource).setParentMessageSource(this.parent);
  286. }
  287. }
  288. catch (NoSuchBeanDefinitionException ex) {
  289. logger.info("No MessageSource found for context [" + getDisplayName() + "]: using empty StaticMessageSource");
  290. // use empty message source to be able to accept getMessage calls
  291. this.messageSource = new StaticMessageSource();
  292. }
  293. }
  294. /**
  295. * Template method which can be overridden to add context-specific refresh work.
  296. * Called on initialization of special beans, before instantiation of singletons.
  297. * @throws BeansException in case of errors during refresh
  298. * @see #refresh
  299. */
  300. protected void onRefresh() throws BeansException {
  301. // for subclasses: do nothing by default
  302. }
  303. /**
  304. * Add beans that implement ApplicationListener as listeners.
  305. * Doesn't affect other listeners, which can be added without being beans.
  306. */
  307. private void refreshListeners() throws BeansException {
  308. logger.info("Refreshing listeners");
  309. Collection listeners = getBeansOfType(ApplicationListener.class, true, false).values();
  310. logger.debug("Found " + listeners.size() + " listeners in bean factory");
  311. for (Iterator it = listeners.iterator(); it.hasNext();) {
  312. ApplicationListener listener = (ApplicationListener) it.next();
  313. addListener(listener);
  314. if (logger.isInfoEnabled()) {
  315. logger.info("Application listener [" + listener + "] added");
  316. }
  317. }
  318. }
  319. /**
  320. * Subclasses can invoke this method to register a listener.
  321. * Any beans in the context that are listeners are automatically added.
  322. * @param listener the listener to register
  323. */
  324. protected void addListener(ApplicationListener listener) {
  325. this.applicationEventMulticaster.addApplicationListener(listener);
  326. }
  327. /**
  328. * Destroy the singletons in the bean factory of this application context.
  329. */
  330. public void close() {
  331. logger.info("Closing application context [" + getDisplayName() + "]");
  332. // Destroy all cached singletons in this context,
  333. // invoking DisposableBean.destroy and/or "destroy-method".
  334. getBeanFactory().destroySingletons();
  335. // publish corresponding event
  336. publishEvent(new ContextClosedEvent(this));
  337. }
  338. //---------------------------------------------------------------------
  339. // Implementation of BeanFactory
  340. //---------------------------------------------------------------------
  341. public Object getBean(String name) throws BeansException {
  342. return getBeanFactory().getBean(name);
  343. }
  344. public Object getBean(String name, Class requiredType) throws BeansException {
  345. return getBeanFactory().getBean(name, requiredType);
  346. }
  347. public boolean containsBean(String name) {
  348. return getBeanFactory().containsBean(name);
  349. }
  350. public boolean isSingleton(String name) throws NoSuchBeanDefinitionException {
  351. return getBeanFactory().isSingleton(name);
  352. }
  353. public String[] getAliases(String name) throws NoSuchBeanDefinitionException {
  354. return getBeanFactory().getAliases(name);
  355. }
  356. //---------------------------------------------------------------------
  357. // Implementation of ListableBeanFactory
  358. //---------------------------------------------------------------------
  359. public int getBeanDefinitionCount() {
  360. return getBeanFactory().getBeanDefinitionCount();
  361. }
  362. public String[] getBeanDefinitionNames() {
  363. return getBeanFactory().getBeanDefinitionNames();
  364. }
  365. public String[] getBeanDefinitionNames(Class type) {
  366. return getBeanFactory().getBeanDefinitionNames(type);
  367. }
  368. public boolean containsBeanDefinition(String name) {
  369. return getBeanFactory().containsBeanDefinition(name);
  370. }
  371. public Map getBeansOfType(Class type, boolean includePrototypes, boolean includeFactoryBeans)
  372. throws BeansException {
  373. return getBeanFactory().getBeansOfType(type, includePrototypes, includeFactoryBeans);
  374. }
  375. //---------------------------------------------------------------------
  376. // Implementation of HierarchicalBeanFactory
  377. //---------------------------------------------------------------------
  378. public BeanFactory getParentBeanFactory() {
  379. return getParent();
  380. }
  381. /**
  382. * Return the internal bean factory of the parent context if it implements
  383. * ConfigurableApplicationContext; else, return the parent context itself.
  384. * @see org.springframework.context.ConfigurableApplicationContext#getBeanFactory
  385. */
  386. protected BeanFactory getInternalParentBeanFactory() {
  387. return (getParent() instanceof ConfigurableApplicationContext) ?
  388. ((ConfigurableApplicationContext) getParent()).getBeanFactory() : (BeanFactory) getParent();
  389. }
  390. //---------------------------------------------------------------------
  391. // Implementation of MessageSource
  392. //---------------------------------------------------------------------
  393. public String getMessage(String code, Object args[], String defaultMessage, Locale locale) {
  394. return this.messageSource.getMessage(code, args, defaultMessage, locale);
  395. }
  396. public String getMessage(String code, Object args[], Locale locale) throws NoSuchMessageException {
  397. return this.messageSource.getMessage(code, args, locale);
  398. }
  399. public String getMessage(MessageSourceResolvable resolvable, Locale locale) throws NoSuchMessageException {
  400. return this.messageSource.getMessage(resolvable, locale);
  401. }
  402. //---------------------------------------------------------------------
  403. // Abstract methods that must be implemented by subclasses
  404. //---------------------------------------------------------------------
  405. /**
  406. * Subclasses must implement this method to perform the actual configuration load.
  407. * The method is invoked by refresh before any other initialization work.
  408. * @see #refresh
  409. */
  410. protected abstract void refreshBeanFactory() throws BeansException;
  411. /**
  412. * Subclasses must return their internal bean factory here.
  413. * They should implement the lookup efficiently, so that it can be called
  414. * repeatedly without a performance penalty.
  415. * @return this application context's internal bean factory
  416. */
  417. public abstract ConfigurableListableBeanFactory getBeanFactory();
  418. /**
  419. * Return information about this context.
  420. */
  421. public String toString() {
  422. StringBuffer sb = new StringBuffer(getClass().getName());
  423. sb.append(": ");
  424. sb.append("displayName=[").append(this.displayName).append("]; ");
  425. sb.append("startup date=[").append(new Date(this.startupTime)).append("]; ");
  426. if (this.parent == null) {
  427. sb.append("root of ApplicationContext hierarchy");
  428. }
  429. else {
  430. sb.append("parent=[").append(this.parent).append(']');
  431. }
  432. return sb.toString();
  433. }
  434. }