我的编程空间,编程开发者的网络收藏夹
学习永远不晚

如何在spring中加载bean

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

如何在spring中加载bean

这篇文章给大家介绍如何在spring中加载bean,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。

一:spring读取配置或注解的过程

先通过扫描指定包路径下的spring注解,比如@Component、@Service、@Lazy @Sope等spring识别的注解或者是xml配置的属性(通过读取流,解析成Document,Document)然后spring会解析这些属性,将这些属性封装到BeanDefintaion这个接口的实现类中.

如何在spring中加载bean

在springboot中,我们也可以采用注解配置的方式:

如何在spring中加载bean

如何在spring中加载bean

比如这个配置Bean,spring也会将className、scope、lazy等这些属性装配到PersonAction对应的BeanDefintaion中.具体采用的是BeanDefinitionParser接口中的parse(Element element, ParserContext parserContext)方法,该接口有很多不同的实现类。通过实现类去解析注解或者xml然后放到BeanDefination中,BeanDefintaion的作用是集成了我们的配置对象中的各种属性,重要的有这个bean的ClassName,还有是否是Singleton、对象的属性和值等(如果是单例的话,后面会将这个单例对象放入到spring的单例池中)。spring后期如果需要这些属性就会直接从它中获取。然后,再注册到一个ConcurrentHashMap中,在spring中具体的方法就是registerBeanDefinition(),这个Map存的key是对象的名字,比如Person这个对象,它的名字就是person,值是BeanDefination,它位于DefaultListableBeanFactory类下面的beanDefinitionMap类属性中,同时将所有的bean的名字放入到beanDefinitionNames这个list中,目的就是方便取beanName;

二:spring的bean的生命周期

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

实例化和初始化的区别:实例化是在jvm的堆中创建了这个对象实例,此时它只是一个空的对象,所有的属性为null。而初始化的过程就是讲对象依赖的一些属性进行赋值之后,调用某些方法来开启一些默认加载。比如spring中配置的数据库属性Bean,在初始化的时候就会将这些属性填充,比如driver、jdbcurl等,然后初始化连接

2.1:实例化 Instantiation

AbstractAutowireCapableBeanFactory.doCreateBean中会调用createBeanInstance()方法,该阶段主要是从beanDefinitionMap循环读取bean,获取它的属性,然后利用反射(core包下有ReflectionUtil会先强行将构造方法setAccessible(true))读取对象的构造方法(spring会自动判断是否是有参数还是无参数,以及构造方法中的参数是否可用),然后再去创建实例(newInstance)

2.2:初始化

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

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

2.2:初始化 Initialization

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

3: 使用和销毁 Destruction

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

三:spring的BeanPostProcessor处理器

spring的另一个强大之处就是允许开发者自定义扩展bean的初始化过程,最主要的实现思路就是通过BeanPostProcessor来实现的,spring有各种前置和后置处理器,这些处理器渗透在bean创建的前前后后,穿插在spring生命周期的各个阶段,每一步都会影响着spring的bean加载过程。接下来我们就来分析具体的过程:

如何在spring中加载bean

3.1:实例化阶段

该阶段会调用对象的空构造方法进行对象的实例化,在进行实例化之后,会调用InstantiationAwareBeanPostProcessor的postProcessBeforeInstantiation方法

BeanPostProcessor(具体实现是InstantiationAwareBeanPostProcessor). postProcessBeforeInstantiation();

这个阶段允许在Bena进行实例化之前,允许开发者自定义逻辑,如返回一个代理对象。不过需要注意的是假如在这个阶段返回了一个不为null的实例,spring就会中断后续的过程。
BeanPostProcessor.postProcessAfterInstantiation();

这个阶段是Bean实例化完毕后执行的后处理操作,所有在初始化逻辑、装配逻辑之前执行

3.2:初始化阶段

2.1:BeanPostProcessor.postProcessBeforeInitialization

该方法在bean初始化方法前被调用,Spring AOP的底层处理也是通过实现BeanPostProcessor来执行代理逻辑的

2.2:InitializingBean.afterPropertiesSet

自定义属性值该方法允许我们进行对对象中的属性进行设置,假如在某些业务中,一个对象的某些属性为null,但是不能显示为null,比如显示0或者其他的固定数值,我们就可以在这个方法实现中将null值转换为特定的值

