🎭 FactoryBean vs BeanFactory:Spring界的"双胞胎"之谜!

47 阅读7分钟

副标题:一字之差,天壤之别! 🤯


🎬 开场白:谁是谁?

嘿,小伙伴们!👋 今天我们要解开Spring中一个让人头疼的谜题——FactoryBean和BeanFactory的区别

这两个名字只差一个字的顺序,但作用完全不同!就像:

  • 🍕 披萨店(BeanFactory)→ 提供披萨的地方
  • 🧑‍🍳 披萨师傅(FactoryBean)→ 制作披萨的人

千万别搞混了! 不然面试官会以为你是来搞笑的!😅


📚 第一幕:BeanFactory - Bean工厂

什么是BeanFactory?

BeanFactory是Spring IOC容器的最顶层接口,它的职责是:

  • 管理Bean的生命周期 🔄
  • 提供Bean的依赖注入 💉
  • 管理Bean的作用域 🎯
public interface BeanFactory {
    
    // 根据名称获取Bean
    Object getBean(String name);
    
    // 根据类型获取Bean
    <T> T getBean(Class<T> requiredType);
    
    // 根据名称和类型获取Bean
    <T> T getBean(String name, Class<T> requiredType);
    
    // 判断是否包含Bean
    boolean containsBean(String name);
    
    // 判断是否单例
    boolean isSingleton(String name);
    
    // 判断是否原型
    boolean isPrototype(String name);
    
    // 获取Bean类型
    Class<?> getType(String name);
    
    // 获取Bean别名
    String[] getAliases(String name);
}

生活比喻:超市(BeanFactory)

超市(BeanFactory)
    ├── 货架A:存放面包(Bean)🍞
    ├── 货架B:存放牛奶(Bean)🥛
    ├── 货架C:存放水果(Bean)🍎
    └── 货架D:存放零食(Bean)🍪

顾客来了:
"老板,给我来个面包!" → 从货架A拿出面包
"老板,给我来瓶牛奶!" → 从货架B拿出牛奶

BeanFactory就是这个"超市",负责管理和提供所有商品(Bean)!

BeanFactory的继承体系

BeanFactory (最基础接口)
    ↓
ListableBeanFactory (可列举Bean)
    ↓
HierarchicalBeanFactory (支持层级结构)
    ↓
ConfigurableBeanFactory (可配置)
    ↓
ConfigurableListableBeanFactory (组合)
    ↓
DefaultListableBeanFactory (默认实现)
    ↓
ApplicationContext (应用上下文)

BeanFactory的使用

public class BeanFactoryDemo {
    
    public static void main(String[] args) {
        
        // 创建BeanFactory
        DefaultListableBeanFactory beanFactory = 
            new DefaultListableBeanFactory();
        
        // 手动注册Bean定义
        BeanDefinition beanDefinition = 
            BeanDefinitionBuilder
                .genericBeanDefinition(UserService.class)
                .setScope("singleton")
                .getBeanDefinition();
        
        beanFactory.registerBeanDefinition("userService", beanDefinition);
        
        // 获取Bean
        UserService userService = beanFactory.getBean(UserService.class);
        userService.doSomething();
        
        // 检查Bean是否存在
        boolean exists = beanFactory.containsBean("userService");
        System.out.println("Bean是否存在:" + exists);
        
        // 检查是否单例
        boolean singleton = beanFactory.isSingleton("userService");
        System.out.println("是否单例:" + singleton);
    }
}

🎪 第二幕:FactoryBean - Bean工厂

什么是FactoryBean?

FactoryBean是一个特殊的Bean,它本身是一个工厂,用来创建其他Bean

public interface FactoryBean<T> {
    
    // 返回由FactoryBean创建的Bean实例
    T getObject() throws Exception;
    
    // 返回FactoryBean创建的Bean类型
    Class<?> getObjectType();
    
    // 返回的Bean是否为单例
    default boolean isSingleton() {
        return true;
    }
}

生活比喻:披萨师傅(FactoryBean)

披萨店里有一位特殊的师傅(FactoryBean)🧑‍🍳

