SpringBoot中Bean的创建过程及扩展操作点 @by_TWJ

news2025/1/13 10:03:40

目录

  • 1. 类含义
  • 2. Bean创建过程 - 流程图
  • 3. 例子
    • 3.1. 可变属性注入到实体中
    • 3.2. 模拟Bean创建的例子

1. 类含义

  • BeanDefinition - 类定义,为Bean创建提供一些定义类的信息。实现类如下:
    • RootBeanDefinition - 类定义信息,包含有父子关系的BeanDefinition。是常用的实例化BeanDefinition。
  • BeanWrapper - 封装Bean,包含有实例化的Bean、Bean类、属性描述集合。一般用来做属性注入。实现类如下:
    • BeanWrapperImpl
  • AbstractApplicationContext - 应用上下文,实现类如下:
    • AnnotationConfigWebApplicationContext - 使用注解的方式配置Web应用上下文(常用)
    • AnnotationConfigReactiveWebApplicationContext - 使用注解的方式配置ReactiveWeb应用上下文
    • FileSystemXmlApplicationContext - 通过本地系统查找XML配置文件来启动的 应用上下文。(略)
    • ClassPathXmlApplicationContext- 通过编译路径查找XML配置文件来启动的 应用上下文。(略)
    • XmlWebApplicationContext- 通过XML配置文件来启动的 Web应用上下文。(略)
    • GenericXmlApplicationContext- 通过XML配置文件配置 应用上下文。(略)
    • StaticWebApplicationContext- 静态web服务的应用上下文。(略)
  • BeanFactory - Bean工厂,负责提供Bean
  • BeanDefinitionRegistry - BeanDefinition的注册表,用来放置BeanDefinition。
  • BeanUtils - 里面有很多Bean操作,例如:使用无参构造函数创建Bean:BeanUtils.instantiateClass(beanClass)
  • ConstructorResolver - 构造函数解析器,用来注入有参的构造函数。有参是一个Bean类,就会从BeanFactory获取该Bean。
  • MutablePropertyValues - 可变的属性值,用来装载属性名称还有属性值。有点类似Map,但它比Map包含有更多的属性定义信息。一般使用beanWrapper.setPropertyValues(mutablePropertyValues),直接把可变的属性值,注入到Bean中。
  • *PostProcessor - 后置处理程序,用于操作的前后事件等。

2. Bean创建过程 - 流程图

忽略了很多中间的判定操作。
这里只记录扩展点,方便以后做扩展。

在这里插入图片描述

3. 例子

3.1. 可变属性注入到实体中

package org.springframework.beans.factory.support;

import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.beans.MutablePropertyValues;

public class MutablePropertyValuesTest {
    // 可变属性注入到实体中。
    public static void main(String[] args) {
        MutablePropertyValues mutablePropertyValues  = new MutablePropertyValues();
        mutablePropertyValues.addPropertyValue("name", "tavion");
        mutablePropertyValues.addPropertyValue("age", 1);
        BeanWrapper beanWrapper = new BeanWrapperImpl(PropertyBean.class);
        beanWrapper.setPropertyValues(mutablePropertyValues);
        System.out.println(beanWrapper.getPropertyValue("name"));//输出:tavion
        System.out.println(((PropertyBean)beanWrapper.getWrappedInstance()).getName());//输出:tavion
        System.out.println(beanWrapper.getPropertyValue("age"));//输出:1
        System.out.println(((PropertyBean)beanWrapper.getWrappedInstance()).getAge());//输出:1
    }
}
class PropertyBean{
    private String name;
    private int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

3.2. 模拟Bean创建的例子



import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.SmartInstantiationAwareBeanPostProcessor;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.util.ClassUtils;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

@Slf4j
public class BeanCreateTest {
    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {

        // 0. 参数初始化
        Object bean = null;//实例化后的Bean

        Class<?> beanClass = BeanTest1.class;//要实例化的Bean类
        String beanName = ClassUtils.getShortName(beanClass);//要实例化的Bean名称


        // 1. 创建Context 上下文和BeanFactory
        AbstractApplicationContext context = new GenericApplicationContext();
        DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) context.getBeanFactory();

