Spring源码-启动过程

扫码关注公众号:Java 技术驿站

发送:vip
将链接复制到本浏览器,永久解锁本站全部文章

【公众号:Java 技术驿站】 【加作者微信交流技术,拉技术群】

Spring源码分析(一)-Spring环境的初始化

Spring的框架特征

以下摘自知道词条
控制反转——Spring通过一种称作控制反转(IoC)的技术促进了低耦合。当应用了IoC,一个对象依赖的其它对象会通过被动的方式传递进来,而不是这个对象自己创建或者查找依赖对象。你可以认为IoC与JNDI相反——不是对象从容器中查找依赖,而是容器在对象初始化时不等对象请求就主动将依赖传递给它。
面向切面——Spring提供了面向切面编程的丰富支持,允许通过分离应用的业务逻辑与系统级服务(例如审计(auditing)和事务(transaction)管理)进行内聚性的开发。应用对象只实现它们应该做的——完成业务逻辑——仅此而已。它们并不负责(甚至是意识)其它的系统级关注点,例如日志或事务支持。
容器——Spring包含并管理应用对象的配置和生命周期,在这个意义上它是一种容器,你可以配置你的每个bean如何被创建——基于一个可配置原型(prototype),你的bean可以创建一个单独的实例或者每次需要时都生成一个新的实例——以及它们是如何相互关联的。然而,Spring不应该被混同于传统的重量级的EJB容器,它们经常是庞大与笨重的,难以使用。
框架——Spring可以将简单的组件配置、组合成为复杂的应用。在Spring中,应用对象被声明式地组合,典型地是在一个XML文件里。Spring也提供了很多基础功能(事务管理、持久化框架集成等等),将应用逻辑的开发留给了你。
MVC——Spring的作用是整合,但不仅仅限于整合,Spring 框架可以被看做是一个企业解决方案级别的框架。客户端发送请求,服务器控制器(由DispatcherServlet实现的)完成请求的转发,控制器调用一个用于映射的类HandlerMapping,该类用于将请求映射到对应的处理器来处理请求。HandlerMapping 将请求映射到对应的处理器Controller(相当于Action)在Spring 当中如果写一些处理器组件,一般实现Controller 接口,在Controller 中就可以调用一些Service 或DAO 来进行数据操作 ModelAndView 用于存放从DAO 中取出的数据,还可以存放响应视图的一些数据。 如果想将处理结果返回给用户,那么在Spring 框架中还提供一个视图组件ViewResolver,该组件根据Controller 返回的标示,找到对应的视图,将响应response 返回给用户。
我们将分章节介绍Spring是如何实现这些功能的。

Spring是如何初始化的

我们知道在WEB项目中集成Spring是需要在web.xml中添加一个监听器

        <listener>
            <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
        </listener>

非Web项目:

    java
    public static void main(String[] args) {

    //所有配置文件
    args = new String[] {
    "classpath:spring/spring-servlet.xml",
    "classpath:spring/ApplicationContext.xml",
    "classpath:spring/mybatis-config.xml",
    };
    ApplicationContext actx = new ClassPathXmlApplicationContext(args);
    //得到类的实例
    UserService userService = (UserService) actx.getBean("userService");
    //调用类的方法
    userService.deleteUser(2);
    }

这里先以非Web项目为准,虽说Spring最长使用场景是在Web项目中,但是非Web项目这种用法更直接,更易跟踪。

看一下这个构造方法,歌词大意是创建一个ClassPathXmlApplicationContext,并从指定的配置文件加载定义,并自动的刷新Context(上下文)

    java
        /** * Create a new ClassPathXmlApplicationContext, loading the definitions * from the given XML file and automatically refreshing the context. * @param configLocation resource location * @throws BeansException if context creation failed */
        public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
            this(new String[] {configLocation}, true, null);
        }

