现在的位置: 首页 > 综合 > 正文

源码学习之BeanFactory

2018年01月31日 ⁄ 综合 ⁄ 共 7064字 ⁄ 字号 评论关闭

在学习源代码和看了http://www.javaeye.com/topic/75171的文章后,决定写一篇更为详细的BeanFactory源码解读

先从我们比较熟悉的用法开始:

ClassPathResource res = new ClassPathResource("config.xml"); 

XmlBeanFactory factory = new XmlBeanFactory(res);

factory.getBean("beanName");

用到了两个类:ClassPathResource和XmlBeanFactory.其中,ClassPathResource是Spring提供的对java.io.InputStream的一系列包装类中的一个,类似的还有FileSystemResource等.

另外的一个类XmlBeanFactory的源码如下:

private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);

public XmlBeanFactory(Resource resource) throws BeansException {

    this(resource, null);

}

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

    super(parentBeanFactory);

    this.reader.loadBeanDefinitions(resource);

}

这里定义了一个成员变量和两个构造方法,仅此而已.

第一个构造方法调用第二个构造方法,在第二个构造方法中,调用了父类的构造方法,并传入参数parentBeanFactory,其最终调用的其实是AbstractBeanFactory的setParentBeanFactory方法,并把参数赋值给该类的成员变量parentBeanFactory.

最重要的一行代码就是最下边的

this.reader.loadBeanDefinitions(resource);

这需要我们先看一下XmlBeanDefinitionReader 类.但在此之前,我想先说明一下XmlBeanFactory的继承关系,包括它继承的基类,实现的接口等,重要的是,我们想弄清楚用BeanFactory的实现类作为Ioc容器时的机制.那么就先从最基本最原始的BeanFactory接口开始吧:

public interface BeanFactory {   

  

    //这里是对FactoryBean的转义定义,因为如果使用bean的名字检索FactoryBean得到的对象是工厂生成的对象,   

    //如果需要得到工厂本身,需要转义          

    String FACTORY_BEAN_PREFIX = "&";   

  

  

    //这里根据bean的名字,在IOC容器中得到bean实例,这个IOC容器就是一个大的抽象工厂。   

    Object getBean(String name) throws BeansException;   

  

    //这里根据bean的名字和Class类型来得到bean实例,和上面的方法不同在于它会抛出异常:如果根据名字取得的bean实例的Class类型和需要的不同的话。   

    Object getBean(String name, Class requiredType) throws BeansException;   

  

    //这里提供对bean的检索,看看是否在IOC容器有这个名字的bean   

    boolean containsBean(String name);   

  

    //这里根据bean名字得到bean实例,并同时判断这个bean是不是单件   

    boolean isSingleton(String name) throws NoSuchBeanDefinitionException;   

  

    //这里对得到bean实例的Class类型   

    Class getType(String name) throws NoSuchBeanDefinitionException;   

  

    //这里得到bean的别名,如果根据别名检索,那么其原名也会被检索出来   

    String[] getAliases(String name);   

  

}

不用多说,此接口提供了最简单的几个方法.在BeanFactory之下,有两个接口直接继承于它,分别是ListableBeanFactory和HierarchicalBeanFactory,前者提供了更多的getXXX型的接口,并且返回类型是数组或者Map.而后者使实现它的BeanFactory可以对parentBeanFactory进行操作.

在这里,我要提及另外一个接口:SingletonBeanRegistry,因为它也像上面的接口一样几乎被所有BeanFactory的实现类所实现.这个接口的主要作用是对singleton类型的bean进行操作,定义了包括getSingleton,containsSingleton等方法.

SingletonBeanRegistry有一个直接子接口ConfigurableBeanFactory,在这个接口中,提供了一些设置BeanFactory的方法.另外SingletonBeanRegistry还有一个默认的实现类,名字叫DefaultSingletonBeanRegistry.

很快的,我们即将说到一个很重要的类了,那就是AbstractBeanFactory,请注意,它是一个虚类,不能直接实例化.AbstractBeanFactory继承于刚才提到的DefaultSingletonBeanRegistry类,并且实现了ConfigurableBeanFactory接口,这个接口也在上一节已经提到了.如果刚才的这些文字没有把您搞晕的话,您应该清楚之所以说它重要,是因为在这个类中,实现了BeanFactory,HierarchicalBeanFactory和ConfigurableBeanFactory这三个接口中的所有方法.当然,它之所以重要,还因为很多BeanFactory要直接或间接的继承于它.

 

如上图所示,AbstractBeanFactory虚类与AutowireCapableBeanFactory接口共同组成了AbstractAutowireCapableBeanFactory这个虚类,其中AutowireCapableBeanFactory接口主要提供了一些用于在自动加载时需要的方法,包括initializeBean这类的方法,此方法的部分代码如下,这样就知道为什么一个bean实现了BeanNameAware接口后,就会在加载时自动调用它的setBeanName方法了

if (bean instanceof BeanNameAware) {

    ((BeanNameAware) bean).setBeanName(beanName);

}



if (bean instanceof BeanClassLoaderAware) {

    ((BeanClassLoaderAware) bean).setBeanClassLoader(getBeanClassLoader());

}



if (bean instanceof BeanFactoryAware) {

    ((BeanFactoryAware) bean).setBeanFactory(this);

}

