当前位置:   article > 正文

带你从源码角度搞懂Spring的加载机制_sprting加载上下文机制

sprting加载上下文机制

前言

Spring 是Java 程序猿的必经之路,但对于 Spring 的学习,相信大多人停留在会使用的阶段,那你了解 Spring 加载时都做了哪些工作?Spring 上下文是如何加载的?Spring 是怎么实现灵活扩展的?只有弄明白了这些,才能更好的明白 Spring 的实现细节,才能更好的驾驭 Spring !

聊聊容器

容器的概念很多人可能经常放嘴边,毕竟,容器概念的热度很高。那什么是容器?Linux Container?Docker?一个简单的Map?答案是都对,这都是容器,我们喝水的杯子也是容器,海边码头的集装箱也是容器,容器的作用就是“装”——“装”东西!容器的概念是很宽泛的,重点是这种隔离性的容器思想。

相信大多数 DevOps 都经历过类似这种的事情,开发好的应用程序要进行部署,于是,安装操作系统和各种依赖环境,部署好了以后,公司现在要清理服务器,需要将部署的应用程序移植到其他的服务器。那我们是不是需要重新部署?这时,聪明的前辈们就在想,有没有办法能让部署好的服务可以轻便的移植到其他地方,可以不用在安装一套操作系统和依赖环境。这就像集装箱运载一样,把货物,一辆兰博基尼(好比开发好的应用程序),打包到一个集装箱里,通过货轮从上海码头(CentOS7环境)运输到别的码头(Ubuntu14环境),而且运输期间,我的兰博基尼(应用程序)没有收到任何损坏(文件丢失),在另一个码头卸货后,依然可以极速飞驰。(启动正常)。当然,这个问题现在已经得到很好的解决了!这就是容器技术的应用~

Spring 最核心的就是容器,那 Spring 容器是Map吗?

Spring 容器不仅仅是 Map,因为 Spring 容器不仅仅是存放Bean,最主要的功能是“管理Bean的声明周期和依赖”。对象的创建,销毁…

组件A依赖组件B和C,C依赖D,D依赖B…现在我要得到组件A,就需要相应的一层层的初始化其他组件,其他组件之间可能存在相互依赖的情况,这种层层依赖的管理如果人工管理就会非常麻烦~容器会帮助我们管理组件,让开发人员专注于程序的开发。

所以,管理Bean是Spring 容器核心要解决的事情!

Spring ApplicationContext的加载

想明白 Spring 的加载机制,就必须先清楚 Spring ApplicationContext 到底是什么,以及与 BeanFactory 的关系。

Spring ApplicationContext 是围绕 Spring 整体来设计的,从类型上看它是 BeanFactory 类型,因为它是 BeanFactory 的实现类,功能比 BeanFactory 丰富,可以理解为 ApplicatonContext 扩展了 BeanFactory,是 Spring ApplicationContext 框架的核心设计。

通过看类图得知,AbstractApplicationContext 是 ApplicationContext 的实现类,也是最重要的核心类。其中核心方法 refresh就是AbstractApplicationContext 类提供的。
在这里插入图片描述
看看AbstractApplicationContext 的 refresh() 方法做了什么?