跟踪下来看看多参构造器

    java
        /** * Create a new ClassPathXmlApplicationContext with the given parent, * loading the definitions from the given XML files. * @param configLocations array of resource locations * @param refresh whether to automatically refresh the context, * loading all bean definitions and creating all singletons. * Alternatively, call refresh manually after further configuring the context. * @param parent the parent context * @throws BeansException if context creation failed * @see #refresh() */
        public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
                throws BeansException {

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

super(ApplicationContext parent) 暂时不管,因为我们通过那个构造器转进来,parent参数是null
setConfigLocations(configLocations); 这个是初始化context中的配置文件路径
refresh() 追进去看下

其实这个方法定义在父类org.springframework.context.support.AbstractApplicationContext 中,从这代码的书写方式上是可以看出Spring一些加载流程的(中文我自己加的,渣英语)

    java
    @Override
        public void refresh() throws BeansException, IllegalStateException {
            synchronized (this.startupShutdownMonitor) {
                // Prepare this context for refreshing. //为正在进行的刷新准备bean工厂
                prepareRefresh();

                // Tell the subclass to refresh the internal bean factory. //告诉子类去刷新内部的beanFactory
                ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

                // Prepare the bean factory for use in this context. 
                // 在当前上下文中,准备Bean工厂
                prepareBeanFactory(beanFactory);

                try {
                    // Allows post-processing of the bean factory in context
                    // subclasses.
                    // 在bean被装载后,提供一个修改BeanFactory的入口 ,即允许子类做一些后处理
                    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.
                    // 检查是否有监听器bean并注册他们
                    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.
                    // 销毁一些已经创建的bean
                    destroyBeans();

                    // Reset 'active' flag.
                    // 重置'active'标记
                    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();
                }
            }
        }

从以上代码,大概可知一个Spring上下文启动或刷新的过程

    java
    /** * Prepare this context for refreshing, setting its startup date and active * flag as well as performing any initialization of property sources. */
        protected void prepareRefresh() {
            this.startupDate = System.currentTimeMillis();
            this.closed.set(false); //AtomicBoolean 类型 
            this.active.set(true);  //AtomicBoolean 类型 

            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<ApplicationEvent>();
        }

obtainFreshBeanFactory 看方法名是一个刷新Bean工厂的方法,其方法签名为 protected ConfigurableListableBeanFactory obtainFreshBeanFactory()
结合Spring源码注释 “Tell the subclass to refresh the internal bean factory.” ,方法含义为刷新并返回内部BeanFactory工厂

    /** * Tell the subclass to refresh the internal bean factory. * @return the fresh BeanFactory instance * @see #refreshBeanFactory() * @see #getBeanFactory() */
        protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
            refreshBeanFactory(); //静态方法,子类覆写
            ConfigurableListableBeanFactory beanFactory = getBeanFactory(); //静态方法子类覆写
            if (logger.isDebugEnabled()) {
                logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
            }
            return beanFactory;
        }

那么实现该方法的子类是谁呢?,回到ClassPathXmlApplicationContext,看看其UML图
20191017100173\_1.png
查看refreshBeanFactory的子类覆写情况,如图,明显是org.springframework.context.support.AbstractRefreshableApplicationContext 这个类
20191017100173\_2.png

通过代码看看BeanFactory是如何刷新的

    /** * This implementation performs an actual refresh of this context's underlying * bean factory, shutting down the previous bean factory (if any) and * initializing a fresh bean factory for the next phase of the context's lifecycle. */
        @Override
        protected final void refreshBeanFactory() throws BeansException {
            if (hasBeanFactory()) {//判断是否已经有BeanFactory
                destroyBeans();  //销毁单例bean,代码(getBeanFactory().destroySingletons()),具体是如何销毁的由具体的BeanFactory去实现
                closeBeanFactory(); //关闭BeanFactory,直接设置实例变量(this.beanFactory)的引用为null
            }
            try {
                DefaultListableBeanFactory beanFactory = createBeanFactory(); //创建一个新的BeanFactory
                beanFactory.setSerializationId(getId());
                customizeBeanFactory(beanFactory); //干了两个事,1:allowBeanDefinitionOverriding(是否允许ID相同的Bean覆盖,不指定时默认为true) 2.allowCircularReferences(是否允许循环引用,不指定时默认为true)
                loadBeanDefinitions(beanFactory); //加载Bean的定义(读取配置文件,并向bean工厂中注册Bean)customizeBeanFactory中设置的作用会在读取Bean定义并注册的时候体现
                synchronized (this.beanFactoryMonitor) {
                    this.beanFactory = beanFactory; //将新的Bean工厂注册给当前的Context
                }
            }
            catch (IOException ex) {
                throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
            }
        }

createBeanFactory();方法中创建了一个beanFactory,Factory实现与层级结构暂不分析,只看Spring的启动准备,loadBeanDefinitions(beanFactory);加载并注册Bean,refreshBeanFactory()主要干了两个事,先把Context中原来的工厂干掉,在重新创建和初始化一个新的Beanfactory.


来源:[]()

赞(0) 打赏
版权归原创作者所有,任何形式的转载请联系博主:daming_90:Java 技术驿站 » Spring源码-启动过程

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