现在,我们知道了AutowireCapableBeanFactory这个虚类,就像上边类图显示的那样,它也是DefaultListableBeanFactory类的直接基类.而DefaultListableBeanFactory类也是我们见到的第一个可以实例化的类.它还有两个接口要实现,一个是ConfigurableListableBeanFactory,另一个是BeanDefinitionRegistry,前者提供一些罗列的接口,而后者可对BeanDefinition进行一系列操作(BeanDefinition可以看做是对一个Bean的定义,它包含这个Bean的名字,属性等)

DefaultListableBeanFactory这个类已经可以让我们直接使用了,如下:

ClassPathResource res = new ClassPathResource("config.xml");  

DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); 

XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);

reader.loadBeanDefinitions(res);

而最开始用到的XmlBeanFactory只是把一个BeanDefinitionReader封装了起来.

到现在,我们已经把XmlBeanFactory的祖先们浏览了一遍,也许对我们编程并没有什么用处,但起码我们知道了每个接口,每个类的基本功能.那么现在,如果还没有忘记,就可以看看文章开始时说的XmlBeanDefinitionReader.loadBeanDefinitions(Resource resource)方法了.

我们可看到在这个方法里代码就一行,调用了一个同名不同参的方法,而参数是EncodedResource的一个实例,这个类实际上是Resource的一个包装类,用来保存资源的Encode的,那接下来我们再看被调用的loadBeanDefinitions方法,这个方法里最主要的部分就是:

InputSource inputSource = new InputSource(inputStream);

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

    inputSource.setEncoding(encodedResource.getEncoding());

}

return doLoadBeanDefinitions(inputSource, encodedResource.getResource());

这里的目的是将资源包装成一个InputSource,连同Resource作为参数传递到doLoadBeanDefinitions方法,其中InputSource把inputStream和encoding封装在一起.doLoadBeanDefinitions如下:

//组装source成Document对象

Document doc = this.documentLoader.loadDocument(inputSource, this.entityResolver, this.errorHandler, validationMode, aceAware);

//注册Bean定义

return registerBeanDefinitions(doc, resource);

再来看registerBeanDefinitions方法

//建立一个BeanDefinitionDocumentReader对象
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
//注册之前的BeanDefinition数量
int countBefore = getBeanFactory().getBeanDefinitionCount();
//注册!
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));

return getBeanFactory().getBeanDefinitionCount() - countBefore;

到现在,不得不看一下BeanDefinitionDocumentReader类了,这个类实际上负责了BeanDefinition的注册.下面是它的registerBeanDefinitions方法:

Element root = doc.getDocumentElement();

//建立一个BeanDefinitionParserDelegate 实例

BeanDefinitionParserDelegate delegate = createHelper(readerContext, root);

//预留

preProcessXml(root);

//解析Definitions

parseBeanDefinitions(root, delegate);

//预留

postProcessXml(root);
再看parseBeanDefinitions方法:

 

protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {

    if (delegate.isDefaultNamespace(root.getNamespaceURI())) {

        NodeList nl = root.getChildNodes();

        for (int i = 0; i < nl.getLength(); i++) {

            Node node = nl.item(i);

	if (node instanceof Element) {

	    Element ele = (Element) node;

	    String namespaceUri = ele.getNamespaceURI();

	    if (delegate.isDefaultNamespace(namespaceUri)) {

	        parseDefaultElement(ele, delegate);

	    }

	    else {

	        delegate.parseCustomElement(ele);

	    }

	}

        }

    }

    else {

        delegate.parseCustomElement(root);

    }

}

它得到resource的每个节点,并循环调用parseDefaultElement或parseCustomElement方法,进行解析:

if (DomUtils.nodeNameEquals(ele, IMPORT_ELEMENT)) {

    importBeanDefinitionResource(ele);

}

else if (DomUtils.nodeNameEquals(ele, ALIAS_ELEMENT)) {

    processAliasRegistration(ele);

}

else if (DomUtils.nodeNameEquals(ele, BEAN_ELEMENT)) {

    processBeanDefinition(ele, delegate);

}

根据节点类型的不同,调用不同的解析方法,这里看bean的解析方法processBeanDefinition:

//通过传入的delegate得到BeanDefinitionHolder 

BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);

if (bdHolder != null) {

    bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);

    try {

        // Register the final decorated instance.

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

    }

    catch (BeanDefinitionStoreException ex) {

    ......

    }

}

BeanDefinitionReaderUtils的registerBeanDefinition方法最终会调用:

// Register bean definition under primary name.

String beanName = bdHolder.getBeanName();

beanFactory.registerBeanDefinition(beanName, bdHolder.getBeanDefinition());

这样,回到了beanFactory中定义的方法registerBeanDefinition,是在BeanDefinitionRegistry中提供的接口,在DefaultListableBeanFactory类中有它的实现.我们在这个方法中终于可以看到想看到的内容:

this.beanDefinitionMap.put(beanName, beanDefinition);

至此,完成了BeanDefinitions的注册. 这个过程中,DefaultBeanDefinitionDocumentReader包括了注册的过程,BeanDefinitionParserDelegate负责返回一个BeanDefinitionHolder对象,而这个对象持有要注册的definition,它被传入BeanDefinitionReaderUtils的registerBeanDefinition方法,完成最终的注册.

抱歉!评论已关闭.