全知全能SpringBoot Bean的生命周期

Posted 香菜+

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了全知全能SpringBoot Bean的生命周期相关的知识,希望对你有一定的参考价值。

系列文章:https://gamwatcher.blog.csdn.net/article/details/124603278

这篇文章也是计划了蛮久的了,一直没写,正所谓大道行思,取则行远,总结也是学习的一种方式。

🙈记得看目录哦

1、关于spring

1.1 什么是spring

Spring 是一个容器, 包含并且管理应用对象的生命周期。spring主要包括三大部分

Beans 模块:提供了 BeanFactory,是工厂模式的经典实现,Spring 将管理对象称为 Bean。

Core 核心模块:提供了 Spring 框架的基本组成部分,主要是 IoC 和 DI 功能。

Context 上下文模块:建立在核心和 Beans 模块的基础之上,它是访问定义和配置任何对象的媒介。ApplicationContext 接口是上下文模块的焦点。

1.2 spring和springboot

springboot 看名字也能看出来,spring的启动器,我们看下springboot到底解决了哪些问题

  • 自动配置,还记得在使用spring的时候被xml支配的恐惧吗? 一个又一个的xml不会配置,springboot将一些配置进行缺省,自动配置

  • 部署简单,内嵌式 web 服务器(Tomcat\\jetty)等

  • 第三方集成方便,很多插件都提供了starter,直接使用,缺省配置

2、什么是bean

In Spring, the objects that form the backbone of your application and that are managed by the Spring
IoC container are called beans. A bean is an object that is instantiated, assembled, and managed by a Spring IoC container.

Spring bean是Spring框架在运行时管理的对象,Bean是一个由Spring IoC容器实例化、组装和管理的对象。

3、bean的生命周期

spring的框架发展了好多年,代码实在太复杂了,我们自己做个IOC容器,或者说实现一个spring

3.1 实现步骤

  1. 创建一个factory,用来管理bean,这里假设用map 做缓存

  1. 容器管理bean,在容器启动的时候创建bean的定义,等待复制

  1. 创建单例的bean,

  1. 反射注入,根据构造函数进行注入对应的bean

3.2 实现过程中的问题

  1. bean的定义来源问题,可能来自xml,也可能来自注解

这个就是常规来说的ClassPathXmlApplicationContext(对应xml),FileSystemXmlApplicationContext,AnnotationConfigApplicationContext

  1. 怎么定义BeanDefinition

BeanDefinition中的常用属性

beanClass:表示Bean类型,未加载类的时候存放Bean的名字,加载类后存放Bean的class信息。

scope:表示Bean的作用域,一般值为单例或者原型。

lazyInit:表示Bean是否是懒加载。

initMethodName:Bean初始化需要执行的方法。

destroyMethodName:Bean销毁时要执行的方法。

factoryBeanName:创建当前Bean的工厂。

  1. 怎么读取BeanDefinition

AnnotatedBeanDefinitionReader:解析类上的注解,包含某些注解的时候(如:@Bean、@Component)会成为Bean。

XmlBeanDefinitionReader:可以解析xml文件中的标签。

ClassPathBeanDefinitionScanner:扫描包路径的读取器。

  1. 怎么创建bean

常规的对象创建是直接调用构造函数,然后调用对象的set函数设置属性,这一步要实现自动化

4、正儿八经聊聊spring

4.1、常见图

4.2 个人理解

上面的图画的挺好的很多细节,说实在话开始的时候我只是觉得烦,因为找不到纲领

❤️从三点进行分解

1、bean的实例化和销毁

2、容器的操作,前置,后置处理

3、依赖的解决

4.3 bean 的实例化

bean的实例化无外乎从beanDefinition中进行创建,这部分的源码可以参考AbstractAutowireCapableBeanFactory

4.4 bean的前后置处理

都知道可以在bean引用环境变量@Value,这个值在实例化的时候是怎么设置进去的? 这就是bean的后置处理

ConfigurationClassPostProcessor是spring内置的bean工厂处理器,在进行refresh的时候会被调用,实现对配置类的解析也即对我们注解的

bean进行扫描处理为bd放到缓存beanDefinitionMap中,用于后续进行实例化。

4.5 依赖的解决

正常的依赖解决直接通过赋值就可以,但是Spring的重点是循环依赖,也就是A 引用B,B引用A

循环依赖的问题 在spring中解决主要是通过三级缓存进行解决,这三个缓存其实本质上是三个Map集合。

单例对象的缓存:key存储bean名称,value存储Bean对象【一级缓存】,日常获取bean的位置

早期单例对象的缓存:key存储bean名称,value存储早期的Bean对象【二级缓存】,还没进行属性注入,由三级缓存放入

单例工厂缓存:key存储bean名称,value存储该Bean对应的ObjectFactory对象【三级缓存】

Spring的bean在实例化的过程中不需要全部初始化完成,则直接将对象放入缓存

举个例子:

A,B相互依赖,在实例化A的过程中,发现有依赖B,缓存中不存在,则直接将A放入缓存,

继续实例化B,发现依赖A,则从缓存中取出A,给B赋值,初始化完成后放入缓存,解决了循环依赖的问题

5、Spring中bean 相关的

5.1 bean 相关的类注解

@Component :通用的注解,可标注任意类为 Spring 组件。如果一个 Bean 不知道属于哪个层,可以使用@Component 注解标注。

