001/* 002 * Copyright 2002-2020 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; 020 021import org.springframework.beans.BeansException; 022import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; 023import org.springframework.beans.factory.support.DefaultListableBeanFactory; 024import org.springframework.context.ApplicationContext; 025import org.springframework.context.ApplicationContextException; 026 027/** 028 * Base class for {@link org.springframework.context.ApplicationContext} 029 * implementations which are supposed to support multiple calls to {@link #refresh()}, 030 * creating a new internal bean factory instance every time. 031 * Typically (but not necessarily), such a context will be driven by 032 * a set of config locations to load bean definitions from. 033 * 034 * <p>The only method to be implemented by subclasses is {@link #loadBeanDefinitions}, 035 * which gets invoked on each refresh. A concrete implementation is supposed to load 036 * bean definitions into the given 037 * {@link org.springframework.beans.factory.support.DefaultListableBeanFactory}, 038 * typically delegating to one or more specific bean definition readers. 039 * 040 * <p><b>Note that there is a similar base class for WebApplicationContexts.</b> 041 * {@link org.springframework.web.context.support.AbstractRefreshableWebApplicationContext} 042 * provides the same subclassing strategy, but additionally pre-implements 043 * all context functionality for web environments. There is also a 044 * pre-defined way to receive config locations for a web context. 045 * 046 * <p>Concrete standalone subclasses of this base class, reading in a 047 * specific bean definition format, are {@link ClassPathXmlApplicationContext} 048 * and {@link FileSystemXmlApplicationContext}, which both derive from the 049 * common {@link AbstractXmlApplicationContext} base class; 050 * {@link org.springframework.context.annotation.AnnotationConfigApplicationContext} 051 * supports {@code @Configuration}-annotated classes as a source of bean definitions. 052 * 053 * @author Juergen Hoeller 054 * @author Chris Beams 055 * @since 1.1.3 056 * @see #loadBeanDefinitions 057 * @see org.springframework.beans.factory.support.DefaultListableBeanFactory 058 * @see org.springframework.web.context.support.AbstractRefreshableWebApplicationContext 059 * @see AbstractXmlApplicationContext 060 * @see ClassPathXmlApplicationContext 061 * @see FileSystemXmlApplicationContext 062 * @see org.springframework.context.annotation.AnnotationConfigApplicationContext 063 */ 064public abstract class AbstractRefreshableApplicationContext extends AbstractApplicationContext { 065 066 private Boolean allowBeanDefinitionOverriding; 067 068 private Boolean allowCircularReferences; 069 070 /** Bean factory for this context */ 071 private volatile DefaultListableBeanFactory beanFactory; 072 073 074 /** 075 * Create a new AbstractRefreshableApplicationContext with no parent. 076 */ 077 public AbstractRefreshableApplicationContext() { 078 } 079 080 /** 081 * Create a new AbstractRefreshableApplicationContext with the given parent context. 082 * @param parent the parent context 083 */ 084 public AbstractRefreshableApplicationContext(ApplicationContext parent) { 085 super(parent); 086 } 087 088 089 /** 090 * Set whether it should be allowed to override bean definitions by registering 091 * a different definition with the same name, automatically replacing the former. 092 * If not, an exception will be thrown. Default is "true". 093 * @see org.springframework.beans.factory.support.DefaultListableBeanFactory#setAllowBeanDefinitionOverriding 094 */ 095 public void setAllowBeanDefinitionOverriding(boolean allowBeanDefinitionOverriding) { 096 this.allowBeanDefinitionOverriding = allowBeanDefinitionOverriding; 097 } 098 099 /** 100 * Set whether to allow circular references between beans - and automatically 101 * try to resolve them. 102 * <p>Default is "true". Turn this off to throw an exception when encountering 103 * a circular reference, disallowing them completely. 104 * @see org.springframework.beans.factory.support.DefaultListableBeanFactory#setAllowCircularReferences 105 */ 106 public void setAllowCircularReferences(boolean allowCircularReferences) { 107 this.allowCircularReferences = allowCircularReferences; 108 } 109 110 111 /** 112 * This implementation performs an actual refresh of this context's underlying 113 * bean factory, shutting down the previous bean factory (if any) and 114 * initializing a fresh bean factory for the next phase of the context's lifecycle. 115 */ 116 @Override 117 protected final void refreshBeanFactory() throws BeansException { 118 if (hasBeanFactory()) { 119 destroyBeans(); 120 closeBeanFactory(); 121 } 122 try { 123 DefaultListableBeanFactory beanFactory = createBeanFactory(); 124 beanFactory.setSerializationId(getId()); 125 customizeBeanFactory(beanFactory); 126 loadBeanDefinitions(beanFactory); 127 this.beanFactory = beanFactory; 128 } 129 catch (IOException ex) { 130 throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex); 131 } 132 } 133 134 @Override 135 protected void cancelRefresh(BeansException ex) { 136 DefaultListableBeanFactory beanFactory = this.beanFactory; 137 if (beanFactory != null) { 138 beanFactory.setSerializationId(null); 139 } 140 super.cancelRefresh(ex); 141 } 142 143 @Override 144 protected final void closeBeanFactory() { 145 DefaultListableBeanFactory beanFactory = this.beanFactory; 146 if (beanFactory != null) { 147 beanFactory.setSerializationId(null); 148 this.beanFactory = null; 149 } 150 } 151 152 /** 153 * Determine whether this context currently holds a bean factory, 154 * i.e. has been refreshed at least once and not been closed yet. 155 */ 156 protected final boolean hasBeanFactory() { 157 return (this.beanFactory != null); 158 } 159 160 @Override 161 public final ConfigurableListableBeanFactory getBeanFactory() { 162 DefaultListableBeanFactory beanFactory = this.beanFactory; 163 if (beanFactory == null) { 164 throw new IllegalStateException("BeanFactory not initialized or already closed - " + 165 "call 'refresh' before accessing beans via the ApplicationContext"); 166 } 167 return beanFactory; 168 } 169 170 /** 171 * Overridden to turn it into a no-op: With AbstractRefreshableApplicationContext, 172 * {@link #getBeanFactory()} serves a strong assertion for an active context anyway. 173 */ 174 @Override 175 protected void assertBeanFactoryActive() { 176 } 177 178 /** 179 * Create an internal bean factory for this context. 180 * Called for each {@link #refresh()} attempt. 181 * <p>The default implementation creates a 182 * {@link org.springframework.beans.factory.support.DefaultListableBeanFactory} 183 * with the {@linkplain #getInternalParentBeanFactory() internal bean factory} of this 184 * context's parent as parent bean factory. Can be overridden in subclasses, 185 * for example to customize DefaultListableBeanFactory's settings. 186 * @return the bean factory for this context 187 * @see org.springframework.beans.factory.support.DefaultListableBeanFactory#setAllowBeanDefinitionOverriding 188 * @see org.springframework.beans.factory.support.DefaultListableBeanFactory#setAllowEagerClassLoading 189 * @see org.springframework.beans.factory.support.DefaultListableBeanFactory#setAllowCircularReferences 190 * @see org.springframework.beans.factory.support.DefaultListableBeanFactory#setAllowRawInjectionDespiteWrapping 191 */ 192 protected DefaultListableBeanFactory createBeanFactory() { 193 return new DefaultListableBeanFactory(getInternalParentBeanFactory()); 194 } 195 196 /** 197 * Customize the internal bean factory used by this context. 198 * Called for each {@link #refresh()} attempt. 199 * <p>The default implementation applies this context's 200 * {@linkplain #setAllowBeanDefinitionOverriding "allowBeanDefinitionOverriding"} 201 * and {@linkplain #setAllowCircularReferences "allowCircularReferences"} settings, 202 * if specified. Can be overridden in subclasses to customize any of 203 * {@link DefaultListableBeanFactory}'s settings. 204 * @param beanFactory the newly created bean factory for this context 205 * @see DefaultListableBeanFactory#setAllowBeanDefinitionOverriding 206 * @see DefaultListableBeanFactory#setAllowCircularReferences 207 * @see DefaultListableBeanFactory#setAllowRawInjectionDespiteWrapping 208 * @see DefaultListableBeanFactory#setAllowEagerClassLoading 209 */ 210 protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) { 211 if (this.allowBeanDefinitionOverriding != null) { 212 beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding); 213 } 214 if (this.allowCircularReferences != null) { 215 beanFactory.setAllowCircularReferences(this.allowCircularReferences); 216 } 217 } 218 219 /** 220 * Load bean definitions into the given bean factory, typically through 221 * delegating to one or more bean definition readers. 222 * @param beanFactory the bean factory to load bean definitions into 223 * @throws BeansException if parsing of the bean definitions failed 224 * @throws IOException if loading of bean definition files failed 225 * @see org.springframework.beans.factory.support.PropertiesBeanDefinitionReader 226 * @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader 227 */ 228 protected abstract void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) 229 throws BeansException, IOException; 230 231}