Spring中的FactoryBean实现原理详解

 更新时间:2024年02月14日 08:50:49   作者:军伟@  
这篇文章主要介绍了Spring中的FactoryBean实现原理详解,spring中有两种类型的Bean,一种是普通的JavaBean,另一种就是工厂Bean(FactoryBean),这两种Bean都受Spring的IoC容器管理,但它们之间却有一些区别,需要的朋友可以参考下

1、概述

spring中有两种类型的Bean:

  1. 一种是普通的JavaBean;
  2. 另一种就是工厂Bean(FactoryBean)

这两种Bean都受Spring的IoC容器管理,但它们之间却有一些区别。

2、详述

普通的JavaBean不再多说,我们将其定义好,然后在配置文件中定义并配置其依赖关系,就可以通过IoC容器的getBean获取到。

那么FactoryBean呢?

FactoryBean跟普通Bean不同,它是实现了FactoryBean<T>接口的Bean,通过BeanFactory类的getBean方法直接获取到的并不是该FactoryBean的实例,而是该FactoryBean中方法getObject返回的对象。但我们可以通过其它途径获取到该FactoryBean的实例,方法就是在通过getBean方法获取实例时在参数name前面加上“&”符号即可。

FactoryBean接口提供的方法如下:

public interface FactoryBean<T> {
	//获取FactoryBean初始化的Bean实例
	T getObject() throws Exception;
	//获取Bean实例的类型
	Class<?> getObjectType();
	//判断是否是单例模式
	boolean isSingleton();
}

3、示例

创建MyFactoryBean

public class MyFactoryBean implements FactoryBean<Date>,BeanNameAware {  
    private String name;  
    @Override  
    public Date getObject() throws Exception {  
        return new Date();  
    }  
    @Override  
    public Class<?> getObjectType() {  
        return Date.class;  
    }  
    @Override  
    public boolean isSingleton() {  
        return false;  
    }  
    public void sayName() {  
        System.out.println("My name is " + this.name);  
    }  
    @Override  
    public void setBeanName(String name) {  
        this.name = name;  
    }  
}  

在Spring的配置文件ApplicationContext.xml中注入MyFactoryBean

<bean id ="myFactoryBean" class="com.xxxx.MyFactoryBean"></bean>

测试代码

public class MainFactoryBean {
 
	@SuppressWarnings("resource")
	public static void main(String [] args){  
		ApplicationContext appCtx = new ClassPathXmlApplicationContext("applicationContext.xml");
	    Date now = (Date) appCtx.getBean("myFactoryBean");  
	    System.out.println(now);  
	    MyFactoryBean factoryBean = (MyFactoryBean) appCtx.getBean("&myFactoryBean");  
	    factoryBean.sayName();  
	}  
}

运行结果

通过myFactoryBean名称获取到的Bean是Date对象实例,通过&myFactoryBean获取到的是MyFactoryBean对象实例。

4、实现原理

我们来看一下执行Date now = (Date) appCtx.getBean("myFactoryBean");  时会做的处理操作。 AbstractBeanFactory中会进行一系列的操作。

getBean获取bean

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

doGetBean中获取bean实例

protected <T> T doGetBean(
			final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
			throws BeansException {
		.........//省略部分代码
		bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
		.........//省略部分代码
		return (T) bean;
	}

getObjectForBeanInstance中会选择bean实例是普通的Bean还是FactoryBean,同时通过判断name中是否有&来选择判断是或者FactoryBean还是其getObject方法中获取的bean

protected Object getObjectForBeanInstance(
			Object beanInstance, String name, String beanName, RootBeanDefinition mbd) {
		.........//省略部分代码
		//判断bean类型是否是FactoryBean,或者name是否是以&开头,如果是则直接返回
		if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
			return beanInstance;
		}
		//如果是则从getObjectFromFactoryBean中获取
		if (object == null) {
			// Return bean instance from factory.
			FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
			if (mbd == null && containsBeanDefinition(beanName)) {
				mbd = getMergedLocalBeanDefinition(beanName);
			}
			boolean synthetic = (mbd != null && mbd.isSynthetic());
			object = getObjectFromFactoryBean(factory, beanName, !synthetic);
		}
		return object;
	}

