通过DefaultListableBeanFactory加载.xml配置文件学习Spring-IoC容器注册/加载bean的机制(源码走读)
本文参考了https://my.oschina.net/kaywu123/blog/614325?p={{totalPage}}
首先看看测试源码结构:
就这么简单。一共四个文件,
SimpleMain是项目入口:
SimpleMain.java
package chak; import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; import org.springframework.core.io.ClassPathResource; import java.io.IOException; public class SimpleMain { public static void main(String[] args) throws IOException { ClassPathResource resource = new ClassPathResource("spring-context.xml"); DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory); reader.loadBeanDefinitions(resource); //MyComponent是自己写的测试类 MyComponent component = factory.getBean("myComponent", MyComponent.class); component.method(); } }
MyComponent.java是一个简单的POJO对象,只有一个method()方法打印一串”Hello World”。这里就不列出来了。
logback.xml是日志,方便我们看到运行情况,但是因为我们这里是直接研究源代码,其实要这个日志也没什么用,可以选择无视之。
spring-context.xml是beans的定义文件。是整个spring项目的核心配置文件,虽然在这里它变得异常简单:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd" default-lazy-init="true"> <bean class="chak.MyComponent" name="myComponent"/> </beans>
仅仅定义了一个bean。
很好,这就是我们要准备的所有代码。然后让我们深入spring内部,看看这个麻雀的五脏是如何运转的。
在开始之前,可以先来一句提纲携领的话总结整个过程: 先注册BeanDefinition,再获取Bean。
某种程度上,从这句话里也可以看到ioc的一点影子。大家总说的IoC其实本质上就实现了一个功能,帮我们的应用程序去管理众多的对象(也就是bean),当我们需要用到某一个对象的时候,我们只需要直接跟IoC容器(BeanFactory)拿就可以,而不再关心构造这个bean需要什么依赖。但是为什么IoC可以帮我们去管理bean呢?实际上就是因为我们通过别的手段告诉它要怎样组织一个容器,而这个组织容器的过程,在我们这个简单的Demo里,就是注册BeanDefinition。
好了,我也相信,看完上面那句话你当然还是不清楚Spring的原理,所以下面让我们通过代码来体会这句话到底概括了什么。
SimpleMain.java 中 main()方法第一行:
ClassPathResource resource = new ClassPathResource("spring-context.xml");
利用xml文件名构造了一个ClassPathResource对象,这个资源对象在稍后将作为BeanDefinitionReader解析的根据。
第二行:
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
这里引入了一个关键的对象: DefaultListableBeanFactory。看字面名称,他是一个可枚举(列举)的[Listable],Bean工厂(即IoC容器,Bean容器)[BeanFactory]的默认实现[Default]。而实际上,除了BeanFactory这一支,DefaultListableBeanFactory还有另一条重要的继承线,来自于AliasRegistry实际上主要是BeanDefinitionRegistry。这条线赋予了它可以动态注册BeanDefinition进Factory的功能。
有了构造Factory的接口,自然而然会想到的就是谁来使用它呢?又是怎样使用的呢?
接着看main()方法第三行
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
将上面的factory对象拿去构造了一个XmlBeanDefinitionReader实例,而构造函数实际上是这样的:public XmlBeanDefinitionReader(BeanDefinitionRegistry registry)。也就是说这里只用到了DefaultListableBeanFactory的其中一条继承线上的特性——注册BeanDefinition。
在XmlBeanDefinitionReader的构造方法中,我们传进去了一个BeanDefinitionRegistry(同时也是ioc容器本身)。
具体来说,构造方法是这样的:
XmlBeanDefinitionReader.java
/** * Create new XmlBeanDefinitionReader for the given bean factory. * @param registry the BeanFactory to load bean definitions into, * in the form of a BeanDefinitionRegistry//简而言之,传进来的registry就是最终要承载beanDefinition的容器 */ public XmlBeanDefinitionReader(BeanDefinitionRegistry registry) { super(registry); }
而实际上在实例化过程中做了实事的是父类的构造方法
/** * Create a new AbstractBeanDefinitionReader for the given bean factory. * <p>If the passed-in bean factory does not only implement the BeanDefinitionRegistry * interface but also the ResourceLoader interface, it will be used as default * ResourceLoader as well. This will usually be the case for * {@link org.springframework.context.ApplicationContext} implementations. * <p>If given a plain BeanDefinitionRegistry, the default ResourceLoader will be a * {@link org.springframework.core.io.support.PathMatchingResourcePatternResolver}. * <p>If the passed-in bean factory also implements {@link EnvironmentCapable} its * environment will be used by this reader. Otherwise, the reader will initialize and * use a {@link StandardEnvironment}. All ApplicationContext implementations are * EnvironmentCapable, while normal BeanFactory implementations are not. * @param registry the BeanFactory to load bean definitions into, * in the form of a BeanDefinitionRegistry * @see #setResourceLoader * @see #setEnvironment */ protected AbstractBeanDefinitionReader(BeanDefinitionRegistry registry) { Assert.notNull(registry, "BeanDefinitionRegistry must not be null"); this.registry = registry; // Determine ResourceLoader to use. if (this.registry instanceof ResourceLoader) { this.resourceLoader = (ResourceLoader) this.registry; } else {//没错,从 DefaultListableBeanFactory类图就可以看出, //它并没有继承ResourceLoader接口,所以在這使用 //默认的PathMatchingResourcePatternResolver作为资源装载器 this.resourceLoader = new PathMatchingResourcePatternResolver(); } // Inherit Environment if possible if (this.registry instanceof EnvironmentCapable) { this.environment = ((EnvironmentCapable) this.registry).getEnvironment(); } else {//同样,DefaultListableBeanFactory也没有继承EnvironmentCapable接口, //所以这里也使用默认的StandardEnviroment作为环境 this.environment = new StandardEnvironment(); } }
初始化到這了就完成了,其实就做了两件事:
- 把registry绑定到reader上,作为后续解析出来的beanDefinition的承载器;
- 初始化resourceLoader和enviroment,后续才能从环境中读取Resource
然后就是第四行:
reader.loadBeanDefinitions(resource);
也很容易理解,就是从上面我们定义的”spring-context.xml”资源里,解析出定义bean的BeanDefinition实例,并把它保存到reader所绑定的registry里面。
通过类图,我们可以看到main()方法第四行所调用的loadBeanDeinitions(resource : Resource) : int 方法是在BeanDefinitionReader中定义的基础方法,入参为定义bean的资源,返回成功加载的beanDefinition的数量。 但是在这里,XmlBeanDefinitionReader没有直接在这个方法里实现加载功能,而是通过定义一个doLoadBeanDefinitions(inputSource : InputSource, resource : Resource) : int方法来为所有这些loadBeanDefinitions(Resource/String/Resource…/String…)装载方法服务——其中就有第四行所用的loadBeanDeinitions(resource : Resource) : int
XmlBeanDefinitionReader.java
/*添加一些资源修饰属性,包括此资源的字符集, *编码类型等(虽然在这里最后实际上还是用了默认值) */ @Override public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException { return loadBeanDefinitions(new EncodedResource(resource)); } public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException { Assert.notNull(encodedResource, "EncodedResource must not be null"); if (logger.isInfoEnabled()) { logger.info("Loading XML bean definitions from " + encodedResource.getResource()); } //这里的resourceCurrentlyBeingLoaded是线程变量, //用来记录当前线程正在加载的Resource Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get(); if (currentResources == null) { currentResources = new HashSet<EncodedResource>(4); this.resourcesCurrentlyBeingLoaded.set(currentResources); } if (!currentResources.add(encodedResource)) {//正在加载的Resource中包含当前资源,说明存在循环import throw new BeanDefinitionStoreException( "Detected cyclic loading of " + encodedResource + " - check your import definitions!"); } try { InputStream inputStream = encodedResource.getResource().getInputStream(); try { InputSource inputSource = new InputSource(inputStream); if (encodedResource.getEncoding() != null) { inputSource.setEncoding(encodedResource.getEncoding()); } //这里是将资源传给doLoadBeanDefinitions()进行真正的解析, //但是笔者很好奇为什么要在这里把一个对象拆开为InputSource和Resource, //直接把EncodeResource或者Resource传给下面的方法不就ok了么? //总感觉这里这样的写法不够优雅.有哪位同学如果知道这样设计的原因麻烦告知下(mail:mr_djzhu@163.com) return doLoadBeanDefinitions(inputSource, encodedResource.getResource()); } finally { inputStream.close(); } } catch (IOException ex) { throw new BeanDefinitionStoreException( "IOException parsing XML document from " + encodedResource.getResource(), ex); } finally { currentResources.remove(encodedResource);//加载完成(或者失败)后,从正在加载资源集合中删除当前资源 if (currentResources.isEmpty()) { this.resourcesCurrentlyBeingLoaded.remove(); } } } protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException { try { //正如XmlBeanDefinitionReader名字定义的那样, //这是一个xml解析器(reader),所以固然要把输入的资源解析成可读的org.w3c.dom.Document //但是这里不打算展开如何得到这个Document的过程,要提醒一下的就是这里的解析不仅仅做了解析xml的工作, //还利用DTD或XSD对xml进行了校验.如果有同学深入研究可以注意一下. Document doc = doLoadDocument(inputSource, resource); //有了document,接下来要做的肯定就是读取它的信息并构造注册beanDefinition return registerBeanDefinitions(doc, resource); } catch (BeanDefinitionStoreException ex) { throw ex; } catch (SAXParseException ex) { throw new XmlBeanDefinitionStoreException(resource.getDescription(), "Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex); } catch (SAXException ex) { throw new XmlBeanDefinitionStoreException(resource.getDescription(), "XML document from " + resource + " is invalid", ex); } catch (ParserConfigurationException ex) { throw new BeanDefinitionStoreException(resource.getDescription(), "Parser configuration exception parsing XML from " + resource, ex); } catch (IOException ex) { throw new BeanDefinitionStoreException(resource.getDescription(), "IOException parsing XML document from " + resource, ex); } catch (Throwable ex) { throw new BeanDefinitionStoreException(resource.getDescription(), "Unexpected exception parsing XML document from " + resource, ex); } } public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException { //获取BeanDefinitionDocumentReader,这里要注意一下别绕晕了, //现在这个方法所在类本身是XmlBeanDefinitionDocumentReader, //它是一个可以解析xml文件并注册相关definition的类(他可以解析xml资源文件本身得到Document); //而BeanDefinitionDocumentReader接口只关心如何解析Document,实例化并注册beanDefinition. //从这个角度可以把后者理解成一个简单的工具类. //这里用到的是此接口的默认实现DefaultBeanDefinitionDocumentReader BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader(); //获取当前registry(IoC)容器已注册的BeanDefinition数量,当前第一次调用肯定就是0 int countBefore = getRegistry().getBeanDefinitionCount(); //实例化和注册beanDefinition documentReader.registerBeanDefinitions(doc, createReaderContext(resource)); //获取此次注册新增的beanDefinition数量 return getRegistry().getBeanDefinitionCount() - countBefore; }
然后解析Document的接力棒就传到了DefaultBeanDefinitionDocumentReader手中,继续往下看:
作为一个目的单纯的工具类,DefaultBeanDefinitionDocumentReader仅实现了一个DefinitionDocumentReader接口,这个接口也很只是单纯地定义了一个方法:
BeanDefinitionDocumentReader.java
/** * SPI for parsing an XML document that contains Spring bean definitions. * Used by {@link XmlBeanDefinitionReader} for actually parsing a DOM document. * 实际上解析DOM Document的接口 */ public interface BeanDefinitionDocumentReader { /** * Read bean definitions from the given DOM document and * register them with the registry in the given reader context. * @param doc the DOM document * @param readerContext the current context of the reader * (includes the target registry and the resource being parsed) * @throws BeanDefinitionStoreException in case of parsing errors */ void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) throws BeanDefinitionStoreException; }
DefaultBeanDefinitionDocumentReader.java
@Override public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) { this.readerContext = readerContext; logger.debug("Loading bean definitions"); Element root = doc.getDocumentElement(); doRegisterBeanDefinitions(root); } protected void doRegisterBeanDefinitions(Element root) { // 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. //保留了当前的delegate,实际上在这里就是null BeanDefinitionParserDelegate parent = this.delegate; //创建了一个委托类,由它去解析具体的某一个beanDefinition this.delegate = createDelegate(getReaderContext(), root, parent); //下面的代码主要为<beans>节点的profile属性服务,如果不是<beans>那就跳过此步骤 if (this.delegate.isDefaultNamespace(root)) { String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE); if (StringUtils.hasText(profileSpec)) { String[] specifiedProfiles = StringUtils.tokenizeToStringArray( profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS); if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) { if (logger.isInfoEnabled()) { logger.info("Skipped XML bean definition file due to specified profiles [" + profileSpec + "] not matching: " + getReaderContext().getResource()); } return; } } } preProcessXml(root);//解析前操作,在默认的实现中未做任何事情,如果子类想自定义前置方法,可覆写之 parseBeanDefinitions(root, this.delegate); //实际解析BeanDefinition postProcessXml(root);//解析后操作,在默认的实现中未做任何事情,如果子类想自定义前置方法,可覆写之 //重置delegate(这里其实感觉有点多此一举,因为delegate本身是private变量, //且没有提供任何方法可以set它的值,所以实际上它永远都是null. //如有高人看到了如此设计的深意,请赐教mail:mr_djzhu@163.com) this.delegate = parent; } protected BeanDefinitionParserDelegate createDelegate(XmlReaderContext readerContext, Element root, BeanDefinitionParserDelegate parentDelegate) { //默认的实现选用BeanDefinitionParserDelegate来解析,如果需要自定义的解析器,可覆写此方法 BeanDefinitionParserDelegate delegate = new BeanDefinitionParserDelegate(readerContext); delegate.initDefaults(root, parentDelegate); return delegate; } /** * Parse the elements at the root level in the document: * "import", "alias", "bean". //解析root级别(即beans下来的一级)的元素 * @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; //如果是默认的节点则用parseDefaultElement()进行解析, //默认的节点包括import,alias,bean和嵌套的beans if (delegate.isDefaultNamespace(ele)) { parseDefaultElement(ele, delegate); } else { //如果非默认节点,例如<context:annotation-config>, //则需要用delegate自带的解析方法来解析 delegate.parseCustomElement(ele); } } } } else { delegate.parseCustomElement(root); } }
先来看看默认的节点是怎么解析的:
DefaultBeanDefinitionDocumentReader.java
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) { if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) { importBeanDefinitionResource(ele); } else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) { processAliasRegistration(ele); } //bean节点比较简单,也比较有代表性,下面来详细看看 else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) { processBeanDefinition(ele, delegate); } //嵌套的beans节点,递归调用doRegisterBeanDefinitions()来解析它 else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) { // recurse doRegisterBeanDefinitions(ele); } } /** * Process the given bean element, parsing the bean definition * and registering it with the registry. * //真正到了解析注册的地方,分三步走:1.解析 2.装饰 3.注册 */ protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) { //1.这里终于解析出了一个BeanDefinitionHolder,里面包含了BeanDefinition的全部信息以及一些冗余信息 BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); if (bdHolder != null) { //2.把上面的bdHolder做一层装饰 bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); try { // Register the final decorated instance. //3.将装饰过的bdHolder里面的BeanDefinition注册到registry里 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)); } }
解析注册BeanDefinition的最后三步走,一步一步来看:
第一步,解析:
BeanDefinitionParserDelegate.java /** * Parses the supplied {@code <bean>} element. May return {@code null} * if there were errors during parse. Errors are reported to the * {@link org.springframework.beans.factory.parsing.ProblemReporter}. */ public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) { return parseBeanDefinitionElement(ele, null); } /** * Parses the supplied {@code <bean>} element. May return {@code null} * if there were errors during parse. Errors are reported to the * {@link org.springframework.beans.factory.parsing.ProblemReporter}. */ //containingBean指已存在的BeanDeinition,这里是null public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) { String id = ele.getAttribute(ID_ATTRIBUTE);//获取bean-id String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);//获取bean-name List<String> aliases = new ArrayList<String>(); if (StringUtils.hasLength(nameAttr)) { //如果采用分割别名方式定义的bean-name属性,在这里把所有的别名解析出来 String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS); aliases.addAll(Arrays.asList(nameArr)); } //优先把bean-id属性赋值给beanName,如果没有id则取第一个aliases的值作为beanName String beanName = id; if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) { beanName = aliases.remove(0); if (logger.isDebugEnabled()) { logger.debug("No XML 'id' specified - using '" + beanName + "' as bean name and " + aliases + " as aliases"); } } if (containingBean == null) { ////检查beanName和aliases是否跟当前register中已有的beanName冲突, //如果不冲突则把其名字记录到this.usedNames : HashSet<String>中 checkNameUniqueness(beanName, aliases, ele); } //真正最后解析xml标签内属性的方法就在这里.方法创建了一个Entity用以 //保存从Document解析出来的BeanDefinition属性,具体方法实现比较直接也比较简单枯燥, //这里就点到为止,不再深入这方面的细节.有兴趣的朋友可以自行研究. //总而言之,通过这个方法我们就已经获取了一个BeanDefinition. //尽管它叫Abstract- AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean); if (beanDefinition != null) { //如果<bean>节点没有制定任何id或name属性,下面给他生成一个默认的名字 if (!StringUtils.hasText(beanName)) { try { if (containingBean != null) { beanName = BeanDefinitionReaderUtils.generateBeanName( beanDefinition, this.readerContext.getRegistry(), true); } else { beanName = this.readerContext.generateBeanName(beanDefinition); // Register an alias for the plain bean class name, if still possible, // if the generator returned the class name plus a suffix. // This is expected for Spring 1.2/2.0 backwards compatibility. String beanClassName = beanDefinition.getBeanClassName(); if (beanClassName != null && beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() && !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) { aliases.add(beanClassName); } } if (logger.isDebugEnabled()) { logger.debug("Neither XML 'id' nor 'name' specified - " + "using generated bean name [" + beanName + "]"); } } catch (Exception ex) { error(ex.getMessage(), ele); return null; } } String[] aliasesArray = StringUtils.toStringArray(aliases); //拼装BeanDefinitionHolder对象 return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray); } return null; }
第二步,装饰(省略)
第三步, 注册:
这里又用到了一个工具类:BeanDefinitionReaderUtils,这个类提供了一系列注册dbHolder到registry的静态方法
BeanDefinitionReaderUtils.java
/** * 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,beanDefinition). //如果你还记得前面的代码,应该知道我们这里用到的registry是DefaultListableBeanFactory. //所以下面又要回到DefaultListableBeanFactory的registerBeanDefinition方法 registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition()); // Register aliases for bean name, if any. String[] aliases = definitionHolder.getAliases(); if (aliases != null) { for (String alias : aliases) { registry.registerAlias(beanName, alias); } } }
DefaultListableBeanFactory.java
/** Map of bean definition objects, keyed by bean name */ private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>(256); //--------------------------------------------------------------------- // Implementation of BeanDefinitionRegistry interface //--------------------------------------------------------------------- @Override 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 ex) { throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Validation of bean definition failed", ex); } } BeanDefinition oldBeanDefinition; //先看看map中有没有同名beanDefinition oldBeanDefinition = this.beanDefinitionMap.get(beanName); if (oldBeanDefinition != null) { if (!isAllowBeanDefinitionOverriding()) {//不允许overriding beanDefinition,抛异常 throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName + "': There is already [" + oldBeanDefinition + "] bound."); } //判断新的beanDefinition角色值要小于(才合法)旧的beanDefinition(关于角色,还不大了解) else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) { // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE if (this.logger.isWarnEnabled()) { this.logger.warn("Overriding user-defined bean definition for bean '" + beanName + "' with a framework-generated bean definition: replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]"); } } //在实现equals方法时,会定义怎样的两个实例是相等的.如果两个beanDefinition不相等,则打一段info日志出来 else if (!beanDefinition.equals(oldBeanDefinition)) { if (this.logger.isInfoEnabled()) { this.logger.info("Overriding bean definition for bean '" + beanName + "' with a different definition: replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]"); } } else {//排除完以上所有情况,认为这样的override是正常的,只打了一段debug日志 if (this.logger.isDebugEnabled()) { this.logger.debug("Overriding bean definition for bean '" + beanName + "' with an equivalent definition: replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]"); } } //把beanDefinition扔进map中 this.beanDefinitionMap.put(beanName, beanDefinition); } else {//下面只是一些更细节的操作,本质上就是把beanDefinitino扔进map里,没别的了. if (hasBeanCreationStarted()) { // Cannot modify startup-time collection elements anymore (for stable iteration) synchronized (this.beanDefinitionMap) { this.beanDefinitionMap.put(beanName, beanDefinition); List<String> updatedDefinitions = new ArrayList<String>(this.beanDefinitionNames.size() + 1); updatedDefinitions.addAll(this.beanDefinitionNames); updatedDefinitions.add(beanName); this.beanDefinitionNames = updatedDefinitions; if (this.manualSingletonNames.contains(beanName)) { Set<String> updatedSingletons = new LinkedHashSet<String>(this.manualSingletonNames); updatedSingletons.remove(beanName); this.manualSingletonNames = updatedSingletons; } } } else { // Still in startup registration phase this.beanDefinitionMap.put(beanName, beanDefinition); this.beanDefinitionNames.add(beanName); this.manualSingletonNames.remove(beanName); } this.frozenBeanDefinitionNames = null; } if (oldBeanDefinition != null || containsSingleton(beanName)) { resetBeanDefinition(beanName); } }
至此,注册阶段完成.在registry(即我们这里的DefaultListableBeanFactory)实例中,已经有从xml读取进来的bean定义–beanDefinition
下面开始,main()方法的第五行,从registry中获取bean:
MyComponent component = factory.getBean("myComponent", MyComponent.class); //MyComponent是自己写的测试类
首先看到的是这里调用的方法是由BeanFactory接口定义,AbstractBeanFactory抽象类实现的. 类似实现的方法还有以下几个:
//--------------------------------------------------------------------- // Implementation of BeanFactory interface //--------------------------------------------------------------------- @Override public Object getBean(String name) throws BeansException { return doGetBean(name, null, null, false); } @Override public <T> T getBean(String name, Class<T> requiredType) throws BeansException { return doGetBean(name, requiredType, null, false); } @Override public Object getBean(String name, Object... args) throws BeansException { return doGetBean(name, null, args, false); }
会发现,所有的getBean()方法实现最终都是调用了doGetBean()方法,这里是从BeanFactory获取Bean的入口,也即是依赖注入的入口,所以在这里会涉及到Spring-IoC两种不同的Bean构造模式(单例和原型);防止循环定义Bean的判断;定义并保存bean创建状态等。这里我们撇开细节暂且不看,在我们这个简单的main()方法Demo中,只涉及到对一个简单单例Bean的第一次创建。所以,我们忽略细节,看看一个最普通的
bean是怎样被创建出来的:
AbstractBeanFactory.java
protected <T> T doGetBean( final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly) throws BeansException { //获取beanName final String beanName = transformedBeanName(name); Object bean; // 获取单例实例 Object sharedInstance = getSingleton(beanName); if (sharedInstance != null && args == null) { //省略代码... //通过单例实例sharedInstance获取bean。注意这里有可能是bean本身; //也有可能是通过sharedInstance生成的新的bean实例(当sharedInstance时一个FactoryBean的时候) bean = getObjectForBeanInstance(sharedInstance, name, beanName, null); } else { // Fail if we're already creating this bean instance: // We're assumably within a circular reference. //如果当前目标bean属于正在创建的原型模式的bean,我们认为这是循环定义bean,抛异常 if (isPrototypeCurrentlyInCreation(beanName)) { throw new BeanCurrentlyInCreationException(beanName); } // Check if bean definition exists in this factory. //下面的代码负责判断父beanFactory不为空,且当前factory中没有制定的bean, //则将创建bean的工作委托给父beanFactory 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) { //把beanName写入alreadyCreated : Set<String>标记为已创建 markBeanAsCreated(beanName); } try { //A root bean definition represents the merged bean definition that backs //a specific bean in a Spring BeanFactory at runtime. It might have been //created from multiple original bean definitions that inherit from each other, //typically registered as GenericBeanDefinitions. //A root bean definition is essentially the 'unified' bean definition view at runtime. //以上是javadoc中对RootBeanDefinition的定义:一句话总结就是运行时唯一的beanDefinition。 //因为我们有可能在彼此为继承关系的若干个BeanFactory中注册多个同名的bean, //通过此方法可以对这种情况做一定的处理,此处暂不深入 final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); //检查mbd,在当前类的实现当中只判断了对应的bean指向的类不能为abstract checkMergedBeanDefinition(mbd, beanName, args); // Guarantee initialization of beans that the current bean depends on. String[] dependsOn = mbd.getDependsOn(); if (dependsOn != null) { for (String dep : dependsOn) { //...遍历当前bean,确保所有依赖的bean都被初始化 } } // Create bean instance. if (mbd.isSingleton()) {//单例模式,这是我们重点分析的 sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {//构造一个工厂来生产bean @Override public Object getObject() throws BeansException { try { //实际上最终调用的还是AbstractBeanFactory抽象类中定义的createBean方法 //而当前实现此抽象方法的是AbstractAutowireCapableBeanFactory, //下面接着看AbstractAutowireCapableBeanFactory 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. } else { String scopeName = mbd.getScope(); final Scope scope = this.scopes.get(scopeName); if (scope == null) { throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'"); } try { //省略代码... //当scope既非singleton也非prototype时,做特殊的初始化 } catch (IllegalStateException ex) { //省略代码... } } } catch (BeansException ex) { //创建失败,将beanName从alreadyCreated去除 cleanupAfterBeanCreationFailure(beanName); throw ex; } } }
AbstractAutowireCapableBeanFactory.java
//--------------------------------------------------------------------- // Implementation of relevant AbstractBeanFactory template methods //--------------------------------------------------------------------- /** * Central method of this class: creates a bean instance, * populates the bean instance, applies post-processors, etc. * 创建bean实例,调用后置方法的核心入口 * @see #doCreateBean */ @Override protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException { if (logger.isDebugEnabled()) { logger.debug("Creating instance of bean '" + beanName + "'"); } RootBeanDefinition mbdToUse = mbd; // Make sure bean class is actually resolved at this point, and // clone the bean definition in case of a dynamically resolved Class // which cannot be stored in the shared merged bean definition. Class<?> resolvedClass = resolveBeanClass(mbd, beanName); if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) { mbdToUse = new RootBeanDefinition(mbd); mbdToUse.setBeanClass(resolvedClass); } // Prepare method overrides. //省略代码... //准备和校验方法覆盖 try { // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance. //这里主要判断bean有没有配置前置/后置处理器,如果有,则返回一个代理对象 //resolveBeforeInstantiation的javadoc : Apply before-instantiation post-processors, //resolving whether there is a before-instantiation shortcut for the specified bean. Object bean = resolveBeforeInstantiation(beanName, mbdToUse); if (bean != null) { return bean; } } catch (Throwable ex) { throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName, "BeanPostProcessor before instantiation of bean failed", ex); } //正式创建bean Object beanInstance = doCreateBean(beanName, mbdToUse, args); if (logger.isDebugEnabled()) { logger.debug("Finished creating instance of bean '" + beanName + "'"); } return beanInstance; }
AbstractAutowireCapableBeanFactory.java
/** * Actually create the specified bean. Pre-creation processing has already happened * at this point, e.g. checking {@code postProcessBeforeInstantiation} callbacks. * <p>Differentiates between default bean instantiation, use of a * factory method, and autowiring a constructor. * 正式创建bean实体,Pre-creation已经在上一个方法中被执行了 * 这里只处理通过工厂方法或者构造函数创建bean的情况。 * @param beanName the name of the bean * @param mbd the merged bean definition for the bean * @param args explicit arguments to use for constructor or factory method invocation * @return a new instance of the bean * @throws BeanCreationException if the bean could not be created * @see #instantiateBean * @see #instantiateUsingFactoryMethod * @see #autowireConstructor */ protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) throws BeanCreationException { // Instantiate the bean. BeanWrapper instanceWrapper = null; if (mbd.isSingleton()) { instanceWrapper = this.factoryBeanInstanceCache.remove(beanName); } if (instanceWrapper == null) { //没有任何缓存,在这里创建bean实例 instanceWrapper = createBeanInstance(beanName, mbd, args); } final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null); Class<?> beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null); mbd.resolvedTargetType = beanType; // Allow post-processors to modify the merged bean definition. //post-processors处理,如果有定义的话。我们这里没定义,所以忽略 //忽略代码... // Eagerly cache singletons to be able to resolve circular references // even when triggered by lifecycle interfaces like BeanFactoryAware. //处理循环依赖问题,这里没有这样的情况 //忽略代码... // Initialize the bean instance. //bean实例初始化 Object exposedObject = bean; try { //填充beanDefinition中定义的properties到BeanWrapper中 populateBean(beanName, mbd, instanceWrapper); if (exposedObject != null) { //Initialize the given bean instance, //applying factory callbacks as well as init methods and bean post processors. //调用factory回调方法,调用bean post-processors等。这里暂且忽略 exposedObject = initializeBean(beanName, exposedObject, mbd); } } catch (Throwable ex) { if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex) .getBeanName())) { throw (BeanCreationException) ex; } else { throw new BeanCreationException( mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex); } } //还是循环依赖的问题,代码没跑到这里同样先忽略(这里忽略的东西有点多... 回头得补上) //忽略代码... // Register bean as disposable. //根据不同的scope把创建出来的bean实例放到处理标记为已处理的bean的缓存池。 //比如这里scope=singletons,则把bean放到当前registry的disposableBeans : Map<String:Object>中 try { registerDisposableBeanIfNecessary(beanName, bean, mbd); } catch (BeanDefinitionValidationException ex) { throw new BeanCreationException( mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex); } return exposedObject; }
doCreateBean方法本身非常庞杂,处理了包括创建BeanWrapper,post-processors处理,填充properties,处理循环依赖等问题。但罗马非一日建成,代码也不需要一天看完,我们暂且刨去一些高级的“细枝末节”,只关注创建beanWrapper的核心方法,其实就只有一个:
instanceWrapper = createBeanInstance(beanName, mbd, args);//真实创建beanWrapper的方法
AbstractAutowireCapableBeanFactory.java
/** * Create a new instance for the specified bean, using an appropriate instantiation strategy: * factory method, constructor autowiring, or simple instantiation. * 创建一个bean实例,可用的实例化策略有:factory method,constructor autowiring * 和 simple instantiation. * @param beanName the name of the bean * @param mbd the bean definition for the bean * @param args explicit arguments to use for constructor or factory method invocation * @return BeanWrapper for the new instance * @see #instantiateUsingFactoryMethod * @see #autowireConstructor * @see #instantiateBean */ protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) { // Make sure bean class is actually resolved at this point. //获取bean所定义的类 Class<?> beanClass = resolveBeanClass(mbd, beanName); //首先判断指定的类是public,且有public的构造函数 if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Bean class isn't public, and non-public access not allowed: " + beanClass.getName()); } if (mbd.getFactoryMethodName() != null) { //如果beanDefinition中有定义factoryMethod,则按照工厂策略来创建bean,这里显然不是 return instantiateUsingFactoryMethod(beanName, mbd, args); } // Shortcut when re-creating the same bean... //面对多次创建同一个bean实例,这里会直接通过缓存中的构造方法来创建,这里第一次创建,忽略之... //省略代码... // 当指定构造方法的入参为非空时,需要从一众构造方法中选择一个, //这里我们使用没有入参的默认构造函数,所以也忽略之... Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName); if (ctors != null || mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR || mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) { return autowireConstructor(beanName, mbd, ctors, args); } // No special handling: simply use no-arg constructor. //最后是我们需要的,使用没有传入参数的构造方法 return instantiateBean(beanName, mbd); }
AbstractAutowireCapableBeanFactory.java
/** * Instantiate the given bean using its default constructor. * 使用默认的构造函数创建bean实例 * @param beanName the name of the bean * @param mbd the bean definition for the bean * @return BeanWrapper for the new instance */ protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) { try { Object beanInstance; final BeanFactory parent = this; if (System.getSecurityManager() != null) {//如有必要,做安全校验,这里没有 beanInstance = AccessController.doPrivileged(new PrivilegedAction<Object>() { @Override public Object run() { return getInstantiationStrategy().instantiate(mbd, beanName, parent); } }, getAccessControlContext()); } else { //首先获取了当前registry的实例化策略实例,然后传参进去实例化bean。 //注意当前registry默认使用的策略是new CglibSubclassingInstantiationStrategy(), //而它继承了SimpleInstantiationStrategy类, //实际上我们使用的还是SimpleInstantiationStrategy.instantiate() //只有在我们需要通过cglib创建代理类时(比如aop机制)才会用到前者 //这里继续看后者的instantiate()方法 beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent); } //利用创建出来的纯粹bean实例封装成BeanWrapper。 //可能有同学会好奇,既然有了bean还需要BeanWrapper做什么呢?答案是初始化bean属性。还记得前面的 BeanWrapper bw = new BeanWrapperImpl(beanInstance); initBeanWrapper(bw); return bw; } catch (Throwable ex) { throw new BeanCreationException( mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex); } }
@Override public Object instantiate(RootBeanDefinition bd, String beanName, BeanFactory owner) { // Don't override the class with CGLIB if no overrides. if (bd.getMethodOverrides().isEmpty()) {//没有override方法 //注意这里是java.lang.reflect.Constructor,也就是说控制权到了java底层反射机制手中 Constructor<?> constructorToUse; synchronized (bd.constructorArgumentLock) { constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod; if (constructorToUse == null) { final Class<?> clazz = bd.getBeanClass();//获取BeanDefinition中的Class if (clazz.isInterface()) { //如果class是一个借口,那么没戏了,不能用java默认的反射机制来创建实例 throw new BeanInstantiationException(clazz, "Specified class is an interface"); } try { if (System.getSecurityManager() != null) {//有权限控制,那就判断权限 constructorToUse = AccessController .doPrivileged(new PrivilegedExceptionAction<Constructor<?>>() { @Override public Constructor<?> run() throws Exception { //在这里获取无入参的构造方法 return clazz.getDeclaredConstructor((Class[]) null); } }); } else { //在这里获取无入参的构造方法 constructorToUse = clazz.getDeclaredConstructor((Class[]) null); } //把构造方法写入BeanDefinition的缓存中,以后再实例化这个bean就可以跳过获取构造方法的步骤了 bd.resolvedConstructorOrFactoryMethod = constructorToUse; } catch (Throwable ex) { throw new BeanInstantiationException(clazz, "No default constructor found", ex); } } } //利用构造方法创建实例。实际上BeanUtils.instantiateClass还可以接受入参,它是这样定义的: //public static <T> T instantiateClass(Constructor<T> ctor, Object... args) //这里创建的是空参数的实例 return BeanUtils.instantiateClass(constructorToUse); } else { // Must generate CGLIB subclass. //有override方法,就需要通过可供子类覆写的方法instantiateWithMethodInjection来实例化 //这里子类就是CglibSubclassingInstantiationStrategy return instantiateWithMethodInjection(bd, beanName, owner); } }
再往下深入就是BeanUtils.instantiateClass()方法利用java的反射机制创建实例的过程。本文就不再深入了,到这里。我们就把spring创建bean的过程大致地过了一遍。有了这样的一个框架式的印象,如果我们需要深入了解spring的某一个具体特性,就可以再回到某一个代码的细节处,继续研究。这在稍后的文章中会举一些例子来介绍。
以上。
原文地址:https://my.oschina.net/djzhu/blog/847905
相关推荐
-
SpringBoot整合Kafka和Storm Java框架
2019-6-18
-
从Uber微服务看最佳实践如何炼成? Java框架
2019-3-27
-
在SpringBoot下的pageHelper分页实践 Java框架
2019-8-23
-
博客搭建攻略(三):创造收益 Java框架
2019-3-27
-
Spring Transaction Java框架
2019-8-23
-
SpringBoot使用SOFA-Lookout监控 Java框架
2019-9-9
-
最详细的自定义Spring Boot Starter开发教程 Java框架
2019-8-24
-
Spring Boot 中如何使用拦截器(十五) Java框架
2020-6-1
-
【Netty】Netty之Bootstrapping Java框架
2019-7-3
-
springcloud 中 zuul 权限认证 Java框架
2019-8-20