Bootstrap

【Spring高级】FactoryBean

FactoryBean 是 Spring 框架中的一个特殊接口,用于创建并管理对象的生成。通常情况下,Spring IoC 容器负责实例化、配置和组装应用程序中的 bean。但有时bean 的创建过程可能涉及一些特殊的逻辑,或者我们可能希望在某些情况下延迟 bean 的创建。在这些情况下,FactoryBean 就非常有用。

FactoryBean 接口定义了一个方法 getObject(),当 Spring 容器调用这个方法时,它会返回由 FactoryBean 创建的对象实例。此外,FactoryBean 还提供了 getObjectType()isSingleton() 方法,用于返回对象的类型和是否是单例。

下面是 FactoryBean 接口的简化定义:

public interface FactoryBean<T> {  
    T getObject() throws Exception;  
    Class<?> getObjectType();  
    boolean isSingleton();  
}

使用 FactoryBean 的一个常见场景是当你需要返回一个代理对象而不是直接实例化的对象时。例如,AOP(面向切面编程)代理就是通过 FactoryBean 创建的。

下面是使用 FactoryBean 的一个简单示例:

public class MyFactoryBean implements FactoryBean<MyObject> {  
  
    @Override  
    public MyObject getObject() throws Exception {  
        // 这里可以包含一些特殊的逻辑来创建 MyObject 实例  
        MyObject myObject = new MyObject();  
        // 可能的初始化或配置代码  
        return myObject;  
    }  
  
    @Override  
    public Class<?> getObjectType() {  
        return MyObject.class;  
    }  
  
    @Override  
    public boolean isSingleton() {  
        // 根据需要返回 true 或 false  
        return true;  
    }  
}

在 Spring 配置文件中,你可以像配置普通 bean 一样配置 FactoryBean

xml复制代码

<bean id="myFactoryBean" class="com.example.MyFactoryBean"/>

然后,你可以通过以下方式获取由 FactoryBean 创建的对象:

ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");  
MyObject myObject = (MyObject) context.getBean("myFactoryBean");

注意,当从 Spring 容器中获取 bean 时,你使用的是 FactoryBean 的 id,而不是它创建的对象类型的 id。Spring 会自动调用 FactoryBeangetObject() 方法来获取实际的 bean 实例。

FactoryBean 提供了一种灵活的方式来创建和管理 bean,使得 Spring 容器能够处理更复杂的对象创建场景。

看下面一个案例:

创建Bean1:

package com.cys.spring.chapter18;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.annotation.Autowired;

import javax.annotation.PostConstruct;

public class Bean1 implements BeanFactoryAware {
    private static final Logger log = LoggerFactory.getLogger(Bean1.class);

    private Bean2 bean2;

    @Autowired
    public void setBean2(Bean2 bean2) {
        log.debug("setBean2({})", bean2);
        this.bean2 = bean2;
    }

    public Bean2 getBean2() {
        return bean2;
    }

    @PostConstruct
    public void init() {
        log.debug("init");
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        log.debug("setBeanFactory({})", beanFactory);
    }
}

Bean2

package com.cys.spring.chapter18;

import org.springframework.stereotype.Component;

@Component
public class Bean2 {
}

创建FactoryBean

package com.cys.spring.chapter18;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.stereotype.Component;

@Component("bean1")
public class Bean1FactoryBean implements FactoryBean<Bean1> {

    private static final Logger log = LoggerFactory.getLogger(Bean1FactoryBean.class);

    // 决定了根据【类型】获取或依赖注入能否成功
    @Override
    public Class<?> getObjectType() {
        return Bean1.class;
    }

    // 决定了 getObject() 方法被调用一次还是多次
    @Override
    public boolean isSingleton() {
        return true;
    }

    @Override
    public Bean1 getObject() throws Exception {
        Bean1 bean1 = new Bean1();
        log.debug("create bean: {}", bean1);
        return bean1;
    }
}

创建Bean1的后置处理器

package com.cys.spring.chapter18;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;

@Component
public class Bean1PostProcessor implements BeanPostProcessor {

    private static final Logger log = LoggerFactory.getLogger(Bean1PostProcessor.class);

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if (beanName.equals("bean1") && bean instanceof Bean1) {
            log.debug("before [{}] init", beanName);
        }
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if (beanName.equals("bean1") && bean instanceof Bean1) {
            log.debug("after [{}] init", beanName);
        }
        return bean;
    }
}

测试类:

package com.cys.spring.chapter18;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.stereotype.Component;


@ComponentScan
public class TestFactoryBean {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(TestFactoryBean.class);

        Bean2 bean4 = (Bean2) context.getBean("bean2");
        Bean1 bean1 = (Bean1) context.getBean("bean1");
        Bean1 bean2 = (Bean1) context.getBean("bean1");
        Bean1 bean3 = (Bean1) context.getBean("bean1");
        System.out.println(bean1);
        System.out.println(bean2);
        System.out.println(bean3);

        System.out.println(context.getBean(Bean1.class));

        System.out.println(context.getBean(Bean1FactoryBean.class));
        System.out.println(context.getBean("&bean1"));

        context.close();

    }
}

运行结果如下:

21:16:09.244 [main] DEBUG com.cys.spring.chapter18.Bean1FactoryBean - create bean: com.cys.spring.chapter18.Bean1@52b1beb6
21:16:09.245 [main] DEBUG com.cys.spring.chapter18.Bean1PostProcessor - after [bean1] init
com.cys.spring.chapter18.Bean1@52b1beb6
com.cys.spring.chapter18.Bean1@52b1beb6
com.cys.spring.chapter18.Bean1@52b1beb6
com.cys.spring.chapter18.Bean1@52b1beb6
com.cys.spring.chapter18.Bean1FactoryBean@3527942a
com.cys.spring.chapter18.Bean1FactoryBean@3527942a

从上面结果看出,FactoryBean还有以下特点:

  1. 被 FactoryBean 创建的产品
    • 会认为创建、依赖注入、Aware 接口回调、前初始化这些都是 FactoryBean 的职责, 这些流程都不会
    • 唯有后初始化的流程会走, 也就是产品可以被代理增强
    • 单例的产品不会存储于 BeanFactory 的 singletonObjects 成员中, 而是另一个 factoryBeanObjectCache 成员中
  2. 按名字去获取时, 拿到的是产品对象, 名字前面加 & 获取的是工厂对象

他的作用是用制造创建过程较为复杂的产品, 如 SqlSessionFactory, 但 @Bean 已具备等价功能。

;