spring启动流程 (4) FactoryBean详解

这篇具有很好参考价值的文章主要介绍了spring启动流程 (4) FactoryBean详解。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

FactoryBean接口

实现类对象将被用作创建Bean实例的工厂,即调用getObject()方法返回的对象才是真正要使用的Bean实例,而不是直接将FactoryBean对象作为暴露的Bean实例。

FactoryBeans可以支持singleton和prototype,并且可以根据需要懒加载或在启动时立即创建对象。

这个接口在编写扫描接口生成代理对象的场景下经常使用,比如Mybatis Mapper接口扫描、Dubbo接口扫描、Feign接口扫描等。

Spring容器只负责管理FactoryBean实例的生命周期,而不是FactoryBean创建的对象的生命周期。因此不会自动调用暴露的Bean对象的destroy方法。FactoryBean应该实现DisposableBean,并将关闭调用委托给底层对象。

public interface FactoryBean<T> {

	/**
	 * Return an instance (possibly shared or independent) of the object
	 * managed by this factory.
	 */
	T getObject() throws Exception;

	/**
	 * Return the type of object that this FactoryBean creates,
	 * or null if not known in advance.
	 */
	Class<?> getObjectType();

	/**
	 * Is the object managed by this factory a singleton?
	 */
	default boolean isSingleton() {
		return true;
	}
}

我们可以使用正常的getBean(beanName)方式获取通过getObject()方法暴露的Bean实例,也可以使用getBean("&" + beanName)方式获取FactoryBean的实例。

下文将介绍其实现方式。

FactoryBean的实现方式

Spring创建单例Bean的逻辑在DefaultListableBeanFactory的preInstantiateSingletons()方法中:文章来源地址https://www.toymoban.com/news/detail-544332.html

public void preInstantiateSingletons() throws BeansException {

	List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

	// Trigger initialization of all non-lazy singleton beans...
	for (String beanName : beanNames) {
		RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
		if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
			if (isFactoryBean(beanName)) {
				// 此处使用"& + beanName"作为beanName创建FactoryBean实例
				Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
				if (bean instanceof FactoryBean) {
					FactoryBean<?> factory = (FactoryBean<?>) bean;
					boolean isEagerInit;
					if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
						isEagerInit = AccessController.doPrivileged(
								(PrivilegedAction<Boolean>) ((SmartFactoryBean<?>) factory)::isEagerInit,
								getAccessControlContext());
					} else {
						isEagerInit = (factory instanceof SmartFactoryBean &&
								((SmartFactoryBean<?>) factory).isEagerInit());
					}
					if (isEagerInit) {
						getBean(beanName);
					}
				}
			} else {
				getBean(beanName);
			}
		}
	}

	// Trigger post-initialization callback for all applicable beans...
	// ...
}

public Object getBean(String name) throws BeansException {
	return doGetBean(name, null, null, false);
}

