2. spring中IOC的实现源码篇【analyze spring framework source】
2B青年欢乐多啊,最近研究spring源码,做点笔记,欢迎继续补充, 持续更新
接上一篇 1. Introduce how to import the Spring Framework sourcecode into an eclipse project
一. 结构
spring中bean管理设计到下面3个包
core 相当于一个工具类,bean包是对IOC的实现包,context是在bean的基础扩展功能
IOC的实现原理简介
简单实现
package org.benson; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; import org.springframework.core.io.ClassPathResource; public class Test4DebugSpringIOC { ConfigurableListableBeanFactory beanFactory = new DefaultListableBeanFactory();//manage bean factory ClassPathResource resource = new ClassPathResource( "applicationContext.xml");//resource XmlBeanDefinitionReader xmlReader=new XmlBeanDefinitionReader((BeanDefinitionRegistry)beanFactory); //register public Test4DebugSpringIOC() { // TODO load and registered BeanDefinition xmlReader.loadBeanDefinitions(resource); } public static void main(String[] args) { Test4DebugSpringIOC test4DebugSpring= new Test4DebugSpringIOC(); Test4DebugSpringBean test4DebugSpringBean = (Test4DebugSpringBean) test4DebugSpring.beanFactory .getBean("testAlias"); test4DebugSpringBean.SayHolle(); } }
1,找到bean的定义文件(Resource)
如此处classPathResource,用于找到文件位置
2,把定义文件解析成BeanDefinition对象并进行注册,在XmlBeanDefinitionReader中
int validationMode = getValidationModeForResource(resource);//Validation xml file . XmlBeanDefinitionReader doLoadBeanDefinitions Document doc = this.documentLoader.loadDocument( inputSource, getEntityResolver(), this.errorHandler, validationMode, isNamespaceAware());//parse to doc . through documentLoader(DefaultDocumentLoader) return registerBeanDefinitions(doc, resource);
一个普通bean的解析step
i 调用DefaultDocumentLoader把XML解析成DOC并进行XSD,DTD等格式验证.
DefaultDocumentLoader调用了SAX的DocumentBuilderFactory.newInstance(),把XML文件解析成一个org.w3c.dom.Document对象(标准的DOM解析方式),当然也设置XML验证的validationMode,namespace
/** * Load the {@link Document} at the supplied {@link InputSource} using the standard JAXP-configured * XML parser. */ public Document loadDocument(InputSource inputSource, EntityResolver entityResolver, ErrorHandler errorHandler, int validationMode, boolean namespaceAware) throws Exception { DocumentBuilderFactory factory = createDocumentBuilderFactory(validationMode, namespaceAware); if (logger.isDebugEnabled()) { logger.debug("Using JAXP provider [" + factory.getClass().getName() + "]"); } DocumentBuilder builder = createDocumentBuilder(factory, entityResolver, errorHandler); return builder.parse(inputSource); }
ii DefaultBeanDefinitionDocumentReader读取document中的所有Element.
registerBeanDefinitions(doc, resource)中调用BeanDefinitionDocumentReader的registerBeanDefinitions方法获根节点
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) { this.readerContext = readerContext; logger.debug("Loading bean definitions"); Element root = doc.getDocumentElement(); doRegisterBeanDefinitions(root); }
得到XML的根节点,调用doRegisterBeanDefinitions
/** * Register each bean definition within the given root {@code <beans/>} element. * @throws IllegalStateException if {@code <beans profile="..."} attribute is present * and Environment property has not been set * @see #setEnvironment */ protected void doRegisterBeanDefinitions(Element root) { ..//profile // any nested <beans> elements will cause recursion in this method. In // order to propagate and preserve <beans> default-* attributes correctly, // keep track of the current (parent) delegate, which may be null. Create // the new (child) delegate with a reference to the parent for fallback purposes, // then ultimately reset this.delegate back to its original (parent) reference. // this behavior emulates a stack of delegates without actually necessitating one. BeanDefinitionParserDelegate parent = this.delegate; this.delegate = createHelper(readerContext, root, parent); preProcessXml(root); parseBeanDefinitions(root, this.delegate); postProcessXml(root); this.delegate = parent; }
然后从获得根结点的所有子节点,进行循环
/** * Parse the elements at the root level in the document: * "import", "alias", "bean". * @param root the DOM root element of the document */ protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) { if (delegate.isDefaultNamespace(root)) { 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; if (delegate.isDefaultNamespace(ele)) { parseDefaultElement(ele, delegate);//parse defalut element } else { delegate.parseCustomElement(ele); } } } } else { delegate.parseCustomElement(root); } }
此处isDefaultNamespace方法是获取namespace为http://www.springframework.org/schema/beans的node,目前对应schema定义的包括"bean" "alis" "beans" "import" ,处理方法为parseDefaultElement(ele, delegate),如果发现是bean标签则调用processBeanDefinition方法
/** * Process the given bean element, parsing the bean definition * and registering it with the registry. */ protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) { BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); //parse to object of BeanDefinitionHolder if (bdHolder != null) {//if it is not exit. parse it from xml bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); try { // Register the final decorated instance. BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry()); } catch (BeanDefinitionStoreException ex) { getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, ex); } // Send registration event. getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder)); } }
iii 调用BeanDefinitionParserDelegate对象完成doc中Element->BeanDefinitionHolder的转换
/** * Parses the supplied <code><bean></code> element. May return <code>null</code> * if there were errors during parse. Errors are reported to the * {@link org.springframework.beans.factory.parsing.ProblemReporter}. */ public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) { String id = ele.getAttribute(ID_ATTRIBUTE); String nameAttr = ele.getAttribute(NAME_ATTRIBUTE); ... ... //vacation AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean); .... return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray); }
先获得别名,这里叫nameAttr先转成数组,然后通过BeanDefinitionHolder把它和beanName,beandefine绑定在一起
/** * Parse the bean definition itself, without regard to name or aliases. May return * <code>null</code> if problems occurred during the parsing of the bean definition. */ public AbstractBeanDefinition parseBeanDefinitionElement( Element ele, String beanName, BeanDefinition containingBean) { this.parseState.push(new BeanEntry(beanName)); String className = null; if (ele.hasAttribute(CLASS_ATTRIBUTE)) { className = ele.getAttribute(CLASS_ATTRIBUTE).trim(); } try { String parent = null; if (ele.hasAttribute(PARENT_ATTRIBUTE)) { parent = ele.getAttribute(PARENT_ATTRIBUTE); } AbstractBeanDefinition bd = createBeanDefinition(className, parent); parseBeanDefinitionAttributes(ele, beanName, containingBean, bd); bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT)); parseMetaElements(ele, bd); parseLookupOverrideSubElements(ele, bd.getMethodOverrides()); parseReplacedMethodSubElements(ele, bd.getMethodOverrides()); parseConstructorArgElements(ele, bd); parsePropertyElements(ele, bd); parseQualifierElements(ele, bd); bd.setResource(this.readerContext.getResource()); bd.setSource(extractSource(ele)); return bd; }
全部当成属性设置到了AbstractBeanDefinition 的对象中,具体可以看AbstractBeanDefinition 类
最后返回BeanDefinitionHolder;BeanDefinitionHolder是由beanname+aliasArray+beandefinition组成的一个对象
IV 然后回到ii的最后调用BeanDefinitionReaderUtils.registerBeanDefinition注册beandefine对象,并调BeanDefinitionRegistry接口进行注册,如DefaultListableBeanFactory
完成转换后,BeanDefinitionReaderUtils.registerBeanDefinition 调用到 BeanDefinitionRegistry接口实现类的registerBeanDefinition方法把对象放入bean的工厂容器中
* Register the given bean definition with the given bean factory. * @param definitionHolder the bean definition including name and aliases * @param registry the bean factory to register with * @throws BeanDefinitionStoreException if registration failed */ public static void registerBeanDefinition( BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException { // Register bean definition under primary name. String beanName = definitionHolder.getBeanName(); registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition()); // Register aliases for bean name, if any. String[] aliases = definitionHolder.getAliases(); if (aliases != null) { for (String aliase : aliases) { registry.registerAlias(beanName, aliase); } } }
在DefaultListableBeanFactory的实现也很简单了,直接用map添加下就OK了
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException { ....//Validation this.beanDefinitionMap.put(beanName, beanDefinition);//add it to beanDefinitionMap } resetBeanDefinition(beanName); //reset all exist }
3,查找,通过getbean获得bean,用ConfigurableListableBeanFactory,如DefaultListableBeanFactory
这部分功能主要在abstractbeanfactory中完成,如果是singleton(即spring的default)
i transformedBeanName(name) ,得到SimpleAliasRegistry 的 map 属性 aliasMap,转换为beanname(别名功能)
ii Object sharedInstance = getSingleton(beanName); 尝试从DefaultSingletonBeanRegistry的MAP singletonObjects中拿出bean (singleton功能)
iii bean = getObjectForBeanInstance(sharedInstance, name, beanName, null) 处理factorybean部分,附 Spring FactoryBean源码浅析
iv final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); 从bean注册的信息中找到bean 对应的 BeanDefinition
v return createBean(beanName, mbd, args); 创建新的bean,通过BeanDefinition的描述信息来,并填充到DefaultSingletonBeanRegistry的singletonObjects中
beanfactory的主要代码,加上了些注释
/** * Return an instance, which may be shared or independent, of the specified bean. * @param name the name of the bean to retrieve * @param requiredType the required type of the bean to retrieve * @param args arguments to use if creating a prototype using explicit arguments to a * static factory method. It is invalid to use a non-null args value in any other case. * @param typeCheckOnly whether the instance is obtained for a type check, * not for actual use * @return an instance of the bean * @throws BeansException if the bean could not be created */ @SuppressWarnings("unchecked") protected <T> T doGetBean( final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly) throws BeansException { final String beanName = transformedBeanName(name); //get true name from attribute aliasMap of SimpleAliasRegistry Object bean; // Eagerly check singleton cache for manually registered singletons. Object sharedInstance = getSingleton(beanName); //get instance object from the attribute singletonObjects of DefaultSingletonBeanRegistry if (sharedInstance != null && args == null) { if (logger.isDebugEnabled()) { if (isSingletonCurrentlyInCreation(beanName)) { logger.debug("Returning eagerly cached instance of singleton bean '" + beanName + "' that is not fully initialized yet - a consequence of a circular reference"); } else { logger.debug("Returning cached instance of singleton bean '" + beanName + "'"); } } bean = getObjectForBeanInstance(sharedInstance, name, beanName, null); // it is for that class witch is implement interface factorybean } else { // Fail if we're already creating this bean instance: // We're assumably within a circular reference. if (isPrototypeCurrentlyInCreation(beanName)) { throw new BeanCurrentlyInCreationException(beanName); } // Check if bean definition exists in this factory. BeanFactory parentBeanFactory = getParentBeanFactory(); if (parentBeanFactory != null && !containsBeanDefinition(beanName)) { // Not found -> check parent. String nameToLookup = originalBeanName(name); if (args != null) { // Delegation to parent with explicit args. return (T) parentBeanFactory.getBean(nameToLookup, args); } else { // No args -> delegate to standard getBean method. return parentBeanFactory.getBean(nameToLookup, requiredType); } } if (!typeCheckOnly) { markBeanAsCreated(beanName); } final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);//get BeanDefinition from registered information checkMergedBeanDefinition(mbd, beanName, args); // Guarantee initialization of beans that the current bean depends on. String[] dependsOn = mbd.getDependsOn(); if (dependsOn != null) { for (String dependsOnBean : dependsOn) { getBean(dependsOnBean); registerDependentBean(dependsOnBean, beanName); } } // Create bean instance. if (mbd.isSingleton()) { sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() { //create new instance and put in attribute map singletonObjects of DefaultSingletonBeanRegistry public Object getObject() throws BeansException { try { return createBean(beanName, mbd, args); } catch (BeansException ex) { // Explicitly remove instance from singleton cache: It might have been put there // eagerly by the creation process, to allow for circular reference resolution. // Also remove any beans that received a temporary reference to the bean. destroySingleton(beanName); throw ex; } } }); bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); } else if (mbd.isPrototype()) { // It's a prototype -> create a new instance. Object prototypeInstance = null; try { beforePrototypeCreation(beanName); prototypeInstance = createBean(beanName, mbd, args); } finally { afterPrototypeCreation(beanName); } bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd); } else { String scopeName = mbd.getScope(); final Scope scope = this.scopes.get(scopeName); if (scope == null) { throw new IllegalStateException("No Scope registered for scope '" + scopeName + "'"); } try { Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() { public Object getObject() throws BeansException { beforePrototypeCreation(beanName); try { return createBean(beanName, mbd, args); } finally { afterPrototypeCreation(beanName); } } }); bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd); } catch (IllegalStateException ex) { throw new BeanCreationException(beanName, "Scope '" + scopeName + "' is not active for the current thread; " + "consider defining a scoped proxy for this bean if you intend to refer to it from a singleton", ex); } } } // Check if required type matches the type of the actual bean instance. if (requiredType != null && bean != null && !requiredType.isAssignableFrom(bean.getClass())) { try { return getTypeConverter().convertIfNecessary(bean, requiredType); } catch (TypeMismatchException ex) { if (logger.isDebugEnabled()) { logger.debug("Failed to convert bean '" + name + "' to required type [" + ClassUtils.getQualifiedName(requiredType) + "]", ex); } throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass()); } } return (T) bean; }
附 bean中的主要结构
主要类,下列类从上往下继承
SimpleAliasRegistry 用于维护一个 aliasMap,维护别名功能
DefaultSingletonBeanRegistry map 维护 singletonObjects,维护工厂单例,一个工厂一个单例,非N个工厂一个单例
FactoryBeanRegistrySupport,
AbstractBeanFactory ,factorybean的主要实现类,其doGetBean,getBean是主要获得bean的入口 ,维护一个mergedBeanDefinitions
AbstractAutowireCapableBeanFactory,configureableBeanFactory的主要实现类, createBean根据beandefine的信息创建相应的值
DefaultListableBeanFactory ConfigurableListableBeanFactory和BeanDefinitionRegistry接口的主要实现类,维护beanDefiniti信息
主要接口关系如下
Parse XML主要用到的几个相关类
* @see DocumentLoader
* @see DefaultDocumentLoader
TODO 对SAX几个工厂属性进行设置,schema等,调用SAX对XML转换成了DOC对象
* @see BeanDefinitionDocumentReader
* @see DefaultBeanDefinitionDocumentReader
提供registerBeanDefinitions,和setEnvironment方法,用于DOC到beandefine的注册功能,遍历了doc的所有node,调用 BeanDefinitionParserDelegate解析node,并调用BeanDefinitionReaderUtils对解析的beandefine到beandefine注册类的注册
* @BeanDefinitionParserDelegate
主要解析类,各种属性,对beandefine对象属性的设置都是在此类完成
bean中ConfigurableListableBeanFactory接口继承了bean中的基本接口,DefaultListableBeanFactory是其唯一实现类,也是预留接口供扩展
接口因为可以多继承,所以用来表示系统的结构最合适不过,而JAVA中类单继承的,一般只是用来实现设计,侧重实现功能,因为类层次肯定是一条线。