001/* 002 * Copyright 2002-2018 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.beans.factory.config; 018 019import java.lang.reflect.InvocationHandler; 020import java.lang.reflect.InvocationTargetException; 021import java.lang.reflect.Method; 022import java.lang.reflect.Proxy; 023 024import org.apache.commons.logging.Log; 025import org.apache.commons.logging.LogFactory; 026 027import org.springframework.beans.SimpleTypeConverter; 028import org.springframework.beans.TypeConverter; 029import org.springframework.beans.factory.BeanClassLoaderAware; 030import org.springframework.beans.factory.BeanFactory; 031import org.springframework.beans.factory.BeanFactoryAware; 032import org.springframework.beans.factory.DisposableBean; 033import org.springframework.beans.factory.FactoryBean; 034import org.springframework.beans.factory.FactoryBeanNotInitializedException; 035import org.springframework.beans.factory.InitializingBean; 036import org.springframework.lang.Nullable; 037import org.springframework.util.Assert; 038import org.springframework.util.ClassUtils; 039import org.springframework.util.ObjectUtils; 040import org.springframework.util.ReflectionUtils; 041 042/** 043 * Simple template superclass for {@link FactoryBean} implementations that 044 * creates a singleton or a prototype object, depending on a flag. 045 * 046 * <p>If the "singleton" flag is {@code true} (the default), 047 * this class will create the object that it creates exactly once 048 * on initialization and subsequently return said singleton instance 049 * on all calls to the {@link #getObject()} method. 050 * 051 * <p>Else, this class will create a new instance every time the 052 * {@link #getObject()} method is invoked. Subclasses are responsible 053 * for implementing the abstract {@link #createInstance()} template 054 * method to actually create the object(s) to expose. 055 * 056 * @author Juergen Hoeller 057 * @author Keith Donald 058 * @since 1.0.2 059 * @param <T> the bean type 060 * @see #setSingleton 061 * @see #createInstance() 062 */ 063public abstract class AbstractFactoryBean<T> 064 implements FactoryBean<T>, BeanClassLoaderAware, BeanFactoryAware, InitializingBean, DisposableBean { 065 066 /** Logger available to subclasses. */ 067 protected final Log logger = LogFactory.getLog(getClass()); 068 069 private boolean singleton = true; 070 071 @Nullable 072 private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader(); 073 074 @Nullable 075 private BeanFactory beanFactory; 076 077 private boolean initialized = false; 078 079 @Nullable 080 private T singletonInstance; 081 082 @Nullable 083 private T earlySingletonInstance; 084 085 086 /** 087 * Set if a singleton should be created, or a new object on each request 088 * otherwise. Default is {@code true} (a singleton). 089 */ 090 public void setSingleton(boolean singleton) { 091 this.singleton = singleton; 092 } 093 094 @Override 095 public boolean isSingleton() { 096 return this.singleton; 097 } 098 099 @Override 100 public void setBeanClassLoader(ClassLoader classLoader) { 101 this.beanClassLoader = classLoader; 102 } 103 104 @Override 105 public void setBeanFactory(@Nullable BeanFactory beanFactory) { 106 this.beanFactory = beanFactory; 107 } 108 109 /** 110 * Return the BeanFactory that this bean runs in. 111 */ 112 @Nullable 113 protected BeanFactory getBeanFactory() { 114 return this.beanFactory; 115 } 116 117 /** 118 * Obtain a bean type converter from the BeanFactory that this bean 119 * runs in. This is typically a fresh instance for each call, 120 * since TypeConverters are usually <i>not</i> thread-safe. 121 * <p>Falls back to a SimpleTypeConverter when not running in a BeanFactory. 122 * @see ConfigurableBeanFactory#getTypeConverter() 123 * @see org.springframework.beans.SimpleTypeConverter 124 */ 125 protected TypeConverter getBeanTypeConverter() { 126 BeanFactory beanFactory = getBeanFactory(); 127 if (beanFactory instanceof ConfigurableBeanFactory) { 128 return ((ConfigurableBeanFactory) beanFactory).getTypeConverter(); 129 } 130 else { 131 return new SimpleTypeConverter(); 132 } 133 } 134 135 /** 136 * Eagerly create the singleton instance, if necessary. 137 */ 138 @Override 139 public void afterPropertiesSet() throws Exception { 140 if (isSingleton()) { 141 this.initialized = true; 142 this.singletonInstance = createInstance(); 143 this.earlySingletonInstance = null; 144 } 145 } 146 147 148 /** 149 * Expose the singleton instance or create a new prototype instance. 150 * @see #createInstance() 151 * @see #getEarlySingletonInterfaces() 152 */ 153 @Override 154 public final T getObject() throws Exception { 155 if (isSingleton()) { 156 return (this.initialized ? this.singletonInstance : getEarlySingletonInstance()); 157 } 158 else { 159 return createInstance(); 160 } 161 } 162 163 /** 164 * Determine an 'early singleton' instance, exposed in case of a 165 * circular reference. Not called in a non-circular scenario. 166 */ 167 @SuppressWarnings("unchecked") 168 private T getEarlySingletonInstance() throws Exception { 169 Class<?>[] ifcs = getEarlySingletonInterfaces(); 170 if (ifcs == null) { 171 throw new FactoryBeanNotInitializedException( 172 getClass().getName() + " does not support circular references"); 173 } 174 if (this.earlySingletonInstance == null) { 175 this.earlySingletonInstance = (T) Proxy.newProxyInstance( 176 this.beanClassLoader, ifcs, new EarlySingletonInvocationHandler()); 177 } 178 return this.earlySingletonInstance; 179 } 180 181 /** 182 * Expose the singleton instance (for access through the 'early singleton' proxy). 183 * @return the singleton instance that this FactoryBean holds 184 * @throws IllegalStateException if the singleton instance is not initialized 185 */ 186 @Nullable 187 private T getSingletonInstance() throws IllegalStateException { 188 Assert.state(this.initialized, "Singleton instance not initialized yet"); 189 return this.singletonInstance; 190 } 191 192 /** 193 * Destroy the singleton instance, if any. 194 * @see #destroyInstance(Object) 195 */ 196 @Override 197 public void destroy() throws Exception { 198 if (isSingleton()) { 199 destroyInstance(this.singletonInstance); 200 } 201 } 202 203 204 /** 205 * This abstract method declaration mirrors the method in the FactoryBean 206 * interface, for a consistent offering of abstract template methods. 207 * @see org.springframework.beans.factory.FactoryBean#getObjectType() 208 */ 209 @Override 210 @Nullable 211 public abstract Class<?> getObjectType(); 212 213 /** 214 * Template method that subclasses must override to construct 215 * the object returned by this factory. 216 * <p>Invoked on initialization of this FactoryBean in case of 217 * a singleton; else, on each {@link #getObject()} call. 218 * @return the object returned by this factory 219 * @throws Exception if an exception occurred during object creation 220 * @see #getObject() 221 */ 222 protected abstract T createInstance() throws Exception; 223 224 /** 225 * Return an array of interfaces that a singleton object exposed by this 226 * FactoryBean is supposed to implement, for use with an 'early singleton 227 * proxy' that will be exposed in case of a circular reference. 228 * <p>The default implementation returns this FactoryBean's object type, 229 * provided that it is an interface, or {@code null} otherwise. The latter 230 * indicates that early singleton access is not supported by this FactoryBean. 231 * This will lead to a FactoryBeanNotInitializedException getting thrown. 232 * @return the interfaces to use for 'early singletons', 233 * or {@code null} to indicate a FactoryBeanNotInitializedException 234 * @see org.springframework.beans.factory.FactoryBeanNotInitializedException 235 */ 236 @Nullable 237 protected Class<?>[] getEarlySingletonInterfaces() { 238 Class<?> type = getObjectType(); 239 return (type != null && type.isInterface() ? new Class<?>[] {type} : null); 240 } 241 242 /** 243 * Callback for destroying a singleton instance. Subclasses may 244 * override this to destroy the previously created instance. 245 * <p>The default implementation is empty. 246 * @param instance the singleton instance, as returned by 247 * {@link #createInstance()} 248 * @throws Exception in case of shutdown errors 249 * @see #createInstance() 250 */ 251 protected void destroyInstance(@Nullable T instance) throws Exception { 252 } 253 254 255 /** 256 * Reflective InvocationHandler for lazy access to the actual singleton object. 257 */ 258 private class EarlySingletonInvocationHandler implements InvocationHandler { 259 260 @Override 261 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 262 if (ReflectionUtils.isEqualsMethod(method)) { 263 // Only consider equal when proxies are identical. 264 return (proxy == args[0]); 265 } 266 else if (ReflectionUtils.isHashCodeMethod(method)) { 267 // Use hashCode of reference proxy. 268 return System.identityHashCode(proxy); 269 } 270 else if (!initialized && ReflectionUtils.isToStringMethod(method)) { 271 return "Early singleton proxy for interfaces " + 272 ObjectUtils.nullSafeToString(getEarlySingletonInterfaces()); 273 } 274 try { 275 return method.invoke(getSingletonInstance(), args); 276 } 277 catch (InvocationTargetException ex) { 278 throw ex.getTargetException(); 279 } 280 } 281 } 282 283}