GitHub链接:mini-spring
本文仅作学习用,所出现【源码】内容皆为mini-spring中源码。
基本知识
了解IOC和Bean,了解SpringMVC。
源码分析
归根到底,这部分实际上是在逐步的分析bean的生命周期。通过一点一点增加功能和使用单元测试来学习bean生命周期的每一部分。如果你理解了bean的生命周期,简单来说:定义(bean以及对应的IOC容器)-实例化-初始化-使用-销毁,那你就可以理解为什么说IOC是Spring的核心功能:IOC将繁杂的生命周期过程逐步拆解,程序员只需要关注每个部分中需要自定义的内容,将自定义的内容写好,spring会将全部的功能拼接在一起,让你在实际开发中省去大量的时间。 非常建议反复查看源码和自己举例理解。
bean的实例化
Spring中的bean的是使用BeanFactory来产生的,也就是使用工厂类来同一创建。因此对于Bean的内容和创建过程,自然而然有以下几点:
- BeanFactory要怎么实现?或者说创建一个Bean需要什么内容?
- 创建的流程是怎样的?
这里要说明的是,应用Java复杂的继承和实现机制,最终使用的 BeanFactory 实际是DefaultListableBeanFactory。项目ioc包下有一个测试类如下:
public class BeanDefinitionAndBeanDefinitionRegistryTest {
@Test
public void testBeanFactory() throws Exception {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
BeanDefinition beanDefinition = new BeanDefinition(HelloService.class);
beanFactory.registerBeanDefinition("helloService", beanDefinition);
HelloService helloService = (HelloService) beanFactory.getBean("helloService");
helloService.sayHello(); // 输出为 hello
}
}
// 对应的hello类
class HelloService {
public String sayHello() {
System.out.println("hello");
return "hello";
}
}
代码并不复杂,我们分析一下。流程如下
- 创建 BeanFactory:
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
这一行代码创建了一个 DefaultListableBeanFactory 对象,用于管理 Bean 的生命周期和依赖注入。
- 创建 BeanDefinition:
BeanDefinition beanDefinition = new BeanDefinition(HelloService.class); // 使用反射
这一行代码创建了一个 BeanDefinition 对象,用于描述 HelloService 类的信息。BeanDefinition 中包含了 Bean 的类名、构造参数、属性值等信息。显而易见,这里使用了反射来获取信息。
- 注册 BeanDefinition:
beanFactory.registerBeanDefinition("helloService", beanDefinition);
// 这个注册的函数如下:
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
implements ConfigurableListableBeanFactory, BeanDefinitionRegistry {
private Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) {
beanDefinitionMap.put(beanName, beanDefinition);
}
// 后续代码暂时不需要
}
这一行代码将 HelloService 的 BeanDefinition 注册到 beanFactory 中,并指定 Bean 的名称为 “helloService”。不难看出,BeanFactroy类内部有一个ConcurrentHashMap,注册的Bean都存储到这里,而注册的过程只是put到map中。
- 获取 Bean:
这里比较重要,可以多次阅读,尤其是多个方法的调用关系。这些调用关系在后面仍然会用到
HelloService helloService = (HelloService) beanFactory.getBean("helloService");
//getBean 调用后可以获取bean的实例
@Override
public Object getBean(String name) throws BeansException {
Object sharedInstance = getSingleton(name); // 先调用这里,方法在下面。
if (sharedInstance != null) {
//如果是FactoryBean,从FactoryBean#getObject中创建bean 后面会讲FactoryBean。
return getObjectForBeanInstance(sharedInstance, name);
}
// 不是的话,则使用反射获取得到BeanDefinition
BeanDefinition beanDefinition = getBeanDefinition(name);
Object bean = createBean(name, beanDefinition);
return getObjectForBeanInstance(bean, name);
}
// getSingleton 可以自己看代码 源码中是多级缓存的
// 代码首先在多级缓存中查找是否存在这个bean,当然在当前的例子中缓存是什么都不存在的
// 因此最终指向的是return singletonObject的部分,也就是直接返回。
@Override
public Object getSingleton(String beanName) {
Object singletonObject = singletonObjects.get(beanName);
if (singletonObject == null) {
singletonObject = earlySingletonObjects.get(beanName);
if (singletonObject == null) {
ObjectFactory<?> singletonFactory = singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
//从三级缓存放进二级缓存
earlySingletonObjects.put(beanName, singletonObject);
singletonFactories.remove(beanName);
}
}
}
return singletonObject;
}
// 获取BeanDefinition,从BeanFactory的Map中获取
@Override
public BeanDefinition getBeanDefinition(String beanName) throws BeansException {
BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
if (beanDefinition == null) {
throw new BeansException("No bean named '" + beanName + "' is defined");
}
return beanDefinition;
}
// createBean 如果是代理则返回代理对象,否则调用doCreateBean
@Override
protected Object createBean(String beanName, BeanDefinition beanDefinition) throws BeansException {
//如果bean需要代理,则直接返回代理对象
Object bean = resolveBeforeInstantiation(beanName, beanDefinition);
if (bean != null) {
return bean;
}
return doCreateBean(beanName, beanDefinition);
}
// doCreateBean在后面会详细说,因为包含了实例化和postprocessor的内容,只需要知道是创建了一个Bean并且返回即可
这一行代码通过 beanFactory 的 getBean() 方法获取名称为 “helloService” 的 Bean。getBean() 方法内部会根据 BeanDefinition 创建 Bean 实例,并进行依赖注入。getBean方法会先检查是否已经创建过,即是否为单例。多级缓存会在后面解释
- 调用 Bean 方法:
helloService.sayHello(); // 输出hello
总结一下,通过反射,可以获取类的所有结构信息,根据这个class可以创建BeanDefinition,这一个BeanDefinition存储的就是 HelloService的beanClass。其他属性(如 initMethodName、scope、propertyValues)默认为空,需要手动设置或通过注解解析(当然源码中的scope是默认为true,因为bean都是默认单例)。
然后根据BeanDefinition注册到 BeanFactory,调用 beanFactory.registerBeanDefinition(“helloService”, beanDefinition) 方法,BeanFactory 会保存 <beanName, BeanDefinition> 的映射(如 “helloService” -> beanDefinition)。此时 BeanFactory 只是记录了配置,并未真正创建 HelloService 实例。
完成了上述的操作,就可以批量生成 Bean 实例。每次调用 beanFactory.getBean(“helloService”) 时,首先检查缓存:如果 helloService 已创建且 scope=“singleton”,直接返回实例。这样,我们就完成了Bean的实例化。注意这里是实例化,也就是创建了一个Bean对象。而后续还可以加入初始化的操作,为Bean赋值和添加内容。
从上面的过程和代码,我们可以回答上面的两个问题:Bean的创建需要使用反射获取到类信息,流程则是先获取到Definition这样的描述信息,再将其注册到BeanFactory的Map中。当我们需要创建对应的Bean,则检测是否已经注册,如果有则使用创建好的Bean即可。
当然,对于SpringMVC中,Bean可以是一个类,这很常见,例如controller层调用service层的代码,我们肯定是将service层标识为Bean(用@service),然后在controller层中调用service层的方法或者修改对应的成员变量。因此Bean可以有属性。那我们是怎么给Bean填充属性的?这里其实在BeanDefinition的构造函数中能发现:
public BeanDefinition(Class beanClass) {
this(beanClass, null);
}
public BeanDefinition(Class beanClass, PropertyValues propertyValues) {
this.beanClass = beanClass;
this.propertyValues = propertyValues != null ? propertyValues : new PropertyValues();
}
有两种构造函数,首先都需要传入beanClass,这是必要的,因为有BeanClass才能创建BeanDefinition,进而注册和创建Bean。第二种构造方法还需要传入PropertyValues,也就是属性值。这里的propertyValues是一个ArrayList,内部包含的是propertyvalue,是单独的一个类,包含了name和value两个字段。
因此测试代码如下:
@Test
public void testPopulateBeanWithPropertyValues() throws Exception {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
PropertyValues propertyValues = new PropertyValues();
propertyValues.addPropertyValue(new PropertyValue("name", "derek"));
propertyValues.addPropertyValue(new PropertyValue("age", 18));
BeanDefinition beanDefinition = new BeanDefinition(Person.class, propertyValues);
beanFactory.registerBeanDefinition("person", beanDefinition);
Person person = (Person) beanFactory.getBean("person");
System.out.println(person);
assertThat(person.getName()).isEqualTo("derek");
assertThat(person.getAge()).isEqualTo(18);
}
首先还是创建factory,之后创建propertyValues(注意,这是列表),再添加两个propertyValue类型的对象。之后再获取得到BeanDefinition,并且进行注册。完成注册则可以进行Bean的实例化。这样操作就可以给Bean的属性赋值。
这种填充方式只是添加值,那如果是bean中注入bean呢?例如service层是一个bean,其中的一个方法也被声明为bean,这种情况要怎么处理?
这里需要增加一个BeanReference类,包装一个bean对另一个bean的引用。上面BeanDefinition的构造方法只有两种,因此对于Bean中有Bean的情况,我们还是使用的第二种构造方法,区别在于value的值是什么。如果value的类型是BeanReference,引用beanB,则先去实例化beanB。 由于不想增加代码的复杂度提高理解难度,暂时不支持循环依赖,后面会在高级篇中解决该问题。
有测试代码如下:
@Test
public void testPopulateBeanWithBean() throws Exception {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
//注册Car实例
PropertyValues propertyValuesForCar = new PropertyValues();
propertyValuesForCar.addPropertyValue(new PropertyValue("brand", "porsche"));
BeanDefinition carBeanDefinition = new BeanDefinition(Car.class, propertyValuesForCar);
beanFactory.registerBeanDefinition("car", carBeanDefinition);
//注册Person实例
PropertyValues propertyValuesForPerson = new PropertyValues();
propertyValuesForPerson.addPropertyValue(new PropertyValue("name", "derek"));
propertyValuesForPerson.addPropertyValue(new PropertyValue("age", 18));
//Person实例依赖Car实例
propertyValuesForPerson.addPropertyValue(new PropertyValue("car", new BeanReference("car")));
BeanDefinition beanDefinition = new BeanDefinition(Person.class, propertyValuesForPerson);
beanFactory.registerBeanDefinition("person", beanDefinition);
Person person = (Person) beanFactory.getBean("person");
System.out.println(person);
assertThat(person.getName()).isEqualTo("derek");
assertThat(person.getAge()).isEqualTo(18);
Car car = person.getCar();
assertThat(car).isNotNull();
assertThat(car.getBrand()).isEqualTo("porsche");
}
这里的操作就是先构造car的BeanDefinition,再构造person的。而person的部分除了自身的属性值之外,还有一个BeanReference类型的value,这样再声明的BeanDefinition和注册的部分就包含了car。
完成注册之后,就可以使用工厂实例化一个名为person的bean,这个bean本身的属性值,也可以通过person获取到car这个bean。类比SpringMVC的架构,controller既可以直接调用service层的属性值,也可以调用service层中被注册为bean的方法,进而再使用。
资源与资源加载器
springboot中,Resource接口是所有资源类的抽象接口,在mini-spring中是这样的:

有三个实现类,分别为:
- FileSystemResource,文件系统资源的实现类
- ClassPathResource,classpath下资源的实现类
- UrlResource,对java.net.URL进行资源定位的实现类
而ResourceLoader接口,则是对于资源的加载器的抽象接口。在mini-spring中,默认使用DefaultResourceLoader为其实现类。有如下的测试代码。测试代码展示了怎么使用resourceLoader来进行资源的获取。
public class ResourceAndResourceLoaderTest {
@Test
public void testResourceLoader() throws Exception {
DefaultResourceLoader resourceLoader = new DefaultResourceLoader();
//加载classpath下的资源
Resource resource = resourceLoader.getResource("classpath:hello.txt");
InputStream inputStream = resource.getInputStream();
String content = IoUtil.readUtf8(inputStream);
System.out.println(content);
assertThat(content).isEqualTo("hello world");
//加载文件系统资源
resource = resourceLoader.getResource("src/test/resources/hello.txt");
assertThat(resource instanceof FileSystemResource).isTrue();
inputStream = resource.getInputStream();
content = IoUtil.readUtf8(inputStream);
System.out.println(content);
assertThat(content).isEqualTo("hello world");
//加载url资源
resource = resourceLoader.getResource("https://www.baidu.com");
assertThat(resource instanceof UrlResource).isTrue();
inputStream = resource.getInputStream();
content = IoUtil.readUtf8(inputStream);
System.out.println(content);
}
}
而可以使用资源加载器进行资源的获取,就可以从xml中获取bean。虽然现在的springboot更希望用户使用注解来定义bean而不是直接在xml中定义。通过资源加载器,就可以在xml格式配置文件中声明式地定义bean的信息,资源加载器读取xml文件,解析出bean的信息,然后往容器中注册BeanDefinition。
BeanDefinitionReader是读取bean定义信息的抽象接口,XmlBeanDefinitionReader是从xml文件中读取的实现类。BeanDefinitionReader需要有获取资源的能力,且读取bean定义信息后需要往容器中注册BeanDefinition,因此BeanDefinitionReader的抽象实现类AbstractBeanDefinitionReader拥有ResourceLoader和BeanDefinitionRegistry两个属性。
测试代码如下:
public class XmlFileDefineBeanTest {
@Test
public void testXmlFile() throws Exception {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
beanDefinitionReader.loadBeanDefinitions("classpath:spring.xml");
Person person = (Person) beanFactory.getBean("person");
System.out.println(person);
assertThat(person.getName()).isEqualTo("derek");
assertThat(person.getCar().getBrand()).isEqualTo("porsche");
Car car = (Car) beanFactory.getBean("car");
System.out.println(car);
assertThat(car.getBrand()).isEqualTo("porsche");
}
}
这一段的内容仅为从xml中获取,思路就是从xml中读取资源,然后加载BeanDefinition,因此大致相同。
BeanFactoryPostProcessor和BeanPostProcessor
【BeanFactoryPostProcessor和BeanPostProcessor是spring框架中具有重量级地位的两个接口,理解了这两个接口的作用,基本就理解spring的核心原理了】
BeanFactoryPostProcessor是spring提供的容器扩展机制,允许我们在bean实例化之前修改bean的定义信息即BeanDefinition的信息。源码给出的代码如下。首先还是创建BeanFactory,然后从xml中获取beanDefinitionLoader,并且将资源加载器中的真正的definition进行提取。但和之前不同的是,我们需要在使用Definition进行实例化之前进行修改。
public class BeanFactoryProcessorAndBeanPostProcessorTest {
@Test
public void testBeanFactoryPostProcessor() throws Exception {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
beanDefinitionReader.loadBeanDefinitions("classpath:spring.xml");
//在所有BeanDefintion加载完成后,但在bean实例化之前,修改BeanDefinition的属性值
CustomBeanFactoryPostProcessor beanFactoryPostProcessor = new CustomBeanFactoryPostProcessor();
beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
Person person = (Person) beanFactory.getBean("person");
System.out.println(person);
//name属性在CustomBeanFactoryPostProcessor中被修改为ivy
assertThat(person.getName()).isEqualTo("ivy"); // 最终执行结果的name就是ivy。
}
}
// 对应的CustomBeanFactoryPostProcesser,在这里主动修改人名
public class CustomBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println("CustomBeanFactoryPostProcessor#postProcessBeanFactory");
BeanDefinition personBeanDefiniton = beanFactory.getBeanDefinition("person");
PropertyValues propertyValues = personBeanDefiniton.getPropertyValues();
//将person的name属性改为ivy
propertyValues.addPropertyValue(new PropertyValue("name", "ivy"));
}
}
你可能发现这个和给bean添加属性的操作好像类似,事实确实是这样。但是添加属性是在定义Bean的时候,也就是先准备好属性再使用BeanDefinition的构造函数进行初始化(还记得吗?有两个构造函数,一个是只有class信息,另一个还包含了PropertyValues)。但是BeanFactoryPostProcesser则是在BeanDefinition加载后进行的修改。
因此,由于【这种同样类型的操作,在不同时间进行】,我们可以联想到Bean的生命周期,这个项目关于Bean这一块的思路大致出现:最终我们需要复现出的是Bean完整的声明周期,从定义到赋值,再到初始化,最后是销毁。当然这一过程实际远比这四步要复杂。
回到正题,BeanPostProcessor也是spring提供的容器扩展机制,不同于BeanFactoryPostProcessor的是,BeanPostProcessor在bean实例化后修改bean或替换bean。BeanPostProcessor是后面实现AOP的关键。BeanPostProcessor的两个方法分别在bean执行初始化方法(后面实现)之前和之后执行。
public interface BeanPostProcessor {
/**
* 在bean执行初始化方法之前执行此方法
*/
Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
/**
* 在bean执行初始化方法之后执行此方法
*/
Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}
这里的第二个测试代码如下:
@Test
public void testBeanPostProcessor() throws Exception {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
beanDefinitionReader.loadBeanDefinitions("classpath:spring.xml");
//添加bean实例化后的处理器
CustomerBeanPostProcessor customerBeanPostProcessor = new CustomerBeanPostProcessor();
beanFactory.addBeanPostProcessor(customerBeanPostProcessor);
Car car = (Car) beanFactory.getBean("car"); // 打断点!! 这里包含了初始化和实例化的内容
System.out.println(car);
//brand属性在CustomerBeanPostProcessor中被修改为lamborghini
assertThat(car.getBrand()).isEqualTo("lamborghini");
}
这里可以ctrl+B去看源码,我们查看一下CustomerBeanPostProcessor的代码。其就是分为了两个部分,一个是BeforeInitialization,一个是AfterInitialization。这里的前置处理是将car这个Bean的属性进行修改,后置则单纯是返回这个bean,即不会进行任何的处理。也就是这里提前写好了应该在bean的实例化后,初始化之前进行的前置操作和后置操作。这里的前置和后置是相对于bean的初始化而言。
public class CustomerBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("CustomerBeanPostProcessor#postProcessBeforeInitialization, beanName: " + beanName);
//换兰博基尼
if ("car".equals(beanName)) {
((Car) bean).setBrand("lamborghini");
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("CustomerBeanPostProcessor#postProcessAfterInitialization, beanName: " + beanName);
return bean;
}
}
然后我们针对getBean这个方法查看源码。这个方法包含了实例化和初始化的过程。实例化的过程在上面都已经有涉及(BeanDefinition的内容)。
// getBean中会调用createBean。
@Override
public Object getBean(String name) throws BeansException {
Object sharedInstance = getSingleton(name);
if (sharedInstance != null) {
//如果是FactoryBean,从FactoryBean#getObject中创建bean
return getObjectForBeanInstance(sharedInstance, name);
}
BeanDefinition beanDefinition = getBeanDefinition(name);
Object bean = createBean(name, beanDefinition);
return getObjectForBeanInstance(bean, name);
}
// 继续查看createBean:
@Override
protected Object createBean(String beanName, BeanDefinition beanDefinition) throws BeansException {
//如果bean需要代理,则直接返回代理对象
Object bean = resolveBeforeInstantiation(beanName, beanDefinition);
if (bean != null) {
return bean;
}
return doCreateBean(beanName, beanDefinition);
}
// 继续查看doCreateBean
protected Object doCreateBean(String beanName, BeanDefinition beanDefinition) {
Object bean;
try {
bean = createBeanInstance(beanDefinition);
//为解决循环依赖问题,将实例化后的bean放进缓存中提前暴露
if (beanDefinition.isSingleton()) {
Object finalBean = bean;
addSingletonFactory(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
return getEarlyBeanReference(beanName, beanDefinition, finalBean);
}
});
}
//实例化bean之后执行
boolean continueWithPropertyPopulation = applyBeanPostProcessorsAfterInstantiation(beanName, bean);
if (!continueWithPropertyPopulation) {
return bean;
}
//在设置bean属性之前,允许BeanPostProcessor修改属性值
applyBeanPostProcessorsBeforeApplyingPropertyValues(beanName, bean, beanDefinition);
//为bean填充属性
applyPropertyValues(beanName, bean, beanDefinition);
//执行bean的初始化方法和BeanPostProcessor的前置和后置处理方法
bean = initializeBean(beanName, bean, beanDefinition);
} catch (Exception e) {
throw new BeansException("Instantiation of bean failed", e);
}
//注册有销毁方法的bean
// 省略,此处是销毁部分
从doCreate中可以看到,这里的initialize Bean就是我们想要的初始化,这行代码之前的部分是实例化。
protected Object initializeBean(String beanName, Object bean, BeanDefinition beanDefinition) {
if (bean instanceof BeanFactoryAware) {
((BeanFactoryAware) bean).setBeanFactory(this);
}
//执行BeanPostProcessor的前置处理
Object wrappedBean = applyBeanPostProcessorsBeforeInitialization(bean, beanName);
try {
invokeInitMethods(beanName, wrappedBean, beanDefinition);
} catch (Throwable ex) {
throw new BeansException("Invocation of init method of bean[" + beanName + "] failed", ex);
}
//执行BeanPostProcessor的后置处理
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
return wrappedBean;
}
而initializationBean的部分就和我们之前说的是一样的,先进行一个前置处理,然后是初始化,最后是后置处理。
注意!bean的实例化和初始化是两回事。这个概念很基础但容易混淆:实例化类似于new操作,在这里就是使用beanFactory+BeanFactoryPostProcessor进行的实例化,得到了具体的bean,但是初始化则是填充值,初始化的前后包含了这里说的前置操作和后置操作。
经过上面的学习,从bean的角度看,目前的生命周期是这样的。这一套并不完整,但是可以说明除销毁外的大多数流程。