        // 2. 配置TestUser和TestOrg的BeanDefinition
        RootBeanDefinition mbd = new RootBeanDefinition(beanClass);
        beanFactory.registerBeanDefinition(BeanTest2.class.getName(),new RootBeanDefinition(BeanTest2.class));
        beanFactory.registerBeanDefinition(beanName,mbd);

        // 3. 注册 BeanPostProcessor
        registerAutowiredAnnotationBeanPostProcessor(context);

        // 4. 检索构造方法,通过有参构造方法创建Bean
        // tip:这里我只是把beanFactory.getBean()里面的操作,简写重复写一遍。
        for (SmartInstantiationAwareBeanPostProcessor beanPostProcessor : beanFactory.getBeanPostProcessorCache().smartInstantiationAware) {
//            AutowiredAnnotationBeanPostProcessor beanPostProcessor = new AutowiredAnnotationBeanPostProcessor();
            Constructor<?>[] ctors = beanPostProcessor.determineCandidateConstructors(beanClass, beanName);
            if (ctors != null) {
                log.info("1. 通过构造方法的方式创建Bean:"+beanName);
                // 得到构造参数,注入属性,若是Bean类,则会通过beanFactory.getBean() 方式得到传参值。getBean如果没有,则创建新的Bean
                BeanWrapper beanWrapper = new ConstructorResolver(beanFactory)
                        .autowireConstructor(beanName, mbd, ctors, null);
                bean = beanWrapper.getWrappedInstance();
                if(bean!=null){
                    break;
                }

            }
        }
        // 5. 通过无参构造方法创建Bean
        if(bean==null){
            log.info("2. 通过无构造方法的方式创建Bean");
            bean = BeanUtils.instantiateClass(beanClass);
        }

        // 6. 打印实例化后的Bean
        System.out.println(bean);
    }

    private static void registerAutowiredAnnotationBeanPostProcessor(AbstractApplicationContext context) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory)context.getBeanFactory();
        // 1. 加入 AutowiredAnnotationBeanPostProcessor 后置处理器
        beanFactory.registerBeanDefinition(AutowiredAnnotationBeanPostProcessor.class.getName(),
                new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class));

        // 2. AutowiredAnnotationBeanPostProcessor 加入到缓存中,待后续执行
//        2.1. context.invokeBeanFactoryPostProcessors(beanFactory);// 因为是protected修饰的方法,所以我们在这里需要用反射方式调用
        Method method = AbstractApplicationContext.class.getDeclaredMethod("invokeBeanFactoryPostProcessors", ConfigurableListableBeanFactory.class);
        method.setAccessible(true);
        method.invoke(context, beanFactory);
//        2.2。 context.registerBeanPostProcessors(beanFactory);// 因为是protected修饰的方法,所以我们在这里需要用反射方式调用
        Method method2 = AbstractApplicationContext.class.getDeclaredMethod("registerBeanPostProcessors", ConfigurableListableBeanFactory.class);
        method2.setAccessible(true);
        method2.invoke(context, beanFactory);
    }

}
class BeanTest1 {


    private BeanTest2 beanTest2;

    public BeanTest1(BeanTest2 beanTest2) {
        this.beanTest2 = beanTest2;
    }

}
class BeanTest2 {

}




本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1623578.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

智慧健康旅居养老产业,做智慧旅居养老服务的公司

随着社会的进步和科技的飞速发展&#xff0c;传统的养老模式已经无法满足 现代老年人的多元化 需求。智慧健康旅居养老产业应运而生&#xff0c;成为了一种新型的养老模式&#xff0c;旨在为老年人提供更加舒适、便捷、安全的养老生活。随着社会的进步和人口老龄化趋势的加剧&a…

