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: 6.1.6
Show newest version
/*
 * Copyright 2002-2018 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
 *
 *      https://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.BeanClassLoaderAware;
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;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.ReflectionUtils;

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

If the "singleton" flag is {@code 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 * @param the bean type * @see #setSingleton * @see #createInstance() */ public abstract class AbstractFactoryBean implements FactoryBean, BeanClassLoaderAware, BeanFactoryAware, InitializingBean, DisposableBean { /** Logger available to subclasses. */ protected final Log logger = LogFactory.getLog(getClass()); private boolean singleton = true; @Nullable private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader(); @Nullable private BeanFactory beanFactory; private boolean initialized = false; @Nullable private T singletonInstance; @Nullable private T earlySingletonInstance; /** * Set if a singleton should be created, or a new object on each request * otherwise. Default is {@code true} (a singleton). */ public void setSingleton(boolean singleton) { this.singleton = singleton; } @Override public boolean isSingleton() { return this.singleton; } @Override public void setBeanClassLoader(ClassLoader classLoader) { this.beanClassLoader = classLoader; } @Override public void setBeanFactory(@Nullable BeanFactory beanFactory) { this.beanFactory = beanFactory; } /** * Return the BeanFactory that this bean runs in. */ @Nullable 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. */ @Override 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() */ @Override public final T getObject() throws Exception { if (isSingleton()) { return (this.initialized ? this.singletonInstance : getEarlySingletonInstance()); } else { return createInstance(); } } /** * Determine an 'early singleton' instance, exposed in case of a * circular reference. Not called in a non-circular scenario. */ @SuppressWarnings("unchecked") private T 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 = (T) Proxy.newProxyInstance( this.beanClassLoader, ifcs, new EarlySingletonInvocationHandler()); } 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 */ @Nullable private T getSingletonInstance() throws IllegalStateException { Assert.state(this.initialized, "Singleton instance not initialized yet"); return this.singletonInstance; } /** * Destroy the singleton instance, if any. * @see #destroyInstance(Object) */ @Override public void destroy() throws Exception { if (isSingleton()) { destroyInstance(this.singletonInstance); } } /** * This abstract method declaration mirrors the method in the FactoryBean * interface, for a consistent offering of abstract template methods. * @see org.springframework.beans.factory.FactoryBean#getObjectType() */ @Override @Nullable 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 occurred during object creation * @see #getObject() */ protected abstract T 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 {@code null} otherwise. 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 {@code null} to indicate a FactoryBeanNotInitializedException * @see org.springframework.beans.factory.FactoryBeanNotInitializedException */ @Nullable 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(@Nullable T instance) throws Exception { } /** * Reflective InvocationHandler for lazy access to the actual singleton object. */ private class EarlySingletonInvocationHandler implements InvocationHandler { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (ReflectionUtils.isEqualsMethod(method)) { // Only consider equal when proxies are identical. return (proxy == args[0]); } else if (ReflectionUtils.isHashCodeMethod(method)) { // Use hashCode of reference proxy. return System.identityHashCode(proxy); } else if (!initialized && ReflectionUtils.isToStringMethod(method)) { return "Early singleton proxy for interfaces " + ObjectUtils.nullSafeToString(getEarlySingletonInterfaces()); } try { return method.invoke(getSingletonInstance(), args); } catch (InvocationTargetException ex) { throw ex.getTargetException(); } } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy