吊打面试官系列:BeanFactory和FactoryBean的区别

关注我的公众号:【编程朝花夕拾】,可获取首发内容。

01 引言

面试造火箭,入职拧螺丝。这是候选人的进入职场的切身感受。坦白来讲,日常业务开发中根本没有什么用。但是如果涉及架构、脚手架、开发封装或者源码理解,却是大有用处。

面试的目的不是刁难,而是了解候选人的技术深度和广度。

今天,我们来看一个高频面试题:BeanFactory和FactoryBean的区别。

02 考察点

该面试题主要考察了候选人对Spring源码的理解程度。

BeanFactory和FactoryBean是Spring中非常重要的两个接口。其中FactoryBean更是对Bean创建的一个扩展点,独立控制Bean的创建过程,并由Spring容器管理。

BeanFactory和FactoryBean也非常容易混淆,名称相似但功能完全不同。

03 BeanFactory

BeanFactory的本质是一个Bean工厂,是整个Spring中IOC容器的一个接口,负责管理Bean的创建和生命周期。

其中ApplicationContext又是对BeanFactory功能的扩展,如增加AOP、事件等。

3.1 源码分析

先来看看源码中的主要功能:

源码中功能主要是用来获取Bean对象,判断Bean对象的属性。

而之前我们演示过Spring的IOC容器的一个实现类就是AnnotationConfigApplicationContext,来看看简单的继承关系:

3.2 案例分析

这是一个非常典型的使用Spring容器获取Bean对象的案例。因为ApplicationContext继承BeanFactory,并且这里使用了BeanFactory中的方法,所以这里完全可以使用BeanFactory接收。

而在实际的业务项目中,我们通常会使用Spring的扩展接接口ApplicationContextAware,获取到ApplicationContext容器,然后再操作容器中的Bean对象。

java 复制代码
@Component
public final class SpringUtil implements ApplicationContextAware, DisposableBean {

    /**
     * ApplicationContext
     */
    private static ApplicationContext applicationContext;

    public void setApplicationContext(ApplicationContext applicationContext) {
        SpringUtil.applicationContext = applicationContext;
    }
    
    // ......
}

04 FactoryBean

FactoryBean同样是一个接口,用来定义一个工厂Bean,他可以产生某种类型的对象。他生产的Bean仍然被Spring容器管理。也就是说通过BeanFactory的getBean()获取到的。

当Spring启动时,发现一个Bean实现了FactoryBean接口,Spring就不会直接返回这个Bean示例,而是通过FactoryBean#getObject()来返回对象。

4.1 源码

源码非常简单,就3个方法。分别用来获取Bean、Bean类型以及是否单例。

4.2 案例分析

先定义一个UserServiceFactoryBean专门用来生产userService。

java 复制代码
@Component
public class UserServiceFactoryBean implements FactoryBean {
    @Override
    public Object getObject() throws Exception {
        return new UserService();
    }

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

    @Override
    public boolean isSingleton() {
        return true;
    }
}

在容器中获取userService对象:

java 复制代码
@Test
void test() {
    ApplicationContext context = new AnnotationConfigApplicationContext("com.simonking.boot.aop");
    UserService contextBean = (UserService)context.getBean("userServiceFactoryBean");
    contextBean.test();
}

结果就可以获取到UserService对象了。

但是会发现一个问题:

UserServiceFactoryBean上的注解默认的BeanName是userServiceFactoryBean,而在容器中取BeanName为userServiceFactoryBean的时候返回的Bean又是UserService。

这就是开始说的:FactoryBean不直接返回Bean而是通过getObject返回的

isSingleton 如果设为false会怎样?

从容器中获取两次对象返回的Bean是不同的内存地址:

那如何获取对象本身呢?

只需要Bean的名称前加&即可,且内部的方法不影响对象本身:

05 小结

简单总结一下:

BeanFactory由Spring框架实现,负责管理和创建很多Bean,通常不需要开发者自行实现;而FactoryBean到底是一个Bean对象,允许开发者定制化Bean的创建流程,最终还要被BeanFactory管理。

相关推荐
独泪了无痕3 小时前
Spring Data Redis 快速上手
spring boot·redis·后端
考研保研资料分享5 小时前
211公共管理保研北航行政管理:五校考核、论文追问与择校复盘
面试
考研保研资料分享5 小时前
985工科跨保上财应用统计:数学笔试、匿名面试与机试复盘
面试·职场和发展
wangchunyu1145 小时前
JAVA CompletableFuture异步编程实战
java·开发语言·python
paopaokaka_luck6 小时前
流浪动物救助与收养系统(DeepSeek AI对话、 ECharts多维分析、救助流程衔接、领养与回访衔接、 捐赠确认与公示、志愿者协作)
java·前端·javascript·人工智能·mysql·echarts·推荐算法
Thomas.Sir6 小时前
第9课:SpringBoot4.x Web开发基础:WebMvc自动配置、静态资源、请求参数接收
java·spring boot
程序 代码狂人6 小时前
切片表与分区表的区别(数据开发面试版)
java·大数据·开发语言·数据仓库·算法
m0_639906947 小时前
Linux 操作系统入门:目录结构、服务排查常用命令、Shell 脚本基础
linux·运维·后端
2501_944521597 小时前
Deepmerge 跨端三方库仓颉适配全流程
java·python·eclipse·github
Aurora118 小时前
Jane Street OA 真题解析:Mastermind 猜密码与候选集筛选
面试