BeanFactory与FactoryBean终极解析:Spring IoC核心区别与源码原理
“BeanFactory和FactoryBean这两个名字到底是不是一个东西”这个问题我前前后后听过不下几十遍不管是刚转行的小白还是写过三五年Java的老手第一次被问到时多少都会愣一下。更别说有些面试官喜欢把它当成连环炮的第一发后面接着就是“Bean的生命周期有哪些阶段”“Spring如何解决循环依赖”这类深水区问题。这篇文章我打算一次性把这两个概念彻底掰开揉碎。不光是背面试答案而是从名字、接口设计、源码调用链到实际开发里的坑一层层拆给你看。读完之后你不仅能答出“一个管Bean一个造Bean”还能顺手讲清楚前缀、getObject()缓存、以及为什么Spring要设计出这么个“Bean中的特种Bean”来。无论你是在准备面试还是想彻底搞懂IoC容器的底层逻辑这篇都值得看完。1. 先拆名字BeanFactory和FactoryBean顺序一换角色完全对调1.1 英文断句字面理解最关键很多人搞混就是因为没注意到英文单词的顺序。BeanFactoryBean Factory意思是“Bean的工厂”核心词是Factory工厂。它描述的是一种能生产、管理、维护Bean对象的东西。FactoryBeanFactory Bean意思是“工厂Bean”核心词是Bean。它本身是一个Bean只不过这个Bean的特殊之处在于它还能充当“工厂”去生产别的对象。一句话先记住BeanFactory是农民合作社的管理系统管着所有田地和庄稼FactoryBean是地里的一台特殊播种机它既能被合作社当成一台设备来管理又能在需要的时候自己播出一片庄稼来。这个类比放代码里就是说BeanFactory是Spring IoC容器的顶层抽象接口整个容器的核心功能都由它定义。FactoryBean也是一个接口实现它的类注册到容器后会变成一个“生产者”你从容器里拿到的并不是它自己而是它生产出来的对象。名字上的误会解决了接下来看各自在Spring里的真实身份。1.2 一句话先记住两者的定位差异在Spring容器中所有被容器管理的东西都叫Bean注册的是普通类就生成普通对象注册的是FactoryBean实现类那它就是一个对象工厂。BeanFactory是整个容器框架的“管理者”而FactoryBean是容器内部的一种“特殊员工”。所以当你面试回答时说“BeanFactory就是Spring容器”这句话是对的又补充“FactoryBean也是容器里的一个Bean只是它会创建别的对象”这也是对的。两者一个是宏观基础一个是微观特例。我见过不少人在这一层就卡住了经常会反问“既然BeanFactory管所有Bean那在BeanFactory眼里FactoryBean是什么”答案很简单FactoryBean本身也是一个Bean。它也要遵循Bean的生命周期也要被实例化、初始化、依赖注入只不过容器在对外返回时额外做了一层“抽产品”的动作。2. BeanFactory的真相整个Spring IoC容器的“地基接口”2.1 BeanFactory接口到底定义了些什么org.springframework.beans.factory.BeanFactory是Spring IoC容器最顶层的接口。它的代码不长但每一行都是核心我直接贴简化后的核心方法public interface BeanFactory { String FACTORY_BEAN_PREFIX ; Object getBean(String name) throws BeansException; T T getBean(String name, ClassT requiredType) throws BeansException; T T getBean(ClassT requiredType) throws BeansException; boolean containsBean(String name); boolean isSingleton(String name) throws NoSuchBeanDefinitionException; boolean isPrototype(String name) throws NoSuchBeanDefinitionException; boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException; Class? getType(String name) throws NoSuchBeanDefinitionException; String[] getAliases(String name); }注意第一行有一个常量String FACTORY_BEAN_PREFIX ;这个符号是后面理解FactoryBean的关键先记住它。BeanFactory作为顶层接口它规定的是“一个IoC容器必须能干什么”。它不关心你的Bean定义是从XML来的还是从注解来的也不关心你是按名字查找还是按类型查找。它只定了规矩容器必须能根据名字拿Bean、判断类型、判断作用域、获取别名。所有具体能力都由下层实现类去扩展。2.2 ApplicationContext和BeanFactory是什么关系这里有个非常重要的关系面试经常顺带问ApplicationContext接口继承自ListableBeanFactory和HierarchicalBeanFactory而这两个接口又都继承自BeanFactory。所以完全可以说ApplicationContext是一个增强版的BeanFactory。它除了具备BeanFactory的所有能力外还增加了国际化支持MessageSource事件发布与监听ApplicationEventPublisher资源加载ResourcePatternResolver环境信息封装EnvironmentCapable自动注册BeanPostProcessor和BeanFactoryPostProcessor更完善的AOP集成环境平时我们写SpringBoot项目直接注入的ApplicationContext本质上就是一个功能更丰富的容器实现。但在面试里如果面试官单独问“BeanFactory”你要知道他在问的是最小容器抽象而不是你的IoC工具类。2.3 面试官为什么执着于问BeanFactory因为BeanFactory是整个IoC的基石。问BeanFactory其实是在问你你知道Bean从定义到销毁的完整流程吗你清楚依赖注入发生在哪一步吗你了解scope与循环依赖之间怎么处理吗你能区分容器和Bean生命周期的边界吗只要你说得清BeanFactory的核心职责面试官就能判断你对Spring的理解深度。反过来如果你把BeanFactory和FactoryBean当成一回事那基本上后面关于容器的题都会答得含糊。2.4 我踩过的一个认知误区早期我总觉得BeanFactory离我们很远直到有一次排查问题看到某段代码里直接调用getBean(userService)我心想这有什么好调的后来发现那个userService其实是一个FactoryBean实现类结果getBean返回的不是UserService类型的工厂而是产品对象。那一刻才意识到我们平时通过Autowired和Resource拿到的对象背后的获取路径全都要过BeanFactory的getBean方法而getBean内部必须判断“这个Bean是不是FactoryBean”。所以BeanFactory不是和FactoryBean八竿子打不着恰恰相反FactoryBean必须依托BeanFactory才能发挥作用。3. FactoryBean的套路当一个Bean变成“工厂”3.1 FactoryBean接口的三个方法org.springframework.beans.factory.FactoryBean也是一个接口代码更短public interface FactoryBeanT { T getObject() throws Exception; Class? getObjectType(); default boolean isSingleton() { return true; } }三个方法各司其职getObject()返回由FactoryBean生产的对象实例。也就是说容器最终对外暴露的产品对象是getObject()的返回值。getObjectType()返回生产出来的对象类型用于容器在无法获得实例时判断类型是否匹配。isSingleton()返回产品是否为单例。默认是true如果返回false每次getBean都会调用一次getObject()得到一个新产品。从接口上看FactoryBean的设计目标非常清晰把对象的创建过程单独封装到一个Bean中由这个Bean去完成那些“不适合写在构造方法里的初始化逻辑”比如动态代理、连接池预热、复杂配置加载等。3.2 Spring是怎么处理FactoryBean的当一个Bean的实例是FactoryBean时容器不会直接把该实例返回给调用方而是会做一次判断调用getBean(beanName)时先根据名称找到对应的Bean实例。检查这个实例是不是FactoryBean类型。如果是就进入getObjectForBeanInstance逻辑。在这个逻辑中若请求的名字不带前缀则调用FactoryBean.getObject()把产物返回。若请求的名字带前缀则直接把FactoryBean实例本身返回。用代码模拟这个判断逻辑非常简单Object bean getBeanFromContainer(beanName); if (bean instanceof FactoryBean) { if (beanName.startsWith()) { return bean; // 返回工厂本身 } return ((FactoryBean?) bean).getObject(); // 返回产品 } return bean; // 普通Bean直接返回这就是为什么有时候你在调试时明明getBean一个Class类型返回的对象却跟你注册的Bean类对不上。因为注册的那个类实现了FactoryBean接口getBean拿到的其实是getObject()生产的东西。3.3 “”符号到底怎么用深入源码看一眼回到BeanFactory接口里那个常量String FACTORY_BEAN_PREFIX ;源码注释里明确写着获取FactoryBean本身时需要在beanName前加。举一个实际例子。假设我在配置类中注册了这样一个BeanComponent public class UserFactory implements FactoryBeanUser { Override public User getObject() throws Exception { return new User(张三); } Override public Class? getObjectType() { return User.class; } }如果直接getBean(userFactory)容器调用链会走到getObject()返回一个User对象而不是UserFactory实例。但如果getBean(userFactory)返回的就是UserFactory实例本身。这里有一个非常细节的点容器在doGetBean方法中会先把去掉找出真正的beanName去定位BeanDefinition然后再根据原始的带的name决定返回工厂还是产品。这也是为什么MapString, Object里如果通过beanName遍历还是会看到不带的名字而手动显示name却也能查得到。3.4 产品对象的缓存机制Spring对FactoryBean生产的产品对象有一套单独的缓存放在FactoryBeanRegistrySupport中字段叫factoryBeanObjectCache。在单例模式下getObject()只会被调用一次之后产品对象会被缓存起来。后续所有getBean(userFactory)都从缓存直接拿产品不会再让工厂重复创建。但如果isSingleton()返回false产品不放进缓存每次获取都会重新执行getObject()。源码里对应的方法大概是protected Object getObjectFromFactoryBean(FactoryBean? factory, String beanName, boolean shouldPostProcess) { if (factory.isSingleton() containsSingleton(beanName)) { synchronized (getSingletonMutex()) { Object object this.factoryBeanObjectCache.get(beanName); if (object null) { object doGetObjectFromFactoryBean(factory, beanName); this.factoryBeanObjectCache.put(beanName, object); } return object; } } else { return doGetObjectFromFactoryBean(factory, beanName); } }这个缓存机制和普通Bean的单例缓存singletonObjects是两套搞清楚这一点面试时能加分很多。但也不要死记代码理解逻辑即可产品对象是通过工厂现造的造完之后单独留一个货架存放。4. 核心区别一张表看懂BeanFactory和FactoryBean4.1 直接上对比表对比维度BeanFactoryFactoryBean翻译Bean的工厂工厂Bean接口定位IoC容器顶层接口一种特殊Bean规范存在的意义管理所有Bean的生命周期与依赖专门负责生产某个/某类复杂对象与容器关系它就是容器本身它是容器管理的一个BeangetBean返回值返回Bean实例默认返回getObject()产物加前缀返回工厂本身方法数十来个全局方法三个方法getObject, getObjectType, isSingleton是否可被容器注册不注册它是容器本身可以注册class为FactoryBean实现类产品缓存普通Bean缓存在singletonObjects产品对象缓存在factoryBeanObjectCache自定义复杂初始化不提供这种钩子通过在getObject()内自定义实现典型代表XmlBeanFactory, DefaultListableBeanFactorySpring内部的一些集成工厂Bean这张表是面试回答的“速查卡”建议收藏。4.2 说说它们之间那条隐藏的联系有人会误以为这两个接口没有任何关系这不对。FactoryBean本身作为一个Bean也必须服从BeanFactory的生命周期管理。FactoryBean这个类在成为“工厂”前先要被容器实例化、初始化和依赖注入。如果FactoryBean实现了InitializingBean、BeanNameAware、ApplicationContextAware等接口容器同样会执行对应的回调。也就是说BeanFactory负责“管”。FactoryBean负责“生”。但FactoryBean的“生”也发生在FactoryBean被“管”之后。所以完整的创建顺序是容器先创建FactoryBean实例然后当你首次getBean产品时容器调用FactoryBean的getObject方法生成产品对象并把产品对象按单例或原型的规则管理起来。4.3 实战场景举例为什么需要FactoryBean实际项目里最常用到FactoryBean的场景大概有这么几类创建需要动态代理的对象比如AOP代理创建、事务代理创建没法用new直接完成需要通过代理工厂动态生成。创建需要复杂环境准备的对象比如数据库连接、消息客户端、带连接池的组件初始化时要读取配置、建立连接、准备资源。创建需要循环依赖周旋的对象有些对象彼此依赖利用FactoryBean可以把第二层对象的生产延迟到getObject时执行。创建集成第三方框架的对象很多ORM、RPC框架为了将核心对象交给Spring管理内部都会实现对应的FactoryBean。举一个贴近生活的例子假设你要在Spring里注册一个“分布式缓存客户端”这个客户端的创建需要先从配置中心拉取配置、建立连接、做心跳检测最后返回一个可用的客户端实例。如果你在Bean方法里手动写这些初始化代码代码会很臃肿而且不好复用。但把这些逻辑移到getObject()里然后用一个FactoryBean去承载每次获取都通过统一入口拿到创建好的客户端就清晰很多。当然如果你只用过Bean注解可能觉得“Bean也能干这事啊”。确实Bean是更简单的选择但FactoryBean有它独特的价值它更底层、更标准而且能通过前缀来获取工厂本身这在做框架集成、需要暴露底层工厂能力时很有用。5. 源码链路当调用getBean时容器背地里做了哪些事5.1 从doGetBean开始分析假设容器类型是DefaultListableBeanFactory你执行Object obj beanFactory.getBean(userFactory);真正的入口逻辑在AbstractBeanFactory.doGetBean里。我先贴简化版的伪代码protected T T doGetBean(String name, ClassT requiredType, Object[] args, boolean typeCheckOnly) { String beanName transformedBeanName(name); Object bean getSingleton(beanName); if (bean null) { // 创建Bean或者从父容器查找 } return (T) getObjectForBeanInstance(bean, name, beanName, mbd); }注意这一段里有两个细节transformedBeanName(name)会把前缀去掉转换成真正的beanName。getObjectForBeanInstance会重新判断原始传入的name是否带来决定返回产物还是工厂本身。5.2 getObjectForBeanInstance的判断逻辑getObjectForBeanInstance核心逻辑大致是protected Object getObjectForBeanInstance(Object beanInstance, String name, String beanName, RootBeanDefinition mbd) { // 如果 name 以 开头代表调用方想要工厂本身 if (BeanFactoryUtils.isFactoryDereference(name)) { return beanInstance; } // 如果 beanInstance 不是 FactoryBean直接返回 if (!(beanInstance instanceof FactoryBean)) { return beanInstance; } // 走到这里说明beanInstance是FactoryBean且调用方想要产品对象 FactoryBean? factory (FactoryBean?) beanInstance; return getObjectFromFactoryBean(factory, beanName, !mbd.isSynthetic()); }这里的BeanFactoryUtils.isFactoryDereference(name)判断的就是name是否以开头。所以关键点有两个带直接原样返回工厂Bean实例。不带进入生产流程。平时我们用Autowired注入时基本不会去考虑前缀因为类型匹配过程会自动选择产品对象。但当你用getBean(xxx)硬编码时就必须搞清楚这一点。5.3 getObjectFromFactoryBean里的后处理继续深入getObjectFromFactoryBean并不是拿到getObject()结果就完事了。它还会执行一段非常有价值的工作如果产品对象是单例并且容器里配置了BeanPostProcessor那么产品对象也会被后处理器加工一遍。简化的逻辑是if (shouldPostProcess) { object postProcessObjectFromFactoryBean(object, beanName); }这意味着FactoryBean生产出来的对象同样能统一享受AOP代理、属性填充等后处理能力。这也是理解Spring“所有Bean都经过BeanPostProcessor”的关键虽然产品对象不是普通Bean但它还是要走加工管线。不过这里有个很容易混淆的细节一个普通Bean的实例化过程包括属性填充、初始化回调等而FactoryBean产品的创建绕开了普通Bean的实例化流程直接调用getObject。产品是否执行PostConstruct之类的方法取决于getObject内部是否自行调用。这点我在实际排查代理失效问题时踩过坑后面再细说。5.4 面试如何用源码链路作答如果你在面试时能把这条链路说出来面试官基本就放心了“当调用getBean时容器先通过transformedBeanName去掉前缀拿到真正的beanName去定位BeanDefinition创建或者获取Bean实例。接下来getObjectForBeanInstance会判断如果原始name带直接返回这个Bean实例本体如果不带再判断Bean实例是否属于FactoryBean。如果是就调FactoryBean的getObject方法并且单例下会缓存到factoryBeanObjectCache。这样一来返回给调用方的是产品对象而FactoryBean本身通过带的名字获取。”这段描述虽然只有几句话但包含transformedBeanName、FactoryBeanRegistrySupport、factoryBeanObjectCache、产品后处理等细节属于面试加分项。6. 面试应答模板从30秒速答到3分钟完整版6.1 30秒版本适合开场快速作答“BeanFactory是Spring IoC容器最顶层的抽象接口定义了一整套管理Bean的方法比如getBean、containsBean、getType。FactoryBean是Spring提供的一个特殊接口如果一个类实现了FactoryBean注册到容器后容器对外返回的是这个类中getObject()方法生成的对象而不是它自己。如果要获取FactoryBean本身使用带前缀的名称。”这个回答能拿到及格分但没体现源码深度。别急接着看进阶版。6.2 3分钟版本适合面试官深挖在30秒版本的基础上再补上这些内容“FactoryBean一共有三个方法getObject、getObjectType、isSingleton。默认Singleton为true也就是默认情况下一个FactoryBean生产的产品单例缓存getObject只会被调用一次。”“Spring在BeanFactory中定义了一个常量FACTORY_BEAN_PREFIX值为用于在getBean时区分获取的是工厂本身还是产品。”“在源码doGetBean方法中会先transformedBeanName去掉前缀定位到真正的Bean定义。然后getObjectForBeanInstance方法判断如果原始name以开头直接返回工厂实例如果Bean实例是FactoryBean则调getObjectFromFactoryBean生产产品并把产品放入factoryBeanObjectCache。”“FactoryBean主要用于需要复杂初始化、代理生成、第三方集成等场景。它本身也是一个Bean它的生命周期也由BeanFactory管理。”“FactoryBean产品的创建不经过普通Bean的实例化流程但是产品如果是单例同样会被BeanPostProcessor后处理加工。”把这段话流畅说出来面试官基本不会继续为难你。6.3 连环追问这样接招面试官听完上面的回答通常会继续追问下面这几个问题问题1如果isSingleton返回false会怎样回答每次getBean获取产品时都会重新调用getObject()方法产品对象不会被缓存。如果产品对象本身是重量级资源开销会很大所以一般保持默认的true。问题2如果FactoryBean本身是Prototype产品是Singleton合理吗合理。FactoryBean和产品是两回事。FactoryBean的作用域决定的是工厂实例本身每次获取是否新建而产品是否单例由FactoryBean.isSingleton决定。你可以配置一个原型的FactoryBean但它的产品是单例这种情况下getBean(“beanName”)得到的都是同一个产品但getBean(“beanName”)每次拿到的工厂是不同实例。问题3既然Bean也能创建复杂对象那FactoryBean是不是多余回答二者不在同一层。Bean是Spring容器的配置方式本质上它也是通过BeanFactory来管理。FactoryBean是更低层次的扩展点它提供了一种可以复用的对象工厂抽象并支持前缀获取工厂本身。如果只是简单创建一个BeanBean完全够用但如果要做框架级集成、需要暴露工厂对象FactoryBean更合适。问题4我的BeanFactory.getBean(xxx)返回了工厂对象而不是产品为什么这种情况通常是因为你使用的不是beanName而是通过某些特殊方式获取到了FactoryBean实例本身。正常getBean不带前缀是取不到工厂的除非你的xxx根本不是FactoryBean注册名。换句话说这条编码路径不会犯这种错误但自己通过依赖注入FactoryBean类型时可能拿到工厂比如通过Autowired注入FactoryBean类型的字段。这里一定要注意用Autowired注入FactoryBean类型时由于按类型匹配是有可能匹配到FactoryBean实例的。但是这种写法不够清晰容易让别人困惑。真需要工厂对象建议用Resource(name xxx)或者直接getBean(xxx)。6.4 一个万能结尾话术最后可以用一句高度概括的话收尾“BeanFactory是Spring容器的心脏Whole系统都围绕它运转FactoryBean是心脏里的一颗特殊细胞用工厂模式的思想把对象创建过程封装成Bean。一个负责管一个负责生两者配合让Spring既能掌控所有Bean的生命周期又保留了高度灵活的对象创建能力。”这句有点文绉绉但面试现场用上效果不错。7. 实战手写Demo自己动手验证一次7.1 定义产品和工厂我们先写一个简单的产品类模拟一个需要复杂初始化的对象public class SpecialConnection { private String url; public SpecialConnection(String url) { this.url url; } public void connect() { System.out.println(连接 url 成功); } }然后定义一个FactoryBean实现类模拟复杂创建过程Component(specialConnectionFactory) public class SpecialConnectionFactory implements FactoryBeanSpecialConnection { Override public SpecialConnection getObject() throws Exception { // 模拟读取配置、初始化连接池等耗时操作 System.out.println(getObject() 被调用了开始创建特殊连接对象...); Thread.sleep(1000); return new SpecialConnection(jdbc:demo://localhost:3306/test); } Override public Class? getObjectType() { return SpecialConnection.class; } Override public boolean isSingleton() { return true; } }7.2 编写测试代码在一个SpringBoot启动类或者任意能用ApplicationContext的场景下测试SpringBootApplication public class DemoApplication implements ApplicationRunner { Autowired private ApplicationContext context; Override public void run(ApplicationArguments args) { // 获取产品对象 SpecialConnection conn context.getBean(specialConnectionFactory, SpecialConnection.class); System.out.println(拿到产品类型: conn.getClass()); // 再次获取验证getObject是否只调用一次 SpecialConnection conn2 context.getBean(specialConnectionFactory, SpecialConnection.class); System.out.println(两次产品是否同一个: (conn conn2)); // 获取工厂本身 SpecialConnectionFactory factory (SpecialConnectionFactory) context.getBean(specialConnectionFactory); System.out.println(工厂类型: factory.getClass()); } }输出结果预期是getObject() 被调用了开始创建特殊连接对象... 拿到产品类型: class com.example.SpecialConnection 两次产品是否同一个: true 工厂类型: class com.example.SpecialConnectionFactory注意第一行“getObject()被调用”只打印了一次因为isSingleton返回true产品被缓存了。第二次getBean直接返回缓存对象没有重新调getObject。而最后一次用前缀拿到了工厂本身没有触发getObject。7.3 把isSingleton改成false再试一次如果你把isSingleton()返回false再次运行会看到getObject() 被调用了开始创建特殊连接对象... getObject() 被调用了开始创建特殊连接对象... 拿到产品类型: class com.example.SpecialConnection 两次产品是否同一个: false打印了两次getObject并且两次拿到的连接对象不是同一个。这就验证了isSingleton对产品缓存的影响。7.4 用Spring容器对象再确认一下getType的行为还有一个小细节非常有迷惑性context.getType(specialConnectionFactory)返回的不是SpecialConnectionFactory类型而是产品类型SpecialConnection。这是因为容器在getType底层遇到了FactoryBean会优先返回getObjectType()的结果这不是bug而是设计如此。7.5 写代码的几个小提示我建议你自己动手跑一遍这个Demo。纸上谈兵永远记不牢只有亲手看到控制台输出你才真正明白“getBean返回的是产品而不是工厂”这句话的分量。8. 实际开发中FactoryBean的三个坑与排查手法8.1 坑一产品对象没有被Spring代理这是我曾经踩得最深的坑。当时写了一个FactoryBeangetObject返回一个Service实现类但返回的Service没有被事务代理。后来排查发现FactoryBean产品对象虽然会被BeanPostProcessor后处理但如果你在FactoryBean内部直接new了对象并且这个对象的类不是通过Spring上下文注册那后处理可能不会生效到预期的切面上。正确的做法是让FactoryBean依赖容器或者在后处理前把对象先包裹成代理。说白了FactoryBean并不是万能的。如果你需要在产品上叠加Spring的AOP、事务等能力要在getObject()内部就完成代理的创建或者在FactoryBean返回前利用ProxyFactory生成代理对象而不是指望Spring事后自动帮你代理一切。8.2 坑二产品对象的销毁没被处理FactoryBean的destroy()方法销毁的是工厂实例而不是产品对象。如果你的产品对象持有连接、文件句柄等资源容器关闭时不一定能通过FactoryBean的销毁方法关闭。最好在产品类上实现DisposableBean接口或者在产品类中声明destroy-method由Spring按普通Bean的销毁流程处理。Spring对产品对象的销毁处理是有的但细节很多人不清楚产品被缓存后Spring会尝试把它注册为可销毁Bean。只要产品本身实现了DisposableBean容器关闭时会自动调用其destroy()。如果产品只是一个普通类没有实现任何销毁接口那很可能会产生资源泄漏。8.3 坑三用Autowired注入FactoryBean时容易困惑某些场景下你真正想注入的是FactoryBean本身但Autowired按类型自动匹配时可能会因为类型匹配到产品类型而注入失败或者匹配到FactoryBean。这种“凭直觉写代码”导致的困惑很常见。我的建议是当某个Bean是FactoryBean时不要直接注入它的产品类型来猜。要么显式注入FactoryBean类型要么用Resource(name beanName)或者在代码里通过ApplicationContext.getBean(beanName)获取。虽然前缀写法不够优雅但它语义清晰一眼就能看出来是工厂而不是产品。8.4 排查技巧如何快速判断当前Bean是不是FactoryBean第一种看Bean类声明是否实现了FactoryBean接口。最简单。第二种用context.getBean(beanName)如果返回的类型是你自定义的类说明它就是FactoryBean。第三种查看日志或者Debug时对getBean返回对象打印getClass()和Bean定义里的类对比不一致就说明存在FactoryBean生产逻辑。第四种利用IDE的显示Spring插件通常会在Bean列表里标出FactoryBean。9. 给准备面试的人一点私房建议最后我想说的是BeanFactory和FactoryBean这对概念本质上就是在考察两个思维层次宏观管理能力和微观扩展能力。很多人在简历上写“精通Spring”但如果连这两个接口都分不清楚那基本是站不住脚的。反过来如果能把这对概念讲透面试官会觉得你的源码阅读能力是过关的因为你已经摸到了IoC容器的地基。我个人的习惯是先理解“容器管理Bean”这条主线再理解“FactoryBean是Bean的特殊形态”。主线抓住了分支就不容易迷路。如果你正在准备面试建议把本文提到的源码简化链路自己画一遍然后用自己的话复述一遍。能做到不用笔记、对着白板自然讲出来这道题基本就稳了。另外一个特别实用的扩展点把这道题和循环依赖、BeanPostProcessor连接起来一起复习。因为Spring容器的核心工作就是创建、加工、缓存Bean。BeanFactory负责入口FactoryBean负责特殊生产BeanPostProcessor负责统一加工三者串起来你对IoC容器的理解会上一整个台阶。希望这篇长文能帮你在下一场面试里少踩一个坑多拿一分印象分。有问题欢迎在评论区交流我会挑典型的再做一期拆解。