这是我参与8月更文挑战的第27天,活动详情查看:8月更文挑战
今天我们唠唠一些最基本的东西,我们用的框架都是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生明周期:
- 实例化 Instantiation
AbstractAutowireCapableBeanFactory.doCreateBean中会调用createBeanInstance()方法,该阶段主要是从beanDefinitionMap循环读取bean,获取它的属性。
然后利用反射(core包下有ReflectionUtil会先强行将构造方法setAccessible(true))读取对象的构造方法(spring会自动判断是否是有参数还是无参数,以及构造方法中的参数是否可用),然后再去创建实例(newInstance)
-
初始化
2.1. 初始化主要包括两个步骤,一个是属性填充,另一个就是具体的初始化过程
2.1.1 属性赋值 PopulateBean()会对bean的依赖属性进行填充,@AutoWired注解注入的属性就发生这个阶段,假如我们的bean有很多依赖的对象,那么spring会依次调用这些依赖的对象进行实例化,注意这里可能会有循环依赖的问题。后面我们会讲到spring是如何解决循环依赖的问题
2.1.2 初始化 Initialization。初始化的过程包括将初始化好的bean放入到spring的缓存中、填充我们预设的属性进一步做后置处理等
-
销毁
在Spring将所有的bean都初始化好之后,我们的业务系统就可以调用了。而销毁主要的操作是销毁bean,主要是伴随着spring容器的关闭,此时会将spring的bean移除容器之中。此后spring的生命周期到这一步彻底结束,不再接受spring的管理和约束。
接下来简单看一副图片。快速记忆下bean的生命周期
总结
本篇文章主要是介绍了一下spring的bean加载过程,没有详细展开某个细节分析。spring的内部源码非常复杂,每个接口的实现类都在5个以上,如果深入细节,恐怕不是一篇文章能讲清楚的。这篇文章的目的就是在阐述spring的基本脉络中心路线顺序,首先我们需要有一个总体的认识,然后再深入到细节就是轻而易举的了。这也是一种学习的方法论
后面我会对Spring专门出一个专栏,欢迎关注。我以后会持续输出干货文章
弦外之音
感谢你的阅读,如果你感觉学到了东西,麻烦您点赞,关注。也欢迎有问题我们下面评论交流
加油! 我们下期再见!
给大家分享几个我前面写的几篇骚操作