protected <T> T doGetBean(
		String name, Class<T> requiredType, Object[] args, boolean typeCheckOnly)
		throws BeansException {

	// 此步骤将&符移除
	String beanName = transformedBeanName(name);
	Object bean;

	Object sharedInstance = getSingleton(beanName);
	if (sharedInstance != null && args == null) {
		bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
	} else {
		if (isPrototypeCurrentlyInCreation(beanName)) {
			throw new BeanCurrentlyInCreationException(beanName);
		}

		BeanFactory parentBeanFactory = getParentBeanFactory();
		if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
			String nameToLookup = originalBeanName(name);
			if (parentBeanFactory instanceof AbstractBeanFactory) {
				return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
						nameToLookup, requiredType, args, typeCheckOnly);
			} else if (args != null) {
				return (T) parentBeanFactory.getBean(nameToLookup, args);
			} else if (requiredType != null) {
				return parentBeanFactory.getBean(nameToLookup, requiredType);
			} else {
				return (T) parentBeanFactory.getBean(nameToLookup);
			}
		}

		if (!typeCheckOnly) {
			markBeanAsCreated(beanName);
		}

		try {
			RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
			checkMergedBeanDefinition(mbd, beanName, args);

			String[] dependsOn = mbd.getDependsOn();
			if (dependsOn != null) {
				for (String dep : dependsOn) {
					if (isDependent(beanName, dep)) {
						throw new BeanCreationException(mbd.getResourceDescription(), beanName,
								"Circular depends-on relationship between");
					}
					registerDependentBean(dep, beanName);
					try {
						getBean(dep);
					} catch (NoSuchBeanDefinitionException ex) {
						throw new BeanCreationException(mbd.getResourceDescription(), beanName,
								"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
					}
				}
			}

			if (mbd.isSingleton()) {
				// getSingleton方法中会先从单例池查找Bean
				// 如果没有则会调用lambda中的createBean(beanName, mbd, args)创建Bean并将其注册到单例池
				// 所以此时放入单例池的是FactoryBean实例
				sharedInstance = getSingleton(beanName, () -> {
					try {
						// 此处的beanName参数是不带&符的字符串
						return createBean(beanName, mbd, args);
					} catch (BeansException ex) {
						destroySingleton(beanName);
						throw ex;
					}
				});
				// beanName参数是不带&符的字符串
				// name是原始的带&符的字符串
				// 该方法里面会判断name是否有&符,如果有直接返回FactoryBean实例
				// 如果没有&符会调用getObject()方法获取真正要暴露的Bean实例
				bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
			} else if (mbd.isPrototype()) {
				Object prototypeInstance = null;
				try {
					beforePrototypeCreation(beanName);
					prototypeInstance = createBean(beanName, mbd, args);
				} finally {
					afterPrototypeCreation(beanName);
				}
				bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
			} else {
				String scopeName = mbd.getScope();
				if (!StringUtils.hasLength(scopeName)) {
					throw new IllegalStateException("No scope name defined for bean");
				}
				Scope scope = this.scopes.get(scopeName);
				if (scope == null) {
					throw new IllegalStateException("No Scope registered for scope name");
				}
				try {
					Object scopedInstance = scope.get(beanName, () -> {
						beforePrototypeCreation(beanName);
						try {
							return createBean(beanName, mbd, args);
						} finally {
							afterPrototypeCreation(beanName);
						}
					});
					bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
				} catch (IllegalStateException ex) {
					throw new BeanCreationException(beanName, "", ex);
				}
			}
		} catch (BeansException ex) {
			cleanupAfterBeanCreationFailure(beanName);
			throw ex;
		}
	}

	return (T) bean;
}

