Spring原始碼學習之路---IOC實現原理(三)
原文地址:https://blog.csdn.net/zuoxiaolong8810/article/details/8548478
上一章我們已經初步認識了BeanFactory和BeanDefinition,一個是IOC的核心工廠介面,一個是IOC的bean定義介面,上章提到說我們無法讓BeanFactory持有一個Map<String,Object>來完成bean工廠的功能,是因為spring的初始化是可以控制的,可以到用的時候才將bean例項化供開發者使用,除非我們將bean的lazy-init屬性設定為true,初始化bean工廠時採用延遲載入。
那麼知道了上述兩個介面,我相信不少人甚至不看原始碼都已經猜到spring是如何做的了。沒錯,就是讓bean工廠持有一個Map<String,BeanDefinition>,這樣就可以在任何時候我們想用哪個bean,取到它的bean定義,我們就可以創造出一個新鮮的例項。
介面當然不可能持有這樣一個物件,那麼這個物件一定是在BeanFactory的某個實現類或者抽象實現類當中所持有的,我經過跋山涉水,終於把它給找出來了,來看DefaultListableBeanFactory。
- /*
- * Copyright 2002-2010 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.io.NotSerializableException;
- import java.io.ObjectStreamException;
- import java.io.Serializable;
- import java.lang.annotation.Annotation;
- import java.lang.ref.Reference;
- import java.lang.ref.WeakReference;
- import java.lang.reflect.ParameterizedType;
- import java.lang.reflect.Type;
- import java.security.AccessController;
- import java.security.PrivilegedAction;
- import java.util.ArrayList;
- import java.util.Arrays;
- import java.util.Collection;
- import java.util.HashMap;
- import java.util.LinkedHashMap;
- import java.util.LinkedHashSet;
- import java.util.List;
- import java.util.Map;
- import java.util.Set;
- import java.util.concurrent.ConcurrentHashMap;
- import javax.inject.Provider;
- import org.springframework.beans.BeansException;
- import org.springframework.beans.FatalBeanException;
- import org.springframework.beans.TypeConverter;
- 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.BeanFactoryAware;
- 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.ObjectFactory;
- import org.springframework.beans.factory.SmartFactoryBean;
- import org.springframework.beans.factory.config.BeanDefinition;
- import org.springframework.beans.factory.config.BeanDefinitionHolder;
- import org.springframework.beans.factory.config.ConfigurableBeanFactory;
- import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
- import org.springframework.beans.factory.config.DependencyDescriptor;
- import org.springframework.core.annotation.AnnotationUtils;
- 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.
- *
- * <p>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.
- *
- * <p>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}.
- *
- * <p>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
- * @author Sam Brannen
- * @author Costin Leau
- * @since 16 April 2001
- * @see StaticListableBeanFactory
- * @see PropertiesBeanDefinitionReader
- * @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader
- */
- publicclass DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
- implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
- privatestatic Class javaxInjectProviderClass = null;
- static {
- ClassLoader cl = DefaultListableBeanFactory.class.getClassLoader();
- try {
- javaxInjectProviderClass = cl.loadClass("javax.inject.Provider");
- }
- catch (ClassNotFoundException ex) {
- // JSR-330 API not available - Provider interface simply not supported then.
- }
- }
- /** Map from serialized id to factory instance */
- privatestaticfinal Map<String, Reference<DefaultListableBeanFactory>> serializableFactories =
- new ConcurrentHashMap<String, Reference<DefaultListableBeanFactory>>();
- /** Optional id for this factory, for serialization purposes */
- private String serializationId;
- /** Whether to allow re-registration of a different definition with the same name */
- privateboolean allowBeanDefinitionOverriding = true;
- /** Whether to allow eager class loading even for lazy-init beans */
- privateboolean allowEagerClassLoading = true;
- /** Resolver to use for checking if a bean definition is an autowire candidate */
- private AutowireCandidateResolver autowireCandidateResolver = new SimpleAutowireCandidateResolver();
- /** Map from dependency type to corresponding autowired value */
- privatefinal Map<Class, Object> resolvableDependencies = new HashMap<Class, Object>();
- /** Map of bean definition objects, keyed by bean name */
- privatefinal Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>();
- /** List of bean definition names, in registration order */
- privatefinal List<String> beanDefinitionNames = new ArrayList<String>();
- /** Whether bean definition metadata may be cached for all beans */
- privateboolean configurationFrozen = false;
- /** Cached array of bean definition names in case of frozen configuration */
- private String[] frozenBeanDefinitionNames;
- }
註明下,這裡我省略了下面N多行原始碼,原始碼太長,而且太多的話容易混亂,切勿認為此類就這麼多了。
看它名字就知道,這是一個預設的bean工廠實現類,也就是說,如果你需要的功能非常單一,這個實現類已經足夠可以滿足你了,而以後如果你想要對spring的容器擴充套件,那麼只需要擴充套件或者持有這個物件即可。
- /** Map of bean definition objects, keyed by bean name */
- final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>();
看到這一行,其實已經證明了我們的猜測,即使英文不太好,也能看懂它所註釋的意思是bean定義的MAP物件,採用beanName作為key值。
走到這裡,思路已經很明確了,bean工廠的初始化其實就是往這個Map裡填充東西。只要把我們XML檔案中定義的bean都填充到這裡,其實這個工廠就已經可以工作了。
那麼從現在來看,我們需要什麼才能把Map填充呢?也就是初始化bean工廠呢,或者說建立IOC容器。我首先列出來以下幾步。
1.需要一個File指向我們的XML檔案(本文的配置檔案都已XML為例,因為這是我們最熟悉的),專業點可以叫資源定位,簡單點可以說我們需要一些工具來完成找到XML檔案的所在位置。
2.需要一個Reader來讀取我們的XML檔案,專業點叫DOM解析,簡單點說,就是把XML檔案的各種定義都給拿出來。
3.需要將讀出來的資料都設定到Map當中。
這三部總結起來就是定位、解析、註冊。我們首先按照這個思路來試一下