博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Spring源码解析(三)——容器创建
阅读量:5894 次
发布时间:2019-06-19

本文共 10136 字,大约阅读时间需要 33 分钟。

hot3.png

前言

    承接上篇“容器刷新”,容器创建其实是“容器刷新”的一个子分支,但却涉及了许多内容,包括配置解析、IOC容器创建等。

 

源码解读

    让我们来回顾一下refresh的子分支之一,obtainFreshBeanFactory。

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {        // 刷新 beanFactory,之前存在的话会先关闭再重新创建        refreshBeanFactory();        // 这一步其实就是获取上面这一步的结果        ConfigurableListableBeanFactory beanFactory = getBeanFactory();        if (logger.isDebugEnabled()) {            logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);        }        return beanFactory;    }

    主要的创建集中在refreshBeanFactory,由AbstractRefreshableApplicationContext实现,让我们展开来看。

public abstract class AbstractRefreshableApplicationContext extends AbstractApplicationContext {    @Override    protected final void refreshBeanFactory() throws BeansException {        // 如果之前初始化过 BeanFoctory,销毁并将成员变量置为 null        if (hasBeanFactory()) {            // 清空工厂已经注册的所有单例            destroyBeans();            // 将成员变量 beanFactory赋值 null            closeBeanFactory();        }        try {            /**             * 创建 DefaultListableBeanFactory,此步只是创建了一个空壳             * 如果存在父容器,将父容器 beanFactory传入构造器进行创建,这也是为什么父容器中 bean为什么对子容器可见的原因             * 寻找 bean会优先从子容器查找,找不到才会从父容器查找             */            DefaultListableBeanFactory beanFactory = createBeanFactory();            // 为序列化指定id,其实将 id与一个 指向该工厂的弱引用关联在一起            beanFactory.setSerializationId(getId());            // 定制 beanFactory            customizeBeanFactory(beanFactory);            // 加载 BeanDefinition            loadBeanDefinitions(beanFactory);            // 赋值给成员变量 beanFactory            synchronized (this.beanFactoryMonitor) {                this.beanFactory = beanFactory;            }        } catch (IOException ex) {            throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);        }    }    protected DefaultListableBeanFactory createBeanFactory() {        return new DefaultListableBeanFactory(getInternalParentBeanFactory());    }    /**     * 如果它实现ConfigurableApplicationContext,则返回父上下文的内部 Bean工厂;     * 否则,返回父上下文本身     */    protected BeanFactory getInternalParentBeanFactory() {        return (getParent() instanceof ConfigurableApplicationContext) ?                ((ConfigurableApplicationContext) getParent()).getBeanFactory() : getParent();    }    // 设置:1.同名对象覆盖;2.循环依赖    protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {        if (this.allowBeanDefinitionOverriding != null) {            beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);        }        if (this.allowCircularReferences != null) {            beanFactory.setAllowCircularReferences(this.allowCircularReferences);        }    }    protected abstract void loadBeanDefinitions(DefaultListableBeanFactory beanFactory)            throws BeansException, IOException;}

       AbstractRefreshableApplicationContext只是把架子给搭建起来了,创建了一个空壳子DefaultListableBeanFactory,具体的填充工作是loadBeanDefinitions。由第一篇容器启动可知,默认使用的ApplicationContext是XmlWebApplicationContext,让我们继续看代码。

public class XmlWebApplicationContext extends AbstractRefreshableWebApplicationContext {    @Override    protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {        // 创建 XmlBeanDefinitionReader 以解析配置文件        XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);        // 配置 XmlBeanDefinitionReader        beanDefinitionReader.setEnvironment(getEnvironment());        beanDefinitionReader.setResourceLoader(this);        beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));        // 空实现:留给子类扩展        initBeanDefinitionReader(beanDefinitionReader);        // 调用 reader的 loadBeanDefinitions        loadBeanDefinitions(beanDefinitionReader);    }    // 留给子类自定义扩展 XmlBeanDefinitionReader    protected void initBeanDefinitionReader(XmlBeanDefinitionReader beanDefinitionReader) {    }    protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws IOException {        // 获取配置的文件路径        String[] configLocations = getConfigLocations();        if (configLocations != null) {            // 遍历解析配置文件            for (String configLocation : configLocations) {                reader.loadBeanDefinitions(configLocation);            }        }    }}

    遍历配置文件路径数组解析,也就是我们在web.xml中配置的<init-param> contextConfigLocation(见第一篇),之后的工作就看XmlBeanDefinitionReader的了,如果之前研究过Spring源码的朋友可能有印象,XmlBeanFactory的构造器就是调用了XmlBeanDefinitionReader来解析配置文件的,不过在Spring 3.1版本之后,XmlBeanFactory被标记为废弃了。

 

配置解析

public abstract class AbstractBeanDefinitionReader implements EnvironmentCapable, BeanDefinitionReader {    @Override    public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException {        return loadBeanDefinitions(location, null);    }    public int loadBeanDefinitions(String location, Set
actualResources) throws BeanDefinitionStoreException { ResourceLoader resourceLoader = getResourceLoader(); if (resourceLoader == null) { throw new BeanDefinitionStoreException( "Cannot import bean definitions from location [" + location + "]: no ResourceLoader available"); } if (resourceLoader instanceof ResourcePatternResolver) { try { // 支持“*”通配符匹配,例如:spring-mybatis.xml、spring-mvc.xml,配置成 spring-*.xml即可 Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location); int loadCount = loadBeanDefinitions(resources); if (actualResources != null) { for (Resource resource : resources) { actualResources.add(resource); } } ......// 省略日志 return loadCount; } catch (IOException ex) { throw new BeanDefinitionStoreException( "Could not resolve bean definition resource pattern [" + location + "]", ex); } } else { // 只能通过绝对路径加载单个资源. Resource resource = resourceLoader.getResource(location); int loadCount = loadBeanDefinitions(resource); if (actualResources != null) { actualResources.add(resource); } ......// 省略日志 return loadCount; } } @Override public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException { Assert.notNull(resources, "Resource array must not be null"); int counter = 0; for (Resource resource : resources) { // 这里由子类实现:XmlBeanDefinitionReader counter += loadBeanDefinitions(resource); } return counter; } int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException;}

    抽象父类同样是搭架子,主要工作就是把原本String类型的路径(支持通配符 *),解析为Resource

public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {    @Override    public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {        return loadBeanDefinitions(new EncodedResource(resource));    }    public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {        ......// 省略断言和日志        // 往 ThreadLocal放一个正在加载的 Resource        Set
currentResources = this.resourcesCurrentlyBeingLoaded.get(); if (currentResources == null) { currentResources = new HashSet
(4); this.resourcesCurrentlyBeingLoaded.set(currentResources); } // 此步为了防止循环加载,Set机制:add相同的元素返回 false if (!currentResources.add(encodedResource)) { throw new BeanDefinitionStoreException( "Detected cyclic loading of " + encodedResource + " - check your import definitions!"); } try { // 获取输入流 InputStream inputStream = encodedResource.getResource().getInputStream(); try { // 使用 SAX解析配置文件 InputSource inputSource = new InputSource(inputStream); if (encodedResource.getEncoding() != null) { inputSource.setEncoding(encodedResource.getEncoding()); } return doLoadBeanDefinitions(inputSource, encodedResource.getResource()); } finally { // 关闭 IO流(一定要做好资源的清理、关闭工作) 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 { // 将 xml文件封装成 Document对象 Document doc = doLoadDocument(inputSource, resource); // 注册 BeanDefinition return registerBeanDefinitions(doc, resource); } .....// 省略catch处理 } public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException { /** * 默认实现类:DefaultBeanDefinitionDocumentReader * 对
等标签的解析 */ BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader(); // 获取注册前已经注册的 BeanDefinition数量 int countBefore = getRegistry().getBeanDefinitionCount(); // 对 Document对象的解析——> BeanDefinition注册 documentReader.registerBeanDefinitions(doc, createReaderContext(resource)); // 作差获取本次解析注册的 BeanDefinition数量 return getRegistry().getBeanDefinitionCount() - countBefore; }}

    到这里位置,XmlBeanDefinitionReader的工作基本也告于段落了,主要就是把Resource类型,通过IO流处理封装成 Document对象。其实我们从命名当中就可以看出各自的作用,顺理成章,接下来就是BeanDefinitionDocumentReader的功能介绍了。

 

总结

    由于接下来主要是对xml中的标签进行解析,主要包含<beans>、<bean>、<import>、<alias>,内容也算比较多,所以另算章节进行展开解读。

    回头看本篇,内容相对来说还是很简单,主要就是“空壳”工厂的创建、配置文件的解析,我们最关心的Bean解析注册将放在下节讲解。

转载于:https://my.oschina.net/marvelcode/blog/1829849

你可能感兴趣的文章
瀑布开发模式和敏捷开发模式
查看>>
1.单一职责原则
查看>>
98.Ext.form.Label组件的基本用法
查看>>
Maven配置ojdbc14-10.2.0.4.0.jar
查看>>
Java的封装性、继承性和多态性
查看>>
靶形数独
查看>>
支持向量机(四)——非线性支持向量机
查看>>
php遍历对象属性,可以使用foreach,直接打印出属性
查看>>
jquery下ie的margin-left ----bug 以及parseInt方法bug
查看>>
jdbc
查看>>
[c++]合并排序多个已排好序的单项链表
查看>>
[六省联考2017]相逢是问候——欧拉定理+线段树
查看>>
vue2.x 时间范围 date range timepicker。只在项目中使用elementUI的date-picker
查看>>
牛客练习赛22 简单瞎搞题
查看>>
Codeforces Round #450 (Div. 2)
查看>>
oss上传文件0字节
查看>>
Django 对接 支付宝支付, 回调
查看>>
实验验证redis的快照和AOF
查看>>
promise、resolve、reject、拦截响应
查看>>
DNS使用的是TCP协议还是UDP协议简析
查看>>