001/* 002 * Copyright 2002-2016 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.context.support; 018 019import java.io.IOException; 020import java.util.concurrent.atomic.AtomicBoolean; 021 022import org.springframework.beans.BeansException; 023import org.springframework.beans.factory.BeanDefinitionStoreException; 024import org.springframework.beans.factory.NoSuchBeanDefinitionException; 025import org.springframework.beans.factory.config.AutowireCapableBeanFactory; 026import org.springframework.beans.factory.config.BeanDefinition; 027import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; 028import org.springframework.beans.factory.support.BeanDefinitionRegistry; 029import org.springframework.beans.factory.support.DefaultListableBeanFactory; 030import org.springframework.context.ApplicationContext; 031import org.springframework.core.io.Resource; 032import org.springframework.core.io.ResourceLoader; 033import org.springframework.core.io.support.ResourcePatternResolver; 034import org.springframework.util.Assert; 035 036/** 037 * Generic ApplicationContext implementation that holds a single internal 038 * {@link org.springframework.beans.factory.support.DefaultListableBeanFactory} 039 * instance and does not assume a specific bean definition format. Implements 040 * the {@link org.springframework.beans.factory.support.BeanDefinitionRegistry} 041 * interface in order to allow for applying any bean definition readers to it. 042 * 043 * <p>Typical usage is to register a variety of bean definitions via the 044 * {@link org.springframework.beans.factory.support.BeanDefinitionRegistry} 045 * interface and then call {@link #refresh()} to initialize those beans 046 * with application context semantics (handling 047 * {@link org.springframework.context.ApplicationContextAware}, auto-detecting 048 * {@link org.springframework.beans.factory.config.BeanFactoryPostProcessor BeanFactoryPostProcessors}, 049 * etc). 050 * 051 * <p>In contrast to other ApplicationContext implementations that create a new 052 * internal BeanFactory instance for each refresh, the internal BeanFactory of 053 * this context is available right from the start, to be able to register bean 054 * definitions on it. {@link #refresh()} may only be called once. 055 * 056 * <p>Usage example: 057 * 058 * <pre class="code"> 059 * GenericApplicationContext ctx = new GenericApplicationContext(); 060 * XmlBeanDefinitionReader xmlReader = new XmlBeanDefinitionReader(ctx); 061 * xmlReader.loadBeanDefinitions(new ClassPathResource("applicationContext.xml")); 062 * PropertiesBeanDefinitionReader propReader = new PropertiesBeanDefinitionReader(ctx); 063 * propReader.loadBeanDefinitions(new ClassPathResource("otherBeans.properties")); 064 * ctx.refresh(); 065 * 066 * MyBean myBean = (MyBean) ctx.getBean("myBean"); 067 * ...</pre> 068 * 069 * For the typical case of XML bean definitions, simply use 070 * {@link ClassPathXmlApplicationContext} or {@link FileSystemXmlApplicationContext}, 071 * which are easier to set up - but less flexible, since you can just use standard 072 * resource locations for XML bean definitions, rather than mixing arbitrary bean 073 * definition formats. The equivalent in a web environment is 074 * {@link org.springframework.web.context.support.XmlWebApplicationContext}. 075 * 076 * <p>For custom application context implementations that are supposed to read 077 * special bean definition formats in a refreshable manner, consider deriving 078 * from the {@link AbstractRefreshableApplicationContext} base class. 079 * 080 * @author Juergen Hoeller 081 * @author Chris Beams 082 * @since 1.1.2 083 * @see #registerBeanDefinition 084 * @see #refresh() 085 * @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader 086 * @see org.springframework.beans.factory.support.PropertiesBeanDefinitionReader 087 */ 088public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry { 089 090 private final DefaultListableBeanFactory beanFactory; 091 092 private ResourceLoader resourceLoader; 093 094 private boolean customClassLoader = false; 095 096 private final AtomicBoolean refreshed = new AtomicBoolean(); 097 098 099 /** 100 * Create a new GenericApplicationContext. 101 * @see #registerBeanDefinition 102 * @see #refresh 103 */ 104 public GenericApplicationContext() { 105 this.beanFactory = new DefaultListableBeanFactory(); 106 } 107 108 /** 109 * Create a new GenericApplicationContext with the given DefaultListableBeanFactory. 110 * @param beanFactory the DefaultListableBeanFactory instance to use for this context 111 * @see #registerBeanDefinition 112 * @see #refresh 113 */ 114 public GenericApplicationContext(DefaultListableBeanFactory beanFactory) { 115 Assert.notNull(beanFactory, "BeanFactory must not be null"); 116 this.beanFactory = beanFactory; 117 } 118 119 /** 120 * Create a new GenericApplicationContext with the given parent. 121 * @param parent the parent application context 122 * @see #registerBeanDefinition 123 * @see #refresh 124 */ 125 public GenericApplicationContext(ApplicationContext parent) { 126 this(); 127 setParent(parent); 128 } 129 130 /** 131 * Create a new GenericApplicationContext with the given DefaultListableBeanFactory. 132 * @param beanFactory the DefaultListableBeanFactory instance to use for this context 133 * @param parent the parent application context 134 * @see #registerBeanDefinition 135 * @see #refresh 136 */ 137 public GenericApplicationContext(DefaultListableBeanFactory beanFactory, ApplicationContext parent) { 138 this(beanFactory); 139 setParent(parent); 140 } 141 142 143 /** 144 * Set the parent of this application context, also setting 145 * the parent of the internal BeanFactory accordingly. 146 * @see org.springframework.beans.factory.config.ConfigurableBeanFactory#setParentBeanFactory 147 */ 148 @Override 149 public void setParent(ApplicationContext parent) { 150 super.setParent(parent); 151 this.beanFactory.setParentBeanFactory(getInternalParentBeanFactory()); 152 } 153 154 /** 155 * Set whether it should be allowed to override bean definitions by registering 156 * a different definition with the same name, automatically replacing the former. 157 * If not, an exception will be thrown. Default is "true". 158 * @since 3.0 159 * @see org.springframework.beans.factory.support.DefaultListableBeanFactory#setAllowBeanDefinitionOverriding 160 */ 161 public void setAllowBeanDefinitionOverriding(boolean allowBeanDefinitionOverriding) { 162 this.beanFactory.setAllowBeanDefinitionOverriding(allowBeanDefinitionOverriding); 163 } 164 165 /** 166 * Set whether to allow circular references between beans - and automatically 167 * try to resolve them. 168 * <p>Default is "true". Turn this off to throw an exception when encountering 169 * a circular reference, disallowing them completely. 170 * @since 3.0 171 * @see org.springframework.beans.factory.support.DefaultListableBeanFactory#setAllowCircularReferences 172 */ 173 public void setAllowCircularReferences(boolean allowCircularReferences) { 174 this.beanFactory.setAllowCircularReferences(allowCircularReferences); 175 } 176 177 /** 178 * Set a ResourceLoader to use for this context. If set, the context will 179 * delegate all {@code getResource} calls to the given ResourceLoader. 180 * If not set, default resource loading will apply. 181 * <p>The main reason to specify a custom ResourceLoader is to resolve 182 * resource paths (without URL prefix) in a specific fashion. 183 * The default behavior is to resolve such paths as class path locations. 184 * To resolve resource paths as file system locations, specify a 185 * FileSystemResourceLoader here. 186 * <p>You can also pass in a full ResourcePatternResolver, which will 187 * be autodetected by the context and used for {@code getResources} 188 * calls as well. Else, default resource pattern matching will apply. 189 * @see #getResource 190 * @see org.springframework.core.io.DefaultResourceLoader 191 * @see org.springframework.core.io.FileSystemResourceLoader 192 * @see org.springframework.core.io.support.ResourcePatternResolver 193 * @see #getResources 194 */ 195 public void setResourceLoader(ResourceLoader resourceLoader) { 196 this.resourceLoader = resourceLoader; 197 } 198 199 200 //--------------------------------------------------------------------- 201 // ResourceLoader / ResourcePatternResolver override if necessary 202 //--------------------------------------------------------------------- 203 204 /** 205 * This implementation delegates to this context's ResourceLoader if set, 206 * falling back to the default superclass behavior else. 207 * @see #setResourceLoader 208 */ 209 @Override 210 public Resource getResource(String location) { 211 if (this.resourceLoader != null) { 212 return this.resourceLoader.getResource(location); 213 } 214 return super.getResource(location); 215 } 216 217 /** 218 * This implementation delegates to this context's ResourceLoader if it 219 * implements the ResourcePatternResolver interface, falling back to the 220 * default superclass behavior else. 221 * @see #setResourceLoader 222 */ 223 @Override 224 public Resource[] getResources(String locationPattern) throws IOException { 225 if (this.resourceLoader instanceof ResourcePatternResolver) { 226 return ((ResourcePatternResolver) this.resourceLoader).getResources(locationPattern); 227 } 228 return super.getResources(locationPattern); 229 } 230 231 @Override 232 public void setClassLoader(ClassLoader classLoader) { 233 super.setClassLoader(classLoader); 234 this.customClassLoader = true; 235 } 236 237 @Override 238 public ClassLoader getClassLoader() { 239 if (this.resourceLoader != null && !this.customClassLoader) { 240 return this.resourceLoader.getClassLoader(); 241 } 242 return super.getClassLoader(); 243 } 244 245 246 //--------------------------------------------------------------------- 247 // Implementations of AbstractApplicationContext's template methods 248 //--------------------------------------------------------------------- 249 250 /** 251 * Do nothing: We hold a single internal BeanFactory and rely on callers 252 * to register beans through our public methods (or the BeanFactory's). 253 * @see #registerBeanDefinition 254 */ 255 @Override 256 protected final void refreshBeanFactory() throws IllegalStateException { 257 if (!this.refreshed.compareAndSet(false, true)) { 258 throw new IllegalStateException( 259 "GenericApplicationContext does not support multiple refresh attempts: just call 'refresh' once"); 260 } 261 this.beanFactory.setSerializationId(getId()); 262 } 263 264 @Override 265 protected void cancelRefresh(BeansException ex) { 266 this.beanFactory.setSerializationId(null); 267 super.cancelRefresh(ex); 268 } 269 270 /** 271 * Not much to do: We hold a single internal BeanFactory that will never 272 * get released. 273 */ 274 @Override 275 protected final void closeBeanFactory() { 276 this.beanFactory.setSerializationId(null); 277 } 278 279 /** 280 * Return the single internal BeanFactory held by this context 281 * (as ConfigurableListableBeanFactory). 282 */ 283 @Override 284 public final ConfigurableListableBeanFactory getBeanFactory() { 285 return this.beanFactory; 286 } 287 288 /** 289 * Return the underlying bean factory of this context, 290 * available for registering bean definitions. 291 * <p><b>NOTE:</b> You need to call {@link #refresh()} to initialize the 292 * bean factory and its contained beans with application context semantics 293 * (autodetecting BeanFactoryPostProcessors, etc). 294 * @return the internal bean factory (as DefaultListableBeanFactory) 295 */ 296 public final DefaultListableBeanFactory getDefaultListableBeanFactory() { 297 return this.beanFactory; 298 } 299 300 @Override 301 public AutowireCapableBeanFactory getAutowireCapableBeanFactory() throws IllegalStateException { 302 assertBeanFactoryActive(); 303 return this.beanFactory; 304 } 305 306 307 //--------------------------------------------------------------------- 308 // Implementation of BeanDefinitionRegistry 309 //--------------------------------------------------------------------- 310 311 @Override 312 public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) 313 throws BeanDefinitionStoreException { 314 315 this.beanFactory.registerBeanDefinition(beanName, beanDefinition); 316 } 317 318 @Override 319 public void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException { 320 this.beanFactory.removeBeanDefinition(beanName); 321 } 322 323 @Override 324 public BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException { 325 return this.beanFactory.getBeanDefinition(beanName); 326 } 327 328 @Override 329 public boolean isBeanNameInUse(String beanName) { 330 return this.beanFactory.isBeanNameInUse(beanName); 331 } 332 333 @Override 334 public void registerAlias(String beanName, String alias) { 335 this.beanFactory.registerAlias(beanName, alias); 336 } 337 338 @Override 339 public void removeAlias(String alias) { 340 this.beanFactory.removeAlias(alias); 341 } 342 343 @Override 344 public boolean isAlias(String beanName) { 345 return this.beanFactory.isAlias(beanName); 346 } 347 348}