• Spring源码分析之ApplicationContext


    前言

    通过前面的博客我们已经对Spring的IOC容器有了一定的了解,它的底层实现为DefaultListableBeanFactory,这是一个BeanFactory,
    ApplicationContext在BeanFactory容器的基础上又增加了很多功能,如事件分发,国际化等。相关类图如下

    可以看到ApplicationContext是BeanFactory的子接口,但是它没有自己实现这些方法,对于Bean的操作,都是委托给BeanFactory来处理的。
    ApplicationContext有很多实现类,如支持XML配置的ClassPathXmlApplicationContext,支持注解配置的AnnotationConfigApplicationContext,
    支持内嵌Tomcat和注解的AnnotationConfigServletWebServerApplicationContext(SpringBoot默认使用)。
    这里我们以ClassPathXmlApplicationContext为例来分析,AnnotationConfigApplicationContext对于注解的处理额外做了很多工作,不利于分析流程。

    简单使用

    首先在classpath下创建一个XML配置文件

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    
      <bean id="userService"
        class="com.imooc.sourcecode.java.spring.ioc.test4.TestXmlContext.UserService"/>
    </beans>
    

    使用ClassPathXmlApplicationContext来解析此配置文件

    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class TestXmlContext {
    
      public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext();
        context.setConfigLocation("spring.xml");
        context.refresh();
        UserService userService = (UserService) context.getBean("userService");
        userService.userList();//userList
      }
    
      public static class UserService {
    
        public void userList() {
          System.out.println("userList");
        }
      }
    }
    

    使用方式很简单,但Spring内部帮我们做了很多工作。

    源码分析

    核心为refresh()方法,进入父类AbstractApplicationContext中

    @Override
    public void refresh() throws BeansException, IllegalStateException {
    		synchronized (this.startupShutdownMonitor) {
    			//做一些准备工作,主要是environment对象的创建
    			prepareRefresh();
    
    			//创建DefaultListableBeanFactory容器,并从XML配置文件中加载BeanDefinition,注册到容器中
    			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
    
    			//配置BeanFactory,设置ClassLoader,设置SpringEL表达式解析器,向BeanFactory中添加特定的BeanPostProcessor
    			prepareBeanFactory(beanFactory);
    
    			try {
    				//对beanFactory做一些处理,留给子类扩展
    				postProcessBeanFactory(beanFactory);
    
    				//从容器中获取所有类型为BeanDefinitionRegistryPostProcessor和BeanFactoryPostProcessor的Bean,并执行他们的扩展方法
                                    //这两个类是Spring提供的两种扩展
                                    //ConfigurationClassPostProcessor(用来解析@Configuration类,注解自动扫描等)就是在这一步执行的
    				invokeBeanFactoryPostProcessors(beanFactory);
    
    				//从容器中获取所有类型为BeanPostProcessor的Bean,并设置到BeanFactory中(调用BeanFactory的addBeanPostProcessor()方法)
                                    //最重要的AutowiredAnnotationBeanPostProcessor(处理@Autowired注解)就是在这添加的
    				registerBeanPostProcessors(beanFactory);
    
    				//初始化MessageSource,这是一个支持国际化的组件
    				initMessageSource();
    
    				//初始化事件分发器,默认类型为SimpleApplicationEventMulticaster,通过它我们可以实现事件的订阅和发布
    				initApplicationEventMulticaster();
    
    				//留给子类扩展,ServletWebServerApplicationContext(SpringBoot使用的是它的子类)在这一步创建了WebServer(默认是Tomcat),注意,还没启动
    				onRefresh();
    
    				//从容器中获取所有类型为ApplicationListener的Bean,并注册到事件分发器中
                                    //SpringBoot会从spring.factories中获取配置的ApplicationListener列表,
                                    //如ConfigFileApplicationListener(用来解析application.yml文件或application.properties文件)
    				registerListeners();
    
    				//实例化所有非懒加载的单例Bean,其实就是依次调用getBean(name)方法,BeanFactory会在第一次调用时创建Bean
    				finishBeanFactoryInitialization(beanFactory);
    
    				//实例化DefaultLifecycleProcessor对象(这是一个生命周期处理器),
                                    //发布ContextRefreshedEvent事件(监听此事件的ApplicationListener都会处理)
                                    //ServletWebServerApplicationContext(SpringBoot使用的是它的子类)在这一步启动WebServer(默认是Tomcat)
    				finishRefresh();
    			}
    
    			catch (BeansException ex) {
    				//如果抛出异常,销毁所有已经创建的Bean
    				destroyBeans();
    
    				//重置active标识
    				cancelRefresh(ex);
    
    				throw ex;
    			}
    
    			finally {
    				//清空缓存,如反射的缓存
    				resetCommonCaches();
    			}
    		}
    	}
    

    此方法执行完,我们的ApplicationContext对象可以算是初始化完成了,所有的非懒加载Bean也已经创建完成了。
    上面的每一个方法实现都是比较复杂的,细节很多,这里我们再简单分析一下obtainFreshBeanFactory()方法。

    protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
                    //创建并初始化BeanFactory
    		refreshBeanFactory();
    		return getBeanFactory();
    	}
    

    继续跟进去refreshBeanFactory()方法,AbstractRefreshableApplicationContext类重写了此方法

    @Override
    protected final void refreshBeanFactory() throws BeansException {
                    //如果已经创建过BeanFactory,销毁所有Bean
    		if (hasBeanFactory()) {
    			destroyBeans();
    			closeBeanFactory();
    		}
    		try {
                            //创建一个新的beanFactory,可以看到实现为DefaultListableBeanFactory类型
    			DefaultListableBeanFactory beanFactory = createBeanFactory();
    			beanFactory.setSerializationId(getId());
    			customizeBeanFactory(beanFactory);
                            //从XML配置文件中加载BeanDefinition
    			loadBeanDefinitions(beanFactory);
    			synchronized (this.beanFactoryMonitor) {
    				this.beanFactory = beanFactory;
    			}
    		}
    	}
    

    分析总结

    从上面的类图可以看到,ApplicationContext接口继承ApplicationEventPublisher(事件分发器),MessageSource(国际化相关),BeanFactory(IOC容器),
    但ApplicationContext的实现类本身没有实现这些接口的方法,而是委托给对应的实现类,如事件分发委托给SimpleApplicationEventMulticaster,
    国际化委托给ResourceBundleMessageSource(我们需要自己定义此Bean),IOC容器委托给DefaultListableBeanFactory。

    @Override
    public Object getBean(String name) throws BeansException {
    		return getBeanFactory().getBean(name);
    	}
    

    以getBean()方法为例,可以看到确实是交给内部的BeanFactory来处理的。

    关于国际化,可以查看Spring对国际化的支持

    参考

    Spring IOC 容器源码分析

  • 相关阅读:
    通过POST请求上传文件
    接口测试及常用接口测试工具
    maven-surefire-plugin插件
    BDD框架之Cucumber研究
    一分钟认识:Cucumber框架
    ACM团队周赛题解(3)
    C++11新增容器以及元组
    ACM团队周赛题解(2)
    C++11部分特性
    ACM团队周赛题解(1)
  • 原文地址:https://www.cnblogs.com/strongmore/p/16227246.html
Copyright © 2020-2023  润新知