文章目录
Spring源码合集:
Spring源码解析(一)IOC容器
前言
本章我们要分析的是使用 ClassPathXmlApplicationContext 读取 xml 配置文件启动 Spring 的源码流程。在梳理流程之前,我们需要对 Spring 容器的继承结构有一个大致的认识(有一些读过 Spring 源码的小伙伴应该有这样一种感觉,为啥 Spring 源码跳来跳去的,往往一个方法要重载,重写多次,最后跟了很久才到真正干事的地方。我个人觉得这就是 Spring 源码很精髓的一个点,是对“面向对象”和“设计模式”一种精妙的运用。想要感受这种设计的妙处,Spring 容器的继承结构是一个很好的出发点)。
BeanFactory继承结构
这里先给出 BeanFactory 的继承结构图。
下面列出我认为比较重要的接口,建议读者可以打开源码看一下这些接口。
BeanFactory 接口
Bean 工厂的根接口,提供了获取单个 Bean 实例的基本方法(根据类型,名称…)
使用到的设计模式:
- 简单工厂模式
- 单例模式
- 原型模式(prototype 原型),生成多例对象时是通过序列化来进行深拷贝。
BeanFactory 中的方法:
interface BeanFactory {
String FACTORY_BEAN_PREFIX = "&";
Object getBean(String name) throws BeansException;
<T> T getBean(String name, Class<T> requiredType) throws BeansException;
Object getBean(String name, Object... args) throws BeansException;
<T> T getBean(Class<T> requiredType) throws BeansException;
<T> T getBean(Class<T> requiredType, Object... args) throws BeansException;
<T> ObjectProvider<T> getBeanProvider(Class<T> requiredType);
<T> ObjectProvider<T> getBeanProvider(ResolvableType requiredType);
boolean containsBean(String name);
boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;
boolean isTypeMatch(String name, Class<?> typeToMatch) throws NoSuchBeanDefinitionException;
@Nullable
Class<?> getType(String name) throws NoSuchBeanDefinitionException;
@Nullable
Class<?> getType(String name, boolean allowFactoryBeanInit) throws NoSuchBeanDefinitionException;
String[] getAliases(String name);
}
ListableBeanFactory 接口
继承 BeanFactory 接口,提供了根据类型、名称,注解等获取 Bean 集合(多个 bean,前面 BeanFactory 只支持获取单个 bean)的方法。
比如:
interface ListableBeanFactory {
boolean containsBeanDefinition(String beanName);
int getBeanDefinitionCount();
String[] getBeanDefinitionNames();
String[] getBeanNamesForType(ResolvableType type);
String[] getBeanNamesForType(ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit);
String[] getBeanNamesForType(@Nullable Class<?> type);
String[] getBeanNamesForType(@Nullable Class<?> type, boolean includeNonSingletons, boolean allowEagerInit);
<T> Map<String, T> getBeansOfType(@Nullable Class<T> type) throws BeansException;
<T> Map<String, T> getBeansOfType(@Nullable Class<T> type, boolean includeNonSingletons, boolean allowEagerInit)
throws BeansException;
String[] getBeanNamesForAnnotation(Class<? extends Annotation> annotationType);
Map<String, Object> getBeansWithAnnotation(Class<? extends Annotation> annotationType) throws BeansException;
@Nullable
<A extends Annotation> A findAnnotationOnBean(String beanName, Class<A> annotationType)
throws NoSuchBeanDefinitionException;
}
HierarchicalBeanFactory 接口
继承BeanFactory接口,允许以可配置的方式设置父级的工厂
interface HierarchicalBeanFactory {
/**
* 返回父 BeanFactory,没有返回 null
*/
@Nullable
BeanFactory getParentBeanFactory();
/**
* 判断当前 BeanFactory 中(不在父 BeanFactory 中查)是否包含名称为 name 的 Bean
*/
boolean containsLocalBean(String name);
}
AutowireCapableBeanFactory 接口
继承 BeanFactory 接口,autowire 我们非常熟悉,这个接口主要用于自动装配 Bean。
里面有一些很重要(熟悉,如果你看过 bean 创建流程源码的话)的方法:
interface AutowireCapableBeanFactory {
int AUTOWIRE_NO = 0;
int AUTOWIRE_BY_NAME = 1;
int AUTOWIRE_BY_TYPE = 2;
int AUTOWIRE_CONSTRUCTOR = 3;
@Deprecated
int AUTOWIRE_AUTODETECT = 4;
<T> T createBean(Class<T> beanClass) throws BeansException;
Object createBean(Class<?> beanClass, int autowireMode, boolean dependencyCheck) throws BeansException;
void applyBeanPropertyValues(Object existingBean, String beanName) throws BeansException;
Object initializeBean(Object existingBean, String beanName) throws BeansException;
Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
throws BeansException;
Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException;
void destroyBean(Object existingBean);
@Nullable
Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName) throws BeansException;
@Nullable
Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException;
}
ConfigurableBeanFactory 接口
继承 HierarchicalBeanFactory,SingletonBeanRegistry,它的方法主要是对 Bean 工厂进行配置,主要是框架内部使用。
SingletonBeanRegistry 提供对单例对象的一些操作。
ConfigurableListableBeanFactory 接口
它的特殊之处在于继承了 ConfigurableBeanFactory,ListableBeanFactory ,AutowireCapableBeanFactory三个接口(也就是说它会拥有这个三个接口所拥有的功能,后面会看到DefaultListableBeanFactory 就是继承这个接口的)。
ApplicationContext 的继承结构
这是 ApplicationContext 的继承结构图。
ApplicationContext 官方介绍:
为应用程序提供配置的中央接口。
在应用程序运行时,这是只读的,但如果实现类支持,可以重新加载(刷新refresh)。ApplicationContext提供:
- 访问应用程序组件的Bean工厂方法。继承自{@link org.springframework.beans.factory.ListableBeanFactory}。
- 以通用方式加载文件资源的能力。继承自{@link org.springframework.core.io.ResourceLoader}接口。
- 向注册的侦听器发布事件的能力。继承自{@link ApplicationEventPublisher}接口。
- 能够解析消息,支持国际化。继承自{@link MessageSource}接口。
- 从父上下文继承。后代上下文中的定义将始终优先考虑。例如,这意味着单亲家长整个web应用程序都可以使用上下文,而每个servlet都有它自己的子上下文独立于任何其他servlet的子上下文。
除了标准的{@link org.springframework.beans.factory.BeanFactory}生命周期功能、ApplicationContext实现、检测和调用{@link ApplicationContextAware}bean以及{@link resourceLoaderware},{@link ApplicationEventPublisherAware}和{@link MessageSourceAware}bean。
这些内容都会在后面的源码中得到体现。
ConfigurableApplicationContext
提供一些SPI接口(会被大多数实现类实现)和一些来配置ApplicationContext的方法。(refresh方法就是在这个类中定义的,后面分析源码会提到)
AbstractApplicationContext
采用模板方法模式,里面定义了很多属性和抽象方法,抽象方法需要子类实现。
FileSystemXmlApplicationContext
构造函数需要一个 xml 配置文件在系统中的路径,其他和 ClassPathXmlApplicationContext 基本上一样。
AnnotationConfigApplicationContext
基于注解来使用的,它不需要配置文件,采用 java 配置类和各种注解来配置。
容器启动流程分析
首先我们先写一个简单的例子,启动Spring容器。
1.导入Spring依赖
2.创建类
// class: MainTest
public class MainTest {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
HelloService helloService = (HelloService) applicationContext.getBean("helloService");
helloService.hello();
}
}
// interface: HelloService
public interface HelloService {
void hello();
}
// class: HelloServiceImpl
public class HelloServiceImpl implements HelloService {
@Override
public void hello() {
System.out.println("你好呀~");
}
}
3.编写配置文件 spring.xml
<?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 class="github.yuanlin.service.HelloServiceImpl" id="helloService"/>
</beans>
4.编译启动主类
我们是使用配置文件来构建 Spring 容器的,构建容器主要的逻辑应该下面这段代码中:
public class MainTest {
public static void main(String[] args) {
// 构建 Spring 容器
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
...
}
}
跟进去看
// ClassPathXmlApplicationContext 84
public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
// 参数一: 配置文件位置
// 参数二: 是否刷新(执行 refresh 方法)
// 调用重载的构造方法
this(new String[] {
configLocation}, true, null);
}
// 继续看
// ClassPathXmlApplicationContext 139
public ClassPathXmlApplicationContext(
String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
throws BeansException {
// 设置父容器, 此处为 null(注: 个人感觉父容器和类加载器的双亲委派模型有一些相似之处)
// 最终是设置到(父类 AbstractApplicationContext 的 parent 属性中,之前提到过 AbstractApplicationContext 使用了模板方法模式,里面定义了很多属性和抽象方法,抽象方法需要子类实现)
super(parent);
// 设置配置文件地址(父类 AbstractRefreshableConfigApplicationContext 的方法)
setConfigLocations(configLocations);
// 刷新容器, 重点!!
if (refresh) {
// (父类 AbstractApplicationContext 中的方法)
// (接口 ConfigurableApplicationContext 的方法)
refresh