老板(BeanFactory):
"师傅,做个披萨!"

披萨师傅(FactoryBean):
"好嘞,我这就给你做一个特别的披萨!"
[复杂的制作过程...]
"披萨做好了!" 🍕

顾客拿到的是**披萨(getObject()返回的对象)**,
而不是披萨师傅本人!

但如果你想见师傅本人,可以说:"&披萨师傅"

FactoryBean实战案例

案例1:简单的FactoryBean

@Component
public class CarFactoryBean implements FactoryBean<Car> {
    
    private String brand;
    private String color;
    
    @Override
    public Car getObject() throws Exception {
        System.out.println("🏭 FactoryBean正在制造汽车...");
        
        // 复杂的创建逻辑
        Car car = new Car();
        car.setBrand(brand != null ? brand : "Tesla");
        car.setColor(color != null ? color : "Black");
        car.setProductionDate(new Date());
        
        // 可以进行复杂的初始化
        car.initialize();
        
        System.out.println("✅ 汽车制造完成:" + car);
        return car;
    }
    
    @Override
    public Class<?> getObjectType() {
        return Car.class;
    }
    
    @Override
    public boolean isSingleton() {
        return true;  // 每次返回同一个Car实例
    }
    
    // getters and setters...
}

@Data
public class Car {
    private String brand;
    private String color;
    private Date productionDate;
    
    public void initialize() {
        System.out.println("🔧 初始化汽车系统...");
        // 复杂的初始化逻辑
    }
}

使用FactoryBean

@SpringBootTest
public class FactoryBeanTest {
    
    @Autowired
    private ApplicationContext context;
    
    @Test
    public void testFactoryBean() {
        
        // 获取Car对象(FactoryBean创建的对象)
        Car car = context.getBean("carFactoryBean", Car.class);
        System.out.println("🚗 获取到Car:" + car);
        
        // 获取FactoryBean本身(注意&前缀)
        CarFactoryBean factoryBean = 
            context.getBean("&carFactoryBean", CarFactoryBean.class);
        System.out.println("🏭 获取到FactoryBean:" + factoryBean);
        
        // 验证类型
        System.out.println("car是Car类型?" + (car instanceof Car));
        System.out.println("factoryBean是CarFactoryBean类型?" + 
                          (factoryBean instanceof CarFactoryBean));
    }
}

输出:

🏭 FactoryBean正在制造汽车...
🔧 初始化汽车系统...
✅ 汽车制造完成:Car(brand=Tesla, color=Black, productionDate=...)
🚗 获取到Car:Car(brand=Tesla, color=Black, productionDate=...)
🏭 获取到FactoryBean:CarFactoryBean@12345678
car是Car类型?true
factoryBean是CarFactoryBean类型?true

&前缀的魔法

// 不加&:获取FactoryBean创建的对象
Car car = context.getBean("carFactoryBean", Car.class);

// 加&:获取FactoryBean本身
CarFactoryBean factoryBean = 
    context.getBean("&carFactoryBean", CarFactoryBean.class);

记忆口诀:

不加& → 产品(Product)🍕
加上& → 工厂(Factory)🏭

🎯 第三幕:核心区别对比

对比表

对比项BeanFactoryFactoryBean
定位IOC容器特殊的Bean
职责管理所有Bean创建特定Bean
层级容器顶层接口普通Bean
使用场景Spring框架内部使用应用开发使用
获取方式直接使用通过&前缀获取
比喻超市 🏪披萨师傅 🧑‍🍳

关系图

┌─────────────────────────────────────┐
│       BeanFactory(容器)            │
│                                     │
│   ┌─────────────────────────┐     │
│   │   普通Bean               │     │
│   │   - UserService          │     │
│   │   - OrderService         │     │
│   └─────────────────────────┘     │
│                                     │
│   ┌─────────────────────────┐     │
│   │   FactoryBean(特殊Bean) │     │
│   │   ├─ getObject() → Car   │     │
│   │   └─ FactoryBean本身     │     │
│   └─────────────────────────┘     │
│                                     │
└─────────────────────────────────────┘

