Spring IOC容器源码:BeanFactory简介 | Java提升营

Spring IOC容器源码:BeanFactory简介

Spring 最重要的概念是 IOCAOP,我将用几篇文章带领大家来分析下 SpringIOC容器AOP 。既然大家平时都要用到 Spring,怎么可以不好好了解 Spring 呢?阅读这些文并不能让你成为Spring专家,不过一定有助于大家理解Spring的很多概念,帮助大家排查应用中和Spring相关的一些问题。为了降低难度,所有的内容都是基于 xml 的配置的方式。

阅读建议:读者至少需要知道怎么配置 Spring,了解 Spring 中的各种概念,少部分内容我还假设读者使用过 SpringMVC。对于 IOC 总体来说有两处地方最重要,创建 Bean 容器初始化 Bean

引言

先看下最基本的启动 Spring 容器的例子:

1
2
3
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationfile.xml");
}

以上代码就可以利用配置文件来启动一个 Spring 容器了,请使用 maven 的小伙伴直接在 dependencies 中加上以下依赖即可,个人比较反对那些不知道要添加什么依赖,然后把 Spring 的所有相关的东西都加进来的方式。

1
2
3
4
5
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.11.RELEASE</version>
</dependency>

spring-context 会自动将 spring-corespring-beansspring-aopspring-expression 这几个基础 jar 包带进来。

ApplicationContext context = new ClassPathXmlApplicationContext(…) 其实很好理解,从名字上就可以猜出一二,就是在 ClassPath 中寻找 xml 配置文件,根据 xml 文件内容来构建 ApplicationContext。当然,除了 ClassPathXmlApplicationContext 以外,我们也还有其他构建 ApplicationContext 的方案可供选择,我们先来看看大体的继承结构是怎么样的:​

读者可以大致看一下类名,源码分析的时候不至于找不着哪个类,因为 Spring 为了适应各种使用场景,提供的各个接口都可能有很多的实现类。对于我们来说,就是揪着一个完整的分支看完。当然,读本文的时候读者也不必太担心,每个代码块分析的时候,我都会告诉读者我们在说哪个类第几行。

我们可以看到,ClassPathXmlApplicationContext 兜兜转转了好久才到 ApplicationContext 接口,同样的,我们也可以使用绿颜色的 FileSystemXmlApplicationContextAnnotationConfigApplicationContext 这两个类。

FileSystemXmlApplicationContext 的构造函数需要一个 xml 配置文件在系统中的路径,其他和 ClassPathXmlApplicationContext 基本上一样。

AnnotationConfigApplicationContext 是基于注解来使用的,它不需要配置文件,采用 java 配置类和各种注解来配置,是比较简单的方式,也是大势所趋吧。不过本文旨在帮助大家理解整个构建流程,所以决定使用 ClassPathXmlApplicationContext 进行分析。我们先来一个简单的例子来看看怎么实例化ApplicationContext

首先,定义一个接口:

1
2
3
public interface MessageService {
String getMessage();
}

定义接口实现类:

1
2
3
4
5
6
public class MessageServiceImpl implements MessageService {

public String getMessage() {
return "hello world";
}
}

接下来,我们在 resources 目录新建一个配置文件,文件名随意,通常叫 application.xmlapplication-xxx.xml 就可以了:

1
2
3
4
5
6
7
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd" default-autowire="byName">

<bean id="messageService" class="com.javadoop.example.MessageServiceImpl"/>
</beans>

这样,我们就可以跑起来了:

1
2
3
4
5
6
7
8
9
10
11
12
13
public class App {
public static void main(String[] args) {
// 用我们的配置文件来启动一个 ApplicationContext
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:application.xml");

System.out.println("context 启动成功");

// 从 context 中取出我们的 Bean,而不是用 new MessageServiceImpl() 这种方式
MessageService messageService = context.getBean(MessageService.class);
// 这句将输出: hello world
System.out.println(messageService.getMessage());
}
}

以上例子很简单,不过也够引出主题了,就是怎么样通过配置文件来启动 Spring 的 ApplicationContext?也就是我们随后要分析的 IOC 的核心了。ApplicationContext 启动过程中,会负责创建实例 Bean,往各个 Bean 中注入依赖等。

BeanFactory简介

BeanFactory 从名字上也很好理解,生产 bean 的工厂,它负责生产和管理各个 bean 实例。

初学者可别以为我之前说那么多和 BeanFactory 无关,前面说的 ApplicationContext 其实就是一个 BeanFactory。我们来看下和 BeanFactory 接口相关的主要的继承结构:​

我想,大家看完这个图以后,可能就不是很开心了。ApplicationContext 往下的继承结构前面一张图说过了,这里就不重复了。这张图呢,背下来肯定是不需要的,有几个重点和大家说明下就好。

  1. ApplicationContext 继承了 ListableBeanFactory,这个 Listable 的意思就是,通过这个接口,我们可以获取多个 Bean,大家看源码会发现,最顶层 BeanFactory 接口的方法都是获取单个 Bean 的。
  2. ApplicationContext 继承了 HierarchicalBeanFactoryHierarchical 单词本身已经能说明问题了,也就是说我们可以在应用中起多个 BeanFactory,然后可以将各个 BeanFactory 设置为父子关系。
  3. AutowireCapableBeanFactory 这个名字中的 Autowire 大家都非常熟悉,它就是用来自动装配 Bean 用的,但是仔细看上图,ApplicationContext 并没有继承它,不过不用担心,不使用继承,不代表不可以使用组合,如果你看到 ApplicationContext 接口定义中的最后一个方法 getAutowireCapableBeanFactory() 就知道了。
  4. ConfigurableListableBeanFactory 也是一个特殊的接口,看图,特殊之处在于它继承了第二层所有的三个接口,而 ApplicationContext 没有。这点之后会用到。

请读者打开编辑器,翻一下 BeanFactoryListableBeanFactoryHierarchicalBeanFactoryAutowireCapableBeanFactoryApplicationContext 这几个接口的代码,大概看一下各个接口中的方法,大家心里要有底,限于篇幅,我就不贴代码介绍了。

给老奴加个鸡腿吧 🍨.