之前一篇,整体描述了一下 Spring的整体概况和 jar包的介绍。 现在开始进入具体的源码解析,从本篇开始,先介绍spring的ioc容器。之前也看过一些介绍spring源码的, 有的是只讲整体的接口,缺少和源码的结合,有的是一直源码跟进的讲解,由于类的调用太深, 导致看着看着就晕了。 所以自己决定动手写一遍,结合两者的优点。
该图摘自spring技术内幕。
图中的两条线路是主要的两条接口设计线路图。
整体接口系统都是以beanfactory和applicationContext为核心。
beanfactory是ioc容器最基本的接口。
applicationContext 是在继承了 beanfactory的基础上,新增了一些高级的ioc特性。
这里采用相对原始的方式使用spring,方便深入了解springioc容器的初始化。其他的各种不同的实现,针对不懂得资源加载方式,扩展了一些功能,整体思路是相同的。
ClassPathResource resource = new ClassPathResource("beans.xml"); DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory); reader.loadBeanDefinitions(resource)
主要分为了三个过程。
1.resource定位
2.beanDefinition的载入。
3.向ioc容器注册beanDefinition的过程。这个过程通过调用BeanDefinitionRegistry接口的实现来完成。
在这里DefaultListableBeanFactory是一个纯粹的ioc容器,需要给他配置特定的读取器才能完成功能。而我们常用的application已经提供了一系列不同的resource,不需要手动指定。例如:
FileSystemXmlApplicationContext 从文件系统中载入,ClassPathXmlApplicationContext 从class path载入,XmlWebApplicationContext 可以在web容器中载入。
下面以FileSystemXmlApplicationContext为例详细的介绍。
先给出整体的uml图。
整个加载的入口不再过多的描述。
public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent) throws BeansException { super(parent); setConfigLocations(configLocations); if (refresh) { refresh(); } }
直接找到FileSystemXmlApplicationContext的构造函数即可。refresh()方法就是这个ioc容器加载的入口,该方法的具体实现在AbstractApplicationContext。
下面我不去按照源码一步步的跟进。而是去按照ioc容器的整体的一个加载流程,做介绍。有一个整体思路,大家在一步步的去跟进代码,也比较清晰。
public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // 刷新上下文 prepareRefresh(); //这里是在子类中启动refreshBeanFactort()的地方 ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context. prepareBeanFactory(beanFactory); try { // 设置beanFactory的后置处理 postProcessBeanFactory(beanFactory); //调用beanFactory的后处理器,这些后处理器是在bean定义中向容器注册的 invokeBeanFactoryPostProcessors(beanFactory); //注册bean的后处理器,在bean创建过程中调用 registerBeanPostProcessors(beanFactory); //对上下文中的消息源进行初始化 initMessageSource(); //初始化上下文中的事件机制 initApplicationEventMulticaster(); //初始化其他的特殊bean onRefresh(); //检查监听bean并且将这些bean向容器注册 registerListeners(); //实例化所有的(non-lazy-init)单利 finishBeanFactoryInitialization(beanFactory); //发布容器事件,结束refresh过程 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(); } } }
Resource定位
整体的调用链
protected final void refreshBeanFactory() throws BeansException {
//这里判断是否已经建立了beanFactory,如果存在就销毁并关闭 if (hasBeanFactory()) { destroyBeans(); closeBeanFactory(); } try {
//这里就是在上下文中创建defaultListableBeanFactory的地方。 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); } }
public int loadBeanDefinitions(String location, Set<Resource> actualResources) throws BeanDefinitionStoreException {
//这里取得resourceLoader,采用的是DefaultResourceLoader ResourceLoader resourceLoader = getResourceLoader(); if (resourceLoader == null) { throw new BeanDefinitionStoreException( "Cannot import bean definitions from location [" + location + "]: no ResourceLoader available"); } if (resourceLoader instanceof ResourcePatternResolver) { // Resource pattern matching available. try {
//这里是具体的加载 Resource的地方 Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location); int loadCount = loadBeanDefinitions(resources); if (actualResources != null) { for (Resource resource : resources) { actualResources.add(resource); } } if (logger.isDebugEnabled()) { logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]"); } return loadCount; } catch (IOException ex) { throw new BeanDefinitionStoreException( "Could not resolve bean definition resource pattern [" + location + "]", ex); } } else { // Can only load single resources by absolute URL. Resource resource = resourceLoader.getResource(location); int loadCount = loadBeanDefinitions(resource); if (actualResources != null) { actualResources.add(resource); } if (logger.isDebugEnabled()) { logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]"); } return loadCount; } }
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<EncodedResource>(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(); } } }
BeanDefinition的载入和解析
从abstractRefreshableApplicationContext的refreshBeanFactory方法开始入手,了解整个bean定义信息的载入过程。
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException { // 创建 XmlBeanDefinitionReader XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); beanDefinitionReader.setEnvironment(this.getEnvironment());
//为xmlbeanDefinitionReader 设置resourceloader beanDefinitionReader.setResourceLoader(this); beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this)); //启动bean定义信息载入过程 initBeanDefinitionReader(beanDefinitionReader); loadBeanDefinitions(beanDefinitionReader); }
下面是loadBeanDefinitions调用的地方,首先得到beanDefinition信息的resource定位,然后调用xmlBeanDefinitionReader来读取.
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException { //以resource的方式获取配置文件的资源位置 Resource[] configResources = getConfigResources(); if (configResources != null) { reader.loadBeanDefinitions(configResources); } //以String的形式获取 String[] configLocations = getConfigLocations(); if (configLocations != null) { reader.loadBeanDefinitions(configLocations); } }
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<EncodedResource>(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(); } } }
具体的读取过程在doLoadBeanDefinitions。
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException { try {
//完成具体的文档读取 Document doc = doLoadDocument(inputSource, resource);
//按照spring的bean的语义要求进行解析并转化为容器的内部数据结构。
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); } }
beanDefinition 的载入分为两部分。首先调用xml的解析器得到document对象。然后documentReader中按照spring的bean的规则进行解析。
BeanDefinition的注册
在DefaultListableBeanFactory中,通过一个map来持有载入的beanDefinition的。
/** Map of bean definition objects, keyed by bean name */
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>(256);
再DefaultListableBeanFactory中实现了beanDefinitionRegistry的接口,这个接口完成了beanDefinition向容器的注册。就是将解析得到的beandefinition设置到hashmap中。
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; oldBeanDefinition = this.beanDefinitionMap.get(beanName); if (oldBeanDefinition != null) { if (!isAllowBeanDefinitionOverriding()) { throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName + "': There is already [" + oldBeanDefinition + "] bound."); } 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 + "]"); } } 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 { if (this.logger.isDebugEnabled()) { this.logger.debug("Overriding bean definition for bean '" + beanName + "' with an equivalent definition: replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]"); } } this.beanDefinitionMap.put(beanName, beanDefinition); } else { 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); } }