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}