读者如果比较敏感,应该可有发现上面有一些小问题,即我们是需要手动在代码中声明BeanPostProcessor,能不能将其加入到spring中自主处理呢?应用上下文ApplicationContext,是spring中较之于BeanFactory更为先进的IOC容器,ApplicationContext除了拥有BeanFactory的所有功能外,还支持特殊类型bean如上一节中的BeanFactoryPostProcessor和BeanPostProcessor的自动识别、资源加载、容器事件和监听器、国际化支持、单例bean自动初始化等。
也许有的面试题会问IOC容器有哪些,那除了之前的BeanFactory,还有就是ApplicationContext。 比较重要的功能就是BeanFactoryProcessor和BeanPostProcessor的自动识别,即不需要手动写入而是可以通过配置或者注解的方式来加入。
测试代码如下。跟之前使用BeanFactory相比,就省去了手动添加处理器的过程。
@Test
public void testApplicationContext() throws Exception {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:spring.xml");
Person person = applicationContext.getBean("person", Person.class);
System.out.println("111" + person);
//name属性在CustomBeanFactoryPostProcessor中被修改为ivy
assertThat(person.getName()).isEqualTo("ivy");
Car car = applicationContext.getBean("car", Car.class);
System.out.println(car);
//brand属性在CustomerBeanPostProcessor中被修改为lamborghini
assertThat(car.getBrand()).isEqualTo("lamborghini");
}
关于自动装配的代码,主要看的是AbstractApplicationContext#refresh方法。这个方法也很重要,是spring容器启动和刷新的核心逻辑。通过这个方法,spring会在启动的时候自动扫描和装配Bean(除去懒加载的),然后将这些Bean实例化、初始化完成并且放到IOC容器中,等待被调用。
@Override
public void refresh() throws BeansException {
//创建BeanFactory,并加载BeanDefinition
refreshBeanFactory();
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
//添加ApplicationContextAwareProcessor,让继承自ApplicationContextAware的bean能感知bean
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
//在bean实例化之前,执行BeanFactoryPostProcessor
invokeBeanFactoryPostProcessors(beanFactory);
//BeanPostProcessor需要提前与其他bean实例化之前注册
registerBeanPostProcessors(beanFactory);
//初始化事件发布者
initApplicationEventMulticaster();
//注册事件监听器
registerListeners();
//注册类型转换器和提前实例化单例bean
finishBeanFactoryInitialization(beanFactory);
//发布容器刷新完成事件
finishRefresh();
}
// 这里着重看一下finishBeanFactoryInitialization(beanFactory);
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
//设置类型转换器
if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME)) {
Object conversionService = beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME);
if (conversionService instanceof ConversionService) {
beanFactory.setConversionService((ConversionService) conversionService);
}
}
//提前实例化单例bean
beanFactory.preInstantiateSingletons();
}
// preInstantiateSingletons,看注释可以得知是创建一个Bean,创建要满足的条件和我上面写得一样。
@Override
public void preInstantiateSingletons() throws BeansException {
beanDefinitionMap.forEach((beanName, beanDefinition) -> {
//只有当bean是单例且不为懒加载才会被创建
if (beanDefinition.isSingleton() && !beanDefinition.isLazyInit()) {
getBean(beanName);
}
});
}
Bean的初始化和销毁方法
在spring中,定义bean的初始化和销毁方法有三种方法:
- 在xml文件中制定init-method和destroy-method
- 继承自InitializingBean和DisposableBean
- 在方法上加注解PostConstruct和PreDestroy(在springboot中比较常用)
第三种通过BeanPostProcessor实现,在扩展篇中实现。
第一种:在xml中制定init-method和destroy-method
这种在springboot中并不常用,主要使用的还是注解。
首先我们看一下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"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<bean id="person" class="org.springframework.test.bean.Person" init-method="customInitMethod" destroy-method="customDestroyMethod">
<property name="name" value="derek"/>
<property name="car" ref="car"/>
</bean>
<bean id="car" class="org.springframework.test.bean.Car">
<property name="brand" value="porsche"/>
</bean>
</beans>
然后再对应的person中声明即可。
第二种:继承InitializingBean和DisposableBean
- 初始化方法
这里声明了person的bean,这个bean加入了init和destroy的方法,也就是基于这两个方法进行初始化和销毁。
public class Person implements InitializingBean, DisposableBean {
private String name;
private int age;
private Car car;
public void customInitMethod() {
System.out.println("I was born in the method named customInitMethod");
}
public void customDestroyMethod() {
System.out.println("I died in the method named customDestroyMethod");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("I was born in the method named afterPropertiesSet");
}
@Override
public void destroy() throws Exception {
System.out.println("I died in the method named destroy");
}
//setter and getter
}
// 测试代码:
public class InitAndDestoryMethodTest {
@Test
public void testInitAndDestroyMethod() throws Exception {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:init-and-destroy-method.xml");
applicationContext.registerShutdownHook(); //或者手动关闭 applicationContext.close();
}
}
这个person包含了初始化和销毁的方法。最终的输出结果为:
I was born in the method named afterPropertiesSet
I was born in the method named customInitMethod
I died in the method named destroy
I died in the method named customDestroyMethod
也就说执行顺序是先调用的afterPropertiesSet,这个方法重写了 invokeInitMethods方法,这个方法在initializeBean中被调用(还记得doCreate吗?这里调用的initializeBean,后者的作用是调用BeanPostProcessor的前置和后置方法,以及invokeInitMethods,也就是Bean的初始化方法)。所以说明afterPropertiesSet方法是在Bean初始化的时候被调用的。然后才是customInitMethod,也就是说明,Bean的InitMethod方法是在自定义的初始化方法之前执行的。下面的代码其实就是这个意思
protected void invokeInitMethods(String beanName, Object bean, BeanDefinition beanDefinition) throws Throwable {
// 先执行InitMethod
if (bean instanceof InitializingBean) {
((InitializingBean) bean).afterPropertiesSet();
}
// 再执行自定义的初始化方法,以反射的方式来执行
String initMethodName = beanDefinition.getInitMethodName();
if (StrUtil.isNotEmpty(initMethodName) && !(bean instanceof InitializingBean && "afterPropertiesSet".equals(initMethodName))) {
Method initMethod = ClassUtil.getPublicMethod(beanDefinition.getBeanClass(), initMethodName);
if (initMethod == null) {
throw new BeansException("Could not find an init method named '" + initMethodName + "' on bean with name '" + beanName + "'");
}
initMethod.invoke(bean);
}
}
- 销毁方法
在DefaultSingletonBeanRegistry中增加属性disposableBeans保存拥有销毁方法的bean,拥有销毁方法的bean在AbstractAutowireCapableBeanFactory#registerDisposableBeanIfNecessary中注册到disposableBeans中。
也就是说,还是在refresh中会调用finishBeanFactoryInitialization,后者调用了getBean,最终会调用doCreateBean,也就会注册有销毁方法的Beans,这样就可以在JVM关闭之前通过一个单独的关闭线程将Beans都进行销毁。
这里可以看之前的doCreateBean的完整内容了。之前的内容是实例化和初始化,之后才是销毁。
protected Object doCreateBean(String beanName, BeanDefinition beanDefinition) {
// 前面是实例化和初始化
//注册有销毁方法的bean
registerDisposableBeanIfNecessary(beanName, bean, beanDefinition);
Object exposedObject = bean;
if (beanDefinition.isSingleton()) {
//如果有代理对象,此处获取代理对象
exposedObject = getSingleton(beanName);
addSingleton(beanName, exposedObject);
}
return exposedObject;
}
// 检测是否满足销毁的要求:是单例,且有销毁方法
protected void registerDisposableBeanIfNecessary(String beanName, Object bean, BeanDefinition beanDefinition) {
//只有singleton类型bean会执行销毁方法
if (beanDefinition.isSingleton()) {
if (bean instanceof DisposableBean || StrUtil.isNotEmpty(beanDefinition.getDestroyMethodName())) {
registerDisposableBean(beanName, new DisposableBeanAdapter(bean, beanName, beanDefinition));
}
}
}
// 其实也就是把需要销毁的Bean放到DisposableBean中,最后统一销毁。
public void registerDisposableBean(String beanName, DisposableBean bean) {
disposableBeans.put(beanName, bean);
}
测试的代码如下。整个的调用流程是先在refresh中一路调用,调用到了doCreateBean,其中包含了将【有销毁方法】的bean注册到disposableBeans中,然后销毁的时候则会钩子函数进行销毁,销毁的对象为注册到disposableBeans中的Bean。
public class InitAndDestoryMethodTest {
@Test
public void testInitAndDestroyMethod() throws Exception {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:init-and-destroy-method.xml");
applicationContext.registerShutdownHook(); //或者手动关闭 applicationContext.close();
}
}
// 查看registerShutdownHook,创建一个shutdown线程执行doclose。
// 为了确保销毁方法在虚拟机关闭之前执行,向虚拟机中注册一个钩子方法。
// 当 JVM 接收到关闭信号时(例如用户按下 Ctrl+C 或操作系统发送终止信号),这个钩子线程会被执行。
// 这个线程会调用 doClose() 方法,进而发布关闭事件和销毁单例 Bean。
public void registerShutdownHook() {
Thread shutdownHook = new Thread() {
public void run() {
doClose();
}
};
Runtime.getRuntime().addShutdownHook(shutdownHook);
}
protected void doClose() {
//发布容器关闭事件
publishEvent(new ContextClosedEvent(this));
//执行单例bean的销毁方法
destroyBeans();
}
protected void destroyBeans() {
getBeanFactory().destroySingletons();
}
// 销毁disposableBeans中的Beans。
public void destroySingletons() {
ArrayList<String> beanNames = new ArrayList<>(disposableBeans.keySet());
for (String beanName : beanNames) {
DisposableBean disposableBean = disposableBeans.remove(beanName); // remove
try {
disposableBean.destroy();
} catch (Exception e) {
throw new BeansException("Destroy method on bean with name '" + beanName + "' threw an exception", e);
}
}
}
生命周期如下:

