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

org.springframework.beans.factory.support.DefaultListableBeanFactory 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.support;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.BeanCurrentlyInCreationException;
import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.CannotLoadBeanClassException;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.core.CollectionFactory;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

/**
 * Default implementation of the
 * {@link org.springframework.beans.factory.ListableBeanFactory} and
 * {@link BeanDefinitionRegistry} interfaces: a full-fledged bean factory
 * based on bean definition objects.
 *
 * 

Typical usage is registering all bean definitions first (possibly read * from a bean definition file), before accessing beans. Bean definition lookup * is therefore an inexpensive operation in a local bean definition table, * operating on pre-built bean definition metadata objects. * *

Can be used as a standalone bean factory, or as a superclass for custom * bean factories. Note that readers for specific bean definition formats are * typically implemented separately rather than as bean factory subclasses: * see for example {@link PropertiesBeanDefinitionReader} and * {@link org.springframework.beans.factory.xml.XmlBeanDefinitionReader}. * *

For an alternative implementation of the * {@link org.springframework.beans.factory.ListableBeanFactory} interface, * have a look at {@link StaticListableBeanFactory}, which manages existing * bean instances rather than creating new ones based on bean definitions. * * @author Rod Johnson * @author Juergen Hoeller * @since 16 April 2001 * @see StaticListableBeanFactory * @see PropertiesBeanDefinitionReader * @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader */ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements ConfigurableListableBeanFactory, BeanDefinitionRegistry { /** Whether to allow re-registration of a different definition with the same name */ private boolean allowBeanDefinitionOverriding = true; /** Whether to allow eager class loading even for lazy-init beans */ private boolean allowEagerClassLoading = true; /** Map of bean definition objects, keyed by bean name */ private final Map beanDefinitionMap = new HashMap(); /** List of bean definition names, in registration order */ private final List beanDefinitionNames = new ArrayList(); /** * Create a new DefaultListableBeanFactory. */ public DefaultListableBeanFactory() { super(); } /** * Create a new DefaultListableBeanFactory with the given parent. * @param parentBeanFactory the parent BeanFactory */ public DefaultListableBeanFactory(BeanFactory parentBeanFactory) { super(parentBeanFactory); } /** * Set whether it should be allowed to override bean definitions by registering * a different definition with the same name, automatically replacing the former. * If not, an exception will be thrown. Default is "true". */ public void setAllowBeanDefinitionOverriding(boolean allowBeanDefinitionOverriding) { this.allowBeanDefinitionOverriding = allowBeanDefinitionOverriding; } /** * Set whether the factory is allowed to eagerly load bean classes * even for bean definitions that are marked as "lazy-init". *

Default is "true". Turn this flag off to suppress class loading * for lazy-init beans unless such a bean is explicitly requested. * In particular, by-type lookups will then simply ignore bean definitions * without resolved class name, instead of loading the bean classes on * demand just to perform a type check. * @see AbstractBeanDefinition#setLazyInit */ public void setAllowEagerClassLoading(boolean allowEagerClassLoading) { this.allowEagerClassLoading = allowEagerClassLoading; } public void copyConfigurationFrom(ConfigurableBeanFactory otherFactory) { super.copyConfigurationFrom(otherFactory); if (otherFactory instanceof DefaultListableBeanFactory) { DefaultListableBeanFactory otherListableFactory = (DefaultListableBeanFactory) otherFactory; this.allowBeanDefinitionOverriding = otherListableFactory.allowBeanDefinitionOverriding; this.allowEagerClassLoading = otherListableFactory.allowEagerClassLoading; } } //--------------------------------------------------------------------- // Implementation of ListableBeanFactory interface //--------------------------------------------------------------------- public boolean containsBeanDefinition(String beanName) { return this.beanDefinitionMap.containsKey(beanName); } public int getBeanDefinitionCount() { return this.beanDefinitionMap.size(); } public String[] getBeanDefinitionNames() { return StringUtils.toStringArray(this.beanDefinitionNames); } public String[] getBeanNamesForType(Class type) { return getBeanNamesForType(type, true, true); } public String[] getBeanNamesForType(Class type, boolean includePrototypes, boolean allowEagerInit) { List result = new ArrayList(); // Check all bean definitions. for (Iterator it = this.beanDefinitionNames.iterator(); it.hasNext();) { String beanName = (String) it.next(); // Only consider bean as eligible if the bean name // is not defined as alias for some other bean. if (!isAlias(beanName)) { RootBeanDefinition mbd = getMergedBeanDefinition(beanName, false); // Only check bean definition if it is complete. if (!mbd.isAbstract() && (allowEagerInit || mbd.hasBeanClass() || !mbd.isLazyInit() || this.allowEagerClassLoading)) { // In case of FactoryBean, match object created by FactoryBean. try { boolean isFactoryBean = isBeanClassMatch(beanName, mbd, FactoryBean.class); if (isFactoryBean || mbd.getFactoryBeanName() != null) { if (allowEagerInit && (includePrototypes || isSingleton(beanName)) && isTypeMatch(beanName, type)) { result.add(beanName); // Match found for this bean: do not match FactoryBean itself anymore. continue; } // We're done for anything but a full FactoryBean. if (!isFactoryBean) { continue; } // In case of FactoryBean, try to match FactoryBean itself next. beanName = FACTORY_BEAN_PREFIX + beanName; } // Match raw bean instance (might be raw FactoryBean). if ((includePrototypes || mbd.isSingleton()) && isTypeMatch(beanName, type)) { result.add(beanName); } } catch (CannotLoadBeanClassException ex) { // Probably contains a placeholder: let's ignore it for type matching purposes. if (logger.isDebugEnabled()) { logger.debug("Ignoring bean class loading failure for bean '" + beanName + "'", ex); } } } } } // Check singletons too, to catch manually registered singletons. String[] singletonNames = getSingletonNames(); for (int i = 0; i < singletonNames.length; i++) { String beanName = singletonNames[i]; // Only check if manually registered. if (!containsBeanDefinition(beanName)) { // In case of FactoryBean, match object created by FactoryBean. if (isFactoryBean(beanName)) { if ((includePrototypes || isSingleton(beanName)) && isTypeMatch(beanName, type)) { result.add(beanName); // Match found for this bean: do not match FactoryBean itself anymore. continue; } // In case of FactoryBean, try to match FactoryBean itself next. beanName = FACTORY_BEAN_PREFIX + beanName; } // Match raw bean instance (might be raw FactoryBean). if (isTypeMatch(beanName, type)) { result.add(beanName); } } } return StringUtils.toStringArray(result); } public Map getBeansOfType(Class type) throws BeansException { return getBeansOfType(type, true, true); } public Map getBeansOfType(Class type, boolean includePrototypes, boolean allowEagerInit) throws BeansException { String[] beanNames = getBeanNamesForType(type, includePrototypes, allowEagerInit); Map result = CollectionFactory.createLinkedMapIfPossible(beanNames.length); for (int i = 0; i < beanNames.length; i++) { String beanName = beanNames[i]; try { result.put(beanName, getBean(beanName)); } catch (BeanCreationException ex) { Throwable rootCause = ex.getMostSpecificCause(); if (rootCause instanceof BeanCurrentlyInCreationException) { BeanCreationException bce = (BeanCreationException) rootCause; if (isCurrentlyInCreation(bce.getBeanName())) { if (logger.isDebugEnabled()) { logger.debug("Ignoring match to currently created bean '" + beanName + "': " + ex.getMessage()); } // Ignore: indicates a circular reference when autowiring constructors. // We want to find matches other than the currently created bean itself. continue; } } throw ex; } } return result; } //--------------------------------------------------------------------- // Implementation of ConfigurableListableBeanFactory interface //--------------------------------------------------------------------- public void preInstantiateSingletons() throws BeansException { if (logger.isInfoEnabled()) { logger.info("Pre-instantiating singletons in " + this); } for (Iterator it = this.beanDefinitionNames.iterator(); it.hasNext();) { String beanName = (String) it.next(); if (!containsSingleton(beanName) && containsBeanDefinition(beanName)) { RootBeanDefinition bd = getMergedBeanDefinition(beanName, false); if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) { Class beanClass = resolveBeanClass(bd, beanName); if (beanClass != null && FactoryBean.class.isAssignableFrom(beanClass)) { getBean(FACTORY_BEAN_PREFIX + beanName); } else { getBean(beanName); } } } } } //--------------------------------------------------------------------- // Implementation of BeanDefinitionRegistry interface //--------------------------------------------------------------------- public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException { Assert.hasText(beanName, "'beanName' must not be empty"); Assert.notNull(beanDefinition, "BeanDefinition must not be null"); if (beanDefinition instanceof AbstractBeanDefinition) { try { ((AbstractBeanDefinition) beanDefinition).validate(); } catch (BeanDefinitionValidationException ex) { throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Validation of bean definition failed", ex); } } Object oldBeanDefinition = this.beanDefinitionMap.get(beanName); if (oldBeanDefinition != null) { if (!this.allowBeanDefinitionOverriding) { throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName + "': There is already [" + oldBeanDefinition + "] bound."); } else { if (logger.isInfoEnabled()) { logger.info("Overriding bean definition for bean '" + beanName + "': replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]"); } } } else { this.beanDefinitionNames.add(beanName); } this.beanDefinitionMap.put(beanName, beanDefinition); // Remove corresponding bean from singleton cache, if any. Shouldn't usually // be necessary, rather just meant for overriding a context's default beans // (e.g. the default StaticMessageSource in a StaticApplicationContext). synchronized (getSingletonMutex()) { removeSingleton(beanName); } } //--------------------------------------------------------------------- // Implementation of superclass abstract methods //--------------------------------------------------------------------- public BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException { BeanDefinition bd = (BeanDefinition) this.beanDefinitionMap.get(beanName); if (bd == null) { if (logger.isTraceEnabled()) { logger.trace("No bean named '" + beanName + "' found in " + this); } throw new NoSuchBeanDefinitionException(beanName); } return bd; } protected Map findAutowireCandidates(String beanName, Class requiredType) { String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this, requiredType); Map result = CollectionFactory.createLinkedMapIfPossible(candidateNames.length); for (int i = 0; i < candidateNames.length; i++) { String candidateName = candidateNames[i]; if (!candidateName.equals(beanName) && (!containsBeanDefinition(candidateName) || getMergedBeanDefinition(candidateName).isAutowireCandidate())) { result.put(candidateName, getBean(candidateName)); } } return result; } public String toString() { StringBuffer sb = new StringBuffer(ObjectUtils.identityToString(this)); sb.append(": defining beans ["); sb.append(StringUtils.arrayToCommaDelimitedString(getBeanDefinitionNames())); sb.append("]; "); BeanFactory parent = getParentBeanFactory(); if (parent == null) { sb.append("root of factory hierarchy"); } else { sb.append("parent: " + ObjectUtils.identityToString(parent)); } return sb.toString(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy