• Spring Framework框架容器核心源码逐步剖析


    构建Spring环境

    采用ApplicationContext context = new ClassPathXmlApplicationContext("classpath:spring.xml");方式构建Spring容器并查看其内部运行过程.

    Spring 版本 5.1.3.RELEASE

            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-context</artifactId>
                <version>5.1.3.RELEASE</version>
            </dependency>
    

    测试类

    public class User {
        private String username;
        private String password;
    
        public User(String username, String password) {
            this.username = username;
            this.password = password;
        }
    
        public String getUsername() {
            return username;
        }
    
        public void setUsername(String username) {
            this.username = username;
        }
    
        public String getPassword() {
            return password;
        }
    
        public void setPassword(String password) {
            this.password = password;
        }
    }
    

    Spring 配置文件

    <?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 name="user" class="com.jimisun.learnspringboot.web.User">
            <constructor-arg index="0" value="jimisun"/>
            <constructor-arg index="1" value="jimisun"/>
        </bean>
    
    </beans>
    

    测试方法Main

    public class Main {
            public static void main(String[] args) {
                // 用我们的配置文件来启动一个 ApplicationContext
                ApplicationContext context = new ClassPathXmlApplicationContext("classpath:spring.xml");
                System.out.println("context 启动成功");
                User user = context.getBean(User.class);
                System.out.println(user.toString());
            }
    }
    

    快速进入Debug查看IOC容器构建源码

    ApplicationContext 启动过程中,会创建SPring Bean容器,然后初始化相关Bean,再向Bean中注入其相关依赖。

    所以我们仅仅需要Debug跟踪Main方法中ApplicationContext context = new ClassPathXmlApplicationContext("classpath:spring.xml");这一句代码,查看Spring是如何创建ApplicationContext容器并将xml中的配置信息装配进容器的.

    Spring IOC源码步骤分析

    第一步: 检查并设置Spring XML配置文件

    功能:设置此应用程序上下文的配置文件位置,如果未设置;Spring可以根据需要使用默认值

    setConfigLocations(configLocations);

    在Main方法Debug启动进入断点,按F7跟进入其方法查看,会进入ClassPathXmlApplicationContext类的构造方法中

    public class ClassPathXmlApplicationContext extends AbstractXmlApplicationContext {
      private Resource[] configResources;
      // 如果已经有 ApplicationContext 并需要配置成父子关系,那么调用这个构造方法
      public ClassPathXmlApplicationContext(ApplicationContext parent) {
        super(parent);
      }
      ...
      public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
          throws BeansException {
    
        super(parent);
        // 根据提供的路径,处理成配置文件数组(以分号、逗号、空格、tab、换行符分割)
        setConfigLocations(configLocations);
        if (refresh) {
          refresh(); // 核心方法  剩余的所有步骤都在此方法中!!!
        }
      }
        ...
    }
    
    

    首先执行"设置配置位置setConfigLocations"的方法,解析SpringXML配置文件地址存储到configLocations属性中。

    	public void setConfigLocations(@Nullable String... locations) {
            //判断配置路径是否为null
    		if (locations != null) {
    			Assert.noNullElements(locations, "Config locations must not be null");
                //循环将配置文件路径存储到属性configLocations中
    			this.configLocations = new String[locations.length];
    			for (int i = 0; i < locations.length; i++) {
    				this.configLocations[i] = resolvePath(locations[i]).trim();
    			}
    		}
    		else {
    			this.configLocations = null;
    		}
    	}
    

    第二步:执行创建Bean容器之前的准备工作

    注意:除了第一步设置XML配置文件路径,剩余的步骤都在该类的refresh();这个方法中执行,所以我们需要Debug跟进入这个方法

    refresh();方法如下所示;因为整个SpringApplication的构建都在这个方法 里面所以就现在这里展现一下和大家混个脸熟.

    public void refresh() throws BeansException, IllegalStateException {
         //对下面的代码块添加同步锁
       synchronized (this.startupShutdownMonitor) {
        //第二步: 执行创建容器前的准备工作 :记录下容器的启动时间、标记“已启动”状态、处理配置文件中的占位符
          prepareRefresh();
      //第三步:创建Bean容器,加载XML配置信息 : 如果存在容器进行销毁旧容器,创建新容器,解析XML配置文件为一个个BeanDefinition定义注册到新容器(BeanFactory)中,注意Bean未初始化 
          ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
          //第四步: 设置 BeanFactory 的类加载器,添加几个 BeanPostProcessor,手动注册几个特殊的 bean
          prepareBeanFactory(beanFactory);
          try {
             //第五步:加载并执行后置处理器 
             postProcessBeanFactory(beanFactory);
             //执行postProcessBeanFactory()方法
             invokeBeanFactoryPostProcessors(beanFactory);
              // 实例化拦截Bean创建的后置处理器beanPostProcessors
             registerBeanPostProcessors(beanFactory);
             //第六步: 初始化Spring容器的消息源
             initMessageSource();
             //第七步:初始化Spring容器事件广播器
             initApplicationEventMulticaster();
             // 空方法
             onRefresh();
             //第八步:注册事件监听器 
             registerListeners();
             //第九步核心方法:初始化(构造)所有在XML文件中配置的单例非延迟加载的bean
             finishBeanFactoryInitialization(beanFactory);
             //第十步:清理缓存,如果容器中存Bean名为lifecycleProcessor的Bean 对其进行注册,如果不存在创建一个DefaultLifecycleProcessor进行注册
             finishRefresh();
          }
          catch (BeansException ex) {
             if (logger.isWarnEnabled()) {
                logger.warn("Exception encountered during context initialization - " +
                      "cancelling refresh attempt: " + ex);
             }
             // 摧毁已经创建的单身人士以避免悬空资源。
             destroyBeans();
             // 重置'有效'标志。
             cancelRefresh(ex);
             // 向调用者传播异常。
             throw ex;
          }
    
          finally {
             //重置Spring核心的工具类的缓存
             resetCommonCaches();
          }
       }
    }
    

    第二步的主要工作:准备工作,记录下容器的启动时间、标记“已启动”状态、处理配置文件中的占位符,初始化事件属性。

    prepareRefresh();

    protected void prepareRefresh() {
       // 记录启动时间,
       // 将 active 属性设置为 true,closed 属性设置为 false,它们都是 AtomicBoolean类型
       this.startupDate = System.currentTimeMillis();
       this.closed.set(false);
       this.active.set(true);
    	//打印Logger
       	if (logger.isDebugEnabled()) {
    			if (logger.isTraceEnabled()) {
    				logger.trace("Refreshing " + this);
    			}
    			else {
    				logger.debug("Refreshing " + getDisplayName());
    			}
    	}
    	
       // 在上下文环境中初始化任何占位符属性源 空方法  默认情况下不执行任何操作。
       initPropertySources();
       // 校验 xml 配置文件
       getEnvironment().validateRequiredProperties();
       this.earlyApplicationEvents = new LinkedHashSet<ApplicationEvent>();
    }
    

    第三步:创建 Bean 容器,加载并注册 Bean

    主要工作:进行销毁旧容器,创建新容器,加载BeanDefinition到BeanFactory

    ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

    @Override
    	protected final void refreshBeanFactory() throws BeansException {
    	      // 如果ApplicationContext中已经的BeanFactory属性已经有值,销毁此BeanFactory所有 Bean,关闭 BeanFactory,重新创建一个新的Bean容器设置给ApplicationContext的beanFactory属性
    		if (hasBeanFactory()) {
    		    //销毁容器
    			destroyBeans();
    			//创建类型为DefaultListableBeanFactory新容器放入BeanFactory变量中
    			closeBeanFactory();
    		}
    		try {
    		    //创建类型为DefaultListableBeanFactory新容器放入BeanFactory变量中
    			DefaultListableBeanFactory beanFactory = createBeanFactory();
    			//设置BeanFactory的序列化ID也就是其类名
    			beanFactory.setSerializationId(getId());
    			// 设置 BeanFactory 的两个配置属性:是否允许 Bean 覆盖、是否允许循环引用
    			customizeBeanFactory(beanFactory);
    			//这个方法将根据配置,加载各个Bean,然后放到 BeanFactory 中 注意:这里的加载并不是初始化这个Bean  而是以Key-value的形式存储在beanFactory; beanName-> beanDefinition 的 map
    			loadBeanDefinitions(beanFactory);
    			synchronized (this.beanFactoryMonitor) {
    				this.beanFactory = beanFactory;
    			}
    		}
    		catch (IOException ex) {
    			throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
    		}
    	}
    

    第四步:配置 Bean容器: prepareBeanFactory

    主要工作:在Bean容器创建完毕会"手动"注册一些特殊的 bean。官网这样解释: " 配置工厂的标准上下文特征,例如上下文的ClassLoader和后处理器 "。

    具体方法 : prepareBeanFactory(factory) ;

    protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
       		// 这里设置为加载当前 ApplicationContext 类的类加载器
    		beanFactory.setBeanClassLoader(getClassLoader());
    		// 设置 Bean的表达式解析器
    		beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
    		beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
        //默认添加一个ApplicationContextAwareProcessor的BeanPostProcessor,实现了ApplicationContextAware接口的Bean,Spring会将上下文ApplicationContext注入Bean属性中
    		beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
    		   // 下面几行的意思就是,如果某个 bean 依赖于以下几个接口的实现类,在自动装配的时候忽略它们,
    beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
    		beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);	beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);	beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
    beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
    beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
     /**
        * 下面几行就是为特殊的几个 bean 赋值,如果有 bean 依赖了以下几个,会注入这边相应的值,
        * 之前我们说过,"当前 ApplicationContext 持有一个 BeanFactory",这里解释了第一行
        * ApplicationContext 还继承了 ResourceLoader、ApplicationEventPublisher、MessageSource
        * 所以对于这几个依赖,可以赋值为 this,注意 this 是一个 ApplicationContext
        * 那这里怎么没看到为 MessageSource 赋值呢?那是因为 MessageSource 被注册成为了一个普通的 bean
        */	beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);	beanFactory.registerResolvableDependency(ResourceLoader.class, this);
    beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
    beanFactory.registerResolvableDependency(ApplicationContext.class, this);
    		//注册早期后处理器以检测内部bean作为ApplicationListeners
    		beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
    	// 如果检测到LoadTimeWeaver 准备编织  不是我们本章的重点无需关注
    	if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
    		beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
    		beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
    	}
    	//默认注册 environment systemEnvironment systemProperties的Bean 我们可以选择覆盖
    	if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
    		beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
    	}
    	if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
    		beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
    	}
    	if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
    		beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
    	}
    }
    ```
    	
    

    第五步: 处理自定义Bean的后置处理器

    主要功能:实例化在XML配置中实现了BeanFactoryPostProcessor和BeanPostProcessors接口的Bean并执行其回调方法.注意:此时普通的Bean仍然并没有初始化

    //实例化并调用XML配置中实现了BeanFactoryPostProcessors接口的的回调
    postProcessBeanFactory(beanFactory);
    invokeBeanFactoryPostProcessors(beanFactory);
    //实例化并调用XML配置中实现了BeanPostProcessors接口的的回调
    registerBeanPostProcessors(beanFactory);
    
    //注解:这里在创建完成Bean容器后执行BeanFactoryPostProcessors接口的回调,我们可以在Bean容器初始化完成的时候完成我们自己的业务逻辑(很少用),然后是registerBeanPostProcessors(beanFactory)方法,此方法的官方解释是:"Register bean processors that intercept bean creation(如果存在则注册拦截bean创建的bean后置处理器)"
    

    第六步: 初始化Spring容器的消息源

    主要功能: 初始化MessageSource。如果在此上下文中未定义,则使用parent。

    // 初始化ApplicationContext的消息源。
    initMessageSource();
    
    	protected void initMessageSource() {
    		ConfigurableListableBeanFactory beanFactory = getBeanFactory();
            //判断beanFactory中是否有messageSource的Bean
    		if (beanFactory.containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) {
    			this.messageSource = beanFactory.getBean(MESSAGE_SOURCE_BEAN_NAME, MessageSource.class);
    			// 使MessageSource知道父MessageSource
    			if (this.parent != null && this.messageSource instanceof HierarchicalMessageSource) {
    				HierarchicalMessageSource hms = (HierarchicalMessageSource) this.messageSource;
    				if (hms.getParentMessageSource() == null) {
    				//如果没有父MessageSource,则此消息源设置为父MessageSource
    					hms.setParentMessageSource(getInternalParentMessageSource());
    				}
    			}
    			if (logger.isTraceEnabled()) {
    				logger.trace("Using MessageSource [" + this.messageSource + "]");
    			}
    		}
    		else {
    			// 如果没有则创建一个默认的DelegatingMessageSource消息源
    			DelegatingMessageSource dms = new DelegatingMessageSource();
    			dms.setParentMessageSource(getInternalParentMessageSource());
    			this.messageSource = dms;
    			beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.messageSource);
    			if (logger.isTraceEnabled()) {
    				logger.trace("No '" + MESSAGE_SOURCE_BEAN_NAME + "' bean, using [" + this.messageSource + "]");
    			}
    		}
    	}
    

    第七步: 初始化Spring容器事件广播器

    PS : 在实际项目中我们很少会用到Spring的事件广播器,因为现在都是分布式应用了局部通讯很少使用了 一篇很棒的关于Spring容器的事件讲解 https://juejin.im/post/5a543ceb518825734a748c44

    主要功能 : 注册Spring的事件广播器用于广播Spring的内置事件和自定义事件

    initApplicationEventMulticaster();

    	
    protected void initApplicationEventMulticaster() {
    	//初始化ApplicationEventMulticaster
    		ConfigurableListableBeanFactory beanFactory = getBeanFactory();
    		if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
    			this.applicationEventMulticaster =
    					beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
    			if (logger.isTraceEnabled()) {
    				logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
    			}
    		}
        //如果在上下文中没有定义,则创建一个默认的SimpleApplicationEventMulticaster。
    		else {
    			this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
    			beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
    			if (logger.isTraceEnabled()) {
    				logger.trace("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using " +
    						"[" + this.applicationEventMulticaster.getClass().getSimpleName() + "]");
    			}
    		}
    	}
    

    第八步:注册事件监听器

    主要功能 : 实例化实现ApplicationListener接口的bean。

    // 注册监听器
    finishBeanFactoryInitialization(beanFactory);
    
    	protected void registerListeners() {
    		//首先注册静态指定的侦听器
    		for (ApplicationListener<?> listener : getApplicationListeners()) {
    			getApplicationEventMulticaster().addApplicationListener(listener);
    		}
            //下面是我们自定义的监听器,Spring文档中给出的建议是 "不要在这里初始化FactoryBeans:我们需要保留所有常规bean"
    String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
    		for (String listenerBeanName : listenerBeanNames) {
    			getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
    		}
            //使用已经注册的事件广播器,发布早期的应用程序事件......
    		Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
    		this.earlyApplicationEvents = null;
    		if (earlyEventsToProcess != null) {
    			for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
    				getApplicationEventMulticaster().multicastEvent(earlyEvent);
    			}
    		}
    	}
    

    第九步: 实例化所有的单例Bean

    功能:执行到这一步,Spring.xml配置文件中的特殊的Bean该注册的也注册了,该调用的也调用了,就剩下了普通的Bean了,在这一步就都实例化了.(仅仅是非延迟实例化的单例Bean),也就是说这一步就已经完成了Bean工厂(ApplicationContext)的初始化了.

    // 实例化所有SPring.xml配置文件中配置的非延迟实例化的单例Bean
    finishBeanFactoryInitialization(beanFactory);
    
    protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
    		// 初始化此上下文的转换服务
    		if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
    				beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
    			beanFactory.setConversionService(
    					beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
    		}
    
    		//如果没有bean后处理器,则注册默认的嵌入值解析器(例如PropertyPlaceholderConfigurer bean)之前注册过;此时,主要用于注释属性值的分辨率。
    		if (!beanFactory.hasEmbeddedValueResolver()) {
    			beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
    		}
    
    		// 尽早初始化LoadTimeWeaverAware bean以允许尽早注册其变换器。
    		String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
    		for (String weaverAwareName : weaverAwareNames) {
    			getBean(weaverAwareName);
    		}
    		// 停止使用临时ClassLoader进行类型匹配。
    		beanFactory.setTempClassLoader(null);
    		// 允许缓存所有bean定义元数据,而不期望进一步的更改。
    		beanFactory.freezeConfiguration();
    		// 实例化所有剩余(非延迟初始化)单例。
    		beanFactory.preInstantiateSingletons();
    	}
    

    第十步:完成ApplicationContext容器的初始化收

    功能:进行相关的容器创建完成时的操作,回收相关资源

     finishRefresh();
     resetCommonCaches();
    
    	protected void finishRefresh() {
    		//清除上下文级资源缓存(例如来自扫描的ASM元数据)。
    		clearResourceCaches();
    		//为此上下文初始化生命周期处理器。
    		initLifecycleProcessor();
    		// 首先将刷新传播到生命周期处理器。
    		getLifecycleProcessor().onRefresh();
    		// 广播最终事件
    		publishEvent(new ContextRefreshedEvent(this));
    		// 如果处于活动状态,请参与LiveBeansView 
    		LiveBeansView.registerApplicationContext(this);
    	}
    
    //清除一些单例的工具类的缓存
    protected void resetCommonCaches() {
    		ReflectionUtils.clearCache();
    		AnnotationUtils.clearCache();
    		ResolvableType.clearCache();
    CachedIntrospectionResults.clearClassLoader(getClassLoader());
    	}
    

    应该学习到的知识

    • Spring容器中管理的Bean是Class吗?

    可以看到Bean容器中的Bean定义映射关系的Map中存放的是key(String)->GenericBeanDefinition的映射,那么GenericBeanDefinition又是什么呢?

    BeanDefinition 中保存了我们的 Bean 信息,比如这个 Bean 指向的是哪个类、是否是单例的、是否懒加载、这个 Bean 依赖了哪些 Bean 等等。

    • SpringBean是被ApplicationContext管理的吗?

    通过Debug的过程中我们可以看到我们使用ClassPathXmlApplicationContext构造的ApplicationContext对象其实在内部维护了一个属性名为beanFactory,我们的SpringBean都被定义在这个属性里面,也就是说beanFactory这个属性才是容器,ApplicationContext仅仅是做了一层包装.那么beanFactory又是什么呢?

    public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
    		implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
    		...
    }
    

    3

    可以看到DefaultListableBeanFactory类也是Bean容器,而且是继承了所有其他的容器的功能,可以说是最为强大的容器;例如具有(分层,获取多个容器,注入功能....)

    本章小结

    第一次参阅源码写的比较慎重,其中由于身体抱恙又有所当误,所以在发布本章的时候也是几天后了,总的来说本章并没有什么重点,仅仅是把Spring的IOC容器的启动过程进行了标注,并未做过多底层的深度剖析,例如loadBeanDefinitions(beanFactory)Spring如何将XMl文件的配置装载入Bean工厂,以及后面的每个注释都可以新开一篇长篇大论的文章,后面尽可能的在Spring Framework深度剖析专栏中更为详细的学习Spring整体架构源码

    该教程所属Java工程师之Spring Framework深度剖析专栏,本系列相关博文目录 Java工程师之Spring Framework深度剖析专栏

  • 相关阅读:
    Drozer渗透测试工具(使用篇)
    Teamcenter中TCComponentItem与TCComponentBOMLine的创建
    Swing中分割面板JSplitPane的使用
    Swing中菜单栏JToolBar的使用
    Javaweb项目导出成jar包并使用Windows定时任务定时执行
    TCSOA获取BOMLine
    SQLite Expert安装与注册
    获取分类节点
    处理TC的Command问题
    通过TCComponentBomLine获取ItemRevision的两种情况
  • 原文地址:https://www.cnblogs.com/jimisun/p/10104002.html
Copyright © 2020-2023  润新知