Spring源码分析-Bean创建流程三

目录

一、 列举一些创建对象有哪几种方式

二、自定义BeanPostProcess生成代理对象

1、实战案例

2、源码分析

三、通过supplier创建对象

1、实战案例

2、源码分析

四、通过FactoryMethod创建对象

1、实战案例

2、源码分析

五、小总结


一、 列举一些创建对象有哪几种方式

 这篇文章我们主要聊聊BeanPostProcess、Supplier、FactoryMethod这三种方式是怎么创建对象,

至于FactoryBean前面已经介绍到,反射的话不说了,自行解决

二、自定义BeanPostProcess生成代理对象

1、实战案例

先上案例,通过现象,挖掘本质,

mian测试方法如下:

public class ResolveBeforeInstantiationTest {

    public static void main(String[] args) {
        ApplicationContext ac = new ClassPathXmlApplicationContext("resolvebeforeinstantiation.xml");
        BeforeInstantiation bean = ac.getBean(BeforeInstantiation.class);
        bean.doSomeThing();
    }
}

XML配置如下:

<?xml version="1.0" encoding="UTF-8"?>
<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="beforeInstantiation" class="com.yang.test.resolvebeforeinstantiation.BeforeInstantiation"></bean>
    <bean id="myInstantiationAwareBeanPostProcessor" class="com.yang.test.resolvebeforeinstantiation.MyInstantiationAwareBeanPostProcessor"></bean>
</beans>

BeanPostProcessor方法如下:

public class MyInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {

    @Override
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
        System.out.println("beanName:"+beanName+"----执行postProcessBeforeInstantiation方法");
        if (beanClass == BeforeInstantiation.class){
            Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(beanClass);
            enhancer.setCallback(new MyMethodInterceptor());
            BeforeInstantiation beforeInstantiation = (BeforeInstantiation) enhancer.create();
            System.out.println("创建代理对象:"+beforeInstantiation);
            return new BeforeInstantiation();
        }
        return null;
    }

    @Override
    public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
        System.out.println("beanName:"+beanName+"----执行postProcessAfterInstantiation方法");

        return false;
    }

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("beanName:"+beanName+"----执行postProcessBeforeInitialization方法");

        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("beanName:"+beanName+"----执行postProcessAfterInitialization方法");

        return bean;
    }

    @Override
    public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
        System.out.println("beanName:"+beanName+"----执行postProcessProperties方法");

        return pvs;
    }
}

代理方法如下:

public class MyMethodInterceptor implements MethodInterceptor {
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("目标方法执行之前:" + method);
        Object o1 = methodProxy.invokeSuper(o, objects);
        System.out.println("目标方法执行之后:" + method);
        return o1;
    }
}

真实类如下:

public class BeforeInstantiation {

    public void doSomeThing(){
        System.out.println("执行do some thing....");
    }
}

运行结果如下:

2、源码分析

大家有没有想过他是怎么执行到 postProcessBeforeInstantiation方法的呢?

来!上源码,下面只列举关键代码,至于流程,还是需要自己去debug过才最清楚,因为学源码不debug,单纯看=白学

	@Nullable
	protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
		Object bean = null;
		// 如果beforeInstantiationResolved值为null或者true,那么表示尚未被处理,进行后续的处理
		if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
			// Make sure bean class is actually resolved at this point.
			// 确认beanclass确实在此处进行处理
			// 判断当前mbd是否是合成的,只有在实现aop的时候synthetic的值才为true,并且是否实现了InstantiationAwareBeanPostProcessor接口
			if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
				// 是否解析了
				Class<?> targetType = determineTargetType(beanName, mbd);
				if (targetType != null) {
					bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
					if (bean != null) {
						bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
					}
				}
			}
			mbd.beforeInstantiationResolved = (bean != null);
		}
		return bean;
	}

