Spring中的FactoryBean和BeanFactory

时间:2022-07-23
本文章向大家介绍Spring中的FactoryBean和BeanFactory,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

缘起

在spring的常见面试题中,经常会被问及FactoryBean和BeanFactory的区别与联系。这两个类虽然长得很像,但是他们的作用确实完全不像。其实这二者本就并没有什么关系,要是一定要说说关系,那或者就是二者都是一个接口吧。但要是说区别却能说出一大堆

  • BeanFactory 以Factory结尾,表示它是一个工厂类,用于管理Bean的一个工厂,在Spring中,所有的Bean都是由BeanFactory(也就是IOC容器)来进行管理的。
  • FactoryBean 以Bean结尾,就是一个Bean,但这个Bean不是简单的Bean,而是一个能生产或者修饰对象生成的工厂Bean,它的实现与设计模式中的工厂模式和修饰器模式类似。BeanFactory外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Fj4cJo1T-1587805016676)(http://www.bxoon.com/upload/2020/3/image-2a976aeb208b449cb2927d9a606c27ee.png) 可以看到,对应BeanFactory来说,它的职责包括:实例化、定位、配置应用程序中的对象及建立这些对象间的依赖等等,反正就是对Bean的管理基本都靠他,但她是个接口,Spring容器给出了很多种实现,如 DefaultListableBeanFactory、XmlBeanFactory、ApplicationContext等。FactoryBean外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qhHVLiTl-1587805016678)(http://www.bxoon.com/upload/2020/3/image-0348b670bce84ee8a4434ce9df01ecc1.png) 可以看到在该接口中定义了以下3个方法:
  • T getObject():返回由FactoryBean创建的Bean实例,如果isSingleton()返回true,则该实例会放到Spring容器中单实例缓存池中;
  • boolean isSingleton():返回由FactoryBean创建的Bean实例的作用域是singleton还是prototype;
  • Class<T> getObjectType():返回FactoryBean创建的Bean类型。

那么这个类的使用场景是什么呢?一般情况下,Spring通过反射机制利用<bean>的class属性指定实现类实例化Bean,但这种实例化Bean的方式看起来似乎有点笨拙。我举一个简单的例子,比如你的项目里面需要根据一个参数来判定具体要实例化哪个Bean,Class A或者Class B. 那么你会怎么做呢?可能你会把这两个类都实例化出来,然后业务中根据参数来调用Class A or Class B。但更好的实现方式如下

public class C implements FactoryBean {

    @Value("${icd.version}")
    private String icdVersion;

    @Override
    public Object getObject() throws Exception {
        if (xxx) {
            return SpringManager.getBean(A.class);
        } else{
            return SpringManager.getBean(B.class);
        }
    }

    @Override
    public Class<?> getObjectType() {
	//A和B的共同父类
        return xxx.class;
    }

    @Override
    public boolean isSingleton() {
        return true;
    }
}

SpringManager

@Component
public class SpringManager implements ApplicationContextAware {

    private static ApplicationContext context = null;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        context = applicationContext;
    }

    public static ApplicationContext getApplicationContext() {
        return context;
    }

    public static Object getBean(String name) {
        return context.getBean(name);
    }

    public static <T> T getBean(Class<T> clazz) {
        return context.getBean(clazz);
    }
}

这样我们外面只需要用SpringManager.getBean(C)的方式就可以获取到Class A or Class B了,完美。