2.3:BeanPostProcessor.postProcessAfterInitialization(Object bean, String beanName)。可以在这个方法中进行bean的实例化之后的处理,比如我们的自定义注解,对依赖对象的版本控制自动路由切换。比如有一个服务依赖了两种版本的实现,我们如何实现自动切换呢?这时候可以自定义一个路由注解,假如叫@RouteAnnotaion,然后实现BeanPostProcessor接口,在其中通过反射拿到自定义的注解@RouteAnnotaion再进行路由规则的设定。

如何在spring中加载bean

2.4:SmartInitializingSingleton.afterSingletonsInstantiated

4.1:容器启动运行阶段

1.1:SmartLifecycle.start

容器正式渲染完毕,开始启动阶段,bean已经在spring容器的管理下,程序可以随时调用

5.1:容器停止销毁

1.1:SmartLifecycle.stop(Runnable callback)

spring容器停止运行

1.2:DisposableBean.destroy()

spring会将所有的bean销毁,实现的bean实例被销毁的时候释放资源被调用

四:一些关键性的问题

4.1:FactoryBean和BeanFactory的区别?

如何在spring中加载bean

BeanFactory是个bean 工厂类接口,是负责生产和管理bean的工厂,是IOC容器最底层和基础的接口,spring用它来管理和装配普通bean的IOC容器,它有多种实现,比如AnnotationConfigApplicationContext、XmlWebApplicationContext等。

如何在spring中加载bean

FactoryBean是FactoryBean属于spring的一个bean,在IOC容器的基础上给Bean的实现加上了一个简单工厂模式和装饰模式,是一个可以生产对象和装饰对象的工厂bean,由spring管理,生产的对象是由getObject()方法决定的。注意:它是泛型的,只能固定生产某一类对象,而不像BeanFactory那样可以生产多种类型的Bean。在对于某些特殊的Bean的处理中,比如Bean本身就是一个工厂,那么在其进行单独的实例化操作逻辑中,可能我们并不想走spring的那一套逻辑,此时就可以实现FactoryBean接口自己控制逻辑。

4.2:spring如何解决循环依赖问题

循环依赖问题就是A->B->A,spring在创建A的时候,发现需要依赖B,因为去创建B实例,发现B又依赖于A,又去创建A,因为形成一个闭环,无法停止下来就可能会导致cpu计算飙升

如何解决这个问题呢?spring解决这个问题主要靠巧妙的三层缓存,所谓的缓存主要是指这三个map,singletonObjects主要存放的是单例对象,属于第一级缓存;singletonFactories属于单例工厂对象,属于第三级缓存;earlySingletonObjects属于第二级缓存,如何理解early这个标识呢?它表示只是经过了实例化尚未初始化的对象。Spring首先从singletonObjects(一级缓存)中尝试获取,如果获取不到并且对象在创建中,则尝试从earlySingletonObjects(二级缓存)中获取,如果还是获取不到并且允许从singletonFactories通过getObject获取,则通过singletonFactory.getObject()(三级缓存)获取。如果获取到了则移除对应的singletonFactory,将singletonObject放入到earlySingletonObjects,其实就是将三级缓存提升到二级缓存,这个就是缓存升级。spring在进行对象创建的时候,会依次从一级、二级、三级缓存中寻找对象,如果找到直接返回。由于是初次创建,只能从第三级缓存中找到(实例化阶段放入进去的),创建完实例,然后将缓存放到第一级缓存中。下次循环依赖的再直接从一级缓存中就可以拿到实例对象了。

如何在spring中加载bean

如何在spring中加载bean

五:测试

我们来写一个测试类,验证一下上面的问题:

5.1:首先声明一个自定义的Bean

@Componentpublic class CustomBean {    public CustomBean(){        System.out.println("调用CustomBean空的构造方法");    }}

5.2:声明一个Bean来实现BeanPostProcessor