🔧 第四幕:FactoryBean的高级用法

案例1:创建代理对象

@Component
public class ProxyFactoryBean implements FactoryBean<UserService> {
    
    @Autowired
    private UserService target;  // 目标对象
    
    @Override
    public UserService getObject() throws Exception {
        
        System.out.println("🎭 创建UserService的代理对象");
        
        return (UserService) Proxy.newProxyInstance(
            UserService.class.getClassLoader(),
            new Class[]{UserService.class},
            (proxy, method, args) -> {
                System.out.println("⏱️ 方法执行前:" + method.getName());
                
                long start = System.currentTimeMillis();
                Object result = method.invoke(target, args);
                long end = System.currentTimeMillis();
                
                System.out.println("⏱️ 方法执行后:" + (end - start) + "ms");
                
                return result;
            }
        );
    }
    
    @Override
    public Class<?> getObjectType() {
        return UserService.class;
    }
}

案例2:创建连接池

@Component
public class DataSourceFactoryBean implements FactoryBean<DataSource> {
    
    @Value("${db.url}")
    private String url;
    
    @Value("${db.username}")
    private String username;
    
    @Value("${db.password}")
    private String password;
    
    @Value("${db.pool.size:10}")
    private int poolSize;
    
    @Override
    public DataSource getObject() throws Exception {
        
        System.out.println("🗄️ 创建数据源连接池...");
        
        HikariConfig config = new HikariConfig();
        config.setJdbcUrl(url);
        config.setUsername(username);
        config.setPassword(password);
        config.setMaximumPoolSize(poolSize);
        config.setMinimumIdle(2);
        config.setConnectionTimeout(30000);
        
        HikariDataSource dataSource = new HikariDataSource(config);
        
        System.out.println("✅ 数据源创建完成,连接池大小:" + poolSize);
        
        return dataSource;
    }
    
    @Override
    public Class<?> getObjectType() {
        return DataSource.class;
    }
    
    @Override
    public boolean isSingleton() {
        return true;  // 数据源单例
    }
}

案例3:创建复杂配置对象

@Component
public class RedisClientFactoryBean implements FactoryBean<RedisClient> {
    
    @Value("${redis.host:localhost}")
    private String host;
    
    @Value("${redis.port:6379}")
    private int port;
    
    @Value("${redis.password:}")
    private String password;
    
    @Value("${redis.database:0}")
    private int database;
    
    @Value("${redis.timeout:3000}")
    private int timeout;
    
    @Override
    public RedisClient getObject() throws Exception {
        
        System.out.println("📮 创建Redis客户端...");
        
        RedisClient client = new RedisClient();
        client.setHost(host);
        client.setPort(port);
        
        if (!password.isEmpty()) {
            client.setPassword(password);
        }
        
        client.setDatabase(database);
        client.setTimeout(timeout);
        
        // 初始化连接
        client.connect();
        
        // 执行健康检查
        if (!client.ping()) {
            throw new IllegalStateException("Redis连接失败!");
        }
        
        System.out.println("✅ Redis客户端创建成功:" + host + ":" + port);
        
        return client;
    }
    
    @Override
    public Class<?> getObjectType() {
        return RedisClient.class;
    }
    
    @PreDestroy
    public void destroy() {
        System.out.println("🗑️ 关闭Redis连接");
    }
}

🎨 第五幕:Spring内置的FactoryBean

1. ProxyFactoryBean

@Configuration
public class ProxyConfig {
    
    @Bean
    public ProxyFactoryBean userServiceProxy(UserService userService) {
        
        ProxyFactoryBean proxyFactory = new ProxyFactoryBean();
        proxyFactory.setTarget(userService);
        proxyFactory.setInterfaces(UserService.class);
        
        // 添加增强
        proxyFactory.addAdvice((MethodInterceptor) invocation -> {
            System.out.println("🎯 调用方法:" + invocation.getMethod().getName());
            return invocation.proceed();
        });
        
        return proxyFactory;
    }
}

