java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Spring BeanFactory和FactoryBean

Spring BeanFactory和FactoryBean有哪些区别

作者:每天都要进步一点点

这篇文章主要介绍了Spring BeanFactory 与 FactoryBean 的区别详情,BeanFactory 和 FactoryBean 的区别却是一个很重要的知识点,在本文中将结合源码进行分析讲解,需要的小伙伴可以参考一下

一、简介

在Spring中,有这么2个接口:BeanFactory和FactoryBean,名字很相似,很多小伙伴经常混淆,在面试的时候也经常会被问BeanFactory和FactoryBean两者的区别。本篇文章将详细介绍它们的区别,并结合示例,帮助大家对BeanFactory和FactoryBean有一个很好的认识。

二、BeanFactory

BeanFactory是Spring IoC 容器的顶层接口,主要负责实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。

BeanFactory只是一个接口,并不是IOC容器的具体实现,但是Spring容器给出了很多种实现,如 DefaultListableBeanFactory、XmlBeanFactory、ApplicationContext等,都是附加了某种功能的实现。BeanFactory主要的实现类(包括抽象类):

BeanFactory是Bean工厂,它是一个接口,定义如下:

public interface BeanFactory {
	/**
	 * 区分FactoryBean实例,例如,如果bean命名为myJndiObject是一个FactoryBean,通过&myJndiObject将返回工厂,而不是由工厂返回的实例
	 */
	String FACTORY_BEAN_PREFIX = "&";
	/**
	 * 返回指定bean的实例
	 */
	Object getBean(String name) throws BeansException;
	/**
	 * 返回指定bean的实例,并指定返回类型
	 */
	<T> T getBean(String name, Class<T> requiredType) throws BeansException;
	/**
	 * 返回指定bean的实例,并指定创建bean实例时使用的参数
	 */
	Object getBean(String name, Object... args) throws BeansException;
	/**
	 * 返回的bean实例唯一匹配给定的对象类型
	 */
	<T> T getBean(Class<T> requiredType) throws BeansException;
	/**
	 * 返回的bean实例唯一匹配给定的对象类型,并指定创建bean实例时使用的参数
	 */
	<T> T getBean(Class<T> requiredType, Object... args) throws BeansException;
	/**
	 * 返回一个指定bean提供者
	 */
	<T> ObjectProvider<T> getBeanProvider(Class<T> requiredType);
	/**
	 * 返回一个指定bean提供者
	 */
	<T> ObjectProvider<T> getBeanProvider(ResolvableType requiredType);
	/**
	 * 判断工厂中是否包含给定名称的bean定义,若有则返回true
	 */
	boolean containsBean(String name);
	/**
	 * 判断bean的作用域是否是singleton:单例模式
	 */
	boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
	/**
	 * 判断bena的作用域是否是prototype:多例模式
	 */
	boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
	/**
	 * 检查具有指定名称的bean是否与指定的类型匹配
	 */
	boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;
	/**
	 * 检查具有指定名称的bean是否与指定的类型匹配
	 */
	boolean isTypeMatch(String name, Class<?> typeToMatch) throws NoSuchBeanDefinitionException;
	/**
	 * 用给定的名称确定bean的类型
	 */
	@Nullable
	Class<?> getType(String name) throws NoSuchBeanDefinitionException;
	/**
	 * 用给定的名称确定bean的类型
	 */
	@Nullable
	Class<?> getType(String name, boolean allowFactoryBeanInit) throws NoSuchBeanDefinitionException;
	/**
	 * 返回给定bean名称的所有别名 
	 */
	String[] getAliases(String name);
}

下面列举一下ClassPathXmlApplicationContext的使用示例:

ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:spring-config.xml");
User user = (User) applicationContext.getBean("user");
user.hello();

三、FactoryBean

