001/* 002 * Copyright 2002-2019 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.lang.reflect.Constructor; 021import java.util.concurrent.atomic.AtomicBoolean; 022import java.util.function.Supplier; 023 024import org.springframework.beans.BeanUtils; 025import org.springframework.beans.BeansException; 026import org.springframework.beans.factory.BeanDefinitionStoreException; 027import org.springframework.beans.factory.NoSuchBeanDefinitionException; 028import org.springframework.beans.factory.config.AutowireCapableBeanFactory; 029import org.springframework.beans.factory.config.BeanDefinition; 030import org.springframework.beans.factory.config.BeanDefinitionCustomizer; 031import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; 032import org.springframework.beans.factory.support.BeanDefinitionRegistry; 033import org.springframework.beans.factory.support.DefaultListableBeanFactory; 034import org.springframework.beans.factory.support.RootBeanDefinition; 035import org.springframework.context.ApplicationContext; 036import org.springframework.core.io.Resource; 037import org.springframework.core.io.ResourceLoader; 038import org.springframework.core.io.support.ResourcePatternResolver; 039import org.springframework.lang.Nullable; 040import org.springframework.util.Assert; 041 042/** 043 * Generic ApplicationContext implementation that holds a single internal 044 * {@link org.springframework.beans.factory.support.DefaultListableBeanFactory} 045 * instance and does not assume a specific bean definition format. Implements 046 * the {@link org.springframework.beans.factory.support.BeanDefinitionRegistry} 047 * interface in order to allow for applying any bean definition readers to it. 048 * 049 * <p>Typical usage is to register a variety of bean definitions via the 050 * {@link org.springframework.beans.factory.support.BeanDefinitionRegistry} 051 * interface and then call {@link #refresh()} to initialize those beans 052 * with application context semantics (handling 053 * {@link org.springframework.context.ApplicationContextAware}, auto-detecting 054 * {@link org.springframework.beans.factory.config.BeanFactoryPostProcessor BeanFactoryPostProcessors}, 055 * etc). 056 * 057 * <p>In contrast to other ApplicationContext implementations that create a new 058 * internal BeanFactory instance for each refresh, the internal BeanFactory of 059 * this context is available right from the start, to be able to register bean 060 * definitions on it. {@link #refresh()} may only be called once. 061 * 062 * <p>Usage example: 063 * 064 * <pre class="code"> 065 * GenericApplicationContext ctx = new GenericApplicationContext(); 066 * XmlBeanDefinitionReader xmlReader = new XmlBeanDefinitionReader(ctx); 067 * xmlReader.loadBeanDefinitions(new ClassPathResource("applicationContext.xml")); 068 * PropertiesBeanDefinitionReader propReader = new PropertiesBeanDefinitionReader(ctx); 069 * propReader.loadBeanDefinitions(new ClassPathResource("otherBeans.properties")); 070 * ctx.refresh(); 071 * 072 * MyBean myBean = (MyBean) ctx.getBean("myBean"); 073 * ...</pre> 074 * 075 * For the typical case of XML bean definitions, simply use 076 * {@link ClassPathXmlApplicationContext} or {@link FileSystemXmlApplicationContext}, 077 * which are easier to set up - but less flexible, since you can just use standard 078 * resource locations for XML bean definitions, rather than mixing arbitrary bean 079 * definition formats. The equivalent in a web environment is 080 * {@link org.springframework.web.context.support.XmlWebApplicationContext}. 081 * 082 * <p>For custom application context implementations that are supposed to read 083 * special bean definition formats in a refreshable manner, consider deriving 084 * from the {@link AbstractRefreshableApplicationContext} base class. 085 * 086 * @author Juergen Hoeller 087 * @author Chris Beams 088 * @since 1.1.2 089 * @see #registerBeanDefinition 090 * @see #refresh() 091 * @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader 092 * @see org.springframework.beans.factory.support.PropertiesBeanDefinitionReader 093 */ 094public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry { 095 096 private final DefaultListableBeanFactory beanFactory; 097 098 @Nullable 099 private ResourceLoader resourceLoader; 100 101 private boolean customClassLoader = false; 102 103 private final AtomicBoolean refreshed = new AtomicBoolean(); 104 105 106 /** 107 * Create a new GenericApplicationContext. 108 * @see #registerBeanDefinition 109 * @see #refresh 110 */ 111 public GenericApplicationContext() { 112 this.beanFactory = new DefaultListableBeanFactory(); 113 } 114 115 /** 116 * Create a new GenericApplicationContext with the given DefaultListableBeanFactory. 117 * @param beanFactory the DefaultListableBeanFactory instance to use for this context 118 * @see #registerBeanDefinition 119 * @see #refresh 120 */ 121 public GenericApplicationContext(DefaultListableBeanFactory beanFactory) { 122 Assert.notNull(beanFactory, "BeanFactory must not be null"); 123 this.beanFactory = beanFactory; 124 } 125 126 /** 127 * Create a new GenericApplicationContext with the given parent. 128 * @param parent the parent application context 129 * @see #registerBeanDefinition 130 * @see #refresh 131 */ 132 public GenericApplicationContext(@Nullable ApplicationContext parent) { 133 this(); 134 setParent(parent); 135 } 136 137 /** 138 * Create a new GenericApplicationContext with the given DefaultListableBeanFactory. 139 * @param beanFactory the DefaultListableBeanFactory instance to use for this context 140 * @param parent the parent application context 141 * @see #registerBeanDefinition 142 * @see #refresh 143 */ 144 public GenericApplicationContext(DefaultListableBeanFactory beanFactory, ApplicationContext parent) { 145 this(beanFactory); 146 setParent(parent); 147 } 148 149 150 /** 151 * Set the parent of this application context, also setting 152 * the parent of the internal BeanFactory accordingly. 153 * @see org.springframework.beans.factory.config.ConfigurableBeanFactory#setParentBeanFactory 154 */ 155 @Override 156 public void setParent(@Nullable ApplicationContext parent) { 157 super.setParent(parent); 158 this.beanFactory.setParentBeanFactory(getInternalParentBeanFactory()); 159 } 160 161 /** 162 * Set whether it should be allowed to override bean definitions by registering 163 * a different definition with the same name, automatically replacing the former. 164 * If not, an exception will be thrown. Default is "true". 165 * @since 3.0 166 * @see org.springframework.beans.factory.support.DefaultListableBeanFactory#setAllowBeanDefinitionOverriding 167 */ 168 public void setAllowBeanDefinitionOverriding(boolean allowBeanDefinitionOverriding) { 169 this.beanFactory.setAllowBeanDefinitionOverriding(allowBeanDefinitionOverriding); 170 } 171 172 /** 173 * Set whether to allow circular references between beans - and automatically 174 * try to resolve them. 175 * <p>Default is "true". Turn this off to throw an exception when encountering 176 * a circular reference, disallowing them completely. 177 * @since 3.0 178 * @see org.springframework.beans.factory.support.DefaultListableBeanFactory#setAllowCircularReferences 179 */ 180 public void setAllowCircularReferences(boolean allowCircularReferences) { 181 this.beanFactory.setAllowCircularReferences(allowCircularReferences); 182 } 183 184 /** 185 * Set a ResourceLoader to use for this context. If set, the context will 186 * delegate all {@code getResource} calls to the given ResourceLoader. 187 * If not set, default resource loading will apply. 188 * <p>The main reason to specify a custom ResourceLoader is to resolve 189 * resource paths (without URL prefix) in a specific fashion. 190 * The default behavior is to resolve such paths as class path locations. 191 * To resolve resource paths as file system locations, specify a 192 * FileSystemResourceLoader here. 193 * <p>You can also pass in a full ResourcePatternResolver, which will 194 * be autodetected by the context and used for {@code getResources} 195 * calls as well. Else, default resource pattern matching will apply. 196 * @see #getResource 197 * @see org.springframework.core.io.DefaultResourceLoader 198 * @see org.springframework.core.io.FileSystemResourceLoader 199 * @see org.springframework.core.io.support.ResourcePatternResolver 200 * @see #getResources 201 */ 202 public void setResourceLoader(ResourceLoader resourceLoader) { 203 this.resourceLoader = resourceLoader; 204 } 205 206 207 //--------------------------------------------------------------------- 208 // ResourceLoader / ResourcePatternResolver override if necessary 209 //--------------------------------------------------------------------- 210 211 /** 212 * This implementation delegates to this context's ResourceLoader if set, 213 * falling back to the default superclass behavior else. 214 * @see #setResourceLoader 215 */ 216 @Override 217 public Resource getResource(String location) { 218 if (this.resourceLoader != null) { 219 return this.resourceLoader.getResource(location); 220 } 221 return super.getResource(location); 222 } 223 224 /** 225 * This implementation delegates to this context's ResourceLoader if it 226 * implements the ResourcePatternResolver interface, falling back to the 227 * default superclass behavior else. 228 * @see #setResourceLoader 229 */ 230 @Override 231 public Resource[] getResources(String locationPattern) throws IOException { 232 if (this.resourceLoader instanceof ResourcePatternResolver) { 233 return ((ResourcePatternResolver) this.resourceLoader).getResources(locationPattern); 234 } 235 return super.getResources(locationPattern); 236 } 237 238 @Override 239 public void setClassLoader(@Nullable ClassLoader classLoader) { 240 super.setClassLoader(classLoader); 241 this.customClassLoader = true; 242 } 243 244 @Override 245 @Nullable 246 public ClassLoader getClassLoader() { 247 if (this.resourceLoader != null && !this.customClassLoader) { 248 return this.resourceLoader.getClassLoader(); 249 } 250 return super.getClassLoader(); 251 } 252 253 254 //--------------------------------------------------------------------- 255 // Implementations of AbstractApplicationContext's template methods 256 //--------------------------------------------------------------------- 257 258 /** 259 * Do nothing: We hold a single internal BeanFactory and rely on callers 260 * to register beans through our public methods (or the BeanFactory's). 261 * @see #registerBeanDefinition 262 */ 263 @Override 264 protected final void refreshBeanFactory() throws IllegalStateException { 265 if (!this.refreshed.compareAndSet(false, true)) { 266 throw new IllegalStateException( 267 "GenericApplicationContext does not support multiple refresh attempts: just call 'refresh' once"); 268 } 269 this.beanFactory.setSerializationId(getId()); 270 } 271 272 @Override 273 protected void cancelRefresh(BeansException ex) { 274 this.beanFactory.setSerializationId(null); 275 super.cancelRefresh(ex); 276 } 277 278 /** 279 * Not much to do: We hold a single internal BeanFactory that will never 280 * get released. 281 */ 282 @Override 283 protected final void closeBeanFactory() { 284 this.beanFactory.setSerializationId(null); 285 } 286 287 /** 288 * Return the single internal BeanFactory held by this context 289 * (as ConfigurableListableBeanFactory). 290 */ 291 @Override 292 public final ConfigurableListableBeanFactory getBeanFactory() { 293 return this.beanFactory; 294 } 295 296 /** 297 * Return the underlying bean factory of this context, 298 * available for registering bean definitions. 299 * <p><b>NOTE:</b> You need to call {@link #refresh()} to initialize the 300 * bean factory and its contained beans with application context semantics 301 * (autodetecting BeanFactoryPostProcessors, etc). 302 * @return the internal bean factory (as DefaultListableBeanFactory) 303 */ 304 public final DefaultListableBeanFactory getDefaultListableBeanFactory() { 305 return this.beanFactory; 306 } 307 308 @Override 309 public AutowireCapableBeanFactory getAutowireCapableBeanFactory() throws IllegalStateException { 310 assertBeanFactoryActive(); 311 return this.beanFactory; 312 } 313 314 315 //--------------------------------------------------------------------- 316 // Implementation of BeanDefinitionRegistry 317 //--------------------------------------------------------------------- 318 319 @Override 320 public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) 321 throws BeanDefinitionStoreException { 322 323 this.beanFactory.registerBeanDefinition(beanName, beanDefinition); 324 } 325 326 @Override 327 public void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException { 328 this.beanFactory.removeBeanDefinition(beanName); 329 } 330 331 @Override 332 public BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException { 333 return this.beanFactory.getBeanDefinition(beanName); 334 } 335 336 @Override 337 public boolean isBeanNameInUse(String beanName) { 338 return this.beanFactory.isBeanNameInUse(beanName); 339 } 340 341 @Override 342 public void registerAlias(String beanName, String alias) { 343 this.beanFactory.registerAlias(beanName, alias); 344 } 345 346 @Override 347 public void removeAlias(String alias) { 348 this.beanFactory.removeAlias(alias); 349 } 350 351 @Override 352 public boolean isAlias(String beanName) { 353 return this.beanFactory.isAlias(beanName); 354 } 355 356 357 //--------------------------------------------------------------------- 358 // Convenient methods for registering individual beans 359 //--------------------------------------------------------------------- 360 361 /** 362 * Register a bean from the given bean class, optionally providing explicit 363 * constructor arguments for consideration in the autowiring process. 364 * @param beanClass the class of the bean 365 * @param constructorArgs custom argument values to be fed into Spring's 366 * constructor resolution algorithm, resolving either all arguments or just 367 * specific ones, with the rest to be resolved through regular autowiring 368 * (may be {@code null} or empty) 369 * @since 5.2 (since 5.0 on the AnnotationConfigApplicationContext subclass) 370 */ 371 public <T> void registerBean(Class<T> beanClass, Object... constructorArgs) { 372 registerBean(null, beanClass, constructorArgs); 373 } 374 375 /** 376 * Register a bean from the given bean class, optionally providing explicit 377 * constructor arguments for consideration in the autowiring process. 378 * @param beanName the name of the bean (may be {@code null}) 379 * @param beanClass the class of the bean 380 * @param constructorArgs custom argument values to be fed into Spring's 381 * constructor resolution algorithm, resolving either all arguments or just 382 * specific ones, with the rest to be resolved through regular autowiring 383 * (may be {@code null} or empty) 384 * @since 5.2 (since 5.0 on the AnnotationConfigApplicationContext subclass) 385 */ 386 public <T> void registerBean(@Nullable String beanName, Class<T> beanClass, Object... constructorArgs) { 387 registerBean(beanName, beanClass, (Supplier<T>) null, 388 bd -> { 389 for (Object arg : constructorArgs) { 390 bd.getConstructorArgumentValues().addGenericArgumentValue(arg); 391 } 392 }); 393 } 394 395 /** 396 * Register a bean from the given bean class, optionally customizing its 397 * bean definition metadata (typically declared as a lambda expression). 398 * @param beanClass the class of the bean (resolving a public constructor 399 * to be autowired, possibly simply the default constructor) 400 * @param customizers one or more callbacks for customizing the factory's 401 * {@link BeanDefinition}, e.g. setting a lazy-init or primary flag 402 * @since 5.0 403 * @see #registerBean(String, Class, Supplier, BeanDefinitionCustomizer...) 404 */ 405 public final <T> void registerBean(Class<T> beanClass, BeanDefinitionCustomizer... customizers) { 406 registerBean(null, beanClass, null, customizers); 407 } 408 409 /** 410 * Register a bean from the given bean class, optionally customizing its 411 * bean definition metadata (typically declared as a lambda expression). 412 * @param beanName the name of the bean (may be {@code null}) 413 * @param beanClass the class of the bean (resolving a public constructor 414 * to be autowired, possibly simply the default constructor) 415 * @param customizers one or more callbacks for customizing the factory's 416 * {@link BeanDefinition}, e.g. setting a lazy-init or primary flag 417 * @since 5.0 418 * @see #registerBean(String, Class, Supplier, BeanDefinitionCustomizer...) 419 */ 420 public final <T> void registerBean( 421 @Nullable String beanName, Class<T> beanClass, BeanDefinitionCustomizer... customizers) { 422 423 registerBean(beanName, beanClass, null, customizers); 424 } 425 426 /** 427 * Register a bean from the given bean class, using the given supplier for 428 * obtaining a new instance (typically declared as a lambda expression or 429 * method reference), optionally customizing its bean definition metadata 430 * (again typically declared as a lambda expression). 431 * @param beanClass the class of the bean 432 * @param supplier a callback for creating an instance of the bean 433 * @param customizers one or more callbacks for customizing the factory's 434 * {@link BeanDefinition}, e.g. setting a lazy-init or primary flag 435 * @since 5.0 436 * @see #registerBean(String, Class, Supplier, BeanDefinitionCustomizer...) 437 */ 438 public final <T> void registerBean( 439 Class<T> beanClass, Supplier<T> supplier, BeanDefinitionCustomizer... customizers) { 440 441 registerBean(null, beanClass, supplier, customizers); 442 } 443 444 /** 445 * Register a bean from the given bean class, using the given supplier for 446 * obtaining a new instance (typically declared as a lambda expression or 447 * method reference), optionally customizing its bean definition metadata 448 * (again typically declared as a lambda expression). 449 * <p>This method can be overridden to adapt the registration mechanism for 450 * all {@code registerBean} methods (since they all delegate to this one). 451 * @param beanName the name of the bean (may be {@code null}) 452 * @param beanClass the class of the bean 453 * @param supplier a callback for creating an instance of the bean (in case 454 * of {@code null}, resolving a public constructor to be autowired instead) 455 * @param customizers one or more callbacks for customizing the factory's 456 * {@link BeanDefinition}, e.g. setting a lazy-init or primary flag 457 * @since 5.0 458 */ 459 public <T> void registerBean(@Nullable String beanName, Class<T> beanClass, 460 @Nullable Supplier<T> supplier, BeanDefinitionCustomizer... customizers) { 461 462 ClassDerivedBeanDefinition beanDefinition = new ClassDerivedBeanDefinition(beanClass); 463 if (supplier != null) { 464 beanDefinition.setInstanceSupplier(supplier); 465 } 466 for (BeanDefinitionCustomizer customizer : customizers) { 467 customizer.customize(beanDefinition); 468 } 469 470 String nameToUse = (beanName != null ? beanName : beanClass.getName()); 471 registerBeanDefinition(nameToUse, beanDefinition); 472 } 473 474 475 /** 476 * {@link RootBeanDefinition} marker subclass for {@code #registerBean} based 477 * registrations with flexible autowiring for public constructors. 478 */ 479 @SuppressWarnings("serial") 480 private static class ClassDerivedBeanDefinition extends RootBeanDefinition { 481 482 public ClassDerivedBeanDefinition(Class<?> beanClass) { 483 super(beanClass); 484 } 485 486 public ClassDerivedBeanDefinition(ClassDerivedBeanDefinition original) { 487 super(original); 488 } 489 490 @Override 491 @Nullable 492 public Constructor<?>[] getPreferredConstructors() { 493 Class<?> clazz = getBeanClass(); 494 Constructor<?> primaryCtor = BeanUtils.findPrimaryConstructor(clazz); 495 if (primaryCtor != null) { 496 return new Constructor<?>[] {primaryCtor}; 497 } 498 Constructor<?>[] publicCtors = clazz.getConstructors(); 499 if (publicCtors.length > 0) { 500 return publicCtors; 501 } 502 return null; 503 } 504 505 @Override 506 public RootBeanDefinition cloneBeanDefinition() { 507 return new ClassDerivedBeanDefinition(this); 508 } 509 } 510 511}