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

目录

  • 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 {

}




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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

美国RAKSmart服务器性能科普

当我们谈论服务器性能时&#xff0c;无疑会涉及多个维度&#xff0c;包括存储能力、网络连接、稳定性、管理界面以及安全性等。在这篇科普文章中&#xff0c;我们将深入探讨美国RAKSmart服务器的性能特点。 首先&#xff0c;RAKSmart服务器在存储和扩展性方面表现出色。它们配备…

Git 工作原理

Git 工作原理 | CoderMast编程桅杆https://www.codermast.com/dev-tools/git/git-workspace-index-repo.html Workspace&#xff1a;工作区Index / Stage&#xff1a;暂存区Repository&#xff1a;仓库区&#xff08;或本地仓库&#xff09;Remote&#xff1a;远程仓库 Git 一…

绿联 安装transmission

绿联 安装transmission及中文UI 1、镜像 linuxserver/transmission:latest 2、安装 2.1、创建容器 按需配置权重。 2.2、基础设置 2.3、网络 桥接即可。 注&#xff1a;如果使用IPV6&#xff0c;请选择"host"模式。 注&#xff1a;如果使用IPV6&#xff0c;请选…

网络数据包嗅探器工具

组织的网络非常庞大&#xff0c;包含服务器、交换机、路由器和接入点等众多节点&#xff0c;由于许多资源和流量不断通过这些节点&#xff0c;因此很难确定大量流量是真实的还是安全攻击的迹象&#xff0c;了解和了解组织的网络流量至关重要&#xff0c;一个有用的资源是网络数…

JAVA学习笔记31(IO流)

1.IO流 1.文件流 ​ *文件在程序中是以流的形式来操作的 2.常用文件操作 1.创建文件对象 1.new File(String pathname) //根据路径构建一个File对象 main() {}public void create01() {String filePath "e:\\news1.txt";File filePath new File(filePath);tr…

c++ 线性搜索与二分搜索

线性搜索 假设该项目以随机顺序存在于数组中&#xff0c;并且我们必须找到一个项目。那么搜索目标项目的唯一方法就是从第一个位置开始&#xff0c;并将其与目标进行比较。如果项目相同&#xff0c;我们将返回当前项目的位置。否则&#xff0c;我们将转移到下一个位置。…

HTML 中创建 WebSocket服务与接收webSocket发送内容

