2026/4/16 20:38:55
网站建设
项目流程
北京做网站哪家公司最好,wordpress 修改登录地址,免费大型网站,广州市照明建设管理中心网站今天#xff0c;代码又报错了。或者也许是昨天#xff0c;我不清楚。
不管怎样#xff0c;Spring 容器抛出了一个 BeanCreationException。为了解决它#xff0c;我被迫潜入框架的深处#xff0c;去注视那些平时被 Autowired 掩盖的齿轮。在 Spring 的世界里#xff0c;存…今天代码又报错了。或者也许是昨天我不清楚。不管怎样Spring 容器抛出了一个BeanCreationException。为了解决它我被迫潜入框架的深处去注视那些平时被Autowired掩盖的齿轮。在 Spring 的世界里存在着一种必然的复杂性。这种复杂性并非设计者的恶趣味而是为了在一个静态的语言中构建动态世界所付出的代价。在这个庞大的机器中有三个名字极其相似的概念经常被混淆BeanFactory、FactoryBean和ObjectFactory。这并不是命名的贫瘠而是它们在本质上确实存在着微妙的纠缠。今天我们剥离掉那些花哨的比喻和无用的糖衣用一种冷静的、近乎解剖学的视角去审视这三个概念的本质。一、BeanFactory存在的容器让我们首先纠正一个观念BeanFactory 名为工厂但其本质是容器Container。当我们谈论 Spring 容器时我们实际上是在谈论BeanFactory。它是 Spring IoC 容器的根接口是整个世界的物理法则。1.1 唯一的职责它的定义极其克制。它不关心业务逻辑只关心一件事管理对象的生命周期。public interface BeanFactory { Object getBean(String name) throws BeansException; T T getBean(String name, ClassT requiredType); boolean containsBean(String name); // ... }当你启动一个 Spring Boot 应用时ApplicationContext就像一个充满活力的城市而BeanFactory则是支撑这座城市的地下管网。所有的 BeanDefinition关于 Bean 应该如何创建的蓝图都注册在这里。1.2 残酷的现实在大多数情况下你不需要直接与BeanFactory对话。因为ApplicationContext已经为你封装好了一切。但当你试图理解为什么你的 Bean 没有被正确初始化或者为什么你的循环依赖失效时你就必须意识到你所有的 Bean都只是BeanFactory中的 entries条目。它是一个巨大的MapString, BeanDefinition和MapString, Object的管理者。它冷酷无情只按照定义的规则Scope, Lazy, Dependence来实例化对象。二、FactoryBean必要的欺骗如果说BeanFactory是宏观规则的制定者那么FactoryBean就是微观规则的潜行者。2.1 静态语言的困境想象这样一个场景你需要注入一个接口的实现但这个实现类并不存在于代码中它是通过动态代理在运行时生成的。这在 RPC 框架如 Dubbo、Feign和 ORM 框架如 MyBatis中极其常见。你无法通过简单的bean class...或Component来描述一个“不存在的类”。这时候你需要一个中间人。这个中间人表面上是一个普通的 Bean但实际上它是一个工厂。2.2 伪装的艺术以 MyBatis 为例为什么你只需要写一个UserMapper接口就能直接Autowired使用因为 Spring 容器里注册的那个 userMapper Bean根本不是你的接口实现而是一个MapperFactoryBean。// 简化的逻辑示意 public class MapperFactoryBeanT implements FactoryBeanT { private ClassT mapperInterface; Override public T getObject() throws Exception { // 往里跟进最终这里发生了魔法通过 JDK 动态代理生成接口的实 return (T) Proxy.newProxyInstance( mapperInterface.getClassLoader(), new Class[] { mapperInterface }, new MapperProxy() ); } Override public Class? getObjectType() { return mapperInterface; } Override public boolean isSingleton() { return true; } }2.3 这里的真相当容器调用getBean(userMapper)时它发现这是一个FactoryBean。于是它不会返回FactoryBean实例本身而是默默地调用getObject()并返回那个代理对象。这就是欺骗。你以为你拿到了一个 Bean其实你拿到的是 Bean 生产的产品。如果你渴望看到真相看到那个操纵傀儡的幕后黑手你需要在 Bean 名称前加上// 获取的是 MapperProxy 代理对象 Object product context.getBean(userMapper); // 获取的是 FactoryBean 工厂本身 Object factory context.getBean(userMapper);三、ObjectFactory时间的延迟BeanFactory负责掌控空间容器FactoryBean负责掌控构造逻辑而ObjectFactory则是为了掌控时间。3.1 循环的死结在 Spring 的世界里有一个经典的荒谬A 需要 BB 需要 A。如果是构造器注入只需坦然承认失败。但如果是 Setter 注入Spring 试图挽救这种死结。在 A 创建的过程中需要注入 B。B 创建时又需要注入 A。此时 A 还在创建中尚不是一个完整的 Bean。怎么办Spring 引入了三级缓存的概念。而第三级缓存存放的就是一个ObjectFactory。3.2 回调的本质ObjectFactory在源码中简单得令人发指FunctionalInterface public interface ObjectFactoryT { T getObject() throws BeansException; }它只是一个函数式接口一个回调。它存在的意义在于我现在不想要这个对象但我想要一个“在未来某个时刻能获取这个对象”的能力。在循环依赖中Spring 提前暴露了一个ObjectFactoryaddSingletonFactory(beanName, () - getEarlyBeanReference(beanName, mbd, bean));当 B 需要 A 时它通过这个ObjectFactory拿到了 A 的早期引用Early Reference。尽管 A 还没完全初始化好但 B 已经可以持有它的引用了。死结解开了。3.3 作用域的错位另一个场景是一个单例Singleton的 Service 需要使用一个 原型Prototype的 Bean。如果你直接Autowired原型的 Bean 只有在 Service 创建时被注入一次之后也就是永远同一个对象了。这违背了原型的初衷。如何解决使用ObjectFactory延迟获取。Service public class ReportService { Autowired private ObjectFactoryReportBuilder builderFactory; public void generate() { // 每次调用 getObject()容器都会创建一个全新的 ReportBuilder ReportBuilder builder builderFactory.getObject(); builder.build(); } }在这里ObjectFactory就像是一个通往容器的句柄让你随时可以伸手进去拿一个新的对象而不是守着陈旧的缓存。四、审判与裁决让我们在最后用最客观的表格来审判这三者的区别。这不是为了背诵而是为了理清混乱。维度BeanFactoryFactoryBeanObjectFactory存在形式容器(Container)Bean(Component)接口(Interface/Callback)底层逻辑ApplicationContext的父级接口 /宏观工厂实现了FactoryBean接口的类 /微观工厂函数式接口 /延迟回调核心职责管理所有 Bean 的生命周期此 Bean 负责生产另一个复杂的 Bean封装对象的创建过程提供延迟获取能力获取方式ApplicationContext是它的超集getBean(name)拿产品getBean(name)拿工厂注入ObjectFactoryT后调用getObject()真实场景Spring 框架的基石MybatisMapperFactoryBean,ProxyFactoryBean解决循环依赖(三级缓存), Scope(原型模式)适配五、结语在代码的荒原上我们通过构建抽象来对抗混乱。BeanFactory是我们脚下的大地。它被称为工厂但它实际是孕育万物的土壤容器。FactoryBean是我们手中的精密机床。它是一个特殊的 Bean存在的目的却是为了制造另一个 Bean。ObjectFactory是我们预留的时间胶囊。它只是一个单纯的接口为了应对循环与未来的不确定性。理解它们并不是为了通过面试而是为了在下一次抛出异常时你能冷静地凝视堆栈信息知道机器的哪个齿轮发生了错位。既然我们选择了与机器共舞就必须理解机器的逻辑。这或许就是作为开发者的西西弗斯式命运——我们需要一次又一次地将巨石推向山顶以此证明我们对这个庞大系统的掌控。本文通过 AI 润色加缪风格试图以一种冷静、客观甚至存在主义的视角去解构这些在日常 Coding 中被我们习以为常的概念。希望这种独特的叙事风格能让你对这些枯燥的技术概念有更深刻的“存在感”。