resolveBeforeInstantiation在createBean方法里面调用

	@Override
	protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
			throws BeanCreationException {

		if (logger.isTraceEnabled()) {
			logger.trace("Creating instance of bean '" + beanName + "'");
		}
		RootBeanDefinition mbdToUse = mbd;

		// Make sure bean class is actually resolved at this point, and
		// clone the bean definition in case of a dynamically resolved Class
		// which cannot be stored in the shared merged bean definition.
		// 锁定class,根据设置的class属性或者根据className来解析class
		Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
		if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
			mbdToUse = new RootBeanDefinition(mbd);
			mbdToUse.setBeanClass(resolvedClass);
		}

		// Prepare method overrides.
		// 验证及准备覆盖的方法,lookup-method  replace-method,当需要创建的bean对象中包含了lookup-method和replace-method标签的时候,会产生覆盖操作
		try {
			mbdToUse.prepareMethodOverrides();
		}
		catch (BeanDefinitionValidationException ex) {
			throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
					beanName, "Validation of method overrides failed", ex);
		}

		try {
			// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
			// 给BeanPostProcessors一个机会来返回代理来替代真正的实例,应用实例化前的前置处理器,用户自定义动态代理的方式,针对于当前的被代理类需要经过标准的代理流程来创建对象
			Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
			if (bean != null) {
				return bean;
			}
		}
		catch (Throwable ex) {
			throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
					"BeanPostProcessor before instantiation of bean failed", ex);
		}

		try {
			// 真正干活的方法doCreateBean
			Object beanInstance = doCreateBean(beanName, mbdToUse, args);
			if (logger.isTraceEnabled()) {
				logger.trace("Finished creating instance of bean '" + beanName + "'");
			}
			return beanInstance;
		}
		catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
			// A previously detected exception with proper bean creation context already,
			// or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry.
			throw ex;
		}
		catch (Throwable ex) {
			throw new BeanCreationException(
					mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
		}
	}

三、通过supplier创建对象

1、实战案例

测试类

public class TestSupplier {

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

XML配置如下:

<?xml version="1.0" encoding="UTF-8"?>
<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="user" class="com.yang.test.supplier.User"></bean>
    <bean class="com.yang.test.supplier.SupplierBeanFactoryPostProcessor"></bean>
</beans>

SupplierBeanFactoryPostProcessor类:

public class SupplierBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
    	// 这个没有意义,只不过有这么一种创建bean的方式,实际上配了xml正常流程都会创建user 的bean
        BeanDefinition user = beanFactory.getBeanDefinition("user");
        GenericBeanDefinition genericBeanDefinition = (GenericBeanDefinition) user;
        genericBeanDefinition.setInstanceSupplier(CreateSupplier::createUser);
        genericBeanDefinition.setBeanClass(User.class);
    }
}
CreateSupplier类
public class CreateSupplier {
    public static User createUser(){
        return new User("zhangsan");
    }
}

2、源码分析

关键源码位置:

从BFPP已经实例化了

	/**
	 * Invoke the given BeanFactoryPostProcessor beans.
	 */
	private static void invokeBeanFactoryPostProcessors(
			Collection<? extends BeanFactoryPostProcessor> postProcessors, ConfigurableListableBeanFactory beanFactory) {

		for (BeanFactoryPostProcessor postProcessor : postProcessors) {
			StartupStep postProcessBeanFactory = beanFactory.getApplicationStartup().start("spring.context.bean-factory.post-process")
					.tag("postProcessor", postProcessor::toString);
			postProcessor.postProcessBeanFactory(beanFactory);
			postProcessBeanFactory.end();
		}
	}

在createBeanInstance方法里面调用

		// 判断当前beanDefinition中是否包含实例供应器,此处相当于一个回调方法,利用回调方法来创建bean
		Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
		if (instanceSupplier != null) {
			return obtainFromSupplier(instanceSupplier, beanName);
		}

四、通过FactoryMethod创建对象

1、实战案例

Person.java

public class Person {
    private int id;
    private String name;
    private int age;
    private String gender;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    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;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    @Override
    public String toString() {
        return "Person{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                ", gender='" + gender + '\'' +
                '}';
    }
}

PersonInstanceFactory.java

public class PersonInstanceFactory {
    public Person getPerson(String name){
        Person person = new Person();
        person.setId(1);
        person.setName(name);
        return person;
    }
}

PersonStaticFactory.java

public class PersonStaticFactory {

    public static Person getPerson(String name){
        Person person = new Person();
        person.setId(1);
        person.setName(name);
        return person;
    }
}

factoryMethod.xml

<?xml version="1.0" encoding="UTF-8"?>
<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="person5" class="com.mashibing.factoryMethod.PersonStaticFactory" factory-method="getPerson">
        <!--constructor-arg:可以为方法指定参数-->
        <constructor-arg value="lisi"></constructor-arg>
    </bean>
    <bean id="personInstanceFactory" class="com.mashibing.factoryMethod.PersonInstanceFactory"></bean>
    <!--
    factory-bean:指定使用哪个工厂实例
    factory-method:指定使用哪个工厂实例的方法
    -->
    <bean id="person6" class="com.mashibing.factoryMethod.Person" factory-bean="personInstanceFactory" factory-method="getPerson">
        <constructor-arg value="wangwu"></constructor-arg>
    </bean>
