Spring工厂模式全解析:从BeanFactory到FactoryBean的实战指南
1. 从Java到Spring工厂模式的前世今生很多同学在学Spring的时候都卡在“工厂模式”这一步。学之前觉得它就是个简单的创建对象的方式而已学完之后发现到处都有它的影子——BeanFactory、ApplicationContext、FactoryBean还有个叫ObjectFactory的东西名字长得差不多作用又各不相同。今天这篇笔记我尽量把自己的理解一条条捋清楚不绕弯子也不硬凹专业术语只讲这东西在Spring里到底是怎么“生存”的。先给没接触过工厂模式的读者一个直观概念假设你是个顾客去一家餐厅吃饭。你不需要关心厨师怎么备菜、灶台怎么开火、佐料怎么放你只需要看菜单点菜服务员会把做好的成品端上来。在这个类比里餐厅就是“工厂”服务员就是“工厂方法”你点菜的过程就是“调用工厂接口”端上来的菜就是“实例对象”。你从始至终不知道厨师是谁、后厨长什么样也完全不需要知道。这其实就是工厂模式的核心——调用者与创建者解耦。引入到Java里如果你的代码里到处都是new Something()那么一旦某个类的构造方法签名变了或者它的创建逻辑复杂了你就得满世界去改调用点。工厂模式就是把这些“创建细节”集中收编到一个地方统一管辖。Spring框架本身就是工厂模式最极致的应用。我们平常写的ApplicationContext context new ClassPathXmlApplicationContext(beans.xml)这个ApplicationContext的底层就是一个超级工厂。它不是帮你造一杯咖啡而是帮你创建和管理一组完整的、互相依赖的对象我们称之为Bean。这背后是“控制反转”的思想——对象不再自己去new依赖的对象而是由Spring容器这个“大工厂”统一装配、注入。那这篇笔记会覆盖些什么东西呢首先是工厂模式的基本形态简单工厂、工厂方法、抽象工厂然后重点看Spring里的BeanFactory和ApplicationContext这两个核心接口怎么实现工厂思想接着讲FactoryBean——这是很多人容易和BeanFactory搞混的兄弟概念再聊聊ObjectFactory和Provider在解决依赖延迟时的实战用法最后结合代码案例把工厂模式在Spring配置层面的使用串起来。无论是初学者还是写了一段时间Spring但概念模糊的同学这篇文章都能帮你把这块知识补齐。2. 三个经典工厂模式版本你真的搞懂区别了吗2.1 简单工厂一个“大管家”统筹创建先从最基础的说起。假设要创建不同类型的数据库连接池有DruidPool、HikariPool、C3P0Pool它们都实现了同一个接口ConnectionPool。最常见的写法是这样public class PoolFactory { public static ConnectionPool create(String type) { if (druid.equals(type)) { return new DruidPool(); } else if (hikari.equals(type)) { return new HikariPool(); } else if (c3p0.equals(type)) { return new C3P0Pool(); } throw new IllegalArgumentException(Unknown pool type: type); } }这种形态就叫简单工厂它的关键特征是把创建逻辑集中在一个静态方法里客户端只需要传一个type参数拿到对应的对象。看起来很方便但它的缺点也很明显每新增一种池类型就必须修改PoolFactory里的if-else分支。这违反了“开闭原则”对扩展开放、对修改关闭。在生产环境中频繁改既有代码意味着回归测试面变大出问题的概率也随之上升。不过应用场景里也不是完全不能用。如果产品线的类型比较稳定短时间内不会频繁扩容简单工厂反而最直观最省事。像一些内部小工具类用简单工厂完全没问题追求过度设计反而适得其反。2.2 工厂方法把创建动作下放给子类既然简单工厂只是把If-else搬了个家那工厂方法模式更进一步——每个具体产品对应一个具体的工厂类大家继承同一个抽象工厂接口。public interface PoolFactory { ConnectionPool create(); } public class DruidPoolFactory implements PoolFactory { Override public ConnectionPool create() { return new DruidPool(); } } public class HikariPoolFactory implements PoolFactory { Override public ConnectionPool create() { return new HikariPool(); } }调用方持有的类型是PoolFactory具体的实现是DruidPoolFactory还是HikariPoolFactory可以在运行时结合配置或参数去决定。对比简单工厂它的优势在于新增类型时不需要修改已有代码只需要新增一个工厂子类和对应的产品类。相对应的类的数量会变多系统结构会显得更“重”一些。工厂方法模式在项目里常见于封装各类第三方SDK的客户端比如对接多家支付渠道每个渠道一套实现各自维护各自的初始化逻辑。2.3 抽象工厂解决“产品族”问题如果说工厂方法关注的是“一种产品怎么创建”那抽象工厂关注的是“一组有关的、相互关联的产品怎么统一创建”。还是拿连接池举例一个完整的连接池可能需要配套连接校验器、统计采集器、告警器等组件。抽象工厂会一次性定义出一整套接口方法public interface PoolComponentsFactory { ConnectionPool createPool(); Validator createValidator(); MetricsCollector createMetricsCollector(); }每个具体的工厂实现负责生成一套风格一致的组件比如生产环境的池方案配一套生产级监控测试环境配一套轻量级模拟监控。这么做最大的好处是保证同一产品族内部的一致性——你永远不会出现连接池是Druid但监控组件却是配套C3P0的情况。在Spring源码里你其实能看到大量这种分层设计的思想。比如BeanFactory这个顶级接口只定义了getBean这类最基础的能力往下扩展出HierarchicalBeanFactory支持父子容器、ListableBeanFactory支持批量列举、ConfigurableBeanFactory支持配置和生命周期管理等。这本质上就是一套高大上的接口分级体系让不同阶段、不同场景的调用方只面对自己所需的“视角”。学到这里可以给自己提个问题Spring到底是简单工厂还是抽象工厂后面我会给出自己的理解。3. 进入Spring6BeanFactory和ApplicationContext到底怎么运作3.1 BeanFactory所有IoC容器的“老祖宗”BeanFactory是Spring IoC容器的底层根接口。任何一个Spring容器本质上都是在实现BeanFactory的能力。它定义了最核心的getBean(String name)、getBean(ClassT requiredType)等方法调用方只需要告诉容器“我要什么”容器就负责把对应的Bean创建出来并返回。那Spring的BeanFactory和我们自己写的PoolFactory有什么本质区别呢最大的一点是通用性和反射机制。自己写工厂每种产品都要写对应的if-else或子类Spring的工厂本身不关心Bean的类型到底是什么它通过BeanDefinitionBean的定义信息来知道“这个Bean的类型是谁、构造参数是什么、依赖哪些其他Bean”然后利用反射来实例化。换句话讲你只要在配置文件或配置类里声明好元数据工厂不需要改代码就能创建任意类型的对象。为了更直观地说明这一点我画个非常简化的流程容器启动时解析配置文件或扫描注解生成一个或多个BeanDefinition对象。BeanDefinitionRegistry把BeanDefinition注册到容器内部。当调用getBean时DefaultListableBeanFactory根据BeanName找到对应的BeanDefinition。实例化策略如SimpleInstantiationStrategy、CglibSubclassingInstantiationStrategy反射创建实例。根据BeanDefinition中的属性值和依赖配置进行填充依赖注入。执行初始化方法返回最终Bean。我们平时写的applicationContext.getBean(userService)表面上直接拿到了对象但背后发生了一整套复杂的流程。这套流程被封装在BeanFactory的各个子实现类中调用方完全无感。这就是工厂模式“封装创建细节”这一定义在Spring里最精华的体现。3.2 ApplicationContext站在巨人肩膀上的增强型工厂虽然BeanFactory定义了最基本的能力但直接在项目中用BeanFactory作为容器的场景其实很少。原因很简单——它太“素”了。真实的生产环境还需要国际化支持、事件发布、AOP增强、资源加载等能力这些统统不是BeanFactory的职责范围。于是ApplicationContext出场了。它本身继承了ListableBeanFactory和HierarchicalBeanFactory同时扩展出了ApplicationEventPublisher事件发布、ResourcePatternResolver资源解析、MessageSource国际化等接口。你可以这么理解ApplicationContext是在BeanFactory之上做了大量功能增强的“高级工厂版本”。项目里常见的ClassPathXmlApplicationContext、AnnotationConfigApplicationContext都是ApplicationContext的实现类。前者从classpath下的XML配置文件加载上下文后者以注解配置类为入口。无论哪种方式它们最终都会刷新容器、注册配置类、实例化所有单例Bean、发布容器刷新事件。日常开发中我们几乎只跟ApplicationContext打交道而BeanFactory更像是隐藏在背后的“基建”。为了加深理解做一个小测试。看下面这段代码ApplicationContext context new AnnotationConfigApplicationContext(AppConfig.class); UserService userService context.getBean(UserService.class);当我们把ApplicationContext当成工厂来理解时整个调用链就变成——调用方通过context.getBean()向工厂要一个UserService对象工厂内部通过前面的六步流程组装好Bean再交给调用方。UserService到底是怎么new出来的、它依赖的UserDao是从哪来的调用方一概不知。这正是工厂模式追求的效果。3.3 不同容器的创建机制差异很多人会在面试或者实际调试中遇到一个问题AnnotationConfigApplicationContext和ClassPathXmlApplicationContext创建Bean的方式有什么区别其实区别不在“创建Bean”这一步而在“创建BeanDefinition”这一步。AnnotationConfigApplicationContext通过扫描Component注解、解析Bean方法来生成BeanDefinition。ClassPathXmlApplicationContext通过解析XML文档中的bean标签来生成BeanDefinition。GenericApplicationContext更灵活可以在运行时手动注册BeanDefinition。一旦BeanDefinition生成完毕后续的实例化和初始化流程基本是统一调度。可以类比为不管你是用手机App点餐还是在收银台人工下单后厨做菜的方式是同一套。工厂模式设计的关键就是把“产品如何定义”和“产品如何生产”两件事拆开前者的差异在配置解析层收敛后者的差异在实例化层隔离。如果你用Spring Boot通常只需要配合SpringBootApplication就能启动整个应用那是因为SpringApplication在背后帮你创建了AnnotationConfigApplicationContext或者ServletWebServerApplicationContext等然后自动完成配置加载和Web服务器启动。Spring Boot的“自动配置”思路也可以理解成——框架把创建和组装过程进一步封装开发者的配置量被压到了最低。4. FactoryBean最容易和BeanFactory混淆的实战概念4.1 FactoryBean的价值场景FactoryBean是我当年学习Spring时最容易卡壳的一个点。BeanFactory和FactoryBean一个叫“Bean工厂”一个叫“工厂Bean”名字看起来就是换了个词序实际上是两个完全不同的东西。简单讲BeanFactory是顶级容器负责管理一切FactoryBean是一种特殊的Bean它自己本身也是一个Bean但它同时具备“生产其他对象”的能力。什么情况下会用到FactoryBean呢最典型的场景是你要创建的Bean不是一个简单的类对象而是一套复杂的组装产物。比如集成MyBatis框架时每个Mapper接口的动态代理对象生产逻辑都是相似的做配置解析、加载SQL映射、生成动态代理。这时候如果每个Mapper都走一遍普通Bean实例化流程配置量会爆炸。SqlSessionFactoryBean就是专门用来解决这个问题的。它实现FactoryBean接口后Spring在需要SqlSessionFactory时会调用其getObject()方法由这个工厂Bean统一创建SqlSessionFactory实例。public class MyServiceFactoryBean implements FactoryBeanMyService { Override public MyService getObject() throws Exception { // 在这里集中封装复杂创建逻辑 MyService service new MyService(); service.setName(custom-name); service.init(); return service; } Override public Class? getObjectType() { return MyService.class; } Override public boolean isSingleton() { return true; } }4.2 getBean返回的是什么关键细节别搞错如果注册了一个FactoryBeanMyService到Spring容器那么调用context.getBean(myServiceFactoryBean)返回的到底是MyServiceFactoryBean本身还是MyService对象这里就是最容易踩坑的地方按Bean名称获取时如果该Bean实现了FactoryBean接口默认优先返回的是FactoryBean生产的对象即getObject()的返回值。如果想拿FactoryBean本身需要在名称前加一个前缀比如context.getBean(myServiceFactoryBean)。这个设计和JNDI里的java:comp/env名称解析方式一脉相承。加约定是为了区分“工厂对象”和“产品对象”避免两个都已经成为容器中“可用对象”的情况下出现歧义。还有一个细节是isSingleton()方法。它决定getObject()产出的对象是否作为单例缓存。如果返回false则每次getBean都会调用getObject()重新生成一个对象。在写自定义FactoryBean时这一点需要格外留意不然会出现预期单例却越拿越多的Bug。4.3 自定义FactoryBean的注意事项我自己在项目中写自定义FactoryBean时踩过几个很有代表性的坑。如果你是首次动手建议着重关注这三个小心循环依赖。FactoryBean本身也可能被Spring容器当作一个Bean来管理如果它又要依赖别的Bean而别的Bean又反过来依赖这个FactoryBean就可能出现创建顺序难控的连锁问题。getObjectType()不要随意返回null。很多类型匹配逻辑比如按类型拿Bean、自动装配候选人筛选都依赖这个返回值返回null会让框架无法准确识别这个工厂的产品类型。getObject()里不要注入自己所在容器的ApplicationContext。如果非要使用容器资源尽量通过ApplicationContextAware接口拿到上下文引用后再谨慎使用getBean避免引发额外的初始化分支。实践证明FactoryBean在屏蔽复杂创建逻辑、动态代理生成、有参构造策略等场景非常好用。尤其是当你发现某个Bean的创建过程需要组装很多组件、做很多初始化动作时FactoryBean往往比在Bean方法里写一大堆代码更合适——因为你可以复用这套工厂逻辑到多个Bean上抽象程度更高。5. ObjectFactory与Provider延迟依赖到底解决了什么问题5.1 ObjectFactory的基本用法在Spring里如果一个Bean A依赖另一个Bean B默认情况下容器在创建A的同时会创建B如果B是单例且不是懒加载。但有些场景我们不希望这么“急切”——比如B是一个连接池或者缓存的初始化成本比较高A只有在某种特定操作下才真正需要B。这时候如果还在初始化阶段就把B创建出来就会白白增加开销。ObjectFactoryT接口把这种“延迟获取”变成了一种标准姿态Component public class OrderService { Autowired private ObjectFactoryOrderValidator validatorFactory; public void processOrder(Order order) { // 只有在执行到这里时才真正去容器中查找并创建OrderValidator OrderValidator validator validatorFactory.getObject(); validator.validate(order); // 业务逻辑继续... } }注意OrderService本身不直接持有OrderValidator它持有的是一个“供应商”角色。当调用getObject()时才触发容器的Bean查找流程。这个设计的好处有几个启动时不强制完整初始化所有依赖运行时不只是因为用到的时刻才创建还能有效绕开一部分循环依赖问题因为依赖不是构造函数需要的即时引用而是延迟获取。5.2 ObjectFactory与Provider的异同Spring在后续版本中还引入了标准javax.inject.ProviderT接口在Jakarta规范中是jakarta.inject.ProviderT。二者在常规使用上非常相似都是延迟获取Bean的手段。最大的区别是ObjectFactory是Spring自己定义的类型和Spring生态绑定得更紧密Provider则是Java依赖注入标准CDI中定义的接口具备更强的规范性在脱离Spring的架构里也能沿用同一套思想。从使用角度如果项目本身不打算依赖额外标准直接用ObjectFactory最省事源码里自带不需要额外导入。如果团队偏向统一技术规范或者在多框架异构环境中考虑代码的可移植性用Provider会更稳妥。5.3 ObjectFactory在Spring源码中的著名用法ObjectFactory最经典的曝光场景其实藏在循环依赖的解决机制里。Spring在创建单例Bean时为了避免A依赖B、B又依赖A这种相互引用的尴尬会提前暴露一个ObjectFactory通过它对外提供一个“半成品Bean的引用”。一旦后续发现B需要注入A时就把这个提前暴露的引用注入进去从而绕开顺序问题。这个设计思路非常巧妙从工厂模式的视角看它也是一个“延迟到关键时刻再做解析”的典型应用。如果不依赖这个机制Spring的设计就会被迫通过多级缓存或者代理来解决复杂度会直线上升。理解了ObjectFactory的延迟获取价值也就理解了Spring单例池三级缓存里的一部分秘密。5.4 实战建议什么时候用延迟依赖我个人的经验判断是如果依赖的对象满足下面三个特征之一就值得考虑延迟依赖初始化昂贵且系统启动阶段不会立刻使用比如大模型客户端、重型连接池、资源解析器修饰多重、容易产生循环依赖的对象希望在运行时动态决定到底用哪个具体实例的策略型依赖。不过延迟依赖也不是越多越好。过度使用会牺牲些许性能每次getObject()都要走容器查找流程以及类型静态检查能力。在不需要提前解耦的场景直接字段注入或者构造器注入反而更简单直观。6. 深入Spring6实例完整实现一个工厂模式改造案例6.1 案例背景考虑到前面讲了大量概念现在用一个可运行的例子把内容串起来。假设我们要做一个消息推送系统支持短信、邮件、站内信三种渠道。推送消息类型不同对应的处理器逻辑不同。最直观但很蠢的写法是public void push(Message msg) { if (sms.equals(msg.getChannel())) { // 发送短信逻辑 } else if (email.equals(msg.getChannel())) { // 发送邮件逻辑 } else if (inbox.equals(msg.getChannel())) { // 发送站内信逻辑 } }如果后续渠道多起来——比如增加微信、企微、钉钉——这段代码会越来越庞大同时也严重违背了单一职责原则。我们的目标是用Spring6的注解驱动方式把这个过程改造成一个基于工厂模式的优雅结构。6.2 项目结构设计先定义统一的策略接口public interface MessagePushService { void push(String title, String content, String target); boolean supports(String channel); }然后定义短信实现Component public class SmsMessagePushService implements MessagePushService { Override public void push(String title, String content, String target) { // 实际对接短信服务商API System.out.println(发送短信 - 标题: title , 目标: target); } Override public boolean supports(String channel) { return sms.equals(channel); } }邮件和站内信的实现逻辑类似只是支持的channel不同一个返回email一个返回inbox。注意这里每个渠道服务都注册成Spring的Bean由容器统一管理生命周期。6.3 工厂类实现接下来是关键定义一个渠道选择工厂它就是整个模式的调度中枢Component public class MessagePushFactory { private final ListMessagePushService pushServiceList; public MessagePushFactory(ListMessagePushService pushServiceList) { this.pushServiceList pushServiceList; } public MessagePushService getPushService(String channel) { return pushServiceList.stream() .filter(service - service.supports(channel)) .findFirst() .orElseThrow(() - new IllegalArgumentException(No push service for channel: channel)); } }这段代码用了Spring最常用的一招通过构造器注入一个ListMessagePushServiceSpring会自动把IoC容器中所有MessagePushService类型的Bean全部装配进来。未来新增一个渠道只需要新写一个实现类并标注Component工厂本身一行都不用改完全符合“开闭原则”。这种技巧在项目里解决“多实现路由”的问题非常常见本质上就是Spring充当了策略模式的注册中心而工厂则是策略的“调度员”。6.4 使用方视角在Controller或者其他业务层用起来就很简单了RestController public class PushController { private final MessagePushFactory pushFactory; public PushController(MessagePushFactory pushFactory) { this.pushFactory pushFactory; } PostMapping(/push) public void push(RequestBody PushRequest request) { MessagePushService service pushFactory.getPushService(request.getChannel()); service.push(request.getTitle(), request.getContent(), request.getTarget()); } }对比之前的if-else写法业务侧彻底摆脱了渠道的分支判断。要新增渠道改动的只是新增一个实现类原有代码无侵入测试起来也方便——可以针对每个渠道单独构造测试用例。6.5 如何在此基础上扩展抽象工厂如果渠道不止是“推送”功能每个渠道还有自己的“回执查询”、“取消推送”等操作那上面这个简单工厂策略组合就不够用了。此时可以做一次升级每个渠道的处理器不再只是一个单独的服务而是一整套组件比如SmsProcessor包含SmsPusher、SmsReceiptQuerier、SmsCanceller。你可以定义一个抽象工厂public interface ChannelComponentsFactory { MessagePushService createPusher(); ReceiptQueryService createReceiptQuerier(); CancelPushService createCanceller(); }每个渠道对应一个ChannelComponentsFactory的实现负责生成该渠道专属的一整套组件。这个升级路径很平滑本质上是将原本的“选择单一服务”提升为“选择一群配套服务”。在大型项目中这种从简单工厂到抽象工厂的演进几乎是必然的因为业务维度会不断扩张产品之间的“皮带”关系越来越复杂。7. 常见问题与排查技巧实录7.1 为什么getBean拿到的对象类型和我预期的不一样出现这种情况先别急着怀疑Spring坏了。检查一下你定义的类是不是实现了FactoryBean接口。如果是那么直接getBean(xxx)拿到的是getObject()的产物想要工厂本身就必须用xxx。另外还要排查是否在某个Bean方法里返回了代理对象或装配了切面代理对象的类型往往和原始类型不同按类型获取时需要调整搜索策略。7.2 自动匹配多个Bean时抛NoUniqueBeanDefinitionException这种情况在按类型获取Bean时很常见。比如定义了多个MessagePushService实现类然后直接context.getBean(MessagePushService.class)Spring就会发愁不知道给你哪一个。解决办法有三种用工厂模式封装一个调度逻辑就像上面案例做的那样注入ListMessagePushService或MapString,MessagePushService自己决定用哪个为某一个实现类标记Primary让Spring默认选择它。从架构整洁度上说第一种方式最优它把选择逻辑收敛到一处业务代码完全不感知多实现的存在。7.3 FactoryBean的getObject方法被重复执行如果发现某些昂贵的创建逻辑被执行了很多次大概率是getObject()配套的isSingleton()返回了false。默认情况下FactoryBean生产的对象不一定是单例——Spring官方文档里对isSingleton()方法语义有过说明它影响的是getObject()返回对象的缓存行为。如果你的产品对象本身希望全局唯一务必把isSingleton()设为true。另外还需要确认这个FactoryBean是否被多次注册或存在多个容器实例比如父子容器每个容器都会创建各自的一份工厂。7.4 依赖注入的Bean为null但getBean能拿得到这类问题通常涉及循环依赖或初始化顺序。当一个Bean的构造函数里注入了另一个尚未完成初始化的BeanSpring可能会被迫通过三级缓存提前暴露工厂或代理。但某些边界条件下它会选择返回一个未完全初始化的对象。排查方向包括检查是否有两个Bean通过构造器相互引用构造器循环依赖是Spring无法自动解决的、检查是否在PostConstruct或InitializingBean中提前调用了依赖Bean的方法、检查是否存在代理对象导致生命周期回调顺序被打乱。7.5 关于工厂模式使用边界的个人心得我做这个改造时的体会是工厂模式在Spring项目里绝大多数情况下不需要手动new对象而是要善用容器自动装配机制。Spring的IoC本质上已经充当了工厂所以我们要做的更多是“策略分发”而不是“手动创建”。真正需要自己写工厂类的地方通常是创建过程特别复杂、创建逻辑需要复用、或者需要做一批产品的配套组装。把这个边界理清楚能避免很多无意义的抽象。另外要特别说明工厂模式和策略模式经常搭在一起用。工厂负责“如何拿到正确的处理器”策略负责“处理器内部如何展开差异逻辑”。如果只做策略模式而不做工厂分发调用方就还得自己写一堆选择逻辑。反过来如果只做工厂而不把策略抽出来工厂内部又会膨胀成一个大杂烩。两者珠联璧合才是真正优雅的工程结构。8. 写在最后的几个实用建议这篇笔记讲了这么多最后再补几个我自己在实际项目里反复验证过的小心得希望能帮大家少走弯路。第一点别急着上抽象工厂。很多团队一讨论设计模式就总想一步到位用最高级形态。但一旦业务只有两个渠道抽象工厂的收益根本覆盖不了类爆炸带来的维护成本。从简单工厂做起等到业务真正出现多渠道多组件绑定的时候再平滑重构这个过程是合理的。设计模式的应用一定是“被需求驱动”而不是“被风格驱动”。第二点把工厂类的命名规范化。项目里建议统一用XxxFactory、XxxProvider、XxxResolver这类后缀这样团队里其他人一眼就能看清这个类扮演的角色。不要出现叫XxxService里面却放着一大堆工厂逻辑的类那会让维护者非常痛苦。命名清晰本身就是一种可读性资产。第三点结合Spring特性能用容器机制解决的就别硬编码设计模式。比如多实现的自动装配注入ListT、Qualifier按名字选择、Primary默认优先这些框架自带的武器已经消化掉一半设计模式的需求自己写的代码越少出Bug的接口面就越小。工厂模式的核心价值是封装变化Spring帮我们把创建过程都封装完了我们要封装的是“选择逻辑”和“策略组合”而不是重新发明一遍创建逻辑。如果把整个Spring容器理解成一个超级工厂我们所学的一切——BeanFactory、ApplicationContext、FactoryBean、ObjectFactory——都是这个超级工厂体系在不同层次、不同场景下的具体表现。想通这一点工厂模式这篇算是真正过关了。
上一篇/下一篇内容由系统自动关联
返回资讯列表 →