Sping源码(九)—— Bean的初始化(非懒加载)— Bean的创建方式(Supplier)

2024-06-16 21:12

本文主要是介绍Sping源码(九)—— Bean的初始化(非懒加载)— Bean的创建方式(Supplier),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

序言

目前介绍几种Spring创建对象的方式,其中包括 FactoryBean、Cglib动态代理、自定义BeanPostProcessor(InstantiationAwareBeanPostProcessor)。
这篇文章会继续扩展Spring中Bean的创建方式——Supplier。

Supplier

先看下我们的Supplier类,在前面的ObjectFactory中有提到过,类上有@FunctionalInterface注解相当于函数式编程,而当我们调用get()方法时,才会调用我们自定义实现的方法。

@FunctionalInterface
public interface Supplier<T> {/*** Gets a result.** @return a result*/T get();
}

测试类

SupplierBeanFactoryPostProcessor
自定义类实现了BFPP,并在方法中设置InstanceSupplier变量。

public class SupplierBeanFactoryPostProcessor implements BeanFactoryPostProcessor {@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {GenericBeanDefinition gbd = (GenericBeanDefinition)beanFactory.getBeanDefinition("user");gbd.setInstanceSupplier(CreateSupplier::createUser);gbd.setBeanClass(User.class);}
}
// 或者
public class SupplierBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {}@Overridepublic void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {registry.registerBeanDefinition("user", new RootBeanDefinition(User.class,CreateSupplier::createUser));}
}

CreateSupplier
返回User对象。

public class CreateSupplier {public static User createUser(){return new User("zhangsan");}
}

User
简单的一个User类。

public class User {private String name;public User() {}public User(String name) {this.name = name;}public String getName() {return name;}public void setName(String name) {this.name = name;}@Overridepublic String toString() {return "User{" +"name='" + name + '\'' +'}';}
}

supplier.xml
xml文件中定义了SupplierBeanFactoryPostProcessor和准备创建的User类。

<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="supplierBeanFactoryPostProcessor" class="org.springframework.supplier.SupplierBeanFactoryPostProcessor"/><bean id="user" class="org.springframework.supplier.User"/><bean id="supplierBeanDefinitionRegistryPostProcessor" class="org.springframework.supplier.SupplierBeanDefinitionRegistryPostProcessor" /></beans>

main
当代码运行,refresh()主流程方法中调用invokeBeanFactoryPostProcessors()方法时,就会执行我们自定义的类中方法,从而设置instanceSupplier变量,当调用getBean方法生成User对象时,instanceSupplier不为null,调用createBean方法,生成User对象。

public static void main(String[] args) {ApplicationContext ac = new ClassPathXmlApplicationContext("supplier.xml");User user = ac.getBean(User.class);System.out.println(user.toString());}

doCreateBean

回到我们的源码doCreateBean方法中,我们重点关注createBeanInstance()方法。

protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)throws BeanCreationException {// Instantiate the bean.//这个beanWrapper是用来持有创建出来的bean对象的BeanWrapper instanceWrapper = null;//如果是单例对象,从factoryBeanInstanceCache缓存中移除该信息if (mbd.isSingleton()) {// 如果是单例对象,从factoryBean实例缓存中移除当前bean定义信息instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);}// 没有就创建实例if (instanceWrapper == null) {// 根据执行bean使用对应的策略创建新的实例,如,工厂方法,构造函数主动注入、简单初始化instanceWrapper = createBeanInstance(beanName, mbd, args);}// 去除无用代码..... }

createBeanInstance
createBeanInstance方法中,会获取我们自定义的getInstanceSupplier,如果不为 null, 则调用obtainFromSupplier

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {// Make sure bean class is actually resolved at this point.// 锁定class,根据设置的class属性或者根据className来解析classClass<?> beanClass = resolveBeanClass(mbd, beanName);// 如果beanClass != null// 并且,访问修饰符不是public修饰, 抛异常if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {throw new BeanCreationException(mbd.getResourceDescription(), beanName,"Bean class isn't public, and non-public access not allowed: " + beanClass.getName());}// 获取定义的SupplierSupplier<?> instanceSupplier = mbd.getInstanceSupplier();if (instanceSupplier != null) {return obtainFromSupplier(instanceSupplier, beanName);}if (mbd.getFactoryMethodName() != null) {return instantiateUsingFactoryMethod(beanName, mbd, args);}return instantiateBean(beanName, mbd);}

此时创建我们的User对象时,可以进到判断中。
在这里插入图片描述
obtainFromSupplier
此时instanceSupplier.get()方法就会执行我们定义的createUser,从而进行User对象的创建。

protected BeanWrapper obtainFromSupplier(Supplier<?> instanceSupplier, String beanName) {Object instance;// 在缓存中获取原先创建的beanString outerBean = this.currentlyCreatedBean.get();// 用当前BeanName做替换this.currentlyCreatedBean.set(beanName);try {// 调用supplier.get()方法进行实例化instance = instanceSupplier.get();}finally {//if (outerBean != null) {this.currentlyCreatedBean.set(outerBean);}else {this.currentlyCreatedBean.remove();}}// 如果instance == null,则返回NullBeanif (instance == null) {instance = new NullBean();}// 将创建好的示例封装到wrapper包装类BeanWrapper bw = new BeanWrapperImpl(instance);initBeanWrapper(bw);return bw;}

Supplier对象是我们自定义的Supplier。
在这里插入图片描述

这篇关于Sping源码(九)—— Bean的初始化(非懒加载)— Bean的创建方式(Supplier)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1067557

相关文章

SpringBoot中@Value注入静态变量方式

《SpringBoot中@Value注入静态变量方式》SpringBoot中静态变量无法直接用@Value注入,需通过setter方法,@Value(${})从属性文件获取值,@Value(#{})用... 目录项目场景解决方案注解说明1、@Value("${}")使用示例2、@Value("#{}"php

SpringBoot分段处理List集合多线程批量插入数据方式

《SpringBoot分段处理List集合多线程批量插入数据方式》文章介绍如何处理大数据量List批量插入数据库的优化方案:通过拆分List并分配独立线程处理,结合Spring线程池与异步方法提升效率... 目录项目场景解决方案1.实体类2.Mapper3.spring容器注入线程池bejsan对象4.创建

HTTP 与 SpringBoot 参数提交与接收协议方式

《HTTP与SpringBoot参数提交与接收协议方式》HTTP参数提交方式包括URL查询、表单、JSON/XML、路径变量、头部、Cookie、GraphQL、WebSocket和SSE,依据... 目录HTTP 协议支持多种参数提交方式,主要取决于请求方法(Method)和内容类型(Content-Ty

GSON框架下将百度天气JSON数据转JavaBean

《GSON框架下将百度天气JSON数据转JavaBean》这篇文章主要为大家详细介绍了如何在GSON框架下实现将百度天气JSON数据转JavaBean,文中的示例代码讲解详细,感兴趣的小伙伴可以了解下... 目录前言一、百度天气jsON1、请求参数2、返回参数3、属性映射二、GSON属性映射实战1、类对象映

使用shardingsphere实现mysql数据库分片方式

《使用shardingsphere实现mysql数据库分片方式》本文介绍如何使用ShardingSphere-JDBC在SpringBoot中实现MySQL水平分库,涵盖分片策略、路由算法及零侵入配置... 目录一、ShardingSphere 简介1.1 对比1.2 核心概念1.3 Sharding-Sp

Spring创建Bean的八种主要方式详解

《Spring创建Bean的八种主要方式详解》Spring(尤其是SpringBoot)提供了多种方式来让容器创建和管理Bean,@Component、@Configuration+@Bean、@En... 目录引言一、Spring 创建 Bean 的 8 种主要方式1. @Component 及其衍生注解

python中的显式声明类型参数使用方式

《python中的显式声明类型参数使用方式》文章探讨了Python3.10+版本中类型注解的使用,指出FastAPI官方示例强调显式声明参数类型,通过|操作符替代Union/Optional,可提升代... 目录背景python函数显式声明的类型汇总基本类型集合类型Optional and Union(py

Linux系统管理与进程任务管理方式

《Linux系统管理与进程任务管理方式》本文系统讲解Linux管理核心技能,涵盖引导流程、服务控制(Systemd与GRUB2)、进程管理(前台/后台运行、工具使用)、计划任务(at/cron)及常用... 目录引言一、linux系统引导过程与服务控制1.1 系统引导的五个关键阶段1.2 GRUB2的进化优

IDEA与MyEclipse代码量统计方式

《IDEA与MyEclipse代码量统计方式》文章介绍在项目中不安装第三方工具统计代码行数的方法,分别说明MyEclipse通过正则搜索(排除空行和注释)及IDEA使用Statistic插件或调整搜索... 目录项目场景MyEclipse代码量统计IDEA代码量统计总结项目场景在项目中,有时候我们需要统计

C#和Unity中的中介者模式使用方式

《C#和Unity中的中介者模式使用方式》中介者模式通过中介者封装对象交互,降低耦合度,集中控制逻辑,适用于复杂系统组件交互场景,C#中可用事件、委托或MediatR实现,提升可维护性与灵活性... 目录C#中的中介者模式详解一、中介者模式的基本概念1. 定义2. 组成要素3. 模式结构二、中介者模式的特点