protected Object getObjectForBeanInstance(
		Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {

	// 判断name有&符,直接返回FactoryBean实例
	if (BeanFactoryUtils.isFactoryDereference(name)) {
		if (beanInstance instanceof NullBean) {
			return beanInstance;
		}
		if (!(beanInstance instanceof FactoryBean)) {
			throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
		}
		if (mbd != null) {
			mbd.isFactoryBean = true;
		}
		return beanInstance;
	}

	if (!(beanInstance instanceof FactoryBean)) {
		return beanInstance;
	}

	Object object = null;
	if (mbd != null) {
		mbd.isFactoryBean = true;
	} else {
		// 从factoryBeanObjectCache池获取
		object = getCachedObjectForFactoryBean(beanName);
	}
	if (object == null) {
		// Return bean instance from factory.
		FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
		// Caches object obtained from FactoryBean if it is a singleton.
		if (mbd == null && containsBeanDefinition(beanName)) {
			mbd = getMergedLocalBeanDefinition(beanName);
		}
		boolean synthetic = (mbd != null && mbd.isSynthetic());
		// 调用getObject()方法获取真正要暴露的Bean实例并将其放入factoryBeanObjectCache池
		object = getObjectFromFactoryBean(factory, beanName, !synthetic);
	}
	return object;
}

到了这里,关于spring启动流程 (4) FactoryBean详解的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • spring启动流程 (6完结) springmvc启动流程

    SpringMVC的启动入口在SpringServletContainerInitializer类,它是ServletContainerInitializer实现类(Servlet3.0新特性)。在实现方法中使用WebApplicationInitializer创建ApplicationContext、创建注册DispatcherServlet、初始化ApplicationContext等。 SpringMVC已经将大部分的启动逻辑封装在了几个抽象WebApplicationInitia

    2024年02月16日
    浏览(45)
  • 119、Spring容器启动流程是怎样的(配有Spring启动完整流程图)

    在创建Spring容器,也就是启动Spring时: 首先会进行扫描,扫描得到所有的BeanDefinition对象,并存在一个Map中 然后筛选出非懒加载的单例BeanDefinition进行创建Bean,对于多例Bean不需要在启动过程中去进行创建,对于多例Bean会在每次获取Bean时利用BeanDefinition去创建 利用BeanDefinit

    2024年02月14日
    浏览(41)
  • FactoryBean和BeanFactory:Spring IOC容器的两个重要角色简介

    目录 一、简介 二、BeanFactory 三、FactoryBean 四、区别 五、使用场景 总结 在Spring框架中,IOC(Inversion of Control)容器是一个核心组件,它负责管理和配置Java对象及其依赖关系,实现了控制反转(Inversion of Control)和依赖注入(Dependency Injection)两个核心概念。 控制反转是一种设

    2024年02月11日
    浏览(35)
  • spring启动流程 (1) 流程概览

    本文将通过阅读AnnotationConfigApplicationContext源码,分析Spring启动流程。 核心的启动逻辑都在refresh方法中。 定义了多个register方法,用于向Spring容器注册BeanDefinition。 在创建AnnotatedBeanDefinitionReader时,会向容器注册几个注解驱动处理器: org.springframework.context.annotation.internalConf

    2024年02月11日
    浏览(39)
  • 【Spring】1、Spring 框架的基本使用【读取配置文件、IoC、依赖注入的几种方式、FactoryBean】

    Spring 框架可以说是 Java 开发中最重要的框架,功能 非常 强大 中文文档:https://springdoc.cn/spring/ 官网:https://spring.io/ Spring makes Java Simple、modern、productive … Spring 框架的几个核心概念: IoC: I nversion o f C ontrol:控制反转 DI: D ependency I njection:依赖注入 AOP: A spect O riented P rogram

    2024年02月09日
    浏览(67)
  • spring启动流程 (2) Bean实例化流程

    本文通过阅读Spring源码,分析Bean实例化流程。 上一篇文章已经介绍,Bean实例化入口在AbstractApplicationContext类的finishBeanFactoryInitialization方法: 返回指定beanName的(原始)单例对象,如果没有则创建一个新对象: 创建Bean实例、填充属性、调用后置处理器等:

    2024年02月11日
    浏览(81)
  • Spring Boot 启动流程

    加载配置 Spring Boot在启动时会加载应用程序的配置文件(例如application.properties或application.yml),并将其转化为内部的配置对象。 创建应用程序上下文 Spring Boot会创建一个应用程序上下文(ApplicationContext),它是Spring框架的核心容器。应用程序上下文负责管理Bean的生命周期和

    2024年02月06日
    浏览(50)
  • UiPath Orchestrator接口(API)方式启动流程(作业)

    以API的方式调用机器人开始作业 原文来自: How To Start A Job In PowerShell Using Orchestrator API Endpoints? 中文互联网上似乎没有找到相关资料,有一篇似乎是以前的,现在不适用了,故写下本文。 所有接口调试基于Postman 需要用到的接口:{{url}}为:https://cloud.uipath.com/用户名/租户名,

    2024年02月13日
    浏览(32)
  • Spring Boot的启动流程

    Spring Boot是作为Spring的脚手架框架,其本身并不提供Spring的核心功能,而是来达到快速构建项目、预置三方配置、开箱即用的目的 。 从本质上来说,Spring Boot就是Spring,它做了那些没有它你自己也会去做的Spring Bean配置。 Spring Boot使用“习惯优于配置”的理念让你的项目快速

    2024年02月02日
    浏览(38)
  • Spring Boot启动流程简析

    文章首发地址 可以穿件独立的Spring应用程序,可以创建可执行的jars 内嵌tomcat或jetty等Servlet容器 提供“入门”依赖项,以简化构建配置。尽可能自动配置Spring和第三方库 提供可用于生产的功能,例如指标、运行状况检查和外部化配置 了解基本的启动注解 AnnotationUtil.java,该

    2024年02月16日
    浏览(57)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包