Aware接口
Aware是感知、意识的意思,Aware接口是标记性接口,其实现子类能感知容器相关的对象。常用的Aware接口有BeanFactoryAware和ApplicationContextAware,分别能让其实现者感知所属的BeanFactory和ApplicationContext。
有测试代码如下。这里的helloService是实现了两个接口:
public class AwareInterfaceTest {
@Test
public void test() throws Exception {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:spring.xml");
HelloService helloService = applicationContext.getBean("helloService", HelloService.class);
assertThat(helloService.getApplicationContext()).isNotNull();
assertThat(helloService.getBeanFactory()).isNotNull();
}
}
//HelloService类
public class HelloService implements ApplicationContextAware, BeanFactoryAware {
private ApplicationContext applicationContext;
private BeanFactory beanFactory;
// 剩下的代码省略
}
对于BeanFactory,查看aware的部分就是从getBean一路到doCreateBean,在doCreateBean中有initializeBean的前三行就是。因此你可以得知,这部分在生命周期中是Bean的实例化之后,BeanPostProcessor之前进行的。
通过这三行代码,可以让Bean得知其BeanFactory是什么,也就可以获得对应的BeanFactory中其它Bean的内容。
protected Object initializeBean(String beanName, Object bean, BeanDefinition beanDefinition) {
if (bean instanceof BeanFactoryAware) { // 当前的bean是否是实现了BeanFactoryAware接口
((BeanFactoryAware) bean).setBeanFactory(this); // 让创建当前bean的BeanFactory的引用给这个bean
}
//执行BeanPostProcessor的前置处理、初始化方法和后置处理。
}
对于ApplicationContext:是在BeanPostProcessor的前置处理中进行的。对于ApplicationContext,会在Spring运行时自动执行refresh() 方法,refresh会包含各项内容,包括实例化和BeanPostProcessor。
protected Object initializeBean(String beanName, Object bean, BeanDefinition beanDefinition) {
// Aware
//执行BeanPostProcessor的前置处理
Object wrappedBean = applyBeanPostProcessorsBeforeInitialization(bean, beanName);
// 初始化和后置处理
}
// 查看前置处理的代码:
// 传入的第一个参数其实就是我们要创建的Bean
@Override
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean; //将传入的Bean复制一份
for (BeanPostProcessor processor : getBeanPostProcessors()) {
// current是增加了前置处理的bean。
Object current = processor.postProcessBeforeInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
// 查看postProcessBeforeInitialization
// 如果是ApplicationContextAware接口的实现,则会将对于ApplicationContext的引用给当前的bean。最后返回bean
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof ApplicationContextAware) {
((ApplicationContextAware) bean).setApplicationContext(applicationContext);
}
return bean;
}
这个有什么用呢?
实现 Aware 接口(如 ApplicationContextAware)可以让一个普通的 bean 获得对 ApplicationContext 的访问权限,从而能够执行一些普通 bean 通常无法直接执行的操作,比如发布事件。这个后面会提到。
因此现在生命周期如下:

