Spring Bean加载流程分析(通过 XML 方式加载)

Spring Bean 装配过程是一个老生常谈的话题 , 从最开始的通过 xml 形式装配 bean , 到后来使用注解来装配 bean 以及使用 SpringBoot 和 SpringCloud 来进行开发 , Spring 在整个过程中也进行了不断的演化和进步 。 不管是最初的 Spring 还是基于 Spring 开源的 SpringBoot、亦或是 SpringCloud , 它们都是基于 Spring 的转变过来的 , 可能在 Spring 的基础上做了一些封装 , 但是本质上还是 Spring 。
原本就没有那么多自动化的事情 , 只是 Spring 将实现的细节全部都隐藏在框架内部了 。 只有真正理解了 Spring , 那么其实理解 SpringBoot 或者是 SpringCloud 只是一个水到渠成的事情 。
起步基于 Spring 版本 5.2.5
新建一个 maven 工程 , 导入如下几个 jar 包
org.springframeworkspring-context5.2.5.RELEASEorg.springframeworkspring-beans5.2.5.RELEASEorg.springframeworkspring-context-support5.2.5.RELEASEorg.springframeworkspring-core5.2.5.RELEASEorg.springframeworkspring-tx5.2.5.RELEASE复制代码在 classpath 路径下新建 applicationContext.xml 文件 , 配置一个新的 bean
复制代码添加完毕后 , 工程示意图如下
Spring Bean加载流程分析(通过 XML 方式加载)文章插图
通过 XML 形式装载 Bean一个简单且基础获取 Bean 对象的代码示例如下:
public static void main(String[] args) {// Spring Bean 加载流程Resource resource = new ClassPathResource("applicationContext.xml");// 获取一个 BeanFactoryDefaultListableBeanFactory defaultListableBeanFactory = new DefaultListableBeanFactory();// 定义 Bean 定义读取器BeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(defaultListableBeanFactory);// 从资源文件中读取 beanbeanDefinitionReader.loadBeanDefinitions(resource);// 从工厂中获取 beanUser user = (User) defaultListableBeanFactory.getBean("user");System.out.println(user.getId() + " =" + user.getName());}复制代码接下来我们逐行来分析 Bean 是如何被 Spring 容器所装载并缓存的 。
1. 定义资源对象Resource resource = new ClassPathResource("applicationContext.xml");复制代码将 classpath 下的 applicationContext.xml 文件转换成 Resource 文件 。 Resource 也是 Spring 提供的一种资源接口 , 除了我们示例中使用的 ClassPathResource 外 , Spring 也提供了其他形式的 Resource 实现类 。
Spring Bean加载流程分析(通过 XML 方式加载)文章插图
进入 new ClassPathResource("applicationContext.xml") 构造方法 , 看看构造方法做了什么处理?
public ClassPathResource(String path) {this(path, (ClassLoader) null);}复制代码发现该构造方法调用了自身的另一个构造方法
public ClassPathResource(String path, @Nullable ClassLoader classLoader) {Assert.notNull(path, "Path must not be null");String pathToUse = StringUtils.cleanPath(path);if (pathToUse.startsWith("/")) {pathToUse = pathToUse.substring(1);}this.path = pathToUse;// 获取了一个类加载器this.classLoader = (classLoader != null ? classLoader : ClassUtils.getDefaultClassLoader());}复制代码


推荐阅读