2. LocalSessionFactoryBean(MyBatis/Hibernate)

@Configuration
public class MyBatisConfig {
    
    @Bean
    public SqlSessionFactoryBean sqlSessionFactory(DataSource dataSource) {
        
        SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
        factoryBean.setDataSource(dataSource);
        factoryBean.setMapperLocations(
            new PathMatchingResourcePatternResolver()
                .getResources("classpath*:mapper/**/*.xml")
        );
        
        return factoryBean;
    }
}

3. JndiObjectFactoryBean

@Configuration
public class JndiConfig {
    
    @Bean
    public JndiObjectFactoryBean dataSource() {
        
        JndiObjectFactoryBean factoryBean = new JndiObjectFactoryBean();
        factoryBean.setJndiName("java:comp/env/jdbc/myDataSource");
        factoryBean.setResourceRef(true);
        factoryBean.setProxyInterface(DataSource.class);
        
        return factoryBean;
    }
}

🎪 第六幕:实战应用场景

场景1:动态创建不同类型的对象

@Component
public class AnimalFactoryBean implements FactoryBean<Animal> {
    
    @Value("${animal.type:dog}")
    private String animalType;
    
    @Override
    public Animal getObject() throws Exception {
        
        System.out.println("🐾 创建动物:" + animalType);
        
        switch (animalType.toLowerCase()) {
            case "dog":
                return new Dog();
            case "cat":
                return new Cat();
            case "bird":
                return new Bird();
            default:
                throw new IllegalArgumentException("未知的动物类型:" + animalType);
        }
    }
    
    @Override
    public Class<?> getObjectType() {
        return Animal.class;
    }
}

interface Animal {
    void speak();
}

class Dog implements Animal {
    @Override
    public void speak() {
        System.out.println("🐕 汪汪汪!");
    }
}

class Cat implements Animal {
    @Override
    public void speak() {
        System.out.println("🐱 喵喵喵!");
    }
}

class Bird implements Animal {
    @Override
    public void speak() {
        System.out.println("🐦 叽叽喳喳!");
    }
}

场景2:加载外部资源

@Component
public class ConfigLoaderFactoryBean implements FactoryBean<Properties> {
    
    @Value("${config.file.path}")
    private String configFilePath;
    
    @Override
    public Properties getObject() throws Exception {
        
        System.out.println("📄 加载配置文件:" + configFilePath);
        
        Properties properties = new Properties();
        
        try (InputStream is = new FileInputStream(configFilePath)) {
            properties.load(is);
        }
        
        System.out.println("✅ 加载了 " + properties.size() + " 个配置项");
        
        return properties;
    }
    
    @Override
    public Class<?> getObjectType() {
        return Properties.class;
    }
}

场景3:单例到原型的转换

@Component
public class PrototypeFactoryBean implements FactoryBean<PrototypeObject> {
    
    @Override
    public PrototypeObject getObject() throws Exception {
        // 每次都创建新对象
        return new PrototypeObject();
    }
    
    @Override
    public Class<?> getObjectType() {
        return PrototypeObject.class;
    }
    
    @Override
    public boolean isSingleton() {
        return false;  // 返回false,每次创建新对象
    }
}

⚠️ 第七幕:常见坑点

坑点1:忘记&前缀

// ❌ 错误:获取的是Car对象,不是FactoryBean
CarFactoryBean factoryBean = 
    context.getBean("carFactoryBean", CarFactoryBean.class);
// 报错:类型不匹配!

// ✅ 正确:使用&前缀获取FactoryBean本身
CarFactoryBean factoryBean = 
    context.getBean("&carFactoryBean", CarFactoryBean.class);

坑点2:getObjectType()返回null

// ❌ 错误
public class BadFactoryBean implements FactoryBean<Car> {
    
    @Override
    public Class<?> getObjectType() {
        return null;  // 不要返回null!
    }
}

// ✅ 正确
public class GoodFactoryBean implements FactoryBean<Car> {
    
    @Override
    public Class<?> getObjectType() {
        return Car.class;  // 明确返回类型
    }
}

