<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; } } 复制代码
<?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> 复制代码
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()); } } 复制代码
ApplicationContext 启动过程中,会创建SPring Bean容器,然后初始化相关Bean,再向Bean中注入其相关依赖。
所以我们仅仅需要Debug跟踪Main方法中 ApplicationContext context = new ClassPathXmlApplicationContext("classpath:spring.xml");
这一句代码,查看Spring是如何创建ApplicationContext容器并将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; } } 复制代码
注意:除了第一步设置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>(); } 复制代码
主要工作:进行销毁旧容器,创建新容器,加载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容器创建完毕会"手动"注册一些特殊的 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()); } } ``` 复制代码
主要功能:实例化在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后置处理器)" 复制代码
主要功能: 初始化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 + "]"); } } } 复制代码
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); } } } 复制代码
功能:执行到这一步,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(); } 复制代码
功能:进行相关的容器创建完成时的操作,回收相关资源
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()); } 复制代码
可以看到Bean容器中的Bean定义映射关系的Map中存放的是 key(String)
-> GenericBeanDefinition
的映射,那么 GenericBeanDefinition
又是什么呢?
BeanDefinition
中保存了我们的 Bean 信息
,比如这个 Bean 指向的是哪个类、是否是单例的、是否懒加载、这个 Bean 依赖了哪些 Bean 等等。
通过 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的学习笔记,将步骤更为清晰的展现