package com.wyq.spring.bean;import org.springframework.beans.BeansException;import org.springframework.beans.PropertyValues;import org.springframework.beans.factory.DisposableBean;import org.springframework.beans.factory.SmartInitializingSingleton;import org.springframework.beans.factory.config.BeanPostProcessor;import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;import org.springframework.context.annotation.Scope;import org.springframework.stereotype.Component;import java.beans.PropertyDescriptor;@Component@Scope("singleton")public class TestBean implements BeanPostProcessor, SmartInitializingSingleton, InstantiationAwareBeanPostProcessor, DisposableBean{    private static final String BEAN_NAME= "customBean";    @Override    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {        if (BEAN_NAME.equals(beanName)) {            System.out.println("==>BeanPostProcessor.postProcessBeforeInitialization");        }        return null;    }    @Override    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {        if (BEAN_NAME.equals(beanName)) {            System.out.println("==>BeanPostProcessor.postProcessAfterInitialization");        }        return null;    }    @Override    public void afterSingletonsInstantiated() {        System.out.println("==>SmartInitializingSingleton.afterSingletonsInstantiated");    }    @Override    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {        if (BEAN_NAME.equals(beanName)) {            System.out.println("==>InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation");        }        return null;    }    @Override    public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {        if (BEAN_NAME.equals(beanName)) {            System.out.println("==>InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation");        }        return false;    }    @Override    public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {        System.out.println("==>InstantiationAwareBeanPostProcessor.postProcessPropertyValues");        return null;    }    @Override    public void destroy() throws Exception {        System.out.println("==>DisposableBean.destroy");    }}

5.3:启动容器:

如何在spring中加载bean

关于如何在spring中加载bean就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

如何在spring中加载bean

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

如何在spring中加载bean

这篇文章给大家介绍如何在spring中加载bean,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。一:spring读取配置或注解的过程1:先通过扫描指定包路径下的spring注解,比如@Component、@Servic
2023-06-15

在Spring中如何实现加载Bean的

本篇文章给大家分享的是有关在Spring中如何实现加载Bean的,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。之前写过bean的解析,这篇来讲讲bean的加载,加载要比bean
2023-05-31

使用Spring如何实现加载Bean

本篇文章给大家分享的是有关使用Spring如何实现加载Bean,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。1 定义bean的方式常见的定义Bean的方式有:通过xml的方式,
2023-05-31

Spring bean加载控制如何实现

这篇文章主要讲解了“Spring bean加载控制如何实现”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Spring bean加载控制如何实现”吧!1. Controller加载控制因为功能
2023-07-04

Spring Boot如何在加载bean时优先选择我

这篇文章主要介绍了Spring Boot如何在加载bean时优先选择我,在 Spring Boot 应用程序中,我们可以采取三种方式实现自己的 bean 优先加载,本文通过实例代码给大家详细讲解,需要的朋友可以参考下
2023-03-14

如何在Spring框架中装配Bean

这篇文章将为大家详细讲解有关如何在Spring框架中装配Bean,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。Bean的简介Java开发者一般会听过JavaBean这个概念,所谓的JavaB
2023-05-31

spring或spring boot怎么调整bean加载顺序

今天小编给大家分享一下spring或spring boot怎么调整bean加载顺序的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下
2023-07-05

Spring Bean的8种加载方式总结

以前学习Spring框架的时候,总结了几种Bean的加载方式,不过老师说还有其它的加载方式,以下八种并不是全部,但也足以用来做很多事情了,希望对大家有所帮助
2022-11-13

SpringBoot bean如何查询加载顺序

这篇“SpringBoot bean如何查询加载顺序”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“SpringBoot be
2023-07-05

spring重新加载bean的方法是什么

Spring重新加载bean的方法有以下几种:1. 使用Spring的热部署功能:在开发环境中,可以配置Spring Boot的devtools模块,该模块支持热部署,当代码发生变化时自动重新加载bean。2. 使用Spring的刷新作用域
2023-10-10

在Spring中如何使用BeanFactory进行解析bean

这篇文章将为大家详细讲解有关在Spring中如何使用BeanFactory进行解析bean,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。在该文中来讲讲Spring框架中BeanFactory
2023-05-31

如何在spring中回调bean的生命周期

如何在spring中回调bean的生命周期?针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。生命周期回调方法对于spring bean来讲,我们默认可以指定两个生命周期回调方法
2023-05-31

SpringBoot中如何实现自己的bean优先加载

这篇文章主要介绍“SpringBoot中如何实现自己的bean优先加载”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“SpringBoot中如何实现自己的bean优先加载”文章能帮助大家解决问题。一、
2023-07-06

详解Spring简单容器中的Bean基本加载过程

本篇将对定义在 XMl 文件中的 bean,从静态的的定义到变成可以使用的对象的过程,即 bean 的加载和获取的过程进行一个整体的了解,不去深究,点到为止,只求对 Spring IOC 的实现过程有一个整体的感知,具体实现细节留到后面用针
2023-05-31

spring或者springboot调整bean加载顺序的方式

这篇文章主要介绍了spring或者springboot调整bean加载顺序的方式,本文通过实例代码讲解三种调整类加载顺序的方式,代码简单易懂,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
2023-03-01

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录