天天看点

Spring Framework IoC容器启停简介

作者:NiceEleven

本篇我们一起来简单的看一下Spring Framework IoC容器启动停止。我们从上一篇的代码入手:

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.eleven.thinking.in.spring.ioc.overview.container;

import org.eleven.thinking.in.spring.ioc.overview.domain.User;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.Map;

/**
 * 注解能力 {@link ApplicationContext} 作为 IoC 容器示例
 *
 * @author <a href="mailto:[email protected]">eleven</a>
 * @since
 */
@Configuration
public class AnnotationApplicationContextAsIoCContainerDemo {

    public static void main(String[] args) {
        // 创建 BeanFactory 容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        // 将当前类 AnnotationApplicationContextAsIoCContainerDemo 作为配置类(Configuration Class)
        applicationContext.register(AnnotationApplicationContextAsIoCContainerDemo.class);
        // 启动应用上下文
        applicationContext.refresh();
        // 依赖查找集合对象
        lookupCollectionByType(applicationContext);

        // 关闭应用上下文
        applicationContext.close();

    }

    /**
     * 通过 Java 注解的方式,定义了一个 Bean
     */
    @Bean
    public User user() {
        User user = new User();
        user.setId(1L);
        user.setName("eleven");
        return user;
    }

    private static void lookupCollectionByType(BeanFactory beanFactory) {
        if (beanFactory instanceof ListableBeanFactory) {
            ListableBeanFactory listableBeanFactory = (ListableBeanFactory) beanFactory;
            Map<String, User> users = listableBeanFactory.getBeansOfType(User.class);
            System.out.println("查找到的所有的 User 集合对象:" + users);
        }
    }
}           

我们从applicationContext.refresh();这行代码如下,applicationContext的这个方法refresh()翻译过来是刷新的意思,其实这里就是创建整个应用上下文的入口,主要代码如下:

@Override
	public void  refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			/**
			 * 1.刷新预处理
			 */
			// Prepare this context for refreshing.
			prepareRefresh();

			/**
			 * 2.阅读XML中的信息,注册BeanDefinition
			 * obtainFreshBeanFactory 获取 beanFactory 实例并且完成BeanDefinition的注册工作
			 */
			// Tell the subclass to refresh the internal bean factory.
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// Prepare the bean factory for use in this context.
			/**
			 * 3.beanFactory 加载应用上下文中的内建Bean和非Bean对象
			 */
			prepareBeanFactory(beanFactory);

			try {
				// 4. Allows post-processing of the bean factory in context subclasses.
				postProcessBeanFactory(beanFactory);

				/**
				 * 执行bean后场处理器,执行完毕
				 * 解析BeanDefinition对象,put到map里
				 * 再次执行bean后置工厂处理器
				 */
				// 5. Invoke factory processors registered as beans in the context.
				invokeBeanFactoryPostProcessors(beanFactory);

				// 6. Register bean processors that intercept bean creation.
				//注册bean的后置处理器来方便拦截bean的创建
				registerBeanPostProcessors(beanFactory);

				// 7.Initialize message source for this context.
				initMessageSource();

				// 8.Initialize event multicaster for this context.
				initApplicationEventMulticaster();

				// 9.Initialize other special beans in specific context subclasses.
				onRefresh();

				// 10.Check for listener beans and register them.
				registerListeners();

				// 11.创建单实例业务Bean(非懒加载单例bean)
				// 服务启动的时候,就会初始化所有的单例bean
				// Instantiate all remaining (non-lazy-init) singletons.
				finishBeanFactoryInitialization(beanFactory);

				// 12.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();
			}
		}
	}           

启动的步骤如下:

  • 刷新预处理;
  • 阅读XML中的信息,注册BeanDefinition;
  • beanFactory 加载应用上下文中的内建Bean和非Bean对象;
  • 执行beanFactory后处理器;
  • 执行bean后处理器;
  • 注册bean的后置处理器来方便拦截bean的创建;
  • Initialize message source for this context;
  • Initialize event multicaster for this context;
  • Initialize other special beans in specific context subclasses;
  • Check for listener beans and register them;
  • 创建单实例业务Bean(非懒加载单例bean);
  • 完成创建.

另外一方面我们再来看一下停止的方法,代码如下:

@Override
public void destroySingletons() {
	super.destroySingletons();
	updateManualSingletonNames(Set::clear, set -> !set.isEmpty());
	clearByTypeCache();
}           

停止的步骤如下:

  • 销毁所有的Bean对象;
  • 销毁相关的容器。