Spring源码分析系列(一)IOC容器的设计与实现(1)基础容器的实现

        IOC全名Inversion of Control译为控制反转,是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度。其中最常见的方式叫做依赖注入(Dependency Injection,简称DI),还有一种方式叫“依赖查找”(Dependency Lookup)。通过控制反转,对象在被创建的时候,由一个调控系统内所有对象的外界实体将其所依赖的对象的引用传递给它。也可以说,依赖被注入到对象中。写一段最简单的spring启动容器的例子:                                                                                                    

ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");

context.getBean("helloword");

         简单分析这段代码,通过接口ApplicationContext初始化了该结构的实现类,ClassPathXmlAppliction并调用构造方法,传入一个classpath地址去读取。我们以applicationContext为起点,看他上下相关的类。applicationContext接口的最终父类是BeanFactory,他定义了我们IOC容器的基本特征。

1.1

    那么BeanFactory与ApplicaionContext的关系是什么呢?我们可以说BeanFactory是我们定义IOC容器的基础形式,而ApplicationContext则是我们定义容器的高级形式。让我们先从基础IOC开始分析。看图1.2BeanFactory实现的最底层是xmlBeanFactory,仔细读xmlBeanFactory的源码可以看出,xmlBeanFactory是DefaultListableBeanFactory的扩展,在DefaultListableBeanFactory的基础上增加了对xml文件解析的支持。

Spring源码分析系列(一)IOC容器的设计与实现(1)基础容器的实现_第1张图片
1.2

        上xmlBeanFactory源码

    public class XmlBeanFactory extends DefaultListableBeanFactory {

        private final XmlBeanDefinitionReader reader; public XmlBeanFactory(Resource resource) throws BeansException {             this(resource, (BeanFactory)null);

           }

        public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {             super(parentBeanFactory);

            this.reader = new XmlBeanDefinitionReader(this);

            this.reader.loadBeanDefinitions(resource);

        }

}

我们可以看到xmlBeanFactory的构造函数:构造父类,初始化XmlBeanDefinitionReader,执行loadBeanDefinitions。我们将这段代码提炼出来。

ClassPathResource resource = new ClassPathResource("bean.xml");

DefaultListableBeanFactory factory = new DefaultListableBeanFactory();

XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);

reader.loadBeanDefinitions(resource);    

上述代码可以解读为:

(1)Resouce定位发现资源bean的定义资源

(2)bean定义资源的载入

(3)bean定义资源向ioc容器的注册

我们逐步解析代码,首先从XmlBeanDefinitionReader 的初始化开始,加载Resource路径下的文件并转化为流

    public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException { Assert.notNull(encodedResource, "EncodedResource must not be null");

if (this.logger.isTraceEnabled()) {

this.logger.trace("Loading XML bean definitions from " + encodedResource);

}

Set currentResources = (Set)this.resourcesCurrentlyBeingLoaded.get();

if (currentResources == null) {

currentResources = new HashSet(4);

this.resourcesCurrentlyBeingLoaded.set(currentResources);

}

if (!((Set)currentResources).add(encodedResource)) {

throw new BeanDefinitionStoreException("Detected cyclic loading of " + encodedResource + " - check your import definitions!");

} else {

int var5;

try {InputStream inputStream = encodedResource.getResource().getInputStream();

try { InputSource inputSource = new InputSource(inputStream);

if (encodedResource.getEncoding() != null) {

inputSource.setEncoding(encodedResource.getEncoding());

}

var5 = this.doLoadBeanDefinitions(inputSource, encodedResource.getResource());

} finally { inputStream.close();    

}}

catch (IOException var15) {

throw new BeanDefinitionStoreException("IOException parsing XML document from " + encodedResource.getResource(), var15);

}finally {

((Set)currentResources).remove(encodedResource);

if (((Set)currentResources).isEmpty()) {

this.resourcesCurrentlyBeingLoaded.remove();

}}return var5;

}}   

转流后通过调用doLoadBeanDefinitions方法取得xml文件的Document对象,然后开始进行详细的解析过程这个解析过程在DefaultBeanDefinitionDocumentReader.registerBeanDefinitions中完成。

protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException { 

Document doc = this.doLoadDocument(inputSource, resource);

int count = this.registerBeanDefinitions(doc, resource);

if (this.logger.isDebugEnabled()) {

this.logger.debug("Loaded " + count + " bean definitions from " + resource);

} return count;

}

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {

BeanDefinitionDocumentReader documentReader = this.createBeanDefinitionDocumentReader();

int countBefore = this.getRegistry().getBeanDefinitionCount();

documentReader.registerBeanDefinitions(doc, this.createReaderContext(resource));

return this.getRegistry().getBeanDefinitionCount() - countBefore;

}

        关于xml节点的详细解析我们这里就不做一一列举了,主要看bean,bean的解析主要在processBeanDefinition方法中,这里定义了一个BeanDefinitionHolder 对象用来完成对IOC容器的注册,BeanDefinitionHolder本质上是 BeanDefinition的封装类,通过decorateBeanDefinitionIfRequired返回的对象完成BeanDefinitionHolder类的构造。

public BeanDefinitionHolder(BeanDefinitionHolder beanDefinitionHolder) {

Assert.notNull(beanDefinitionHolder, "BeanDefinitionHolder must not be null");

this.beanDefinition = beanDefinitionHolder.getBeanDefinition();

this.beanName = beanDefinitionHolder.getBeanName();

this.aliases = beanDefinitionHolder.getAliases();

}

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {

BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);

if (bdHolder != null) {

bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);

try {

BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, this.getReaderContext().getRegistry());

} catch (BeanDefinitionStoreException var5) {

this.getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, var5);

}

this.getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));

}}


最终通过BeanDefinitionReaderUtils.registerBeanDefinition方法,开始注册,这里注册会根据不同的IOC容器来选择到底在哪里进行注册。我们是从DefaultListableBeanFactory文件初始化过来的,所以我们选它。


看registerBeanDefinition的实现代码,通过一系列的判断校验等,最终会将传进来的BeanName及初始Bean放入到一个

Map beanDefinitionMap =new ConcurrentHashMap(256);的map结构中。

public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException { Assert.hasText(beanName, "Bean name must not be empty");

Assert.notNull(beanDefinition, "BeanDefinition must not be null");

if (beanDefinition instanceof AbstractBeanDefinition) {

try{

((AbstractBeanDefinition)beanDefinition).validate();

} catch (BeanDefinitionValidationException var8) {

throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Validation of bean definition failed", var8);

} }

BeanDefinition existingDefinition = (BeanDefinition)this.beanDefinitionMap.get(beanName);

if (existingDefinition != null) {

if (!this.isAllowBeanDefinitionOverriding()) {

throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);

}

if (existingDefinition.getRole() < beanDefinition.getRole()) {

if (this.logger.isInfoEnabled()) {

this.logger.info("Overriding user-defined bean definition for bean '" + beanName + "' with a framework-generated bean definition: replacing [" + existingDefinition + "] with [" + beanDefinition + "]");

} } else if (!beanDefinition.equals(existingDefinition)) {

if (this.logger.isDebugEnabled()) {

this.logger.debug("Overriding bean definition for bean '" + beanName + "' with a different definition: replacing [" + existingDefinition + "] with [" + beanDefinition + "]");

} } else if (this.logger.isTraceEnabled()) {

this.logger.trace("Overriding bean definition for bean '" + beanName + "' with an equivalent definition: replacing [" + existingDefinition + "] with [" + beanDefinition + "]");

} this.beanDefinitionMap.put(beanName, beanDefinition);

} else {

if (this.hasBeanCreationStarted()) {

synchronized(this.beanDefinitionMap) {

this.beanDefinitionMap.put(beanName, beanDefinition);

List updatedDefinitions = new ArrayList(this.beanDefinitionNames.size() + 1); updatedDefinitions.addAll(this.beanDefinitionNames);

updatedDefinitions.add(beanName);

this.beanDefinitionNames = updatedDefinitions;

this.removeManualSingletonName(beanName);

} } else { this.beanDefinitionMap.put(beanName, beanDefinition);

this.beanDefinitionNames.add(beanName);

this.removeManualSingletonName(beanName);

} this.frozenBeanDefinitionNames = null;

} if (existingDefinition != null || this.containsSingleton(beanName)) {

this.resetBeanDefinition(beanName);

}}

初始bean我们已经完成注入了,接下来我们将在IOC容器中建立依赖关系。首先我们通过getBean方法去向容器索要Bean,这里我们调用DefaultListableBeanFactory中的getBean。

ClassPathResource resource =new ClassPathResource("bean.xml");

