All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.springframework.beans.factory.config.AbstractFactoryBean Maven / Gradle / Ivy

There is a newer version: 5.3.34
Show newest version
/*
 * Copyright 2002-2007 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.beans.factory.config;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.springframework.beans.SimpleTypeConverter;
import org.springframework.beans.TypeConverter;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.FactoryBeanNotInitializedException;
import org.springframework.beans.factory.InitializingBean;

/**
 * Simple template superclass for {@link FactoryBean} implementations that
 * creates a singleton or a prototype object, depending on a flag.
 *
 * 

If the "singleton" flag is true (the default), * this class will create the object that it creates exactly once * on initialization and subsequently return said singleton instance * on all calls to the {@link #getObject()} method. * *

Else, this class will create a new instance every time the * {@link #getObject()} method is invoked. Subclasses are responsible * for implementing the abstract {@link #createInstance()} template * method to actually create the object(s) to expose. * * @author Juergen Hoeller * @author Keith Donald * @since 1.0.2 * @see #setSingleton(boolean) * @see #createInstance() */ public abstract class AbstractFactoryBean implements FactoryBean, BeanFactoryAware, InitializingBean, DisposableBean { /** Logger available to subclasses */ protected final Log logger = LogFactory.getLog(getClass()); private boolean singleton = true; private BeanFactory beanFactory; private boolean initialized = false; private Object singletonInstance; private Object earlySingletonInstance; /** * Set if a singleton should be created, or a new object * on each request else. Default is true (a singleton). */ public void setSingleton(boolean singleton) { this.singleton = singleton; } public boolean isSingleton() { return this.singleton; } public void setBeanFactory(BeanFactory beanFactory) { this.beanFactory = beanFactory; } /** * Return the BeanFactory that this bean runs in. */ protected BeanFactory getBeanFactory() { return this.beanFactory; } /** * Obtain a bean type converter from the BeanFactory that this bean * runs in. This is typically a fresh instance for each call, * since TypeConverters are usually not thread-safe. *

Falls back to a SimpleTypeConverter when not running in a BeanFactory. * @see ConfigurableBeanFactory#getTypeConverter() * @see org.springframework.beans.SimpleTypeConverter */ protected TypeConverter getBeanTypeConverter() { BeanFactory beanFactory = getBeanFactory(); if (beanFactory instanceof ConfigurableBeanFactory) { return ((ConfigurableBeanFactory) beanFactory).getTypeConverter(); } else { return new SimpleTypeConverter(); } } /** * Eagerly create the singleton instance, if necessary. */ public void afterPropertiesSet() throws Exception { if (isSingleton()) { this.initialized = true; this.singletonInstance = createInstance(); this.earlySingletonInstance = null; } } /** * Expose the singleton instance or create a new prototype instance. * @see #createInstance() * @see #getEarlySingletonInterfaces() */ public final Object getObject() throws Exception { if (isSingleton()) { return (this.initialized ? this.singletonInstance : getEarlySingletonInstance()); } else { return createInstance(); } } /** * Determine an 'eager singleton' instance, exposed in case of a * circular reference. Not called in a non-circular scenario. */ private Object getEarlySingletonInstance() throws Exception { Class[] ifcs = getEarlySingletonInterfaces(); if (ifcs == null) { throw new FactoryBeanNotInitializedException( getClass().getName() + " does not support circular references"); } if (this.earlySingletonInstance == null) { this.earlySingletonInstance = Proxy.newProxyInstance(getClass().getClassLoader(), ifcs, new InvocationHandler() { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { try { return method.invoke(getSingletonInstance(), args); } catch (InvocationTargetException ex) { throw ex.getTargetException(); } } }); } return this.earlySingletonInstance; } /** * Expose the singleton instance (for access through the 'early singleton' proxy). * @return the singleton instance that this FactoryBean holds * @throws IllegalStateException if the singleton instance is not initialized */ private Object getSingletonInstance() throws IllegalStateException { if (!this.initialized) { throw new IllegalStateException("Singleton instance not initialized yet"); } return this.singletonInstance; } /** * Destroy the singleton instance, if any. * @see #destroyInstance(Object) */ public void destroy() throws Exception { if (isSingleton()) { destroyInstance(this.singletonInstance); } } /** * This abstract method declaration shadows the method in the FactoryBean interface. * This is necessary to make the getEarlySingletonInterfaces implementation * in this class work on Sun's JDK 1.3 classic VM, which can't find the method * when executing getEarlySingletonInterfaces else. * @see org.springframework.beans.factory.FactoryBean#getObjectType() * @see #getEarlySingletonInterfaces() */ public abstract Class getObjectType(); /** * Template method that subclasses must override to construct * the object returned by this factory. *

Invoked on initialization of this FactoryBean in case of * a singleton; else, on each {@link #getObject()} call. * @return the object returned by this factory * @throws Exception if an exception occured during object creation * @see #getObject() */ protected abstract Object createInstance() throws Exception; /** * Return an array of interfaces that a singleton object exposed by this * FactoryBean is supposed to implement, for use with an 'early singleton * proxy' that will be exposed in case of a circular reference. *

The default implementation returns this FactoryBean's object type, * provided that it is an interface, or null else. The latter * indicates that early singleton access is not supported by this FactoryBean. * This will lead to a FactoryBeanNotInitializedException getting thrown. * @return the interfaces to use for 'early singletons', * or null to indicate a FactoryBeanNotInitializedException * @see org.springframework.beans.factory.FactoryBeanNotInitializedException */ protected Class[] getEarlySingletonInterfaces() { Class type = getObjectType(); return (type != null && type.isInterface() ? new Class[] {type} : null); } /** * Callback for destroying a singleton instance. Subclasses may * override this to destroy the previously created instance. *

The default implementation is empty. * @param instance the singleton instance, as returned by * {@link #createInstance()} * @throws Exception in case of shutdown errors * @see #createInstance() */ protected void destroyInstance(Object instance) throws Exception { } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy