BeanFactory和FactoryBean

(一)BeanFactory

        BeanFactory是一个工厂类接口,定义了IOC容器的最基本形式,并提供了IOC容器应遵守的的最基本的接口,职责包括实例化、定位、配置应用程序中的对象以及建立这些对象之间的依赖。在Spring中有很多具体的实现,在这些实现中对BeanFactory进行了功能扩展,例如:

  1. AbstractBeanFactory:抽象Bean工厂,绝大部分的实现类,都是继承于他
  2. DefaultListableBeanFactory:Spring默认的工厂类
  3. XmlBeanFactory:前期使用XML配置用的比较多的时候用的Bean工厂
  4. AbstractXmlApplicationContext:抽象应用容器上下文对象
  5. ClassPathXmlApplicationContext:XML解析上下文对象,用户创建Bean对象我们早期写Spring的时候用的就是他

(二)FactoryBean

        FactoryBean是一个Bean,但又不仅仅是一个Bean。它是一个能生产或修饰对象生成的工厂Bean,类似于设计模式中的工厂模式和装饰器模式。它能在需要的时候生产一个对象,且不仅仅限于它自身,它能返回任何Bean的实例。一个Bean如果实现了FactoryBean接口,那么根据该Bean的名称获取到的实际上是getObject返回的对象,而不是这个Bean自身实例,如果要获取这个Bean自身实例,那么需要在名称前面加上'&'符号。

一般情况下,Spring通过反射机制利用的class属性指定实现类实例化Bean,在某些情况下,实例化Bean过程比较复杂,如果按照传统的方式,则需要在中提供大量的配置信息。配置方式的灵活性是受限的,这时采用编码的方式可能会得到一个简单的方案。Spring为此提供了一个org.springframework.bean.factory.FactoryBean的工厂类接口,用户可以通过实现该接口定制实例化Bean的逻辑。FactoryBean接口对于Spring框架来说占用重要的地位,Spring自身就提供了70多个FactoryBean的实现。它们隐藏了实例化一些复杂Bean的细节,给上层应用带来了便利。从Spring3.0开始,FactoryBean开始支持泛型,即接口声明改为FactoryBean的形式

下面通过代码练习如何使用FactoryBean,以此加深对上面描述内容的理解。

1)TestBean

实现FactoryBean接口并实现getObject()和getObjectType()方法,其中在getObject()方法中实例化一个TestBean对象,并对message进行了一些特殊处理(区别于构造方法)

@Component
public class TestBean implements FactoryBean {

    private String message;

    public TestBean() {
        this.message = "通过构造方法初始化实例";
    }

    @Override
    public Object getObject() throws Exception {
        TestBean testBean = new TestBean();
        testBean.message = "通过FactoryBean.getObject()创建实例";
        // 这里并不一定要返回TestBean自身的实例,可以是其他任何对象的实例
        return testBean;
    }

    @Override
    public Class getObjectType() {
        return TestBean.class;
    }

    public String getMessage() {
        return message;
    }

}

2)FactoryBeanTest测试类

@RunWith(SpringRunner.class)
@SpringBootTest(classes = TestApplication.class)
public class FactoryBeanTest {

    @Autowired
    private ApplicationContext context;

    @Test
    public void test() {
        TestBean myBean1 = (TestBean) context.getBean("testBean");
        System.out.println("myBean1 = " + myBean1.getMessage());
        TestBean myBean2 = (TestBean) context.getBean("&testBean");
        System.out.println("myBean2 = " + myBean2.getMessage());
        System.out.println("myBean1.equals(myBean2) = " + myBean1.equals(myBean2));

    }

}

3)测试输出

myBean1 = 通过FactoryBean.getObject()初始化实例
myBean2 = 通过构造方法初始化实例
myBean1.equals(myBean2) = false

4)总结

        可见当调用getBean("testBean")时,Spring通过反射机制发现TestBean实现了FactoryBean接口,这时Spring容器就调用接口方法TestBean#getObject()方法返回,这时返回的并不是FactoryBean本身,而是FactoryBean#getObject()方法内部所返回的对象,相当于FactoryBean#getObject()代理了getBean()方法。

        如果希望获取TestBean的实例,则需要在使用getBean(beanName)方法时在beanName前显示的加上"&"前缀:如getBean("&testBean")。

你可能感兴趣的:(Spring,spring,java,后端)