效果图 服务端 html客户端接受的消息 接下来开始实现服务端 创建server.js const WebSocket require(ws);const wss new WebSocket.Server({ port: 8877 });wss.on(connection, function connection(ws) {console.log(WebSocket connection opened.);// 每隔 5 秒发送一次…

NIO之ByteBuffer

NIO中的ByteBuffer是缓冲区&#xff0c;其中有几个比较重要的属性capacity&#xff0c;position和limit。 capacity&#xff1a; 其中&#xff0c;capacity是缓冲区的容量大小&#xff0c;在分配内存空间后不会改变。 limit&#xff1a; limit是限制位置&#xff0c;在读写模…

【MongoDB】数据的自动过期,TTL索引

文章目录 1. 前言2.概念与使用2.1.使用方式2.2.数组中包含日期字段2.3.设置具体的过期时间点2.4.额外的过滤条件 3.总结 1. 前言 在近期的工作中&#xff0c;使用了MongoDB来保存了一些日志数据&#xff0c;但是这些日志数据具有一定的时效性&#xff0c;也就是按照业务的需要…

活动回顾丨雀跃山城•2024重庆爱鸟周主题公益活动落地大坪大融城

重庆&#xff0c;这座美丽的山城&#xff0c;不仅有着独特的山水风光&#xff0c;更是众多鸟类栖息繁衍的家园。重庆将四月第一周定为“重庆爱鸟周”&#xff0c;为提高青少年珍稀动物保护意识&#xff0c;4月20日&#xff0c;大坪大融城携手传益千里开展雀跃山城?2024重庆爱鸟…

cox版本的Boruta+SHAP分析(心力衰竭数据集)

Cox版本的BorutaSHAP分析&#xff08;心力衰竭数据集&#xff09; Boruta算法是变量筛选的有力工具&#xff0c;而SHAP分析是观察预测变量与结局变量间关系的不错的方法&#xff0c;在传统的分析方法的基础上提供了一个全新的视角。Boruta算法SHAP分析&#xff0c;正在逐渐成为…

Python代码格式化工具Black介绍

Black 是一个 Python 代码格式化工具&#xff0c;以其简洁和一致的格式化风格而闻名。它被设计为一个“零妥协”的代码格式化程序&#xff0c;意味着它会自动地将代码格式化为一种统一的风格&#xff0c;而不需要用户进行任何配置。Black 严格遵循 PEP 8 -- Python 的官方编码风…

笔试狂刷--Day2(模拟高精度算法)

大家好,我是LvZi,今天带来笔试狂刷--Day2(模拟高精度算法) 一.二进制求和 题目链接:二进制求和 分析: 代码实现: class Solution {public String addBinary(String a, String b) {int c1 a.length() - 1, c2 b.length() - 1, t 0;StringBuffer ret new StringBuffer()…

甘特图:如何制定一个有效的产品运营规划?

做好一个产品的运营规划是一个复杂且系统的过程&#xff0c;涉及多个方面和阶段。以下是一些关键步骤和考虑因素&#xff0c;帮助你制定一个有效的产品运营规划&#xff1a; 1、明确产品定位和目标用户&#xff1a; 确定产品的核心功能、特点和优势&#xff0c;明确产品在市…

Ubuntu 22最新dockers部署redis哨兵模式,并整合spring boot和配置redisson详细记录(含spring boot项目包)

dockers部署redis哨兵模式&#xff0c;并整合spring boot 环境说明相关学习博客一、在docker中安装redis1、下载dockers镜像包和redis配置文件&#xff08;主从一样&#xff09;2、编辑配置文件3、启动redis&#xff08;主从一样&#xff09;4、进入容器测试&#xff08;主从一…

快速上手Jemter分布式压测实战和代码详细解析

&#x1f680; 作者 &#xff1a;“二当家-小D” &#x1f680; 博主简介&#xff1a;⭐前荔枝FM架构师、阿里资深工程师||曾任职于阿里巴巴担任多个项目负责人&#xff0c;8年开发架构经验&#xff0c;精通java,擅长分布式高并发架构,自动化压力测试&#xff0c;微服务容器化k…

MySQL的事务相关的语句的使用

MySQL的事务相关的语句的使用 事务是数据库管理系统执行过程中的一个程序单位&#xff0c;由一个或多个数据库操作组成。MySQL作为一款流行的关系型数据库管理系统&#xff0c;支持事务处理&#xff0c;允许用户定义一系列的操作&#xff0c;这些操作要么完全执行&#xff0c;…

每日OJ题_其它背包问题③_力扣377. 组合总和 Ⅳ(似包非包)

目录 力扣377. 组合总和 Ⅳ&#xff08;似包非包&#xff09; 解析代码 力扣377. 组合总和 Ⅳ&#xff08;似包非包&#xff09; 377. 组合总和 Ⅳ 难度 中等 给你一个由 不同 整数组成的数组 nums &#xff0c;和一个目标整数 target 。请你从 nums 中找出并返回总和为 t…

随着深度学习的兴起,浅层机器学习没有用武之地了吗?

深度学习的兴起确实在许多领域取得了显著的成功&#xff0c;尤其是那些涉及大量数据和复杂模式的识别任务&#xff0c;如图像识别、语音识别和自然语言处理等。然而&#xff0c;这并不意味着浅层机器学习&#xff08;如支持向量机、决策树、朴素贝叶斯等&#xff09;已经失去了…

【Linux】:文本编辑与输出命令 轻松上手nano、echo和cat

&#x1f3a5; 屿小夏 &#xff1a; 个人主页 &#x1f525;个人专栏 &#xff1a; Linux深造日志 &#x1f304; 莫道桑榆晚&#xff0c;为霞尚满天&#xff01; 文章目录 &#x1f4d1;前言一、nano1.1 打开文件&#xff1a;1.2 常用快捷键&#xff1a;1.3 其他功能&#xff…