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