bean作用域,增加prototype的支持
测试代码如下。这里注册的xml文件的bean的scope发生了变化,这次不是单例(singleton),而是原型(prototype)。也就是说,每次都会新创建一个bean,而不是依赖于IOC容器创建一个单例。使用的时候也是,不会只在缓存中使用缓存好的单例。如果你对之前的代码比较熟,就会知道refresh阶段是只会进行BeanDefinition的注册和BeanFactoryPostProcessor的处理,不会进行实例化以及实例化之后的步骤,这需要手动进行。
public class PrototypeBeanTest {
@Test
public void testPrototype() throws Exception {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:prototype-bean.xml");
Car car1 = applicationContext.getBean("car", Car.class);
Car car2 = applicationContext.getBean("car", Car.class);
assertThat(car1 != car2).isTrue(); // 可以通过,这两个不一样
}
}
// 为了防止忘记,我再写一下
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
//设置类型转换器
if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME)) {
Object conversionService = beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME);
if (conversionService instanceof ConversionService) {
beanFactory.setConversionService((ConversionService) conversionService);
}
}
//提前实例化单例bean
beanFactory.preInstantiateSingletons();
}
//查看这个preInstantiateSingleton:
@Override
public void preInstantiateSingletons() throws BeansException {
beanDefinitionMap.forEach((beanName, beanDefinition) -> {
//只有当bean是单例且不为懒加载才会被创建,才会调用getbean
if (beanDefinition.isSingleton() && !beanDefinition.isLazyInit()) {
getBean(beanName);
}
});
}
而怎么判断是否为单例?会在doCreate的地方操作。先判断是否为singleton,如果是则执行addSingleton,加入到单例中。
@Override
publicvoid addSingleton(String beanName, Object singletonObject) {
singletonObjects.put(beanName, singletonObject); // 1
earlySingletonObjects.remove(beanName); // 2
singletonFactories.remove(beanName); // 3
}
现在可以得到bean的生命周期如下:

FactoryBean
通常情况下,当你从 Spring 容器中通过 getBean(“beanName”) 获取一个 bean 时,你得到的就是名为 beanName 的那个对象本身。但是,如果你获取的 bean 实现了 FactoryBean 接口,那么默认情况下,Spring 会调用该 FactoryBean 实现类的 getObject() 方法,并将该方法返回的对象作为最终的结果给你。
有如下测试代码:
public class FactoryBeanTest {
@Test
public void testFactoryBean() throws Exception {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:factory-bean.xml");
Car car = applicationContext.getBean("car", Car.class);
assertThat(car.getBrand()).isEqualTo("porsche");
}
}
// 对应的carFactoryBean 重点关注getObject方法
public class CarFactoryBean implements FactoryBean<Car> {
private String brand;
@Override
public Car getObject() throws Exception {
Car car = new Car();
car.setBrand(brand);
return car;
}
@Override
public boolean isSingleton() {
return true;
}
public void setBrand(String brand) {
this.brand = brand;
}
}
重点在于getBean方法。之前都只是分析从缓存获取、获取BeanDefinition,然后创建一个Bean,也包括后面的doCreate的部分(实例化、PostProcessor和初始化),并没有深究最后一句getObjectForBeanInstance。代码如下
@Override
public Object getBean(String name) throws BeansException {
Object sharedInstance = getSingleton(name);
if (sharedInstance != null) {
//如果是FactoryBean,从FactoryBean#getObject中创建bean
return getObjectForBeanInstance(sharedInstance, name);
}
BeanDefinition beanDefinition = getBeanDefinition(name);
Object bean = createBean(name, beanDefinition);
return getObjectForBeanInstance(bean, name);
}
// 查看getObjectForBeanInstance
protected Object getObjectForBeanInstance(Object beanInstance, String beanName) {
Object object = beanInstance;
// 首先查看是否实现了FactoryBean的接口。
if (beanInstance instanceof FactoryBean) {
FactoryBean factoryBean = (FactoryBean) beanInstance;
// 如果实现了FactoryBean,则看bean的type是单例还是原型
// 最终获得的结果就是调用getObject方法。
try {
if (factoryBean.isSingleton()) {
//singleton作用域bean,从缓存中获取
object = this.factoryBeanObjectCache.get(beanName);
if (object == null) {
object = factoryBean.getObject();
this.factoryBeanObjectCache.put(beanName, object);
}
} else {
//prototype作用域bean,新创建bean
object = factoryBean.getObject();
}
} catch (Exception ex) {
throw new BeansException("FactoryBean threw exception on object[" + beanName + "] creation", ex);
}
}
// 因此最终返回的是factoryBean调用getObject方法后的结果。
// 当然,如果没有实现factorybean,则返回最初创建的bean
return object;
}
getObject的代码上面已经有了,其实就是setBrand并返回car。因此这里的FactoryBean实现的并非是返回原始的Bean,而是返回getObject的结果。
因此使用FactoryBean往往是在代理对象中,Spring AOP大量使用了FactoryBean来创建代理对象。当你配置一个切面时,Spring 实际上可能配置了一个实现了 FactoryBean 的 bean,它负责根据切面配置生成并返回代理对象。
容器事件和事件监听器
ApplicationContext容器提供了完善的事件发布和事件监听功能。而BeanFactory并不具备这个能力,所以我们下面使用的是ApplicationContext。ApplicationEventMulticaster接口是注册监听器和发布事件的抽象接口,AbstractApplicationContext包含其实现类实例作为其属性,使得ApplicationContext容器具有注册监听器和发布事件的能力。
在 Spring 中,事件监听通常涉及以下几个组件:
ApplicationEvent:Spring 中的事件基类,自定义事件通常继承这个类。
ApplicationListener:监听器的接口,任何实现了这个接口的 Bean 都可以监听特定类型的事件。
ApplicationEventMulticaster:事件多播器,负责将事件分发给所有注册的监听器。
测试代码如下:
public class EventAndEventListenerTest {
@Test
public void testEventListener() throws Exception {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:event-and-event-listener.xml");
applicationContext.publishEvent(new CustomEvent(applicationContext));
applicationContext.registerShutdownHook();//或者applicationContext.close()主动关闭容器;
}
}
其中的xml文件有三个bean:第一个是容器刷新时工作,第二个是自定义的事件监听器,第三个是容器关闭时工作。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<bean class="org.springframework.test.common.event.ContextRefreshedEventListener"/>
<bean class="org.springframework.test.common.event.CustomEventListener"/>
<bean class="org.springframework.test.common.event.ContextClosedEventListener"/>
</beans>
在源码中,可以从refresh进入看一下事件监听器的代码:
@Override
public void refresh() throws BeansException {
// 之前的操作...
//初始化事件发布者
initApplicationEventMulticaster();
//注册事件监听器
registerListeners();
//注册类型转换器和提前实例化单例bean
finishBeanFactoryInitialization(beanFactory);
//发布容器刷新完成事件
finishRefresh();
}
//查看initApplicationEventMulticaster,做的事情也很简单
// 获取容器,并以此为参数创建applicationEventMulicaster的实现类。
// 创建好的Bean是专门为了事件发布使用的bean,因此这个参数调用并未传入IOC容器去操作beans
protected void initApplicationEventMulticaster() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
beanFactory.addSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, applicationEventMulticaster);
}
提前说一下:
singletonObjects 是一级缓存,存储完全初始化好的单例 bean。
earlySingletonObjects 是二级缓存,存储早期引用(可能在 bean 完全初始化之前)。
singletonFactories 是三级缓存,存储 ObjectFactory,用于创建 bean 的代理或其他逻辑。
// 加入一级缓存,并从二三级缓存移除。
@Override
public void addSingleton(String beanName, Object singletonObject) {
singletonObjects.put(beanName, singletonObject); // 1
earlySingletonObjects.remove(beanName); // 2
singletonFactories.remove(beanName); // 3
}
然后是注册,即refresh里的registerListeners(),就是将xml中的三个监听相关的bean注册。顺带一提,springboot中是使用注解。
protected void registerListeners() {
// 找到全部实现了ApplicationListener接口的bean,也就是xml中的三个
Collection<ApplicationListener> applicationListeners = getBeansOfType(ApplicationListener.class).values();
// 对这三个beans进行循环
for (ApplicationListener applicationListener : applicationListeners) {
// 添加到applicationEventMulticaster
// addApplicationListener本质也是添加到Hashset中
applicationEventMulticaster.addApplicationListener(applicationListener);
}
}
最后就是refresh中的finishRefresh()
protected void finishRefresh() {
publishEvent(new ContextRefreshedEvent(this));
}
//
@Override
public void publishEvent(ApplicationEvent event) {
applicationEventMulticaster.multicastEvent(event);
}
//循环,把事件分发给所有感兴趣且兼容的监听器。
@Override
public void multicastEvent(ApplicationEvent event) {
for (ApplicationListener<ApplicationEvent> applicationListener : applicationListeners) {
if (supportsEvent(applicationListener, event)) {
applicationListener.onApplicationEvent(event);
}
}
}
//进行类型匹配,看event和listener是否能匹配。
protected boolean supportsEvent(ApplicationListener<ApplicationEvent> applicationListener, ApplicationEvent event) {
Type type = applicationListener.getClass().getGenericInterfaces()[0];
Type actualTypeArgument = ((ParameterizedType) type).getActualTypeArguments()[0];
String className = actualTypeArgument.getTypeName();
Class<?> eventClassName;
try {
eventClassName = Class.forName(className);
} catch (ClassNotFoundException e) {
throw new BeansException("wrong event class name: " + className);
}
return eventClassName.isAssignableFrom(event.getClass());
}
总体流程就是,在refresh中,先初始化事件发布者(多播器),然后注册监听者(从xml或者注解),最后进行匹配,将事件分发给感兴趣的监听者,这样监听者就可以进行监听,等到事件发生做出相应的操作。
帮你理解的一个例子
例如有如下的代码:
// Service 层
@Service
public class MyService {
private String serviceName;
private int serviceVersion;
// 1. 构造器
public MyService() {
System.out.println("1. MyService: 调用无参构造器,准备实例化");
}
// 2. Setter 方法 (用于依赖注入)
@Autowired
public void setServiceName(String serviceName) {
System.out.println("2. MyService: 通过 setter 注入 serviceName = " + serviceName);
this.serviceName = serviceName;
}
// 3. @PostConstruct 注解的初始化方法
@PostConstruct
public void init() {
System.out.println("6. MyService: 执行 @PostConstruct 注解的初始化方法 init()");
this.serviceVersion = 1;
}
// 业务方法
public String doSomething() {
System.out.println("9. MyService: 执行业务方法 doSomething()");
return "Service " + serviceName + " (v" + serviceVersion + ") is working!";
}
// 4. @PreDestroy 注解的销毁方法
@PreDestroy
public void cleanup() {
System.out.println("12. MyService: 执行 @PreDestroy 注解的销毁方法 cleanup()");
}
}
// Controller 层
@RestController
@RequestMapping("/api")
public class MyController {
private MyService myService; // 依赖 MyService
// 5. 构造器注入 (推荐)
@Autowired
public MyController(MyService myService) {
System.out.println("3. MyController: 调用构造器,注入 myService");
this.myService = myService;
}
@GetMapping("/hello")
public String sayHello() {
System.out.println("8. MyController: 调用 sayHello 方法");
// 9. 调用 Service 的方法
String result = myService.doSomething();
return "Controller received: " + result;
}
}
我们结合上面所学来分析一个bean的生命周期:
- 程序员定义 Bean:
你通过添加 @Service, @Controller, @Repository 等注解来标记类,告诉 Spring 你希望将这些类实例化为 Bean。你还可能使用 @Autowired 或 @Resource 等注解来声明依赖关系,或者直接在构造器/Setter 方法上使用 @Autowired 来实现依赖注入。 - Spring Boot 的注册和定义:
这一部分开始和上面所学相关。
当你的 Spring Boot 应用启动时,SpringApplication.run() 方法会被调用。内部,它会创建一个 ApplicationContext,这是 Spring 的核心容器,负责管理 Bean。容器会扫描你指定的包(通过 @SpringBootApplication 或 @ComponentScan 注解定义的 base packages)。在扫描过程中,容器会识别出带有 @Service, @Controller, @Component 等注解的类。
而对于每个被识别的类,容器会:- 创建 BeanDefinition: 这是一个配置元数据对象,描述了如何创建对应的 Bean,包括类名、作用域(默认是单例 singleton)、是否是懒加载、依赖关系、初始化/销毁方法等。
- 注册 BeanDefinition : 此时,Bean 还没有被创建,只是定义好了如何创建它。
- 第一次调用 Bean(例如 Controller 调用 Service):
假设一个 HTTP 请求到达,Spring MVC 框架(也是 Spring Boot 自动配置的一部分)需要处理这个请求。它会找到匹配的 @Controller 或 @RestController 处理方法。在执行这个 Controller 方法之前,Spring 需要确保 Controller 依赖的 Service Bean 是可用的。
- bean的实例化以及初始化:
如果 Service Bean 还没有被创建(对于一个单例 Bean,通常在应用启动时就已经创建好了,除非它是懒加载的),那么当 Controller 被创建(或者第一次需要其依赖的 Service 时),容器就会:- 根据之前注册的 BeanDefinition,找到对应的 Service 类。
- 调用 BeanFactory.getBean(“serviceName”)(或者更精确地说,是 ApplicationContext.getBean(),它内部委托给 BeanFactory)。 这个 getBean() 调用会触发 Bean 的完整创建和初始化流程。这一部分上面也有源码。
- 实例化(调用构造器):填充属性(依赖注入,调用 Setter 方法或注入构造器参数)
- Aware 接口回调 (如果实现):如果 MyService 实现了 BeanNameAware, ApplicationContextAware 等接口,Spring 会在这一步调用 setBeanName(), setApplicationContext() 等方法,让 Bean 获得自身在容器中的名称或容器引用。
- 应用 BeanPostProcessor 的 postProcessBeforeInitialization
- 调用 @PostConstruct 方法 或 InitializingBean.afterPropertiesSet() 或自定义的 init-method
应用 BeanPostProcessor 的 postProcessAfterInitialization - 最后,将完全初始化好的 Service Bean 返回给 Controller。
- 特别说明:对于单例 Bean: 通常在应用启动、容器刷新(也就是refresh方法调用的时候,上面有源码)的过程中,所有单例 Bean 就已经被创建和初始化好了。所以,在 Controller 调用 Service 时,getBean() 很可能只是从容器缓存中获取一个已经存在的 Bean 实例,而不会重新创建。 这就是单例模式的效率优势。想一想mini-spring的代码,是不是在newSingleon的时候是存在多级缓存的?
对于原型(prototype)Bean: 每次调用 getBean() 都会创建一个新的 Bean 实例。

1469

被折叠的 条评论
为什么被折叠?



