阅读 53

你知道的Bean的加载方式!

这是我参与8月更文挑战的第27天,活动详情查看:8月更文挑战

image.png

今天我们唠唠一些最基本的东西,我们用的框架都是Spring,任何开发工作都是基于Spring,那么所有的代码编译,都得先实例成bean,才能被引用。

所以今天唠唠bean是怎么加载到Spring里面的?

话不多说,进入正题

Bean 的注册方式有几种

Bean 的注册方式有三种:

  • 1、XML 配置文件注册方式
<bean id="person" class="org.springframework.beans.Person">
   <property name="id" value="1"/>
   <property name="name" value="Java"/>
</bean>
复制代码
  • 2、Java 注解注册方式

我们可以用Springboot中的注解 @Component 注解方式来注册 Bean,代码如下

@Component
public class Person {

   private Integer id;

   private String name
   // 忽略其他方法
}
复制代码

也可以使用 @Bean 注解方式来注册 Bean,代码如下

@Configuration
public class Person {

   @Bean
   public Person  person(){
      return new Person();
   }
   // 忽略其他方法
}

复制代码

其中 @Configuration 可理解为 XML 配置里的 bean 标签,而 @Bean 可理解为用 XML 配置里面的 bean 标签。

  • 3、Java API 注册方式

使用 Spring中 BeanDefinitionRegistry.registerBeanDefinition() 方法的方式注册 Bean,代码如下,实现BeanDefinitionRegistryPostProcessor类

public class CustomBeanDefinitionRegistry implements BeanDefinitionRegistryPostProcessor {
	@Override
        public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {

	}

	@Override
        public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {

		RootBeanDefinition personBean = new RootBeanDefinition(Person.class);
		// 新增 Bean
		registry.registerBeanDefinition("person", personBean);
	}

}
复制代码

bean的生命周期

  • 对于 Spring Bean 来说,并不是启动阶段就会触发 Bean 的实例化,只有当客户端通过显式或者隐式的方式调用 BeanFactory 的 getBean() 方法时,它才会触发该类的实例化方法。当然对于 BeanFactory 来说,也不是所有的 getBean() 方法都会实例化 Bean 对象,例如作用域为 singleton 时,只会在第一次,实例化该 Bean 对象,之后会直接返回该对象。但如果使用的是 ApplicationContext 容器,则会在该容器启动的时候,立即调用注册到该容器所有 Bean 的实例化方法。

  • getBean() 既然是 Bean 对象的入口,我们就先从这个方法说起,getBean() 方法是属于 BeanFactory 接口的,它的真正实现是 AbstractAutowireCapableBeanFactory 的 createBean() 方法,而 createBean() 是通过 doCreateBean() 来实现的。

spring的bean生命周期其实最核心的分为4个步骤,只要理清三个关键的步骤,其他的只是在这三个细节中添加不同的细节实现,也就是spring的bean生明周期:

  1. 实例化 Instantiation

AbstractAutowireCapableBeanFactory.doCreateBean中会调用createBeanInstance()方法,该阶段主要是从beanDefinitionMap循环读取bean,获取它的属性。

然后利用反射(core包下有ReflectionUtil会先强行将构造方法setAccessible(true))读取对象的构造方法(spring会自动判断是否是有参数还是无参数,以及构造方法中的参数是否可用),然后再去创建实例(newInstance)

  1. 初始化

    2.1. 初始化主要包括两个步骤,一个是属性填充,另一个就是具体的初始化过程

    2.1.1 属性赋值 PopulateBean()会对bean的依赖属性进行填充,@AutoWired注解注入的属性就发生这个阶段,假如我们的bean有很多依赖的对象,那么spring会依次调用这些依赖的对象进行实例化,注意这里可能会有循环依赖的问题。后面我们会讲到spring是如何解决循环依赖的问题

    2.1.2 初始化 Initialization。初始化的过程包括将初始化好的bean放入到spring的缓存中、填充我们预设的属性进一步做后置处理等

  2. 销毁

在Spring将所有的bean都初始化好之后,我们的业务系统就可以调用了。而销毁主要的操作是销毁bean,主要是伴随着spring容器的关闭,此时会将spring的bean移除容器之中。此后spring的生命周期到这一步彻底结束,不再接受spring的管理和约束。

接下来简单看一副图片。快速记忆下bean的生命周期

image.png

总结

本篇文章主要是介绍了一下spring的bean加载过程,没有详细展开某个细节分析。spring的内部源码非常复杂,每个接口的实现类都在5个以上,如果深入细节,恐怕不是一篇文章能讲清楚的。这篇文章的目的就是在阐述spring的基本脉络中心路线顺序,首先我们需要有一个总体的认识,然后再深入到细节就是轻而易举的了。这也是一种学习的方法论

后面我会对Spring专门出一个专栏,欢迎关注。我以后会持续输出干货文章

弦外之音

感谢你的阅读,如果你感觉学到了东西,麻烦您点赞,关注。也欢迎有问题我们下面评论交流

加油! 我们下期再见!

给大家分享几个我前面写的几篇骚操作

聊聊不一样的策略模式(值得收藏)

copy对象,这个操作有点骚!

文章分类
后端
文章标签