Spring IoC的细节--面试必问之BeanFactory和FactoryBean的区别

BeanFactory和FactoryBean的区别

跳到文末看结论

BeanFactory的介绍:

官网对于BeanFactory的解释:

https://docs.spring.io/spring/docs/5.0.4.RELEASE/spring-framework-reference/core.html#beans-beanfactory

下面给出官网文档截图:
在这里插入图片描述
英文不好的同学,看着头疼吧?没关系,下面有我粗略的中文翻译(有不正确的地方敬请提出):

1.16 The BeanFactory
BeanFactory为spring的IoC功能提供了基础,但是它只能直接与其他第三方框架集成使用,并且对于大多数Spring用户来说,它已成为历史。
BeanFactory和它有关的接口,如BeanFactoryAward、InitializingBean、DisposableBean,仍然存在于Spring中,目的是与大量Spring集成的第三方框架兼容。
通常第三方组件不能使用更现代化的组件,例如@PostConstruction 或者@Predestroy,以避免对JSR-250的依赖。

本节为区分BeanFactory和ApplicationContext提供额外的背景,并介绍如何通过典型的单例查找直接访问IoC容器。

1.16.1 BeanFactory or ApplicationContext?
推荐使用ApplicationContext除非你必须弃用它。
因为ApplicationContext包括了所有BeanFactory的功能,除非一些情况下,比如在资源受限设备上运行的嵌入式应用,内存消化可能很关键,一些额外的KB字节可能会产生影响,才推荐使用BeanFactory。
然而,对于大多数典型的企业应用和系统来讲,ApplicationContext就是您想使用的了。
Spring大量使用BeanPostProcessor扩展点(用于代理等)。
如果你只使用普通的BeanFactory,那么大量的支持功能将会失效(如AOP和事务),至少使用这些功能您并不需要多余步骤。在这种情况下你可能会觉得困惑,因为配置实际上并没有问题,而功能不生效。

上述是Spring官网文档对于BeanFactory的介绍,可能我翻译不是很恰当,或者本身Spring官网讲的就比较晦涩难懂,我总结一下他想表达的意思,分别如下两点:
1)BeanFactory为Spring提供了基础的功能,但是现在大多数已经弃用了,为了保持与第三方框架的兼容性,Spring对它作了保留。
2)在一般企业级开发中,推荐使用ApplicationContext而不是BeanFactory,如果你必须使用BeanFactory,那么有一些支持的功能将不生效,比如AOP和事务之类的。

并且给出示例代码:

在这里插入图片描述
上述代码,如果看过IoC初始化文章的,应该很熟悉,它在ClassPathXmlApplicationContext类中集成了上述操作。
代码片段1,指如果要使用一个Bean的后置处理器,需要创建一个DefaultListableBeanFactory对象,用来存储跟Xml文件对应的BeanDefinition对象。然后创建一个自定义后置处理类,并设置到工厂中。
代码片段2,同样创建DefaultListableBeanFactory对象,并需要创建XML配置文件的解析对象XmlBeanDefinitionReader,然后执行加载过程,将配置文件读入,解析。

上文讲述了两个东西,一个是BeanFactory,一个是ApplicationContext。
下面看看两者的关系:
在这里插入图片描述
由上图可知,ApplicationContext与BeanFactory是父子关系。难怪Spring官网说,ApplicationContext拥有所有BeanFactory的功能。

BeanFactory拥有哪些方法呢:
在这里插入图片描述
从截图得知,其实BeanFactory的方法比较的简单,下面介绍方法的意义:
getBean获取Bean实例,也是依赖注入的入口;
containsBean判断容器是否存在输入的该Bean;
isSingleton判断容器中,输入的BeanName是否为单例;

总结:BeanFactory是一个IoC顶层的接口,定义了IoC容器的基础模型,提供getBean的总入口。其由ClassPathXmlApplicationContext、FileSystemXmlApplicationContext、XMLWebApplicationContext、DefaultListableBeanFactory等提供相应的实现。

FactoryBean的介绍

FactoryBean本身是一种Bean,一种用来创建实例的工厂Bean,spring本身其实就提供了许多FactoryBean的实现。下面将通过一个例子,讲述FactoryBean的实际作用。

首先定义我们需要生产的Bean,Dog.java:

public class Dog {

    private String name;

    private int age;

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

接下来,我们定义一个生产够的工厂DogFactoryBean,其实现了FactoryBean接口,DogFactoryBean.java:

public class DogFactoryBean implements FactoryBean<Dog> {

    private String name;

    private int age;

    @Override
    public Dog getObject() throws Exception {

        Dog dog = new Dog();
        dog.setAge(this.age);
        dog.setName(this.name);
        return dog;
    }

    @Override
    public Class<?> getObjectType() {
        return Dog.class;
    }

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

配置工厂Bean的配置文件:

<?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-3.1.xsd">


    <bean id="dog" class="com.example.demo.test.factory.DogFactoryBean">
        <property name="age" value="1"/>
        <property name="name" value="tom"/>
    </bean>

</beans>

测试方法:

	//FactoryBean的测试
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-context2.xml");
        //使用&,获取工厂bean本身
        Object factoryBean = context.getBean("&dog");
        //不使用&,则获取工厂生产的bean
        Object dog = context.getBean("dog");

        System.out.println("dogFactoryBean:" + factoryBean);
        System.out.printf("dog:" + dog);
    }

输出结果:
在这里插入图片描述
从以上代码可以看出来,FactoryBean就是一个工厂,但其本身又是一个由IoC容器管理的bean,可以通过加&符号的方式获取其本身对象。

总结:其实IoC容器有两种类型的bean,一种是普通bean,就是我们经常使用bean,平时用到的controller、service、dao都是普通bean的一种。另外一种叫工厂bean,这种bean主要用来创建bean的。如果还是不能够理解,建议查看IoC源码AbstraceBeanFactory.getObjectForBeanInstance方法。可以了解其在spring中是如何被使用的。
详情请参考:getObjectForBeanInstance(instance,name,beanName,mbd)




结论

因此,当面试官问你,BeanFactory和FactoryBean的区别的时候,你可以这样子回答:
BeanFactory是IoC容器顶层的一个接口,该接口声明了一些IoC容器应该具备的基础功能,其主要负责对bean的创建,访问等工作。而FactoryBean是一种特殊的Bean,是一个抽象工厂,可以用来生产普通的bean对象(可以自定义其生产方式)。通过+&符号可以获取其对象本身。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值