</beans>

Test.java

public class Test {

    public static void main(String[] args) {
        MyClassPathXmlApplicationContext ac = new MyClassPathXmlApplicationContext("factoryMethod.xml");

    }
}

2、源码分析

关键位置:

createBeanInstance方法里面
		// 如果工厂方法不为空则使用工厂方法初始化策略
		if (mbd.getFactoryMethodName() != null) {
			return instantiateUsingFactoryMethod(beanName, mbd, args);
		}

五、小总结

debug的话,永远要记住这个流程,很关键

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

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

相关文章

作为一个女测试员是什么样的体验?

面试时极度紧张&#xff0c;语无伦次&#xff0c;觉得肯定没戏&#xff0c;最后却拿到高薪offer。 工作之后我听同事们讲&#xff0c;测试总监面试官并没打算要我&#xff0c;但身边的人都问他&#xff1a; 那个小姐姐什么时候来报道&#xff1f;... 于是在众人的期待的目光…

撮合交易系统简介

1 撮合交易系统简介 金融市场&#xff1a; 为了应对更高峰值的成交量&#xff0c;国内各金融机构&#xff0c;主要是交易所和银联、中心之间需求越来越多&#xff1a; 其中最重要的就是撮合系统&#xff1a; 系统拓扑图&#xff1a; 委托终端/柜台&#xff1a; 网关&#xff1…

一四三、人脸识别自动点赞、关注

文章目录脚本功能获取video当前播放帧图片将图片传到后台调用百度人脸识别接口拿到识别结果处理逻辑效果展示问题记录脚本功能 通过获取video当前播放帧图片&#xff0c;截图调用后台接口&#xff0c;再调用百度人脸识别拿到人脸信息&#xff08;年龄、颜值、性别等&#xff09…

元宇宙医生虚拟形象提高远程医疗服务质量

与现实中不同&#xff0c;3D虚拟形象是由个人在数字空间中自由选择并进行扮演的。这种3D虚拟形象在元宇宙中的重要性越来越突出。 在元宇宙虚拟空间中&#xff0c;用户借助元宇宙3D虚拟形象就能与其他用户互动、交流并获得真实的沉浸式体验&#xff0c;因此能广泛融入各种生活、…

「解析」牛客网-华为机考企业真题 41-60

又是一年春招时&#xff0c;有幸收到华为自动驾驶算法岗&#xff0c;之前刷题不多&#xff0c;在此汇总下牛客网的真题&#xff0c;主要采用Python编写&#xff0c;个人觉得语言只是实现工具而已&#xff0c;并不是很关键&#xff0c;Python简洁易懂&#xff0c;更加适合算法工…

基于EB工具的TC3xx_MCAL配置开发06_PWM模块配置

目录 1.概述2. EB配置2.1 PWM->General2.2 PWM->Channel2.2.1 PWMChannel配置2.2.2 PwmChannelClass配置2.2.3 GTM通道选取2.3 MCU关联配置2.4 Port关联配置1.概述 本篇开始我们基于EB Tresos工具对英飞凌TC3xx系列MCU的MCAL开发进行介绍,结合项目经验对各MCAL外设的开…

Docker:关于 Dockerfile 编写优化的一些笔记整理

写在前面 分享一些 Dickerfile 构建镜像优化方式的笔记理解不足小伙伴帮忙指正 对每个人而言&#xff0c;真正的职责只有一个&#xff1a;找到自我。然后在心中坚守其一生&#xff0c;全心全意&#xff0c;永不停息。所有其它的路都是不完整的&#xff0c;是人的逃避方式&#…

【React全家桶】Flux与Redux

&#x1f39e;️&#x1f39e;️&#x1f39e;️ 博主主页&#xff1a; 糖 &#xff0d;O&#xff0d; &#x1f449;&#x1f449;&#x1f449; react专栏&#xff1a;react全家桶 &#x1f339;&#x1f339;&#x1f339;希望各位博主多多支持&#xff01;&#xff01;&a…

javaScript扫雷

文章目录一、准备工作1.图片2.html2.css3.js二、初始化数据1. 配置文件2.工具文件3.逻辑文件1.main函数2.init函数1.随机生成雷2.css添加三、完整代码1.html2.js3.css一、准备工作 1.图片 需要找三张图片 旗子的图片 炸弹的图片 爆炸的图片 2.html html文件夹新建一个html文…