一般情况下,Spring通过反射利用bean的class属性指定实现类来实例化bean。在某些情况下,实例化bean的过程比较复杂,如果按照传统的方式,则需要在<bean>中提供大量的配置信息,配置方式的灵活性是受限的,这时采用编码的方式可能会得到一个简单的方案。

Spring为此提供了一个FactoryBean工厂类接口,用户可以通过实现该接口定制实例化bean的逻辑。

FactoryBean是一个能生产或修饰对象生成的工厂Bean,当我们实现了FactoryBean接口,重写getObject()方法并返回一个实例时,Spring会按照我们指定的内容去注册Bean,来达到定制实例化Bean的效果。

FactoryBean定义如下:

public interface FactoryBean<T> {
	String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";
	/**
	 * 返回需要创建的Bean
	 */
	@Nullable
	T getObject() throws Exception;
	/**
	 * 返回FactoryBean创建的Bean类型
	 */
	@Nullable
	Class<?> getObjectType();
	/**
	 * 是否单例Bean,默认是单例的,存入Spring容器中单例缓存池
	 */
	default boolean isSingleton() {
		return true;
	}
}

当配置文件中<bean>的class属性配置的实现类是FactoryBean时,通过getBean()方法返回的不是FactoryBean本身,而是FactoryBean#getObject()方法所返回的对象,相当于FactoryBean#getObject()代理了getBean()方法。

下面我们通过一个简单的FactoryBean案例,实现自定义注入Bean对象:

public class Student implements Serializable {
    private String id;
    private String name;
    private int age;
    public String getId() {
        return id;
    }
    public void setId(String 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;
    }
    @Override
    public String toString() {
        return "Student{" +
                "id='" + id + '\'' +
                ", name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
@Component
public class MyFactoryBean implements FactoryBean<Student> {
    @Override
    public Student getObject() throws Exception {
        Student student = new Student();
        student.setId(UUID.randomUUID().toString());
        student.setName("张三");
        student.setAge(20);
        return student;
    }
    @Override
    public Class<?> getObjectType() {
        return Student.class;
    }
    @Override
    public boolean isSingleton() {
        return true;
    }
}

简单测试一下Spring是否帮助我们创建Student这个Bean对象:

public void test2() {
        System.out.println("========返回工厂中的实例========");
        //返回工厂中的实例,调用FactoryBean.getObject()创建实例
        Student student1 = (Student) applicationContext.getBean("myFactoryBean");
        System.out.println(student1);
        System.out.println("========返回工厂本身========");
        //返回工厂本身,通过构造方法初始化实例
        Object bean = applicationContext.getBean("&myFactoryBean");
        System.out.println(bean);
    }

运行结果如下:

========返回工厂中的实例========
Student{id='5aa54f31-3d4a-4bc0-989a-5149f393c3db', name='张三', age=20}
========返回工厂本身========
com.wsh.springtransactiondemo.factorybean.MyFactoryBean@24e95e44

可以看到,根据"myFactoryBean"的名称获取到的实际上是FactoryBean工厂调用getObject()返回的对象,而不是MyFactoryBean工厂本身,如果要获取MyFactoryBean工厂本身实例,那么需要在名称前面加上'&'符号。如下:

为什么要使用FactoryBean?

在某些情况下,对于实例Bean对象比较复杂的情况下,如果使用传统方式创建bean会比较复杂,如xml配置繁琐等,于是Spring就提供了FactoryBean接口,让用户通过实现该接口来自定义该Bean接口的实例化过程。

四、总结

Spring 中为我们提供了两种类型的 bean,一种就是普通的 bean,我们通过getBean(id) 方法获得是该 bean 的实际类型,另外还有一种 bean是FactoryBean,也就是工厂 bean,我们通过getBean(id) 获得是该工厂所产生的 Bean的实例,而不是FactoryBean的实例。

到此这篇关于Spring BeanFactory和FactoryBean有哪些区别的文章就介绍到这了,更多相关Spring BeanFactory和FactoryBean内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文