1. 引言
在本系列的上一篇文章《 Spring学习(二):Hello Spring你的第一个Spring应用》中,我们完成了一个简单的Spring应用编写,细看程序,我们发现在该Spring应用中我们只是对Person,WorkTask几个Bean加了一些注解:@Component、@Autowired,Spring就能帮助我们完成对象的创建,依赖注入,那么Spring是如何做的呢?
2. Spring容器简介
首先,所有被Spring管理的对象都是生存在Spring容器(container)中的,Spring负责创建对象、装配对象、配置对象并管理它们的整个生命周期。
容器是Spring的核心,Spring通过依赖注入管理构成Spring应用的组件,包括它们之间的关联,Spring自带了多个容器实现,归结起来,有两种不同的类型:
- bean工厂 (由org.springframework.beans.factory.beanFactory接口定义)
- 应用上下文 (由org.springframework.context.ApplicationContext接口定义)
但是应用上下文的方式更加受欢迎,能够适应大多数应用,所以我们主要谈谈应用上下文的方式。
3. 应用上下文
Spring自带多种类型的应用上下文,主要有以下四种:
- AnnotationConfigApplicationContext:从一个或多个基于Java的配置类中加载Spring应用上下文。
- AnnotationConfigWebApplicationContext:从一个或多个基于Java的配置类中加载Spring Web应用上下文。
- ClassPathXmlApplicationContext:从类路径下的一个或多个XML配置文件中加载上下文定义,把应用上下文的定义文件作为类
资源。 - FileSystemXmlapplicationcontext:从文件系统下的一个或多个XML配置文件中加载上下文定义。
- XmlWebApplicationContext:从Web应用下的一个或多个XML配置文件中加载上下文定义。
回忆上一篇中我们的测试类App.java
package blog.spring.hello;
import blog.spring.hello.config.MyConfig;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = MyConfig.class)
public class App {
@Autowired
Person person;
@Test
public void test(){
person.doTask();
}
}
如果我们不用单元测试的方式,改用main方法的方式,那么App2.java可以这样写:
package blog.spring.hello;
import blog.spring.hello.config.MyConfig;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class App2 {
public static void main(String[] args) {
//加载容器
AnnotationConfigApplicationContext ctx =
new AnnotationConfigApplicationContext(MyConfig.class);
//从容器中获取Person对象
Person person = ctx.getBean(Person.class);
person.doTask();
}
}
我们通过AnnotationConfigApplicationContext完成了从基于Java配置类中加载Spring应用上下文。当然如果你是基于xml的方式进行的配置,那么你可以使用如下代码加载Spring应用上下文,其他三种类型方法也类似。
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
4. Bean的生命周期
在bean准备就绪之前,bean工厂执行了若干启动步骤:
- Spring对bean进行实例化;
- Spring将值和bean的引用注入到bean对应的属性中;
- 如果bean实现了BeanNameAware接口,Spring将bean的ID传递给setBean-Name()方法;
- 如果bean实现了BeanFactoryAware接口,Spring将调用setBeanFactory()方法,将BeanFactory容器实例传入;
- 如果bean实现了ApplicationContextAware接口,Spring将调用setApplicationContext()方法,将bean所在的应用上下文的引用传入进来;
- 如果bean实现了BeanPostProcessor接口,Spring将调用它们的postProcessBeforeInitialization()方法;
- 如果bean实现了InitializingBean接口,Spring将调用它们的afterPropertiesSet()方法。类似地,如果bean使用init-method声明了初始化方法,该方法也会被调用;
- 如果bean实现了BeanPostProcessor接口,Spring将调用它们的postProcessAfterInitialization()方法;
- 此时,bean已经准备就绪,可以被应用程序使用了,它们将一直驻留在应用上下文中,直到该应用上下文被销毁;
- 如果bean实现了DisposableBean接口,Spring将调用它的destroy()接口方法。同样,如果bean使用destroy-method声明了销毁方法,该方法也会被调用。
5. 小结
至此我们初步了解了Spring的容器,并且了解了Spring容器中Bean的生命周期,但是如何往这个容器中装配bean,使我们后面学习的重点。