spring container 实现分析:BeanFactory and ApplicationContext
简介
在之前的文章里,我们讨论过作为spring IOC容器实现里最底层的一部分:BeanWrapper。那里,我们主要了解如何从获取的元数据里来构造一个bean对象的过程。当然,从更广阔的角度来看,这个容器框架里需要的是能够构建一个bean对象的容器,我们可以通过它来方便的获取所需要的bean对象,而不是仅仅单独设置好的某一个对象。在spring框架里,要构造这么一个容器,就需要BeanFactory, ApplicationContext等一系列类的合作。在这里,我们结合它们的实现细节来分析探讨一下它的设计思想。
示例
在讨论它们的具体实现之前,我们先看一个示例。
首先,我们定义一个传统的工程,里面有对spring相关的依赖pom.xml:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.yunzero</groupId> <artifactId>springSample</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>springSample</name> <url>http://maven.apache.org</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <java-version>1.8</java-version> <log4j.version>2.10.0</log4j.version> <spring.version>5.0.6.RELEASE</spring.version> </properties> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-api</artifactId> <version>${log4j.version}</version> <scope>compile</scope> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>${log4j.version}</version> <scope>runtime</scope> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> </dependencies> <build> <finalName>${project.artifactId}-${project.version}</finalName> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.7.0</version> <configuration> <source>${java-version}</source> <target>${java-version}</target> </configuration> </plugin> </plugins> </build> </project>
然后我们定义一个类HelloWorld:
package com.yunzero; public class HelloWorld { private String name; public void setName(String name) { this.name = name; } public void printHello() { System.out.println("Spring 5 : Hello ! " + name); } }
非常简单的一个类。然后再定义相关的xml配置文件applicationContext.xml:
<?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.xsd"> <bean id="helloBean" class="com.yunzero.HelloWorld"> <property name="name" value="frank"/> </bean> </beans>
这里定义了需要设置的bean和它被注入的值。接下来就是一个运行的代码:
package com.yunzero; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class App { public static void main( String[] args ) { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); HelloWorld obj = context.getBean(HelloWorld.class); obj.printHello(); } }
运行程序的话,结果很简单,将输出如下的内容:
Spring 5 : Hello ! frank
我们都知道,程序之所以能够输出如下的结果,是因为在前面的配置文件里,我们设置了HelloWorld对象的name属性为frank。从一个实现者的角度来看的话,我们可以做一些简单的推测。因为在前面的xml文件里定义了<bean>的元素,它的id是helloBean,类型是com.yunzero.HelloWorld。所以,在后面的程序里,我们可以使用applicationContext.getBean方法获取到这个对象。在框架的内部,这个对象的构造肯定包含有解析配置文件,构建bean对象关系图等这么几个步骤。
而从后面的一些分析来看,我们可以确定,就是ApplicationContext这个类及相关的子类提供了一个运行时的环境用来保存相关的对象。
ApplicationContext
虽然我们在之前的一些材料里已经了解到,spring IOC容器的实现包含有3个层面的实现,从下到上是BeanWrapper, BeanFactory和ApplicationContext。我们这里先结合示例代码的使用情况来跟踪分析。既然前面提到过ApplicationContext能够提供对象的运行时环境,我们就看看它的详细实现代码。我们先来看一下spring里ApplicationContext相关的类结构:
这里的类结构非常庞大,我们在讨论到相关的部分的时候会一一看过来。虽然这里没有画出来ClassPathXmlApplicationContext类来,实际上它是继承了类AbstractXmlApplicationContext。现在我们先看看代码里new ClassPathXmlApplicationContext("applicationContext.xml")的实现:
public ClassPathXmlApplicationContext(String configLocation) throws BeansException { this(new String[] {configLocation}, true, null); } public ClassPathXmlApplicationContext( String[] configLocations, boolean refresh, @Nullable ApplicationContext parent) throws BeansException { super(parent); setConfigLocations(configLocations); if (refresh) { refresh(); } }
可见,前面我们调用的ClassPathXmlApplicationContext的构造函数本质上还是调用了一个统一的构造函数方法。里面还有若干个构造函数,也是代理使用了这同一个方法。
在这个方法里,它的实现主要集中在refresh方法里。前面的setConfigLocations方法只是将我们提供的String参数设置到声明的成员变量。我们重点看看refresh方法的实现。它的实现是在类AbstractApplicationContext里:
public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // Prepare this context for refreshing. prepareRefresh(); // Tell the subclass to refresh the internal bean factory. ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context. prepareBeanFactory(beanFactory); try { // Allows post-processing of the bean factory in context subclasses. postProcessBeanFactory(beanFactory); // Invoke factory processors registered as beans in the context. invokeBeanFactoryPostProcessors(beanFactory); // Register bean processors that intercept bean creation. registerBeanPostProcessors(beanFactory); // Initialize message source for this context. initMessageSource(); // Initialize event multicaster for this context. initApplicationEventMulticaster(); // Initialize other special beans in specific context subclasses. onRefresh(); // Check for listener beans and register them. registerListeners(); // Instantiate all remaining (non-lazy-init) singletons. finishBeanFactoryInitialization(beanFactory); // Last step: publish corresponding event. finishRefresh(); } catch (BeansException ex) { if (logger.isWarnEnabled()) { logger.warn("Exception encountered during context initialization - " + "cancelling refresh attempt: " + ex); } // Destroy already created singletons to avoid dangling resources. destroyBeans(); // Reset 'active' flag. cancelRefresh(ex); // Propagate exception to caller. throw ex; } finally { // Reset common introspection caches in Spring's core, since we // might not ever need metadata for singleton beans anymore... resetCommonCaches(); } } }
这个方法的实现可以说是整个容器实现的最核心部分。我们针对详细的细节一一看过来。
第2行代码使用了对象锁,将整段代码的逻辑给加锁,保证在同一个时刻,只有获取到该对象锁的线程才能执行上述的逻辑,这样可以避免在多线程执行的情况带来的混乱。
第4行的prepareRefresh方法的实现如下:
protected void prepareRefresh() { this.startupDate = System.currentTimeMillis(); this.closed.set(false); this.active.set(true); if (logger.isInfoEnabled()) { logger.info("Refreshing " + this); } // Initialize any placeholder property sources in the context environment initPropertySources(); // Validate that all properties marked as required are resolvable // see ConfigurablePropertyResolver#setRequiredProperties getEnvironment().validateRequiredProperties(); // Allow for the collection of early ApplicationEvents, // to be published once the multicaster is available... this.earlyApplicationEvents = new LinkedHashSet<>(); }
这个方法的实现细节其实很简单,就是设置一些初始化的状态标记,比如closed, active等。而其中的initPropertySource方法的实现就是一个空的,具体的实现取决于后续的继承类的需要。而通过getEnvironment方法验证当前需要的property文件是否可以解析。所以,整体来说,这个方法就相当于是一个准备工作。
在前面refresh方法里的第7行,obtainFreshBeanFactory返回一个ConfigurableListableBeanFactory。这个类是系统里面提供的一个默认的BeanFactory的实现,我们在后面会详细的讨论。这个方法的实现细节如下:
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() { refreshBeanFactory(); ConfigurableListableBeanFactory beanFactory = getBeanFactory(); if (logger.isDebugEnabled()) { logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory); } return beanFactory; }
其中refreshBeanFactory的实现在类AbstractRefreshableApplicationContext里:
protected final void refreshBeanFactory() throws BeansException { if (hasBeanFactory()) { destroyBeans(); closeBeanFactory(); } try { DefaultListableBeanFactory beanFactory = createBeanFactory(); beanFactory.setSerializationId(getId()); customizeBeanFactory(beanFactory); loadBeanDefinitions(beanFactory); synchronized (this.beanFactoryMonitor) { this.beanFactory = beanFactory; } } catch (IOException ex) { throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex); } }
它首先判断BeanFactory是不是已经存在了,如果有的话,通过destroyBeans和closeBeanFactory来释放这些创建的bean对象以及BeanFactory的空间。它们的实现主要就是通过将指向的BeanFactory对象设置为null,并事先将相关的Bean对象存储空间都清空。
接着在try块里,createBeanFactory的实现则很直接,就是创建了一个DefaultListableBeanFactory:
protected DefaultListableBeanFactory createBeanFactory() { return new DefaultListableBeanFactory(getInternalParentBeanFactory()); }
而customizeBeanFactory主要是设置创建的beanFactory的几个基本属性:
protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) { if (this.allowBeanDefinitionOverriding != null) { beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding); } if (this.allowCircularReferences != null) { beanFactory.setAllowCircularReferences(this.allowCircularReferences); } }
里面还有一个loadBeanDefinitions方法,它本身是一个定义的虚方法,由继承的类来实现。在从ApplicationContext到ClassPathXmlApplicationContext的继承类体系里,AbstractXmlApplicationContext提供了一个针对读取xml文件的实现:
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException { // Create a new XmlBeanDefinitionReader for the given BeanFactory. XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); // Configure the bean definition reader with this context's // resource loading environment. beanDefinitionReader.setEnvironment(this.getEnvironment()); beanDefinitionReader.setResourceLoader(this); beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this)); // Allow a subclass to provide custom initialization of the reader, // then proceed with actually loading the bean definitions. initBeanDefinitionReader(beanDefinitionReader); loadBeanDefinitions(beanDefinitionReader); } protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException { Resource[] configResources = getConfigResources(); if (configResources != null) { reader.loadBeanDefinitions(configResources); } String[] configLocations = getConfigLocations(); if (configLocations != null) { reader.loadBeanDefinitions(configLocations); } }
获取最终的BeanDefinition实际上是通过一个XmlBeanDefinitionReader来实现的。为什么这里要引入BeanDefinition这个概念呢?因为在spring框架里,通过将定义的bean信息抽象成一个BeanDefinition的类型。这样,在前面示例里xml文件里的内容就是在这里被读取和解析的。我们后面也会针对这一块进行进一步的分析。为了讨论上述obtainFreshBeanFactory这个方法的过程,结果要扯出这么多的方法和对象来。总结一下这个方法的过程,其实它们的交互过程如下图:
我们接着看第10行的prepareBeanFactory,它主要是配置beanFactory的classLoader和postProcessor等信息。这部分很简单。
接着是第14行的postProcessBeanFactory,它的默认实现为空,有必要的情况下在一些ApplicationContext的实现里会实现这个方法。
第17行的invokeBeanFactoryPostProcessors通过PostProcessorRegistrationDelegate的invokeBeanFactoryPostProcessors方法来处理beanFactoryPostProcessor。
后面是第20行的registerBeanPostProcessors方法,它是在bean创建的过程中注册processor的。它也是通过PostProcessorRegistrationDelegate的registerBeanPostProcessors来实现的。由于这部分和IOC的设计关系不是很紧密,具体的实现就不详细分析了。
第23行的initMessageSource用来设置它的messageSource变量。这个东西是用来解析消息用的。主要用于消息的国际化,比如同样的消息内容针对不同国家语言的显示。
后面第26行的initApplicationEventMulticaster方法是用来设置ApplicationEvent的组播的。在ApplicationContext里有一个对事件的支持。针对一些特定的事件,我们可以定义相关的listener。它其实就是相当于一个observer pattern的实现,当然,这也是ApplicationContext里的一个特性。默认的情况下这个成员变量会被设置成SimpleApplicationEventMulticaster对象。
接着的第29行的onRefresh方法也是一个空的实现。后续的继承类如果需要的话可以通过覆写它来提供自己特定的实现。
第32行的registerListeners方法主要将一些ApplicationListener注册到applicationEventMulticaster里。并没有什么特殊的。
等到第35行的finishBeanFactoryInitialization方法时,基本上beanFactory初始化的过程就已经差不多了。这个方法主要设置这时候不能再更新bean definition等元数据信息了。
第38行的finishRefresh方法基本上相当于是做一个收尾工作:
protected void finishRefresh() { // Clear context-level resource caches (such as ASM metadata from scanning). clearResourceCaches(); // Initialize lifecycle processor for this context. initLifecycleProcessor(); // Propagate refresh to lifecycle processor first. getLifecycleProcessor().onRefresh(); // Publish the final event. publishEvent(new ContextRefreshedEvent(this)); // Participate in LiveBeansView MBean, if active. LiveBeansView.registerApplicationContext(this); }
从代码里就可以看到,主要就是这么几个步骤,一个是清除一些resource cache。然后初始化一些lifecycleprocessor。因为在初始化的不同阶段对应一些事件通知机制,这里会调用相关的事件触发方法。然后再通过ApplicationEventMulticaster来发布消息。
BeanDefinition & BeanDefinitionReader
在前面的AbstractRefreshableApplicationContext里,我们分析了refreshBeanFactory方法。里面有一个方法的loadBeanDefinitions的实现在这里讨论。那里的loadBeanDefinitions方法的具体实现是在类XmlBeanDefinitionReader里:
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()); } Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get(); if (currentResources == null) { currentResources = new HashSet<>(4); this.resourcesCurrentlyBeingLoaded.set(currentResources); } if (!currentResources.add(encodedResource)) { 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()); } 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(); } } }
上面这部分代码其实还是比较好理解的,它的主要逻辑在try块里,通过获取当前resource的inputStream,然后通过doLoadBeanDefinitions方法来加载解析文件。这里一个比较有特点的地方就在于它是通过一个Resource接口返回InputStream的方式来统一定义读取的数据源。这样可以根据不同的数据源来进行扩展,但是所有的使用者都是通过面向抽象的接口来操作。标准的OO原则。
再来看看doLoadBeanDefinitions方法的细节:
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException { try { Document doc = doLoadDocument(inputSource, resource); 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); } }
这么长的方法里主要的业务逻辑就在于两个方法,doLoadDocument和registerBeanDefinitions。doLoadDocument方法主要是通过java默认的api来加载xml文件,将加载的文件DOM结构构造成Document对象。它的详细实现是在DefaultDocumentLoader里:
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); }
我们再来看看registerBeanDefinitions的实现:
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException { BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader(); int countBefore = getRegistry().getBeanDefinitionCount(); documentReader.registerBeanDefinitions(doc, createReaderContext(resource)); return getRegistry().getBeanDefinitionCount() - countBefore; }
这部分的逻辑是通过创建一个BeanDefinitionDocumentReader对象,然后调用它的registerBeanDefinitions来实现详细的逻辑。我们继续跟进去看看它的实现。这个具体的实现方法是在类DefaultBeanDefinitionDocumentReader,它的实现如下:
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) { this.readerContext = readerContext; logger.debug("Loading bean definitions"); Element root = doc.getDocumentElement(); doRegisterBeanDefinitions(root); }
这里仅仅是通过获取到文档的根元素,然后在doRegisterBeanDefinitions里继续分析里面的子元素:
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. BeanDefinitionParserDelegate parent = this.delegate; this.delegate = createDelegate(getReaderContext(), root, parent); 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); postProcessXml(root); this.delegate = parent; }
这个方法里的第11到第24行主要是处理xml文件里有profile属性的情况,用于在多个部署环境的配置处理。而后面的3个方法里,preProcessXml和postProcessXml的方法实现为空,由后续的子类根据需要来继承覆写。详细的解析放在parseBeanDefinitions里:
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); } else { delegate.parseCustomElement(ele); } } } } else { delegate.parseCustomElement(root); } }
在这个方法里,它通过遍历它的所有子节点对元素进行分别处理。如果是xml文件里的默认元素,像bean等元素,就通过parseDefaultElement方法来处理。如果是一些自定义的元素,则放到parseCustomElement方法里处理。其中parseDefaultElement是我们最常用到的。它的实现如下:
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) { if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) { importBeanDefinitionResource(ele); } else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) { processAliasRegistration(ele); } else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) { processBeanDefinition(ele, delegate); } else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) { // recurse doRegisterBeanDefinitions(ele); } }
这里的实现根据nodeName来区分,如果nodeName是import,表示我们在这个文件里还要导入别的xml bean定义文件,则需要在importBeanDefinitionResource方法里导入新的文件。而如果nodeName是alias,表示这个元素是另外一个元素的别名,则通过processAliasRegistration来处理,这个方法AliasRegistry接口的一个实现,将有相同别名的元素放到一个HashMap里。如果beanName是嵌套的beans元素,表示我们需要进一步解析里面的元素,这里通过嵌套的调用doRegisterBeanDefinitions来实现。如果里面的nodeName是bean,表示我们要解析处理一个定义的bean对象,这里则通过processBeanDefinition方法来处理。它的细节比较重要,这里详细列出来:
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) { 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) { getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, ex); } // Send registration event. getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder)); } }
这部分的代码大部分还是起到一个代理的作用,它通过BeanDefinitionParseDelegate来解析BeanDefinition里的元素得到BeanDefinitionHolder对象,然后通过registerBeanDefinition来注册这个beanDefinition,详情见parseBeanDefinitionElement:
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) { String id = ele.getAttribute(ID_ATTRIBUTE); String nameAttr = ele.getAttribute(NAME_ATTRIBUTE); List<String> aliases = new ArrayList<>(); if (StringUtils.hasLength(nameAttr)) { String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS); aliases.addAll(Arrays.asList(nameArr)); } 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) { checkNameUniqueness(beanName, aliases, ele); } AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean); if (beanDefinition != null) { 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); return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray); } return null; }
这部分的代码主要处理元素的id, name等属性,对于里面有构造函数以及参数类型的处理则放在另外一个重载的parseBeanDefinitionElement里。可见,这个处理的过程非常繁琐复杂。针对这个loadBeanDefinitions方法牵涉到的过程,我们总结一下她们的交互图,这样有利于整理前面的这些代码。详细的图如下:
这样,到此为止我们就把通过读取配置文件来构造BeanDefinition的过程简单整理了一下。前面费了那么多劲分析的过程里,最终在spring里是定义成BeanDefinition的类型。那么,这个类型是个什么样的定义呢?它相关的类型结构如下图:
在这个结构图里主要继承和定义的接口是AttributeAccessor和BeanMetadataElement。AttributeAccessor比较简单,主要就是定义一个通用的访问属性的接口。主要的定义方法如下:
public interface AttributeAccessor { void setAttribute(String name, @Nullable Object value); @Nullable Object getAttribute(String name); @Nullable Object removeAttribute(String name); boolean hasAttribute(String name); String[] attributeNames(); }
有点像一个典型的增删查改的接口方法。继承这个接口的BeanDefinition增加了更多特定于一个Bean相关的方法,主要有parentName, beanClassName, scope, lazyInit, dependsOn, autowireCandidate, primary, factoryBeanName, factoryMethodName, propertyValues, isSingleton, isPrototype, isAbstract这些在文件里用来设置的主要属性。 绝大多数都是各种get, set方法。
所以,从这个角度来看,BeanDefinition无非就是对从配置里读取到的内容的一个映射。起到一个记录Bean对象生成之前必要属性的效果。没什么特殊的。
在之前分析源代码的时候,我们也已经看到,BeanDefinitionReader被用来读取文件并映射成BeanDefinition对象。它的相关结构如下图:
在这个图里,BeanDefinitionReader主要的方法是loadBeanDefinitions。而从实现里也可以看到,它间接的通过BeanDefinitionDocumentReader来读取各种document,包括xml文件类型的等等。
BeanFactory
在进一步讨论BeanFactory之前,我们看看前面的讨论。这些讨论都是基于前面程序里的示例代码来进行的。而这么多的流程和实现,无非只是覆盖了前面
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
这一行代码的实现细节。而在后面一行里,有context.getBean()的方法。这个方法的实现细节如果我们细究下去的话,就会发现它主要就是通过BeanFactory相关的类实现的。BeanFactory是一个接口,它的定义就是为了要求所有的实现里实现这个接口来获取和构造具体的Bean对象。而Bean对象就是我们最终获得的构造出来的结果对象,也是我们程序里最终直接起作用和代码打交道的对象组了。
我们先看一下它相关的类结构,如下图:
除了BeanFactory定义了一些基本的bean操作方法之外,后续继承的接口像ListableBeanFactory用来支持里面的对象是可以列举的。而HierarchicalBeanFactory用来表示里面的对象是有层级继承关系的。而AutowireCapableBeanFactory表示支持里面的对象可以支持Autowire annotation,可以通过它来组织和构造对象及之间的关系。通过之前ApplicationContext的类图结构,我们看到ApplicationContext也继承了接口ListableBeanFactory和HierarchicalBeanFactory。所以,它的具体实现里就支持bean对象的列举和层级继承关系。
从上图中还看到一个地方,就是所有的接口和抽象类最后都有一个默认的实现:DefaultListableBeanFactory。它在很多地方都被用到。
我们先从前面的context.getBean()方法里继续跟进它的实现细节。BeanFactory接口里主要定义的方法有如下几个:
public interface BeanFactory { String FACTORY_BEAN_PREFIX = "&"; Object getBean(String name) throws BeansException; <T> T getBean(String name, @Nullable Class<T> requiredType) throws BeansException; Object getBean(String name, Object... args) throws BeansException; <T> T getBean(Class<T> requiredType) throws BeansException; <T> T getBean(Class<T> requiredType, Object... args) throws BeansException; boolean containsBean(String name); boolean isSingleton(String name) throws NoSuchBeanDefinitionException; boolean isPrototype(String name) throws NoSuchBeanDefinitionException; boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException; boolean isTypeMatch(String name, @Nullable Class<?> typeToMatch) throws NoSuchBeanDefinitionException; @Nullable Class<?> getType(String name) throws NoSuchBeanDefinitionException; String[] getAliases(String name); }
其中最常用的方法就是Object getBean(String name)。它的实现主要是在AbstractBeanFactory里:
@Override public Object getBean(String name) throws BeansException { return doGetBean(name, null, null, false); } protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType, @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException { final String beanName = transformedBeanName(name); Object bean; // Eagerly check singleton cache for manually registered singletons. Object sharedInstance = getSingleton(beanName); 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); } 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 (parentBeanFactory instanceof AbstractBeanFactory) { return ((AbstractBeanFactory) parentBeanFactory).doGetBean( nameToLookup, requiredType, args, typeCheckOnly); } else 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); } try { final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); 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) { if (isDependent(beanName, dep)) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'"); } registerDependentBean(dep, beanName); try { getBean(dep); } catch (NoSuchBeanDefinitionException ex) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "'" + beanName + "' depends on missing bean '" + dep + "'", ex); } } } // Create bean instance. if (mbd.isSingleton()) { sharedInstance = getSingleton(beanName, () -> { 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 name '" + scopeName + "'"); } try { Object scopedInstance = scope.get(beanName, () -> { 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); } } } catch (BeansException ex) { cleanupAfterBeanCreationFailure(beanName); throw ex; } } // Check if required type matches the type of the actual bean instance. if (requiredType != null && !requiredType.isInstance(bean)) { try { T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType); if (convertedBean == null) { throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass()); } return convertedBean; } 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; }
这里面所有的getBean方法最终都是通过doGetBean方法实现的。doGetBean方法的实现看起来比较长,我们这里相对里面的细节稍微整理一下。
第9行的代码主要是生成beanName,主要这里要考虑FactoryBean,它是以字符&为开头命名的,所以需要处理这种情况。
第13行的getSingleton方法的实现主要是读取已有的ConcurrentHashMap里是否存在这个bean对象了,否则通过singletonObjectFactory这个HashMap来获取对象。之所以这里要考虑从这些缓存的Map里取,是因为在前面ApplicationContext初始化的时候,有个地方预先把一些singleton对象放到里面了。这里的实现是AbstractApplicationContext里的方法finishBeanFactoryInitialization。在这个方法里有一行:
beanFactory.preInstantiateSingletons();
它会预先加载一部分bean对象。我们在后面会详细分析它。
接下来看第36行到51行的过程,它主要是判断,如果当前beanFactory里没找到对应的BeanDefinition,则通过它的父beanFactory来继续查找和构建对象。
第57行到第77行的部分则是获取该bean对象定义里的dependsOn属性,如果有的话,先构造它所依赖的对象,然后再尝试构造这个bean。
第81行到第95行处理bean scope是singleton的情况。如果定义的是singleton,则通过createBean方法构造这个bean对象,并赋值给sharedInstance。
第97行到107行处理bean scope是prototype的情况。它通过将beanName加入到一个ThreadLocal的变量里,并将beanName加入到一个集合里。
第110行到134行处理bean scope为其他的情况。因为我们一般的应用里会仅仅使用到singleton和prototype两种情况,但是在一些web应用里,还会有request, session, application不同范围的情况。所以这里也要采用一定的方法来支持。
我们先不着急把整个过程给描述出来,先看一下之前搁置的beanFactory.preInstantiateSingletons方法。它的实现在类DefaultListableBeanFactory里:
public void preInstantiateSingletons() throws BeansException { if (this.logger.isDebugEnabled()) { this.logger.debug("Pre-instantiating singletons in " + this); } // Iterate over a copy to allow for init methods which in turn register new bean definitions. // While this may not be part of the regular factory bootstrap, it does otherwise work fine. List<String> beanNames = new ArrayList<>(this.beanDefinitionNames); // Trigger initialization of all non-lazy singleton beans... for (String beanName : beanNames) { RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName); if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) { if (isFactoryBean(beanName)) { Object bean = getBean(FACTORY_BEAN_PREFIX + beanName); if (bean instanceof FactoryBean) { final FactoryBean<?> factory = (FactoryBean<?>) bean; boolean isEagerInit; if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) { isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>) ((SmartFactoryBean<?>) factory)::isEagerInit, getAccessControlContext()); } else { isEagerInit = (factory instanceof SmartFactoryBean && ((SmartFactoryBean<?>) factory).isEagerInit()); } if (isEagerInit) { getBean(beanName); } } } else { getBean(beanName); } } } // Trigger post-initialization callback for all applicable beans... for (String beanName : beanNames) { Object singletonInstance = getSingleton(beanName); if (singletonInstance instanceof SmartInitializingSingleton) { final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance; if (System.getSecurityManager() != null) { AccessController.doPrivileged((PrivilegedAction<Object>) () -> { smartSingleton.afterSingletonsInstantiated(); return null; }, getAccessControlContext()); } else { smartSingleton.afterSingletonsInstantiated(); } } } }
这部分代码里要点主要有3个部分,首先是第12行的getMergedLocalBeanDefinition,这里主要是通过一些beanName来得到对应的BeanDefinition,然后和本地的benDefinition进行合并。因为有的Bean和现有的是一种继承的关系。这样可以将多个bean的定义给合并成一个统一的结构。第14行到第31行则是用来处理FactoryBean的情况。因为这是通过某种factory方法构造的对象,所以它的处理方式需要通过调用factoryBean的方法来返回bean对象。正常的情况下,则是直接调用getBean方法。
第40行到后面的部分则处理一些回调方法的情况。比如afterSingletonsInstantiated等。
从上面的讨论过程,我们可以整理出一个如下的顺序图:
总的来说,getBean的过程就是i通过先合并本地的BeanDefinition,然后再通过ObjectFactory的实现来返回这个bean。而在前面doGetBean方法里有调用过createBean方法,这就是最终提供和创建bean的方法。
我们结合源代码再跟进一下createBean方法的实现过程。
它的实现在类AbstractAutowireCapableBeanFactory里:
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable 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 { mbdToUse.prepareMethodOverrides(); } catch (BeanDefinitionValidationException ex) { throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(), beanName, "Validation of method overrides failed", ex); } try { // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance. 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); } try { Object beanInstance = doCreateBean(beanName, mbdToUse, args); if (logger.isDebugEnabled()) { logger.debug("Finished creating instance of bean '" + beanName + "'"); } return beanInstance; } catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) { // A previously detected exception with proper bean creation context already, // or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry. throw ex; } catch (Throwable ex) { throw new BeanCreationException( mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex); } }
这一大段代码在40行之前主要是做一些创建bean对象之前的准备工作,比如说通过resolveBeanClass方法来验证给定beanName的class和BeanDefinition已经构建好。而resolveBeforeInstantiation方法则是调用一些beanPostProcessor的回调方法。真正的实现细节在doCreateBean方法里。
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args) throws BeanCreationException { // Instantiate the bean. BeanWrapper instanceWrapper = null; if (mbd.isSingleton()) { instanceWrapper = this.factoryBeanInstanceCache.remove(beanName); } if (instanceWrapper == null) { instanceWrapper = createBeanInstance(beanName, mbd, args); } final Object bean = instanceWrapper.getWrappedInstance(); Class<?> beanType = instanceWrapper.getWrappedClass(); if (beanType != NullBean.class) { mbd.resolvedTargetType = beanType; } // Allow post-processors to modify the merged bean definition. synchronized (mbd.postProcessingLock) { if (!mbd.postProcessed) { try { applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName); } catch (Throwable ex) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Post-processing of merged bean definition failed", ex); } mbd.postProcessed = true; } } // Eagerly cache singletons to be able to resolve circular references // even when triggered by lifecycle interfaces like BeanFactoryAware. boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName)); if (earlySingletonExposure) { if (logger.isDebugEnabled()) { logger.debug("Eagerly caching bean '" + beanName + "' to allow for resolving potential circular references"); } addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)); } // Initialize the bean instance. Object exposedObject = bean; try { populateBean(beanName, mbd, instanceWrapper); 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); } } if (earlySingletonExposure) { Object earlySingletonReference = getSingleton(beanName, false); if (earlySingletonReference != null) { if (exposedObject == bean) { exposedObject = earlySingletonReference; } else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) { String[] dependentBeans = getDependentBeans(beanName); Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length); for (String dependentBean : dependentBeans) { if (!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."); } } } } // Register bean as disposable. try { registerDisposableBeanIfNecessary(beanName, bean, mbd); } catch (BeanDefinitionValidationException ex) { throw new BeanCreationException( mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex); } return exposedObject; }
这段代码里就是执行创建bean和相关设置的具体逻辑了。首先它判断相应的beanInstance是否已经存在了,如果不存在,则调用第10行的createBeanInstance。createBeanInstance这个方法选择合适的初始化策略来构造bean对象。该方法的实现如下:
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) { // Make sure bean class is actually resolved at this point. Class<?> beanClass = resolveBeanClass(mbd, beanName); 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()); } Supplier<?> instanceSupplier = mbd.getInstanceSupplier(); if (instanceSupplier != null) { return obtainFromSupplier(instanceSupplier, beanName); } if (mbd.getFactoryMethodName() != null) { return instantiateUsingFactoryMethod(beanName, mbd, args); } // Shortcut when re-creating the same bean... boolean resolved = false; boolean autowireNecessary = false; if (args == null) { synchronized (mbd.constructorArgumentLock) { if (mbd.resolvedConstructorOrFactoryMethod != null) { resolved = true; autowireNecessary = mbd.constructorArgumentsResolved; } } } if (resolved) { if (autowireNecessary) { return autowireConstructor(beanName, mbd, null, null); } else { return instantiateBean(beanName, mbd); } } // Need to determine the constructor... 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); }它主要通过传入的RootBeanDefinition来确定某些参数是否被设置了,然后调用对应的构造对象方法。比如它的FactoryMethodName如果不为空的话,则通过factoryMethod方法来构造这个对象。如果instanceSupplier不为空的话,则通过obtainFromSupplier方法返回构造对象。而对于默认的构造方式,则是通过instantiateBean方法来实现的:
protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) { try { Object beanInstance; final BeanFactory parent = this; if (System.getSecurityManager() != null) { beanInstance = AccessController.doPrivileged((PrivilegedAction<Object>) () -> getInstantiationStrategy().instantiate(mbd, beanName, parent), getAccessControlContext()); } else { beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent); } BeanWrapper bw = new BeanWrapperImpl(beanInstance); initBeanWrapper(bw); return bw; } catch (Throwable ex) { throw new BeanCreationException( mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex); } }这部分代码通过具体的某种具体的初始化策略来构造beanInstance。然后在将构造对象通过BeanWrapperImpl来包装起来,最后通过initBeanWrapper来初始化一些属性。到这里,终于将BeanFactory相关的东西和我们之前讨论的BeanWrapper接口相关的东西给关联起来了。前面instantiate方法的具体实现在类SimpleInstantiationStrategy的instantiate里。
这么一通跟下来,发现整个的逻辑过程还是比较错综复杂的。但是到此为止整个BeanFactory构造bean的过程算是整体给缕了一遍。
Resource
在之前的代码分析中,我们还看到一个关键的地方,就是Resource相关接口的使用。 因为从容器运行和配置的流程里,它们需要去读取各种配置文件来作为构造各种bean对象的基础。而读取的配置文件信息来源比较广泛。这时候,需要对它们做一种抽象提炼。于是在spring里,相关的接口结构如下图:
在最*的父类里,InputStreamSource表示所有的实现对象都需要返回一个InputStream的方法。它的定义如下:
public interface InputStreamSource { InputStream getInputStream() throws IOException; }
这样,从最抽象的层面来说,所有通过它的实现都提供了一个获取数据的途径。不管是从哪里来的数据都可以通过这种方式来读取。
而继承InputStreamResource的Resource接口则增加了一些方法,比如说判断资源是否存在,以及是否为文件,内容长度等。
public interface Resource extends InputStreamSource { boolean exists(); default boolean isReadable() { return true; } default boolean isOpen() { return false; } default boolean isFile() { return false; } URL getURL() throws IOException; URI getURI() throws IOException; File getFile() throws IOException; default ReadableByteChannel readableChannel() throws IOException { return Channels.newChannel(getInputStream()); } long contentLength() throws IOException; long lastModified() throws IOException; Resource createRelative(String relativePath) throws IOException; @Nullable String getFilename(); String getDescription(); }
所有对这几个接口的具体实现就是提供一些特定资源类型的获取方式。
从上图还可以看到,当真的要获取资源的时候,我们不是直接通过Resource实现的类来做。而是有一个专门的ResourceLoader。它屏蔽了获取Resource的方式和细节。
public interface ResourceLoader { String CLASSPATH_URL_PREFIX = ResourceUtils.CLASSPATH_URL_PREFIX; Resource getResource(String location); @Nullable ClassLoader getClassLoader(); }
ResourceLoader的一个默认实现DefaultResourceLoader在ApplicationContext的实现里被用到。它的核心实现就是getResource方法:
public Resource getResource(String location) { Assert.notNull(location, "Location must not be null"); for (ProtocolResolver protocolResolver : this.protocolResolvers) { Resource resource = protocolResolver.resolve(location, this); if (resource != null) { return resource; } } if (location.startsWith("/")) { return getResourceByPath(location); } else if (location.startsWith(CLASSPATH_URL_PREFIX)) { return new ClassPathResource(location.substring(CLASSPATH_URL_PREFIX.length()), getClassLoader()); } else { try { // Try to parse the location as a URL... URL url = new URL(location); return (ResourceUtils.isFileURL(url) ? new FileUrlResource(url) : new UrlResource(url)); } catch (MalformedURLException ex) { // No URL -> resolve as resource path. return getResourceByPath(location); } } }
这个方法的实现流程如下:
1. 首先通过ProtocolResolver来获取Resource对象。这样对于一些特定协议的资源一般可以通过它获取到。
2. 如果没有解析成功就尝试判断是否为文件路径结构,如果是的话则返回classpathContextResource。
3. 如果资源前面有classpath:这个字符串的话,表示这是ClassPathResource,返回对应的resource类型。
4. 尝试通过URL的方式来解析资源文件。
IOC容器的扩展点
在之前的文章里我们有讨论过spring bean生命周期的阶段。总的来说,bean的构造要经历几个阶段。即加载class,创建新对象,设置对象属性等阶段。有一些相关的设置和扩展点可以用来定制对象的构造。比如InitializingBean, DisposableBean, BeanPostProcessor, BeanFactoryPostProcessor等。在spring的实现里,这些过程都是统一通过一个方法来调用处理的。也就是AbstractAutowireCapableBeanFactory里的initializeBean方法。在这里,initializeBean方法是在前面doCreateBean方法中populateBean方法之后调用的:
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) { if (System.getSecurityManager() != null) { AccessController.doPrivileged((PrivilegedAction<Object>) () -> { invokeAwareMethods(beanName, bean); return null; }, getAccessControlContext()); } else { invokeAwareMethods(beanName, bean); } Object wrappedBean = bean; if (mbd == null || !mbd.isSynthetic()) { wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); } try { invokeInitMethods(beanName, wrappedBean, mbd); } catch (Throwable ex) { throw new BeanCreationException( (mbd != null ? mbd.getResourceDescription() : null), beanName, "Invocation of init method failed", ex); } if (mbd == null || !mbd.isSynthetic()) { wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); } return wrappedBean; }
从之前的流程图里可以看到,这个方法基本上属于构造bean过程中的最后一步。所有自定义的一些行为也都在这里的到实现。要理解这部分代码的实现,可以引用官方文档里的一部分内容作为参考对比。在beanFactory的定义描述里讲述了bean的生命周期,它的过程如下:
初始化对象的构造调用过程:
- BeanNameAware's
setBeanName
- BeanClassLoaderAware's
setBeanClassLoader
- BeanFactoryAware's
setBeanFactory
- EnvironmentAware's
setEnvironment
- EmbeddedValueResolverAware's
setEmbeddedValueResolver
- ResourceLoaderAware's
setResourceLoader
(only applicable when running in an application context) - ApplicationEventPublisherAware's
setApplicationEventPublisher
(only applicable when running in an application context) - MessageSourceAware's
setMessageSource
(only applicable when running in an application context) - ApplicationContextAware's
setApplicationContext
(only applicable when running in an application context) - ServletContextAware's
setServletContext
(only applicable when running in a web application context) -
postProcessBeforeInitialization
methods of BeanPostProcessors - InitializingBean's
afterPropertiesSet
- a custom init-method definition
-
postProcessAfterInitialization
methods of BeanPostProcessors
在beanFacotry关闭的过程中,如下的方法将被调用:
-
postProcessBeforeDestruction
methods of DestructionAwareBeanPostProcessors - DisposableBean's
destroy
- a custom destroy-method definition
我们结合代码来看这个过程,首先第4行和第9行调用的是invokeAwareMethods,它的实现如下:
private void invokeAwareMethods(final String beanName, final Object bean) { if (bean instanceof Aware) { if (bean instanceof BeanNameAware) { ((BeanNameAware) bean).setBeanName(beanName); } if (bean instanceof BeanClassLoaderAware) { ClassLoader bcl = getBeanClassLoader(); if (bcl != null) { ((BeanClassLoaderAware) bean).setBeanClassLoader(bcl); } } if (bean instanceof BeanFactoryAware) { ((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this); } } }
可见前面的3步都是在这个方法里实现的。
再看第14行的applyBeanPostProcessorsBeforeInitialization方法:
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName) throws BeansException { Object result = existingBean; for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) { Object current = beanProcessor.postProcessBeforeInitialization(result, beanName); if (current == null) { return result; } result = current; } return result; }
所有实现beanPostProcessor接口里的postProcessBeforeInitialization方法都是在这里被调用的。对应前面描述的步骤11。
接着是18行的invokeInitMethods:
protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd) throws Throwable { boolean isInitializingBean = (bean instanceof InitializingBean); if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) { if (logger.isDebugEnabled()) { logger.debug("Invoking afterPropertiesSet() on bean with name '" + beanName + "'"); } if (System.getSecurityManager() != null) { try { AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> { ((InitializingBean) bean).afterPropertiesSet(); return null; }, getAccessControlContext()); } catch (PrivilegedActionException pae) { throw pae.getException(); } } else { ((InitializingBean) bean).afterPropertiesSet(); } } if (mbd != null && bean.getClass() != NullBean.class) { String initMethodName = mbd.getInitMethodName(); if (StringUtils.hasLength(initMethodName) && !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) && !mbd.isExternallyManagedInitMethod(initMethodName)) { invokeCustomInitMethod(beanName, bean, mbd); } } }
这个方法里 主要就是调用了InitializingBean方法的实现以及调用自定义的初始化方法过程。当然,调用InitializingBean方法的过程在前面。所以这里对应前面描述的步骤12和13。
接着的就是第26行的applyBeanPostProcessorsAfterInitialization:
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName) throws BeansException { Object result = existingBean; for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) { Object current = beanProcessor.postProcessAfterInitialization(result, beanName); if (current == null) { return result; } result = current; } return result; }
这里对应步骤14。
对于bean被销毁的过程,它的一个实现在AbstractBeanFactory里:
protected void destroyBean(String beanName, Object bean, RootBeanDefinition mbd) { new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), getAccessControlContext()).destroy(); }
它的实际实现是在DisposableBeanAdapter里:
public void destroy() { if (!CollectionUtils.isEmpty(this.beanPostProcessors)) { for (DestructionAwareBeanPostProcessor processor : this.beanPostProcessors) { processor.postProcessBeforeDestruction(this.bean, this.beanName); } } if (this.invokeDisposableBean) { if (logger.isDebugEnabled()) { logger.debug("Invoking destroy() on bean with name '" + this.beanName + "'"); } try { if (System.getSecurityManager() != null) { AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> { ((DisposableBean) bean).destroy(); return null; }, acc); } else { ((DisposableBean) bean).destroy(); } } catch (Throwable ex) { String msg = "Invocation of destroy method failed on bean with name '" + this.beanName + "'"; if (logger.isDebugEnabled()) { logger.warn(msg, ex); } else { logger.warn(msg + ": " + ex); } } } if (this.destroyMethod != null) { invokeCustomDestroyMethod(this.destroyMethod); } else if (this.destroyMethodName != null) { Method methodToCall = determineDestroyMethod(this.destroyMethodName); if (methodToCall != null) { invokeCustomDestroyMethod(methodToCall); } } }
这里的实现首先会尝试针对DisposableBean的实现来调用它们的destroy方法。在后面还会通过invokeCustomDestroyMethod来调用自定义的destroy方法。
总结
整理和分析spring框架的源代码是一个非常消耗时间和精力的过程。由于整个框架经过10多年的发展和演化,里面的很多细节都被隐藏得很深,有时候有点大海捞针的感觉。在容器实现的细节里,它对于几个部分的责任划分还是比较有意思的。这也是整个系统实现的骨架。首先,它定义专门的BeanFactory系列接口和实现来创建具体的bean对象。而加载具体bean对象的定义放在初始化的过程中。对于不同来源的数据,通过Resource接口相关的类来定义。所有针对不同类型和环境的资源读取都统一返回InputStream。这样方便统一解析和处理。而解析后加载的内容又统一定义成BeanDefinition类族结构。具体的实现里只需要针对详细的定义进行解析和构造。
参考材料
https://www.ibm.com/developerworks/cn/java/j-lo-spring-principle/index.html
推荐阅读
-
spring-session简介及实现原理源码分析
-
Spring Cloud动态配置实现原理与源码分析
-
Spring Cloud动态配置实现原理与源码分析
-
spring AOP的After增强实现方法实例分析
-
spring源码分析系列5:ApplicationContext的初始化与Bean生命周期
-
spring源码分析6: ApplicationContext的初始化与BeanDefinition的搜集入库
-
spring AOP的Around增强实现方法分析
-
九、Spring之BeanFactory源码分析(一)
-
thinkphp5.1框架中容器(Container)和门面(Facade)的实现方法分析
-
深入源码分析Spring注解的实现原理---@Import