【spring源码分析】之启动

 2019-11-02 21:20  阅读(849)
文章分类:Spring boot

spring应该是java中最常用的开源框架,引入spring可以降到应用开发的复杂性。平常大家更关注于spring的应用,本文就和各位一起来分析一下spring的源码。

spring发展到今天,已然是个十分庞大的框架,往往不知从何处下手,本文就从spring的加载过程入手。

ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
            applicationContext.getBean("name");

上面这段简单的代码就是spring的启动方式之一,通过对于ClassPathXmlApplicationContext的实例化就可以完成spring的加载过程。先给出ClassPathXmlApplicationContext的继承关系图,诸如spring的框架,结构都较复杂,列一下继承的关系,对于我们的理解很有帮助,图如下:
20191102100709\_1.png

ClassPathXmlApplicationContext的构造函数

public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
            this(new String[] {configLocation}, true, null);
        }

public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
                throws BeansException {

            super(parent);
            setConfigLocations(configLocations);
            if (refresh) {
                refresh();
            }
        }

构造函数的功能:加载指定的xml文件并且刷新上下文内容。

从以上贴的代码来看很简单,就是做了三件事:

1.super(parent)

设置父级的ApplicationContext,这里设置了null

2.setConfigLocations(configLocations)

设置spring配置文件的路径,并且对于路径中的占位置进行转换

3.refresh()

refresh()是spring加载的核心内容,通过xml、properties、database对于context加载和刷新,完成对于所有单例类的初始化工作。

refresh()方法

上文已经提到refresh()方法是整个spring的加载的核心,这也是我们本次需要提到的重点内容,先展示refresh()的完整代码如下:

@Override
        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) {
                    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;
                }
            }
        }

首先spring的refresh()方法的一些特点:

1.方法从开始到结束都使用了对于this.startupShutdownMonitor的加锁处理

1).避免了多线程同时刷新spring配置

2).close()和refresh()都对startupShutdownMonitor进行加锁,close()的作用和refresh()是相反的:关闭context,销毁所有的bean。避免了2者的同时执行,产生冲突。

2.refresh()方法中没有具体的对于业务逻辑处理的代码,而是分成了若干个子方法,方便项目维护和代码拓展。

本文先讲到这里,下一篇开始,对于refresh()中的各个子方法进行详细的梳理


来源:http://ddrv.cn

点赞(0)
版权归原创作者所有,任何形式转载请联系作者; Java 技术驿站 >> 【spring源码分析】之启动

相关推荐