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 "> <bean> <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 Framework框架容器核心源码逐步剖析

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; } }

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

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

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

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

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(); } } }

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

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpdjws.html