@Override
public void refresh() throws BeansException, IllegalStateException {
	// 互斥锁,防止重复调用,保证上下文的对象状态
    synchronized(this.startupShutdownMonitor) {
    	// 启动前准备参数
        this.prepareRefresh();
        // 获得子类创建的 BeanFactory 实例,如已经存在,销毁重新创建
        ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
        // 给新创建的 BeanFactory实例,准备上下文环境--类加载器,bean表达式解析器,bean后置处理器等
        this.prepareBeanFactory(beanFactory);

        try {
        	// 在标准初始化后,修改应用上下文的内部beanFactory,通过重写此方法加载所有bean,但是不实例化bean。
        	// 调用 BeanFactory 实例化后置处理器
            this.postProcessBeanFactory(beanFactory);
            // 调用 工厂处理器 注册 bean
            this.invokeBeanFactoryPostProcessors(beanFactory);
            // 在 Bean 工厂中注册 Bean 的后置处理器
            this.registerBeanPostProcessors(beanFactory);
            // 初始化消息源,并且设置父消息源来自父容器的配置
            this.initMessageSource();
            // 初始化 消息推送器,注册一个默认的单例 Bean
            this.initApplicationEventMulticaster();
            // 调用子类重写的方法初始化其他 bean,模板方法设计模式的体现!
            this.onRefresh();
            // 注册 bean 监听器
            this.registerListeners();
            // 初始化所有剩余的单例 bean(非延迟加载的)并设置冻结标志位,防止重新实例化 Bean 浪费资源
            this.finishBeanFactoryInitialization(beanFactory);
            // 注册、启动 LifecycleProcessor,并且发送启动完成事件
            this.finishRefresh();
        } catch (BeansException var9) {
            if (this.logger.isWarnEnabled()) {
                this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
            }

			// 销毁已经创建的单例 bean ,避免悬挂资源
            this.destroyBeans();
            // 释放标志位,标识其可以重新启动
            this.cancelRefresh(var9);
            throw var9;
        } finally {
        	// 清除与反射相关的缓存
            this.resetCommonCaches();
        }

    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48

通读以上源码,可得知,初始化 bean 的时候使用了模板方法设计模式,让子类去实现自己的实例加载。下面我们来看看子类是如何通过 AbstractApplicationContext 基类实现灵活扩展实例的。

XmlWebApplicationContext

我们来看看 AbstractApplicationContext 的子类 XmlWebApplicationContext 是如何通过基类的模板方法实现的扩展适应 Web 场景的上下文实例。

@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
	// 创建一个读取XML文件的实例对象,并将读取到的 Bean 描述定义信息加载到 BeanFactory 中
	XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

	// 配置读取 Bean 的上下文环境
	beanDefinitionReader.setEnvironment(getEnvironment());
	beanDefinitionReader.setResourceLoader(this);
	beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

	// 使用当前 reader 读取指定的 XML 文件中的 Bean 描述信息到工厂中
	initBeanDefinitionReader(beanDefinitionReader);
	loadBeanDefinitions(beanDefinitionReader);
}

protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws IOException {
	String[] configLocations = getConfigLocations();
	if (configLocations != null) {
		// 读取 XML 配置文件
		for (String configLocation : configLocations) {
			reader.loadBeanDefinitions(configLocation);
		}
	}
}

// 子类 StaticWebApplicationContext 重写父类 AbstractApplicationContext 的方法,使用 BeanFactory 实例化后置处理器
@Override
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
	// 在当前的 Bean 工厂中添加 Bean 后置处理器
	beanFactory.addBeanPostProcessor(new ServletContextAwareProcessor(this.servletContext, this.servletConfig));
	beanFactory.ignoreDependencyInterface(ServletContextAware.class);
	beanFactory.ignoreDependencyInterface(ServletConfigAware.class);

	// 注册 Web 应用的 Bean 作用范围、WebRequest、Session,详情见下方!
	WebApplicationContextUtils.registerWebApplicationScopes(beanFactory, this.servletContext);
	// 注册 上下文环境和配置参数,并注册两个 Bean 用于存放这些参数
	WebApplicationContextUtils.registerEnvironmentBeans(beanFactory, this.servletContext, this.servletConfig);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38

WebApplicationContextUtils 的 registerWebApplicationScopes 方法!

// 注册 web 应用的 Bean 作用域范围
public static void registerWebApplicationScopes(ConfigurableListableBeanFactory beanFactory,
		@Nullable ServletContext sc) {

	beanFactory.registerScope(WebApplicationContext.SCOPE_REQUEST, new RequestScope());
	beanFactory.registerScope(WebApplicationContext.SCOPE_SESSION, new SessionScope());
	if (sc != null) {
		ServletContextScope appScope = new ServletContextScope(sc);
		beanFactory.registerScope(WebApplicationContext.SCOPE_APPLICATION, appScope);
		// 注册 Servlet 上下文属性
		sc.setAttribute(ServletContextScope.class.getName(), appScope);
	}

	beanFactory.registerResolvableDependency(ServletRequest.class, new RequestObjectFactory());
	beanFactory.registerResolvableDependency(ServletResponse.class, new ResponseObjectFactory());
	beanFactory.registerResolvableDependency(HttpSession.class, new SessionObjectFactory());
	beanFactory.registerResolvableDependency(WebRequest.class, new WebRequestObjectFactory());
	if (jsfPresent) {
		// 避免 jsf 依赖
		FacesDependencyRegistrar.registerFacesDependencies(beanFactory);
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

通读以上源码,可以看出 XmlWebApplicationContext 是如何利用基类 AbstractApplicationContext ,灵活扩展适应 web 场景的上下文实例的。

本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号