DefaultListableBeanFactory factory =new DefaultListableBeanFactory();

XmlBeanDefinitionReader reader =new XmlBeanDefinitionReader(factory);

reader.loadBeanDefinitions(resource);

factory.getBean("helloword");

        由于我们前文中在DefaultListableBeanFactory先执行了初始化,我们通过super()逐层向上抛,完成AbstractAutowire CapableBeanFactory、AbstractBeanFactory、BeanFactory等类的初始化。此时我们在DefaultListableBeanFactory中调用getBean,先会在父类AbstractBeanFactory中执行。等待一系列判断验重后调用createBean方法跳转到子类AbstractAutowireCapableBeanFactory中。


在执行createBean时,也需要判断传入BeanName是否可以实例化,是否可以反射等。最后通过校验调用doCreateBean,我们会初始化一个BeanWrapper 对象,这是我们真正的Bean的数据结构然后校验出多种情况进行处理。

protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)throws BeanCreationException {

BeanWrapper instanceWrapper =null;

    if (mbd.isSingleton()) {

instanceWrapper = (BeanWrapper)this.factoryBeanInstanceCache.remove(beanName);

    }

if (instanceWrapper ==null) {

instanceWrapper =this.createBeanInstance(beanName, mbd, args);

    }

Object bean = instanceWrapper.getWrappedInstance();

    Class beanType = instanceWrapper.getWrappedClass();

    if (beanType != NullBean.class) {

mbd.resolvedTargetType = beanType;

    }

synchronized(mbd.postProcessingLock) {

if (!mbd.postProcessed) {

try {

this.applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);

            }catch (Throwable var17) {

throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Post-processing of merged bean definition failed", var17);

            }

mbd.postProcessed =true;

        }

}

boolean earlySingletonExposure = mbd.isSingleton() &&this.allowCircularReferences &&this.isSingletonCurrentlyInCreation(beanName);

    if (earlySingletonExposure) {

if (this.logger.isTraceEnabled()) {

this.logger.trace("Eagerly caching bean '" + beanName +"' to allow for resolving potential circular references");

        }

this.addSingletonFactory(beanName, () -> {

return this.getEarlyBeanReference(beanName, mbd, bean);

        });

    }

Object exposedObject = bean;

    try {

this.populateBean(beanName, mbd, instanceWrapper);

        exposedObject =this.initializeBean(beanName, exposedObject, mbd);

    }catch (Throwable var18) {

if (var18instanceof BeanCreationException && beanName.equals(((BeanCreationException)var18).getBeanName())) {

throw (BeanCreationException)var18;

        }

throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", var18);

    }

if (earlySingletonExposure) {

Object earlySingletonReference =this.getSingleton(beanName, false);

        if (earlySingletonReference !=null) {

if (exposedObject == bean) {

exposedObject = earlySingletonReference;

            }else if (!this.allowRawInjectionDespiteWrapping &&this.hasDependentBean(beanName)) {

String[] dependentBeans =this.getDependentBeans(beanName);

                Set actualDependentBeans =new LinkedHashSet(dependentBeans.length);

                String[] var12 = dependentBeans;

                int var13 = dependentBeans.length;

                for(int var14 =0; var14 < var13; ++var14) {

String dependentBean = var12[var14];

                    if (!this.removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {

actualDependentBeans.add(dependentBean);

                    }

}

if (!actualDependentBeans.isEmpty()) {

throw new BeanCurrentlyInCreationException(beanName, "Bean with name '" + beanName +"' has been injected into other beans [" + StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +"] in its raw version as part of a circular reference, but has eventually been wrapped. This means that said other beans do not use the final version of the bean. This is often the result of over-eager type matching - consider using 'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");

                }

}

}

}

try {

this.registerDisposableBeanIfNecessary(beanName, bean, mbd);

        return exposedObject;

    }catch (BeanDefinitionValidationException var16) {

throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid destruction signature", var16);

    }

}

这样就完成了我们对bean属性的依赖注入过程,最终我们那些具有依赖关系的Bean都会放在一个ConcurrentMap map = currentHashMap();中。

一个最基础的IOC容器完成了依赖注入。



搞了个技术交流群,不定期的分享技术、划水、接私活什么的。大家有兴趣可以加下这是审核人的微信。


你可能感兴趣的:(Spring源码分析系列(一)IOC容器的设计与实现(1)基础容器的实现)