@Repository : 对应持久层即 Dao 层,主要用于数据库相关操作。

@Service : 对应服务层,主要涉及一些复杂的逻辑,需要用到 Dao 层。

@Controller : 对应 Spring MVC 控制层,主要用户接受用户请求并调用 Service 层返回数据给前端页面。

@Configuration:主要用于配置,配合@Bean使用

5.2 @Component 和 @Bean 的区别

@Bean注解作用于方法。将方法返回的对象加入到容器中,一般在配置类中使用

5.3 bean的注入

Spring 内置的 @Autowired 以及 JDK 内置的 @Resource 和 @Inject 都可以用于注入 Bean。

@Autowired 默认的注入方式为byType(根据类型进行匹配),可以通过 @Qualifier 注解来显示指定名称

@Resource默认注入方式为 byName(根据名称进行匹配),可以通过 name 属性来显示指定名称

@Inject和@Name一起使用

当一个接口存在多个实现类的情况下,@Autowired 和@Resource都需要通过名称才能正确匹配到对应的 Bean。

@Import注解注入bean,一般在写starter情况下,拉入相关的配置

@Import(XXConfig.class)
public class SpringConfig4 

5.4 bean的注入方式

  • 属性注入,通过setXXX( )方法注入bean的属性值或依赖对象

public class UserServiceImpl implents UserService
     private UserDao userDao;
     
     @Autowire
     public serUserDao(UserDao userDao)
         this.userDao = userDao;
     
 
  • 构造函数注入

public class UserServiceImpl implents UserService
    private UserDao userDao;
    
    
    public UserServiceImpl(@Autowire UserDao userDao)
        this.userDao = userDao;
    

5.5 bean 作用域

Spring为你的bean提供了几个作用域,@Scope("prototype")

框架的核心有两个:

单例 - 单个实例,bean的默认作用域是单例

原型 - 多个实例,prototype

Spring专门用于Web应用程序的bean作用域:

请求 @RequestScope

会话 @SessionScope

全局会话

应用级别 @ApplicationScope

5.6 bean的回调方法

实现InitializingBean和DisposableBean接口

通过实现InitializingBean接口的afterPropertiesSet()方法可以在Bean属性值设置好之后做一些操作,

实现DisposableBean接口的destroy()方法可以在销毁Bean之前做一些操作。

5.7 注入容器内置对象

有时候我们需要在 Bean 的初始化中使用 Spring 框架自身的一些对象来执行一些操作,为了让 Bean 可以获取到框架自身的一些对象,Spring 提供了一组名为*Aware的接口。

这些接口均继承于org.springframework.beans.factory.Aware标记接口,并提供一个将由 Bean 实现的set*方法,Spring通过基于setter的依赖注入方式使相应的对象可以被Bean使用。

  • ApplicationContextAware: 获得ApplicationContext对象,可以用来获取所有Bean definition的名字。

  • BeanFactoryAware:获得BeanFactory对象,可以用来检测Bean的作用域。

  • BeanNameAware:获得Bean在配置文件中定义的名字。

  • ResourceLoaderAware:获得ResourceLoader对象,可以获得classpath中某个文件。

  • ServletContextAware:在一个MVC应用中可以获取ServletContext对象,可以读取context中的参数。

  • ServletConfigAware: 在一个MVC应用中可以获取ServletConfig对象,可以读取config中的参数。

5.8 bean注入map和list

在service中分别注入IEntity 的map 和列表

//    map注入
private final Map<String, IEntity> entityMap;
//    list注入
private final List<IEntity> entityList

注意:Map的Key是实现类的名称,Value为具体的类(Value的泛型为接口名称)

entityList中就是所有实现了IEntity 的bean对象

5.9 一些周边注解

@Primary,在存在多个实现的情况下,使用@Primary可以设置缺省的注入对象

@Order 在注入List的时候可以设置顺序

@ComponentScan默认是扫描的路径是同级路径及同级路径的子目录

5.10 导入beanDefinition

@Component
public class UnionPostProcessor implements BeanDefinitionRegistryPostProcessor 
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException 
    //创建BeanDefinition对象
        BeanDefinition beanDefinition =
                BeanDefinitionBuilder.rootBeanDefinition(UnionServiceImpl.class).getBeanDefinition();
        //设置是否单例
        beanDefinition.setScope("singleton");
        beanDefinitionRegistry.registerBeanDefinition("unionService", beanDefinition);
    
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException 
    

在服务启动之后,spring会自动创建bean对象,可以直接使用

6、总结

差不多该讲的都讲了,下面这幅图应该看的懂了,如果有漏的地方可以留言

赠人玫瑰,手留余香,求关注,点赞,收藏

最后推荐1本书

分布式中间件核心原理与RocketMQ实战技术一本通:实战案例+操作步骤+执行效果图,手把手教你吃透分布式中间件技术,轻松实现从小白到大牛的职业跃迁!

以上是关于全知全能SpringBoot Bean的生命周期的主要内容,如果未能解决你的问题,请参考以下文章

Spring Boot 2.1 和 Java 11 中的 Bean 生命周期

第298天学习打卡(知识点回顾 springboot核心注解 spring bean的生命周期)

第298天学习打卡(知识点回顾 springboot核心注解 spring bean的生命周期)

第298天学习打卡(知识点回顾 springboot核心注解 spring bean的生命周期)

spring bean生命周期

Springboot生命周期