getObjectFromFactoryBean接下来会执行FactoryBean的getObject方法获取bean了。

protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
		.........//省略部分代码				
		Object object = doGetObjectFromFactoryBean(factory, beanName);
		.........//省略部分代码
		return object;
	}
	
private Object doGetObjectFromFactoryBean(final FactoryBean<?> factory, final String beanName)
			throws BeanCreationException {
		Object object;
		.........//省略部分代码
		//调用Factory的getObject方法
		object = factory.getObject();
		.........//省略部分代码
		return object;
	}

总结

Spring对FactoryBean的实现机制是当你获取一个Bean时,如果获取的Bean的类型是FactoryBean,并且其name中并没有&则调用bean的getObject方法获取FactoryBean实现类中提供bean,否则就是直接返回普通的bean类型。

到此这篇关于Spring中的FactoryBean实现原理详解的文章就介绍到这了,更多相关FactoryBean实现原理内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Java中截取字符串方法的两种用法

    Java中截取字符串方法的两种用法

    这篇文章主要给大家介绍了关于Java中截取字符串方法的两种用法,在Java开发中经常会涉及到对字符串进行截取操作,字符串截取是一种常见且重要的字符串处理技巧,可以根据实际需求获取字符串的指定部分,需要的朋友可以参考下
    2023-09-09
  • 一文带你深入了解Java的自动拆装箱

    一文带你深入了解Java的自动拆装箱

    Java推出了对于基本数据类型的对应的对象,将基本数据类型转换为对象就称为装箱,反之则是拆箱,本文主要为大家介绍了Java自动拆装箱的原理与应用,需要的可以参考下
    2023-11-11
  • 携程Apollo(阿波罗)安装部署以及java整合实现

    携程Apollo(阿波罗)安装部署以及java整合实现

    这篇文章主要介绍了携程Apollo(阿波罗)安装部署以及java整合实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-08-08
  • Java实战个人博客系统的实现流程

    Java实战个人博客系统的实现流程

    读万卷书不如行万里路,只学书上的理论是远远不够的,只有在实战中才能获得能力的提升,本篇文章手把手带你用java+springboot+mybatis+redis+vue+elementui+Mysql实现一个个人博客系统,大家可以在过程中查缺补漏,提升水平
    2022-01-01
  • SpringBoot加载SQLite数据源方式

    SpringBoot加载SQLite数据源方式

    文章介绍了SpringBoot中配置SQLite数据源的流程,包括DBeaver连接数据库、执行建表与数据插入、引入依赖、初始化连接、定义实体类与Mapper,以及测试查询操作,同时提及多数据源适配的扩展方式
    2025-09-09
  • 浅析Java异常处理中断言的使用

    浅析Java异常处理中断言的使用

    这篇文章主要介绍了Java异常处理中断言的使用,是Java入门学习中的基础知识,需要的朋友可以参考下
    2015-09-09
  • java反射调用方法NoSuchMethodException的解决方案

    java反射调用方法NoSuchMethodException的解决方案

    这篇文章主要介绍了java反射调用方法NoSuchMethodException的解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-03-03
  • Java Lambda表达式语法及用法示例

    Java Lambda表达式语法及用法示例

    这篇文章主要给大家介绍了关于Java Lambda表达式语法及用法的相关资料,lambda表达式是JAVA8中提供的一种新的特性,它支持Java也能进行简单的"函数式编程",文中通过代码介绍的非常详细,需要的朋友可以参考下
    2023-10-10
  • Java中实现对象深克隆的四种方式

    Java中实现对象深克隆的四种方式

    这篇文章主要介绍了如何在Java中实现对象的深克隆,可以通过手动实现clone()方法、使用序列化、第三方库Apache Commons Lang或Hutool等几种方式,每种方式都有其特点,需要的朋友可以参考下
    2025-10-10
  • 多种情况下jar包获取文件的路径,读取文件方式

    多种情况下jar包获取文件的路径,读取文件方式

    文章介绍了在不同情况下(IDEA运行和JAR包运行)获取文件路径的方法,并总结了每种方式的适用场景
    2024-11-11

最新评论