区块链基本原理

区块链的起源 创始者介绍 姓名&#xff1a;中本聪&#xff08;英语&#xff1a;SatoshiNakamoto&#xff09;&#xff0c;自称日裔美国人&#xff0c;日本媒体常译为中本哲史&#xff0c;此名是比特币协议及其相关软件Bitcoin-Qt的创造者&#xff0c;但真实身份未知。 中本聪于…

Chapter9.1:线性系统状态空间基础(上)

该系列博客主要讲述Matlab软件在自动控制方面的应用&#xff0c;如无自动控制理论基础&#xff0c;请先学习自动控制系列博文&#xff0c;该系列博客不再详细讲解自动控制理论知识。 自动控制理论基础相关链接&#xff1a;https://blog.csdn.net/qq_39032096/category_10287468…

解决Visual Studio设置C++标准 但是_cplusplus始终为199711

目录场景复现Visual Studio官方说明C标准对应表解决方案方法一 恢复__cplusplus宏方法二 使用_MSVC_LANG宏场景复现 我在VS2022偶然的一次测试C标准开发环境&#xff0c;发现无论我怎么修改C语言标准&#xff0c;输出的__cplusplus宏总是199711。 Visual Studio官方说明 链…

【C++】vector模拟实现及其应用

文章目录vector的介绍vector的使用及其实现vector的定义vector iterator 的使用vector空间增长问题vector的增删查改vector的介绍 vector是表示可变大小数组的序列容器。就像数组一样&#xff0c;vector也采用的连续存储空间来存储元素。也就是意味着可以采用下标对vector的元素…

开源 Swallow 代码审计系统体验

最近在哔哩哔哩看 到Swallow 代码审计系统的宣传,发现功能比较适合我目前的工作需要,安装使用了一下,简单做了一个笔记,分享给有需要的朋友. 底层架构为蜻蜓编排系统,墨菲SCA,fortify,SemGrep,hema 项目地址:https://github.com/StarCrossPortal/swallow 安装与使用视频教程:ht…

hexo 搭建个人博客记录

看B站的程序羊的关于搭建hexo博客的方法自己搭了一个博客&#xff0c;链接是 手把手教你从0开始搭建自己的个人博客 |无坑版视频教程| hexo 下面就视频所讲做做笔记&#xff0c;以后可以回来查看&#xff0c;推荐小伙伴想搭建hexo博客的可以去看看这个视频。 1. 安装Node.js…

react项目路由组件懒加载和路由传值方式

项目实战 使用useRoutes配置路由&#xff0c;结合插槽配置用户登录检测。 用户登录成功进入login 直接系统主界面 路由模块抽离 整体代码外移 { path: "/admin", element: ( <Author name"admin"> <Index /> </Author> ), }, { path:…

「SAP ABAP」OPEN SQL(七)【GROUP BY | HAVING | ORDER BY】

&#x1f482;作者简介&#xff1a; THUNDER王&#xff0c;一名热爱财税和SAP ABAP编程以及热爱分享的博主。目前于江西师范大学本科在读&#xff0c;同时任汉硕云&#xff08;广东&#xff09;科技有限公司ABAP开发顾问。在学习工作中&#xff0c;我通常使用偏后端的开发语言A…

基于matlab已知地球两点坐标求取距离和方位角函数distance

一、语法1.语法1[arclen,az] distance(lat1,lon1,lat2,lon2)&#xff1b;R6371.393; % 地球半径&#xff0c;单位&#xff1a;km地点1&#xff08;维度lat1&#xff0c;经度lon1&#xff09;&#xff0c;地点2&#xff08;维度lat2&#xff0c;经度lon2&#xff09;假设地点1和…

001 鸿蒙系统环境搭建及运行hello world

1 下载与安装DevEco Studio 在HarmonyOS应用开发学习之前&#xff0c;需要进行一些准备工作&#xff0c;首先需要完成开发工具DevEco Studio的下载与安装以及环境配置。 进入DevEco Studio下载官网&#xff0c;单击“立即下载”进入下载页面。 DevEco Studio提供了Windows版本…

PCIe基础

PCIe基础 PCI Express&#xff0c;简称PCI-E&#xff0c;官方简称PCIe&#xff0c;是计算机总线的一个重要分支&#xff0c;它沿用既有的PCI编程概念及信号标准&#xff0c;并且构建了更加高速的串行通信系统标准。目前这一标准由PCI-SIG组织制定和维护。 拓扑 配置空间 在 P…