五一劳动节活动策划案怎么写?

分享一个五一劳动节活动策划万能模板&#xff0c;直接照着写就好。 一、活动主题&#xff1a; 五一户外露营Party 二、活动时间&#xff1a; 五一节当天&#xff0c;上午点至下午点 三、活动地点&#xff1a; 城市郊外的公园或大型绿地 四、参与人员&#xff1a; 公司员…

自动化测试超详细总结

简介 软件测试是软件开发过程中一个必不可少的环节。传统的软件测试方式通常是手动测试&#xff0c;即由专业的测试人员通过手动操作软件应用程序来验证其功能和性能。然而&#xff0c;这种方式存在许多缺点&#xff0c;例如时间耗费、测试结果不稳定、测试覆盖率不够高等。 为…

Pandas 2.2 中文官方教程和指南(二十·二)

通过组进行迭代 有了 GroupBy 对象&#xff0c;通过分组数据进行迭代非常自然&#xff0c;类似于itertools.groupby()的操作&#xff1a; In [74]: grouped df.groupby(A)In [75]: for name, group in grouped:....: print(name)....: print(group)....: barA B…

AI智能写作工具,一键智能改写文章简单又高效

随着人们生活节奏的加快和工作压力的增大&#xff0c;如何在繁忙的日程中高效地写作成为了许多人的难题。但是随着人工智能技术的不断发展和应用&#xff0c;AI智能写作工具的出现&#xff0c;成为了许多人解决写作难题的利器。今天小编就来跟大家分享下AI智能写作工具&#xf…

go语言并发实战——日志收集系统(八) go语言操作etcd以及利用watch实现对键值的监控

有关包的安装 我们要实现go语言对第三方包的操作需要我们下载第三方包go.etcd.io&#xff0c;下载命令&#xff1a; go get go.etcd.io/etcd/client/v3 ectd的put与get操作 相关函数说明与示例 我们想实现对etcd进行简单的操作的步骤还是比较简单的&#xff0c;在我上一篇文…

Gateway基础知识

文章目录 Spring Cloud GateWay 用法核心概念请求流程两种配置方式设置日志&#xff08;建议设置&#xff09;路由的各种断言断言The After Route Predicate FactoryThe Before Route Predicate FactoryThe Between Route Predicate FactoryThe Cookie Route Predicate Factory…

海外盲盒APP开发:探索海外盲盒市场的商机

随着娱乐消费的流行&#xff0c;盲盒在我国可以说是非常火热&#xff0c;消费群体和市场规模逐年增加。在盲盒热潮下&#xff0c;不少潮玩企业也纷纷加入到了盲盒赛道中&#xff0c;市场竞争非常激烈&#xff01; 此外&#xff0c;我国盲盒出海也成为了一个大趋势。盲盒不仅在…

uni-app canvas 签名

调用方法 import Signature from "/components/signature.vue" const base64Img ref() //监听getSignImg uni.$on(getSignImg, ({ base64, path }) > {base64Img.value base64//console.log(签名base64, path >, base64, path) //拿到的图片数据// 之后取消…

Java程序员必须掌握的数据结构:HashMap

HashMap底层原理实现是每个Java Boy必须掌握的基本技能&#xff0c;HashMap也是业务开发每天都需要遇到的好伙伴。如此基础且核心的底层数据结构&#xff0c;JDK也给其赋予了线程安全的功能类&#xff0c;我们来看看~ &#x1f331;以【面试官面试】形式覆盖Java程序员所需掌握…

使用Kimi快速完成高质量学术论文全流程攻略!

点击下方▼▼▼▼链接直达AIPaperPass &#xff01; AIPaperPass - AI论文写作指导平台 目录 01.论文选题(重要指数:★★★★★) 02.摘要(重要指数:★★★★) 03.关键词(重要指数:★★★★) 04.引言(重要指数:★★★★) 05.正文(重要指数:★★★★★) 06.结论(重要指数…

