看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)是我們自定義的類型,因此我們要寫代碼描述如何創(chuàng)建這個類型。BaseClass obj = new BaseClass(); 的 obj 才占用空間。
class ExtClass extends BaseClass {}; ExtClass ex = new ExtClass() 的 ex 才占用空間。 在給其分配內存的時候 首先分配 BaseClass 描述的成員變量的空間,然后再分配ExtClass中描述的成員變量占用的空間。
obj -> +------------------+
| BaseClass的props |
+------------------+
| 其他 |
+------------------+
ext -> +------------------+
| BaseClass的props |
+------------------+
| 其他 |
+------------------+
| ExtClass的props |
+------------------+
| 其他 |
+------------------+
其他 包括一下存儲類中方法、static等東西的“指針”等。。。
抽象類不能實例化,但其子類可以實例化,子類實例化的時候顯然要要先給其父類定義的成員變量分配空間。
因此,對于static 方法,只能訪問static 變量,因為這個時候其他成員變量還沒有分配空間。static成員實在程序初始化的時候分配的空間,所有的對象共享,所以即使沒有創(chuàng)建對象,這些成員也是在內存中存在的,所以這些值可以通過類名訪問。但是其他方法,必須通過這個類的對象訪問,也就是必須通過一個已經實例化的對象進行訪問,這些成員變量有了內存空間,就可以訪問了。
所以你調用了非static方法,就必然說明在某個地方實例化了這個類或是其子類,通過這個對象對這個函數進行調用,這樣基類所定義的屬性也有了分配空間。
抽象類不能實例化主要是因為其中的一些方法沒有實現,等待其子類實現這些方法,所以它并不是一個完整的類定義。 它說類中有一個方法,但是并沒有實現,因為根據不同的情況可能實現不同,但是部分方法有通用的實現,因此只寫這一部分方法。 還有一種特殊的抽象類,就是所有的方法都是抽象的方法,額,其實這在JAVA一般叫定義為"接口"。只是抽象類不能多繼承,接口可以"多繼承"。
額,寫完發(fā)現,受不同語言影響較大,一些詞用的比較亂,比如基類,父類,屬性,成員變量等。
北大青鳥APTECH成立于1999年。依托北京大學優(yōu)質雄厚的教育資源和背景,秉承“教育改變生活”的發(fā)展理念,致力于培養(yǎng)中國IT技能型緊缺人才,是大數據專業(yè)的國家
達內教育集團成立于2002年,是一家由留學海歸創(chuàng)辦的高端職業(yè)教育培訓機構,是中國一站式人才培養(yǎng)平臺、一站式人才輸送平臺。2014年4月3日在美國成功上市,融資1
北大課工場是北京大學校辦產業(yè)為響應國家深化產教融合/校企合作的政策,積極推進“中國制造2025”,實現中華民族偉大復興的升級產業(yè)鏈。利用北京大學優(yōu)質教育資源及背
博為峰,中國職業(yè)人才培訓領域的先行者
曾工作于聯(lián)想擔任系統(tǒng)開發(fā)工程師,曾在博彥科技股份有限公司擔任項目經理從事移動互聯(lián)網管理及研發(fā)工作,曾創(chuàng)辦藍懿科技有限責任公司從事總經理職務負責iOS教學及管理工作。
浪潮集團項目經理。精通Java與.NET 技術, 熟練的跨平臺面向對象開發(fā)經驗,技術功底深厚。 授課風格 授課風格清新自然、條理清晰、主次分明、重點難點突出、引人入勝。
精通HTML5和CSS3;Javascript及主流js庫,具有快速界面開發(fā)的能力,對瀏覽器兼容性、前端性能優(yōu)化等有深入理解。精通網頁制作和網頁游戲開發(fā)。
具有10 年的Java 企業(yè)應用開發(fā)經驗。曾經歷任德國Software AG 技術顧問,美國Dachieve 系統(tǒng)架構師,美國AngelEngineers Inc. 系統(tǒng)架構師。