首先,我们在代码中是怎样获取bean的,方式有以下几种,但不局限于这两种:
@Test
public void run1(){
//加载配置文件
ApplicationContext ac = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
//获取对象
AccountService as =(AccountService)ac.getBean("accountService");
//调用方法
as.findAll();
}
@Test
public void run2(){
//传入配置类的类实例来告诉spring配置类是哪一个
ApplicationContext ac = new ClassPathXmlApplicationContext(JavaConfig.class);
//获取对象
AccountService as =(AccountService)ac.getBean("accountService");
//调用方法
as.findAll();
ApplicationContext是spring中比较高级的容器。和BeanFactory类似,它可以加载配置文件中定义的bean,并将所有bean集中在一起,当有请求的时候分配bean。
Application接口实现:
FileSystemXmlApplicationContext:该容器从xml文件中加载已被定义的bean。在这里,你需要提供给构造器XML文件的完整路径
ClassPathXmlApplicationContext:该容器从xml文件中加载已经被定义的bean,在这里你不需要提供xml文件的完整路径,只需要正确配置Classpath环境变量即可,因为,容器会从Classpath中搜索bean配置文件
AnnotationConfigApplicationContext其实和xml的原理一致。只是xml方式bean被定义在xml文件中,而Annotation方式是将bean定义在一个java类文件中
一个是ClassPathXmlApplicationContext,基于classpath下的xml配置文件;另一种是AnnotationConfigApplicationContext,基于java配置文件。
现在我们以ClassPathXmlApplicationContext为例,来进行源码的讲解
首先进入ClassPathXmlApplicationContext()之后,他会进入相应的构造方法中
public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
this(new String[] {
configLocation}, true, null);
}
再此调用本类中的对应的构造函数
public ClassPathXmlApplicationContext(
String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
throws BeansException {
//一直调用父类构造,直到 AbstractApplicationContext,设置一个空的 ApplicationContext 对象
super(parent);
设置配置文件路径
setConfigLocations(configLocations);
默认为 true
if (refresh) {
//调用的是AbstractApplicationContext类refresh()方法,实现的ConfigurableApplicationContext接口中的refresh()方法
refresh();
}
}
重点到了:refresh(),这个方法就是bean生命周期的关键点,调用的是AbstractApplicationContext类refresh()方法,实现的ConfigurableApplicationContext接口中的refresh()方法(可以看一下上面的关系图)
我们在看这个方法之前,先要知道一些脉络,以帮助我们更好的理解代码(下图为借鉴马士兵老师的图)
源码分析
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
//为容器初始化做准备
prepareRefresh();
// 解析xml和注解
//该方法会解析所有 Spring 配置文件(通常我们会放在 resources 目录下),将所有 Spring 配置文件中的 bean 定义封装成 BeanDefinition,加载到 BeanFactory 中。
//加载 bean 定义,由 XmlWebApplicationContext 实现
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
//前面已经把配置类的定义已经注册到容器中,还在进行对配置类进行全面分析和处理之前,Spring还要再做一些预处理,比如设置类加载器,设置后置处理器ApplicationContextAwareProcessor,将environment systemProperties systemEnvironment三个对象添加到容器当中,设置Spring框架不需要被自动注入的接口等操作。
prepareBeanFactory(beanFactory);
try {
//这里面代码是空的
// 由子类实现对BeanFacoty的一些后置处理
postProcessBeanFactory(beanFactory);
/* 本方法会实例化和调用所有 BeanFactoryPostProcessor
BeanFactoryPostProcessors:bean工厂的bean属性处理容器,说通俗一些就是可以管理我们的bean工厂内所有的beandefinition(未实例化)数据,可以随心所欲的修改属性。*/
invokeBeanFactoryPostProcessors(beanFactory);
/*本方法会注册所有的 BeanPostProcessor,将所有实现了 BeanPostProcessor 接口的类加载到 BeanFactory 中。
BeanPostProcessor 接口是 Spring 初始化 bean 时对外暴露的扩展点,Spring IoC 容器允许 BeanPostProcessor 在容器初始化 bean 的前后,添加自己的逻辑处理。在 registerBeanPostProcessors 方法只是注册到 BeanFactory 中,具体调用是在 bean 初始化的时候。
具体的:在所有 bean 实例化时,执行初始化方法前会调用所有 BeanPostProcessor 的 postProcessBeforeInitialization 方法,在执行初始化方法后会调用所有 BeanPostProcessor 的 postProcessAfterInitialization 方法。*/
registerBeanPostProcessors(beanFactory);
//初始化ApplicationContext的MessageSource
initMessageSource();
//初始化ApplicationContext事件广播器
initApplicationEventMulticaster();
// 初始化子类特殊bean(钩子方法)
onRefresh();
// 注册事件监听器
registerListeners();
/*
* 1、bean实例化过程
* 2、依赖注入
* 3、解析@PostConstruct,@PreDestroy,@Resource, @Autowired,@Value等注解
* 4、BeanPostProcessor的执行
* 5、Aop的入口
*
* */
finishBeanFactoryInitialization(beanFactory);
// 广播事件,ApplicationContext初始化完成
finishRefresh();
}
catch (BeansException ex) {
...
}
finally {
...
}
}
}
首先我们先看一张流程图,理清脉络
(1)实例化Bean:
对于BeanFactory容器,当客户向容器请求一个尚未初始化的bean时,或初始化bean的时候需要注入另一个尚未初始化的依赖时,容器就会调用createBean进行实例化。对于ApplicationContext容器,当容器启动结束后,通过获取BeanDefinition对象中的信息,实例化所有的bean。
(2)设置对象属性(依赖注入):
实例化后的对象被封装在BeanWrapper对象中,紧接着,Spring根据BeanDefinition中的信息 以及 通过BeanWrapper提供的设置属性的接口完成依赖注入。
(3)处理Aware接口:
接着,Spring会检测该对象是否实现了xxxAware接口,并将相关的xxxAware实例注入给Bean:
①如果这个Bean已经实现了BeanNameAware接口,会调用它实现的setBeanName(String beanId)方法,此处传递的就是Spring配置文件中Bean的id值;
②如果这个Bean已经实现了BeanFactoryAware接口,会调用它实现的setBeanFactory()方法,传递的是Spring工厂自身。
③如果这个Bean已经实现了ApplicationContextAware接口,会调用setApplicationContext(ApplicationContext)方法,传入Spring上下文;
(4)BeanPostProcessor:
如果想对Bean进行一些自定义的处理,那么可以让Bean实现了BeanPostProcessor接口,那将会调用postProcessBeforeInitialization(Object obj, String s)方法。
(5)InitializingBean 与 init-method:
如果Bean在Spring配置文件中配置了 init-method 属性,则会自动调用其配置的初始化方法。
(6)如果这个Bean实现了BeanPostProcessor接口,将会调用postProcessAfterInitialization(Object obj, String s)方法;由于这个方法是在Bean初始化结束时调用的,所以可以被应用于内存或缓存技术;
以上几个步骤完成后,Bean就已经被正确创建了,之后就可以使用这个Bean了。
(7)DisposableBean:
当Bean不再需要时,会经过清理阶段,如果Bean实现了DisposableBean这个接口,会调用其实现的destroy()方法;
(8)destroy-method:
最后,如果这个Bean的Spring配置中配置了destroy-method属性,会自动调用其配置的销毁方法。