能源监控可视化大屏的价值,不要说没啥用了,容易暴露格局

能源监控可视化大屏具有以下几个方面的价值&#xff1a; 实时监控&#xff1a; 能源监控可视化大屏可以实时展示能源系统的运行状态&#xff0c;包括电力、水、气等能源的消耗、供应情况&#xff0c;以及设备运行状态等。通过实时监控&#xff0c;可以及时发现异常情况和故障…

翻译《The Old New Thing》 - What does SHGFI_USEFILEATTRIBUTES mean?

What does SHGFI_USEFILEATTRIBUTES mean? - The Old New Thing (microsoft.com)https://devblogs.microsoft.com/oldnewthing/20040601-00/?p39073 Raymond Chen 2004年06月01日 在使用 SHGetFileInfo 函数时&#xff0c;你可以设置一个名为 SHGFI_USEFILEATTRIBUTES 的标志…

目标检测——3D玩具数据集

在数字化时代&#xff0c;计算机视觉技术取得了长足的进展&#xff0c;其中基于形状的3D物体识别技术更是引起了广泛关注。该技术不仅有助于提升计算机对现实世界物体的感知能力&#xff0c;还在多个领域展现出了广阔的应用前景。本文将探讨基于形状的3D物体识别实验的重要性意…

WMS之添加View

目录 前言一、addview示例二、addview流程2.1 流程图2.2 流程分析2.2.1 Actitity的启动流程创建PhoneWindow和DecorView2.2.2.WindowManagerImpl 添加view2.2.3 ViewRootImpl.setView 三、总结 前言 WMS 功能繁杂&#xff0c;通过添加View流程进一步分析WMS 通过本文了解掌握…

RPC分布式通信框架

在实际开发中单机服务器存在诸多问题&#xff1a; 1.受限于硬件资源无法提高并发量 2.任意模块的修改都将导致整个项目代码重新编译部署 3.在系统中&#xff0c;有些模块属于CPU密集型&#xff0c;有些属于I/O密集型&#xff0c;各模块对于硬件资源的需求不一样 什么是分布式&a…

程序员转技术管理要做哪些努力?

对许多开发者而言&#xff0c;深耕技术&#xff0c;然后成为技术专家或许是职业发展的唯一答案。但如果你赞同「软件开发只是我众多职业目标中的一个」&#xff0c;也许你可以试试「技术管理之路」。 我原来觉得和计算机打交道比跟人打交道轻松得多&#xff0c;所以我成了一名…

每日OJ题_DFS回溯剪枝①_力扣46. 全排列(回溯算法简介)

目录 回溯算法简介 力扣46. 全排列 解析代码 回溯算法简介 回溯算法是一种经典的递归算法&#xff0c;通常⽤于解决组合问题、排列问题和搜索问题等。 回溯算法的基本思想&#xff1a;从一个初始状态开始&#xff0c;按照⼀定的规则向前搜索&#xff0c;当搜索到某个状态无…

【UnityShader入门精要学习笔记】第十一章 Shader动画

本系列为作者学习UnityShader入门精要而作的笔记&#xff0c;内容将包括&#xff1a; 书本中句子照抄 个人批注项目源码一堆新手会犯的错误潜在的太监断更&#xff0c;有始无终 我的GitHub仓库 总之适用于同样开始学习Shader的同学们进行有取舍的参考。 文章目录 UnityShad…

Vuforia AR篇(三)— AR模型出场效果

目录 前言一、AR模型出场二、AR出场特效三、添加过渡效果四、效果 前言 例如&#xff1a;随着人工智能的不断发展&#xff0c;机器学习这门技术也越来越重要&#xff0c;很多人都开启了学习机器学习&#xff0c;本文就介绍了机器学习的基础内容。 一、AR模型出场 创建ARCamer…