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}