内容简介:ApplicationContext 启动过程中,会创建SPring Bean容器,然后初始化相关Bean,再向Bean中注入其相关依赖。所以我们仅仅需要Debug跟踪Main方法中功能:设置此应用程序上下文的配置文件位置,如果未设置;Spring可以根据需要使用默认值
<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容器的事件讲解 juejin.im/post/5a543c…
主要功能 : 注册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 { ... } 复制代码
可以看到 DefaultListableBeanFactory
类也是Bean容器,而且是继承了所有其他的容器的功能,可以说是最为强大的容器;例如具有(分层,获取多个容器,注入功能....)
本章小结
第一次参阅源码写的比较慎重,其中由于身体抱恙又有所当误,所以在发布本章的时候也是几天后了,总的来说本章并没有什么重点,仅仅是把Spring的IOC容器的启动过程进行了标注,并未做过多底层的深度剖析,例如 loadBeanDefinitions(beanFactory)Spring如何将XMl文件的配置装载入Bean工厂
,以及后面的每个注释都可以新开一篇长篇大论的文章,后面尽可能的在 Spring Framework深度剖析专栏 中更为详细的学习Spring整体架构源码
该教程所属 Java 工程师之Spring Framework深度剖析专栏,本系列相关博文目录 Java工程师之Spring Framework深度剖析专栏
本文是根据原文https://juejin.im/post/5bc5c88df265da0b001f5dee的学习笔记,将步骤更为清晰的展现
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 无根容器浅析
- 浅析 Spring 的IOC容器
- 浅析 Docker 容器安全管控方法
- 浅析Docker容器安全管控方法
- 浅析依赖倒转、控制反转、IoC 容器、依赖注入。
- C++中vector容器大小增长规律浅析
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
机器与人:埃森哲论新人工智能
【美】保罗•多尔蒂 詹姆斯•威尔逊 / 赵亚男 / 中信出版社 / 2018-10-1 / 49.00元
自人工智能问世以来,人们普遍持有人机对立的观点,且无时无刻不在害怕自己的工作会被人工智能取代。作者认为,是时候抛开这些无谓的担忧了,因为人类社会正走向一个与机器共融共生的时代。 未来的新型工作模式是什么?未来有哪些工作不会被人工智能取代?人工智能时代重要的生存技能是什么?本书围绕这三大核心问题做了透彻的分析。作者带我们见识了置于业务流程背景之下的人工智能,阐述了其在不同职能部门中起到的推动作......一起来看看 《机器与人:埃森哲论新人工智能》 这本书的介绍吧!