在学习源代码和看了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);
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方法,完成最终的注册.