坑点3:循环依赖问题

// ❌ 可能产生循环依赖
@Component
public class AFactoryBean implements FactoryBean<A> {
    
    @Autowired
    private B b;  // 依赖B
    
    @Override
    public A getObject() {
        return new A(b);
    }
}

@Component
public class BFactoryBean implements FactoryBean<B> {
    
    @Autowired
    private A a;  // 依赖A
    
    @Override
    public B getObject() {
        return new B(a);
    }
}

// ✅ 解决方案:延迟注入
@Component
public class AFactoryBean implements FactoryBean<A> {
    
    @Lazy
    @Autowired
    private B b;
    
    @Override
    public A getObject() {
        return new A(b);
    }
}

🎯 第八幕:最佳实践

✅ 1. 明确使用场景

使用FactoryBean的场景:

  • 创建过程复杂
  • 需要动态决定创建什么对象
  • 需要对创建的对象进行额外处理
  • 第三方库集成

不要用FactoryBean的场景:

  • 简单对象创建
  • 普通Bean就能满足需求

✅ 2. 实现DisposableBean接口

@Component
public class ResourceFactoryBean 
        implements FactoryBean<Resource>, DisposableBean {
    
    private Resource resource;
    
    @Override
    public Resource getObject() throws Exception {
        resource = createResource();
        return resource;
    }
    
    @Override
    public void destroy() throws Exception {
        // 清理资源
        if (resource != null) {
            resource.close();
            System.out.println("🗑️ 资源已释放");
        }
    }
}

✅ 3. 提供清晰的文档

/**
 * UserService的FactoryBean
 * 
 * 这个FactoryBean用于创建UserService的代理对象,
 * 会自动添加性能监控和日志记录功能。
 * 
 * 配置示例:
 * <pre>
 * @Autowired
 * private UserService userService;  // 获取代理对象
 * 
 * @Autowired
 * @Qualifier("&userServiceFactoryBean")
 * private UserServiceFactoryBean factoryBean;  // 获取工厂本身
 * </pre>
 */
@Component
public class UserServiceFactoryBean implements FactoryBean<UserService> {
    // ...
}

🎉 总结

核心要点记忆

BeanFactory = 容器(管理者) 🏪
    └─ 管理所有Bean
    └─ 提供依赖注入
    └─ 控制生命周期

FactoryBean = 特殊Bean(创建者) 🧑‍🍳
    └─ 创建复杂对象
    └─ 封装创建逻辑
    └─ 使用&前缀获取自己

一句话记忆

BeanFactory是"大老板"🏪,管理所有Bean;
FactoryBean是"小师傅"🧑‍🍳,专门制作特殊Bean!

对比总结表

特性BeanFactoryFactoryBean
身份IOC容器接口特殊Bean
作用管理Bean创建Bean
获取方式直接使用需要&前缀
使用频率框架内部应用开发
比喻超市 🏪披萨师傅 🧑‍🍳

🚀 课后作业

  1. 初级: 实现一个简单的FactoryBean,创建配置对象
  2. 中级: 实现一个动态的FactoryBean,根据配置创建不同类型的对象
  3. 高级: 实现一个FactoryBean,创建带有AOP增强的对象

📚 参考资料

  • Spring Framework官方文档 - FactoryBean
  • 《Spring源码深度解析》
  • Spring源码 - org.springframework.beans.factory包

最后的彩蛋: 🎁

面试必杀技:

面试官:"说说BeanFactory和FactoryBean的区别?"

你:"BeanFactory是Spring的IOC容器,就像超市🏪,负责管理所有商品;FactoryBean是一个特殊的Bean,就像披萨师傅🧑‍🍳,专门制作复杂的披萨。获取FactoryBean本身需要加&前缀,不加&获取的是它创建的对象。"

面试官:"👍 回答得很形象!"


记住这句话:

"不加&拿产品,加上&见工厂!" 🎯


关注我,下期更精彩! 🌟

掌握双Bean,面试不慌! 💪✨


#Spring #BeanFactory #FactoryBean #面试必考 #最佳实践