一文讀懂BeanFactory和FactoryBean區別

lonecloud發表於2020-08-23

一直以來,很多人對於Spring中的BeanFactory和FactoryBean都是分不清楚的

BeanFactory

這個其實是所有Spring Bean的容器根介面,給Spring 的容器定義一套規範,給IOC容器提供了一套完整的規範,比如我們常用到的getBean方法等

The root interface for accessing a Spring bean container. This is the basic client view of a bean container;

定義方法:

  • getBean(String name): Spring容器中獲取對應Bean物件的方法,如存在,則返回該物件
  • containsBean(String name):Spring容器中是否存在該物件
  • isSingleton(String name):通過beanName是否為單例物件
  • isPrototype(String name):判斷bean物件是否為多例物件
  • isTypeMatch(String name, ResolvableType typeToMatch):判斷name值獲取出來的bean與typeToMath是否匹配
  • getType(String name):獲取Bean的Class型別
  • getAliases(String name):獲取name所對應的所有的別名

主要的實現類(包括抽象類):

  • AbstractBeanFactory:抽象Bean工廠,絕大部分的實現類,都是繼承於他
  • DefaultListableBeanFactory:Spring預設的工廠類
  • XmlBeanFactory:前期使用XML配置用的比較多的時候用的Bean工廠
  • AbstractXmlApplicationContext:抽象應用容器上下文物件
  • ClassPathXmlApplicationContext:XML解析上下文物件,使用者建立Bean物件我們早期寫Spring的時候用的就是他

使用方式:

  1. 使用ClassPathXmlApplicationContext讀取對應的xml檔案例項對應上下文物件
ApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"applicationContext.xml"});
BeanFactory factory = (BeanFactory) context;

FactoryBean

該類是SpringIOC容器是建立Bean的一種形式,這種方式建立Bean會有加成方式,融合了簡單的工廠設計模式於裝飾器模式

* Interface to be implemented by objects used within a {@link BeanFactory} which
* are themselves factories for individual objects. If a bean implements this
* interface, it is used as a factory for an object to expose, not directly as a
* bean instance that will be exposed itself.

有些人就要問了,我直接使用Spring預設方式建立Bean不香麼,為啥還要用FactoryBean做啥,在某些情況下,對於例項Bean物件比較複雜的情況下,使用傳統方式建立bean會比較複雜,例如(使用xml配置),這樣就出現了FactoryBean介面,可以讓使用者通過實現該介面來自定義該Bean介面的例項化過程。即包裝一層,將複雜的初始化過程包裝,讓呼叫者無需關係具體實現細節。

方法:

  • T getObject():返回例項

  • Class<?> getObjectType();:返回該裝飾物件的Bean的型別

  • default boolean isSingleton():Bean是否為單例

常用類

  • ProxyFactoryBean :Aop代理Bean
  • GsonFactoryBean:Gson

使用

  1. Spring XML方式

application.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="demo" class="cn.lonecloud.spring.example.bo.Person">
        <property name="age" value="10"/>
        <property name="name" value="xiaoMing"/>
    </bean>

    <bean id="demoFromFactory" class="cn.lonecloud.spring.example.bean.PersonFactoryBean">
        <property name="initStr" value="10,init from factory"/>
    </bean>
</beans>

personFactoryBean.java

package cn.lonecloud.spring.example.bean;

import cn.lonecloud.spring.example.bo.Person;
import org.springframework.beans.factory.FactoryBean;

import java.util.Objects;

/**
 * TODO
 *
 * @author lonecloud <lonecloud@aliyun.com>
 * @date 2020/8/4 23:39
 * @since v1.0
 */
public class PersonFactoryBean implements FactoryBean<Person> {

    /**
     * 初始化Str
     */
    private String initStr;

    @Override
    public Person getObject() throws Exception {
        //這裡我需要獲取對應引數
        Objects.requireNonNull(initStr);
        String[] split = initStr.split(",");
        Person p=new Person();
        p.setAge(Integer.parseInt(split[0]));
        p.setName(split[1]);
        //這裡可能需要還要有其他複雜事情需要處理
        return p;
    }

    @Override
    public Class<?> getObjectType() {
        return Person.class;
    }

    public String getInitStr() {
        return initStr;
    }

    public void setInitStr(String initStr) {
        this.initStr = initStr;
    }
}

main方法

package cn.lonecloud.spring.example.factory;

import cn.lonecloud.spring.example.bo.Person;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * BeanFactory 例子
 *
 * @author lonecloud <lonecloud@aliyun.com>
 * @date 2020/8/4 23:32
 * @since v1.0
 */
public class SpringBeanFactoryMain {

    public static void main(String[] args) {
        //這個是BeanFactory
        BeanFactory beanFactory = new ClassPathXmlApplicationContext("application.xml");
        //獲取對應的物件化
        Object demo = beanFactory.getBean("demo");
        System.out.println(demo instanceof Person);
        System.out.println(demo);
        //獲取從工廠Bean中獲取物件
        Person demoFromFactory = beanFactory.getBean("demoFromFactory", Person.class);
        System.out.println(demoFromFactory);
        //獲取對應的personFactory
        Object bean = beanFactory.getBean("&demoFromFactory");
        System.out.println(bean instanceof PersonFactoryBean);
        PersonFactoryBean factoryBean=(PersonFactoryBean) bean;
        System.out.println("初始化引數為:"+factoryBean.getInitStr());
    }
}

輸出

true
Person{name='xiaoMing', age=10}
Person{name='init from factory', age=10}
true
初始化引數為:10,init from factory

區別

  1. BeanFactory:負責生產和管理Bean的一個工廠介面,提供一個Spring Ioc容器規範,
  2. FactoryBean: 一種Bean建立的一種方式,對Bean的一種擴充套件。對於複雜的Bean物件初始化建立使用其可封裝物件的建立細節。

程式碼:GitHub地址

相關文章