看Spring源码想到的一个问题
/*
* Copyright 2002-2004 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.beans.PropertyEditor;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanIsNotAFactoryException;
import org.springframework.beans.factory.BeanNotOfRequiredTypeException;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.FactoryBeanCircularReferenceException;
import org.springframework.beans.factory.HierarchicalBeanFactory;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
/**
* Abstract superclass for BeanFactory implementations.
* Implements the ConfigurableBeanFactory SPI interface.
*
* <p>This class provides singleton/prototype determination, singleton cache,
* aliases, FactoryBean handling, and bean definition merging for child bean
* definitions. It also allows for management of a bean factory hierarchy,
* implementing the HierarchicalBeanFactory interface.
*
* <p>The main template methods to be implemented by subclasses are
* getBeanDefinition and createBean, retrieving a bean definition for
* a given bean name respectively creating a bean instance for a given
* bean definition.
*
* @author Rod Johnson
* @author Juergen Hoeller
* @since 15 April 2001
* @version $Id: AbstractBeanFactory.java,v 1.51 2004/03/23 20:16:59 jhoeller Exp $
* @see #getBeanDefinition
* @see #createBean
*/
public abstract class AbstractBeanFactory implements ConfigurableBeanFactory, HierarchicalBeanFactory {
/**
* Used to dereference a FactoryBean and distinguish it from
* beans <i>created</i> by the factory. For example,
* if the bean named <code>myEjb</code> is a factory, getting
* <code>&myEjb</code> will return the factory, not the instance
* returned by the factory.
*/
public static final String FACTORY_BEAN_PREFIX = "&";
/** Logger available to subclasses */
protected final Log logger = LogFactory.getLog(getClass());
/** Parent bean factory, for bean inheritance support */
private BeanFactory parentBeanFactory;
/** Custom PropertyEditors to apply to the beans of this factory */
private Map customEditors = new HashMap();
/** Dependency types to ignore on dependency check and autowire */
private final Set ignoreDependencyTypes = new HashSet();
/** BeanPostProcessors to apply in createBean */
private final List beanPostProcessors = new ArrayList();
/** Map from alias to canonical bean name */
private final Map aliasMap = Collections.synchronizedMap(new HashMap());
/** Cache of singletons: bean name --> bean instance */
private final Map singletonCache = Collections.synchronizedMap(new HashMap());
/**
* Create a new AbstractBeanFactory.
*/
public AbstractBeanFactory() {
ignoreDependencyType(BeanFactory.class);
}
/**
* Create a new AbstractBeanFactory with the given parent.
* @param parentBeanFactory parent bean factory, or null if none
* @see #getBean
*/
public AbstractBeanFactory(BeanFactory parentBeanFactory) {
this();
this.parentBeanFactory = parentBeanFactory;
}
//---------------------------------------------------------------------
// Implementation of BeanFactory
//---------------------------------------------------------------------
/**
* Return the bean with the given name,
* checking the parent bean factory if not found.
* @param name name of the bean to retrieve
*/
public Object getBean(String name) throws BeansException {
String beanName = transformedBeanName(name);
// eagerly check singleton cache for manually registered singletons
Object sharedInstance = this.singletonCache.get(beanName);
if (sharedInstance != null) {
if (logger.isDebugEnabled()) {
logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
}
return getObjectForSharedInstance(name, sharedInstance);
}
else {
// check if bean definition exists
RootBeanDefinition mergedBeanDefinition = null;
try {
mergedBeanDefinition = getMergedBeanDefinition(beanName, false);
}
catch (NoSuchBeanDefinitionException ex) {
// not found -> check parent
if (this.parentBeanFactory != null) {
return this.parentBeanFactory.getBean(name);
}
throw ex;
}
// create bean instance
if (mergedBeanDefinition.isSingleton()) {
synchronized (this.singletonCache) {
// re-check singleton cache within synchronized block
sharedInstance = this.singletonCache.get(beanName);
if (sharedInstance == null) {
logger.info("Creating shared instance of singleton bean '" + beanName + "'");
sharedInstance = createBean(beanName, mergedBeanDefinition);
addSingleton(beanName, sharedInstance);
}
}
return getObjectForSharedInstance(name, sharedInstance);
}
else {
return createBean(name, mergedBeanDefinition);
}
}
}
public Object getBean(String name, Class requiredType) throws BeansException {
Object bean = getBean(name);
if (!requiredType.isAssignableFrom(bean.getClass())) {
throw new BeanNotOfRequiredTypeException(name, requiredType, bean);
}
return bean;
}
public boolean containsBean(String name) {
String beanName = transformedBeanName(name);
if (this.singletonCache.containsKey(beanName)) {
return true;
}
if (containsBeanDefinition(beanName)) {
return true;
}
else {
// not found -> check parent
if (this.parentBeanFactory != null) {
return this.parentBeanFactory.containsBean(beanName);
}
else {
return false;
}
}
}
public boolean isSingleton(String name) throws NoSuchBeanDefinitionException {
String beanName = transformedBeanName(name);
try {
Class beanClass = null;
boolean singleton = true;
Object beanInstance = this.singletonCache.get(beanName);
if (beanInstance != null) {
beanClass = beanInstance.getClass();
singleton = true;
}
else {
RootBeanDefinition bd = getMergedBeanDefinition(beanName, false);
beanClass = bd.getBeanClass();
singleton = bd.isSingleton();
}
// in case of FactoryBean, return singleton status of created object if not a dereference
if (FactoryBean.class.isAssignableFrom(beanClass) && !isFactoryDereference(name)) {
FactoryBean factoryBean = (FactoryBean) getBean(FACTORY_BEAN_PREFIX + beanName);
return factoryBean.isSingleton();
}
else {
return singleton;
}
}
catch (NoSuchBeanDefinitionException ex) {
// not found -> check parent
if (this.parentBeanFactory != null) {
return this.parentBeanFactory.isSingleton(beanName);
}
throw ex;
}
}
public String[] getAliases(String name) throws NoSuchBeanDefinitionException {
String beanName = transformedBeanName(name);
// check if bean actually exists in this bean factory
if (this.singletonCache.containsKey(beanName) || containsBeanDefinition(beanName)) {
// if found, gather aliases
List aliases = new ArrayList();
for (Iterator it = this.aliasMap.entrySet().iterator(); it.hasNext();) {
Map.Entry entry = (Map.Entry) it.next();
if (entry.getValue().equals(beanName)) {
aliases.add(entry.getKey());
}
}
return (String[]) aliases.toArray(new String[aliases.size()]);
}
else {
// not found -> check parent
if (this.parentBeanFactory != null) {
return this.parentBeanFactory.getAliases(beanName);
}
throw new NoSuchBeanDefinitionException(beanName, toString());
}
}
//---------------------------------------------------------------------
// Implementation of HierarchicalBeanFactory
//---------------------------------------------------------------------
public BeanFactory getParentBeanFactory() {
return parentBeanFactory;
}
//---------------------------------------------------------------------
// Implementation of ConfigurableBeanFactory
//---------------------------------------------------------------------
public void setParentBeanFactory(BeanFactory parentBeanFactory) {
this.parentBeanFactory = parentBeanFactory;
}
public void registerCustomEditor(Class requiredType, PropertyEditor propertyEditor) {
this.customEditors.put(requiredType, propertyEditor);
}
/**
* Return the map of custom editors, with Classes as keys
* and PropertyEditors as values.
*/
public Map getCustomEditors() {
return customEditors;
}
public void ignoreDependencyType(Class type) {
this.ignoreDependencyTypes.add(type);
}
/**
* Return the set of classes that will get ignored for autowiring.
*/
public Set getIgnoredDependencyTypes() {
return ignoreDependencyTypes;
}
public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) {
this.beanPostProcessors.add(beanPostProcessor);
}
/**
* Return the list of BeanPostProcessors that will get applied
* to beans created with this factory.
*/
public List getBeanPostProcessors() {
return beanPostProcessors;
}
public void registerAlias(String beanName, String alias) throws BeanDefinitionStoreException {
logger.debug("Registering alias '" + alias + "' for bean with name '" + beanName + "'");
synchronized (this.aliasMap) {
Object registeredName = this.aliasMap.get(alias);
if (registeredName != null) {
throw new BeanDefinitionStoreException("Cannot register alias '" + alias + "' for bean name '" + beanName +
"': it's already registered for bean name '" + registeredName + "'");
}
this.aliasMap.put(alias, beanName);
}
}
public void registerSingleton(String beanName, Object singletonObject) throws BeanDefinitionStoreException {
synchronized (this.singletonCache) {
Object oldObject = this.singletonCache.get(beanName);
if (oldObject != null) {
throw new BeanDefinitionStoreException("Could not register object [" + singletonObject +
"] under bean name '" + beanName + "': there's already object [" +
oldObject + " bound");
}
addSingleton(beanName, singletonObject);
}
}
/**
* Add the given singleton object to the singleton cache of this factory.
* <p>To be called for eager registration of singletons, e.g. to be able to
* resolve circular references.
* @param beanName the name of the bean
* @param singletonObject the singleton object
*/
protected void addSingleton(String beanName, Object singletonObject) {
this.singletonCache.put(beanName, singletonObject);
}
public void destroySingletons() {
if (logger.isInfoEnabled()) {
logger.info("Destroying singletons in factory {" + this + "}");
}
synchronized (this.singletonCache) {
Set singletonCacheKeys = new HashSet(this.singletonCache.keySet());
for (Iterator it = singletonCacheKeys.iterator(); it.hasNext();) {
destroySingleton((String) it.next());
}
}
}
/**
* Destroy the given bean. Delegates to destroyBean if a corresponding
* singleton instance is found.
* @param beanName name of the bean
* @see #destroyBean
*/
protected void destroySingleton(String beanName) {
Object singletonInstance = this.singletonCache.remove(beanName);
if (singletonInstance != null) {
destroyBean(beanName, singletonInstance);
}
}
//---------------------------------------------------------------------
// Implementation methods
//---------------------------------------------------------------------
/**
* Return the bean name, stripping out the factory dereference prefix if necessary,
* and resolving aliases to canonical names.
*/
protected String transformedBeanName(String name) throws NoSuchBeanDefinitionException {
if (name == null) {
throw new NoSuchBeanDefinitionException(name, "Cannot get bean with null name");
}
if (name.startsWith(FACTORY_BEAN_PREFIX)) {
name = name.substring(FACTORY_BEAN_PREFIX.length());
}
// handle aliasing
String canonicalName = (String) this.aliasMap.get(name);
return canonicalName != null ? canonicalName : name;
}
/**
* Return whether this name is a factory dereference
* (beginning with the factory dereference prefix).
*/
protected boolean isFactoryDereference(String name) {
return name.startsWith(FACTORY_BEAN_PREFIX);
}
/**
* Initialize the given BeanWrapper with the custom editors registered
* with this factory.
* @param bw the BeanWrapper to initialize
*/
protected void initBeanWrapper(BeanWrapper bw) {
for (Iterator it = this.customEditors.keySet().iterator(); it.hasNext();) {
Class clazz = (Class) it.next();
bw.registerCustomEditor(clazz, (PropertyEditor) this.customEditors.get(clazz));
}
}
/**
* Return the names of beans in the singleton cache that match the given
* object type (including subclasses). Will <i>not</i> consider FactoryBeans
* as the type of their created objects is not known before instantiation.
* <p>Does not consider any hierarchy this factory may participate in.
* @param type class or interface to match, or null for all bean names
* @return the names of beans in the singleton cache that match the given
* object type (including subclasses), or an empty array if none
*/
public String[] getSingletonNames(Class type) {
Set keys = this.singletonCache.keySet();
Set matches = new HashSet();
Iterator itr = keys.iterator();
while (itr.hasNext()) {
String name = (String) itr.next();
Object singletonObject = this.singletonCache.get(name);
if (type == null || type.isAssignableFrom(singletonObject.getClass())) {
matches.add(name);
}
}
return (String[]) matches.toArray(new String[matches.size()]);
}
/**
* Get the object for the given shared bean, either the bean
* instance itself or its created object in case of a FactoryBean.
* @param name name that may include factory dereference prefix
* @param beanInstance the shared bean instance
* @return the singleton instance of the bean
*/
protected Object getObjectForSharedInstance(String name, Object beanInstance) {
String beanName = transformedBeanName(name);
// Don't let calling code try to dereference the
// bean factory if the bean isn't a factory
if (isFactoryDereference(name) && !(beanInstance instanceof FactoryBean)) {
throw new BeanIsNotAFactoryException(beanName, beanInstance);
}
// Now we have the bean instance, which may be a normal bean
// or a FactoryBean. If it's a FactoryBean, we use it to
// create a bean instance, unless the caller actually wants
// a reference to the factory.
if (beanInstance instanceof FactoryBean) {
if (!isFactoryDereference(name)) {
// return bean instance from factory
FactoryBean factory = (FactoryBean) beanInstance;
logger.debug("Bean with name '" + beanName + "' is a factory bean");
try {
beanInstance = factory.getObject();
}
catch (BeansException ex) {
throw ex;
}
catch (Exception ex) {
throw new BeanCreationException("FactoryBean threw exception on object creation", ex);
}
if (beanInstance == null) {
throw new FactoryBeanCircularReferenceException(
"Factory bean '" + beanName + "' returned null object - " +
"possible cause: not fully initialized due to circular bean reference");
}
}
else {
// the user wants the factory itself
logger.debug("Calling code asked for FactoryBean instance for name '" + beanName + "'");
}
}
return beanInstance;
}
/**
* Return a RootBeanDefinition, even by traversing parent if the parameter is a child definition.
* Will ask the parent bean factory if not found in this instance.
* @return a merged RootBeanDefinition with overridden properties
*/
public RootBeanDefinition getMergedBeanDefinition(String beanName, boolean includingAncestors)
throws BeansException {
try {
return getMergedBeanDefinition(beanName, getBeanDefinition(beanName));
}
catch (NoSuchBeanDefinitionException ex) {
if (includingAncestors && getParentBeanFactory() instanceof AbstractAutowireCapableBeanFactory) {
return ((AbstractAutowireCapableBeanFactory) getParentBeanFactory()).getMergedBeanDefinition(beanName, true);
}
else {
throw ex;
}
}
}
/**
* Return a RootBeanDefinition, even by traversing parent if the parameter is a child definition.
* @return a merged RootBeanDefinition with overridden properties
*/
protected RootBeanDefinition getMergedBeanDefinition(String beanName, BeanDefinition bd) {
if (bd instanceof RootBeanDefinition) {
return (RootBeanDefinition) bd;
}
else if (bd instanceof ChildBeanDefinition) {
ChildBeanDefinition cbd = (ChildBeanDefinition) bd;
// deep copy
RootBeanDefinition rbd = new RootBeanDefinition(getMergedBeanDefinition(cbd.getParentName(), true));
// override properties
for (int i = 0; i < cbd.getPropertyValues().getPropertyValues().length; i++) {
rbd.getPropertyValues().addPropertyValue(cbd.getPropertyValues().getPropertyValues()[i]);
}
// override settings
rbd.setSingleton(cbd.isSingleton());
rbd.setLazyInit(cbd.isLazyInit());
rbd.setResourceDescription(cbd.getResourceDescription());
return rbd;
}
else {
throw new BeanDefinitionStoreException(bd.getResourceDescription(), beanName,
"Definition is neither a RootBeanDefinition nor a ChildBeanDefinition");
}
}
//---------------------------------------------------------------------
// Abstract methods to be implemented by concrete subclasses
//---------------------------------------------------------------------
/**
* Check if this bean factory contains a bean definition with the given name.
* Does not consider any hierarchy this factory may participate in.
* Invoked by containsBean when no cached singleton instance is found.
* @param beanName the name of the bean to look for
* @return if this bean factory contains a bean definition with the given name
* @see #containsBean
*/
public abstract boolean containsBeanDefinition(String beanName);
/**
* Return the bean definition for the given bean name.
* Subclasses should normally implement caching, as this method is invoked
* by this class every time bean definition metadata is needed.
* @param beanName name of the bean to find a definition for
* @return the BeanDefinition for this prototype name. Must never return null.
* @throws org.springframework.beans.factory.NoSuchBeanDefinitionException
* if the bean definition cannot be resolved
* @throws BeansException in case of errors
* @see RootBeanDefinition
* @see ChildBeanDefinition
*/
public abstract BeanDefinition getBeanDefinition(String beanName) throws BeansException;
/**
* Create a bean instance for the given bean definition.
* The bean definition will already have been merged with the parent
* definition in case of a child definition.
* <p>All the other methods in this class invoke this method, although
* beans may be cached after being instantiated by this method. All bean
* instantiation within this class is performed by this method.
* @param beanName name of the bean
* @param mergedBeanDefinition the bean definition for the bean
* @return a new instance of the bean
* @throws BeansException in case of errors
*/
protected abstract Object createBean(String beanName, RootBeanDefinition mergedBeanDefinition)
throws BeansException;
/**
* Destroy the given bean. Must destroy beans that depend on the given
* bean before the bean itself. Should not throw any exceptions.
* @param beanName name of the bean
* @param bean the bean instance to destroy
*/
protected abstract void destroyBean(String beanName, Object bean);
}
这是Spring1.0的源码,抽象类AbstractBeanFactory作为DefaultListableBeanFactory,XmlBeanFactory等的父类,在Spring factory的继承关系中,XmlBeanFactory的父beanFactory,即都保存在AbstractBeanFactory的parentBeanFactory变量中,我们获取parentBeanFactory可以通过AbstractBeanFactory的
public BeanFactory getParentBeanFactory() {
return parentBeanFactory;
}
获取即可,目前这些都没有问题。
但是,突然想到,作为抽象类AbstractBeanFactory,其并不能实例化,那么问题来了,其抽象类中的成员变量(非类变量)的值是保存在哪里的?或者说抽象类在内存中中是怎样存在的?
请教大家,谢谢。
这个跟 Spring 没有关系。
类,不占用任何空间,只是叙述了对象占用了怎样的空间。 类是类型的意思,就像
int
也是类型。int
并不占用空间,但是int a
的a
占用32 bytes内存空间,而double f;
f
占64 bytes 空间,这些是编译器预定义的类型。但是类(e.g.BaseClass
)是我们自定义的类型,因此我们要写代码描述如何创建这个类型。BaseClass obj = new BaseClass();
的obj
才占用空间。class ExtClass extends BaseClass {}; ExtClass ex = new ExtClass()
的 ex 才占用空间。 在给其分配内存的时候 首先分配BaseClass
描述的成员变量的空间,然后再分配ExtClass
中描述的成员变量占用的空间。其他
包括一下存储类中方法、static
等东西的“指针”等。。。抽象类不能实例化,但其子类可以实例化,子类实例化的时候显然要要先给其父类定义的成员变量分配空间。
因此,对于
static
方法,只能访问static
变量,因为这个时候其他成员变量还没有分配空间。static成员实在程序初始化的时候分配的空间,所有的对象共享,所以即使没有创建对象,这些成员也是在内存中存在的,所以这些值可以通过类名访问。但是其他方法,必须通过这个类的对象访问,也就是必须通过一个已经实例化的对象进行访问,这些成员变量有了内存空间,就可以访问了。所以你调用了非
static
方法,就必然说明在某个地方实例化了这个类或是其子类,通过这个对象对这个函数进行调用,这样基类所定义的属性也有了分配空间。抽象类不能实例化主要是因为其中的一些方法没有实现,等待其子类实现这些方法,所以它并不是一个完整的类定义。 它说类中有一个方法,但是并没有实现,因为根据不同的情况可能实现不同,但是部分方法有通用的实现,因此只写这一部分方法。 还有一种特殊的抽象类,就是所有的方法都是抽象的方法,额,其实这在JAVA一般叫定义为"接口"。只是抽象类不能多继承,接口可以"多继承"。
额,写完发现,受不同语言影响较大,一些词用的比较乱,比如基类,父类,属性,成员变量等。