轻松实现 BeanFactory

BeanFactory 是字面意思是“Bean 工厂”,那么顾名思义“Bean 工厂”就是用来生产 Bean 或者是用来存放 Bean 的吗?
实际上 BeanFactory 是一个 Spring IoC 容器
那这个“Bean 工厂”是如何实现的呢?

BeanFactory 接口

这是一个最简单的容器,它主要的功能是为依赖注入 (DI) 提供支持,这个容器接口在 org.springframework.beans.factory.BeanFactor 中被定义。
我们实际使用的 “Bean 工厂” 都是 BeanFactory 接口的实现类,例如:

  • XmlBeanFactory(用来读取配置文件)
  • StaticListableBeanFactory
  • DefaultListableBeanFactory
//利用 ClassPathResource() 去加载在路径 CLASSPATH 下可用的 bean 配置文件
XmlBeanFactory factory = new XmlBeanFactory(new ClassPathResource("spring.xml"));

BeanFactory 代码实现

看完概念可能还是有点懵,不要着急再往下看看。

Animal.java(接口)

public interface Animal {
    void eat();
}

Cat.java(实现Animal接口)

public class Cat implements Animal {
    public void eat() {
        System.out.println("猫吃鱼");
    }
}

BeanFactory.java(“Bean 工厂”)

import java.util.HashMap;
import java.util.Map;

public class BeanFactory {

    private Map<String, Object> beans = new HashMap<>();

    public void addBeans(String id, Object bean) {
        beans.put(id, bean);
    }
    public Object getBeans(String id) {
        return beans.get(id);
    }
}

BeanUtils.java(工具类封装 BeanFactory )

public class BeanUtils {

    //静态变量
    private static BeanFactory beanFactory =new BeanFactory();

    //静态块 只执行一次
    //使用静态块实现了 BeanFactory(Spring IoC 容器)在创建的时候就实例化了Bean,而不是在 getBean 时才实例化Bean
    static {
        beanFactory.addBeans("Animal",new Cat());
    }

    //静态方法(类调用)
    public static Object getBean(String id) {
        return beanFactory.getBeans(id);
    }
}

Tips:这里为什么要创建BeanUtils来封装BeanFactory 呢?因为BeanFactory 是一个 Spring IoC 容器,在 Spring 中容器将创建对象并进行配置管理,而不是我们主动的去 new 一个对象,也是为依赖注入 (DI) 提供支持。

MainTest.java(测试)

public class MainTest {

    public static void main(String[] args) {
    	//使用BeanUtils直接调用静态方法getBean就获取了Bean
        Animal animal = (Animal) BeanUtils.getBean("Animal");
        animal.eat();
    }
}

在这里插入图片描述
以上就是对 BeanFactory ( Spring IoC 容器)的简单实现,可以将BeanFactory 理解为一个存放和管理 Bean 的集合(至于 Spring 底层源码使用的是什么集合我不确定,但是肯定比这个简单实现要复杂很多)。

FactoryBean 接口

说完了 BeanFactory,那么疑问又来啦,FactoryBean 又是什么呢?
简单的说,BeanFactory 是 Factory 结尾是工厂;FactoryBean 是Bean 结尾是 Bean实例,但是这个Bean 实现了 FactoryBean 接口。

Bean 分类

Spring 中 Bean分为两种,具体如下:
1. 普通的Bean: < bean id="xxx" class="xxx"> ,Spring 直接创建 Bean 实例
2. FactoryBean: FactoryBean 是接口,为IOC容器中Bean的实现提供了更加灵活的方式;是一个特殊的bean,具有工厂生成对象的能力,只能生成特定的对象。Bean必须实现 FactoryBean接口,此接口提供方法 getObject() 用于获得特定bean。

FactoryBean(源码)

public interface FactoryBean<T> {
	
	// 属性名
	String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";

	// 获取bean实例,实例化bean 的逻辑就在这里实现
	@Nullable
	T getObject() throws Exception;
	// 获取bean类型
	@Nullable
	Class<?> getObjectType();
	// 是否是单例
	default boolean isSingleton() {
		return true;
	}
}
  • getObject() 返回 FactoryBean 管理的Bean 实例,并不是FactoryBean 本身的实例。
  • FactoryBean 管理的对象可以是 singleton (单例)也可以是prototype (非单例),所以此接口有了方法 isSingleton() 返回由FactoryBean 创建的Bean 实例的作用域是singleton还是prototype。
  • getObjectType() 最主要的目的就是在不创建实例的情况下就能知道想要创建的Bean 实例的类型。

Tips:从Spring3.0开始,FactoryBean开始支持泛型,即接口声明改为FactoryBean<T>的形式。

FactoryBean 与普通的 Bean 区别

FactoryBean不同于普通Bean的是:它是实现了FactoryBean<T>接口Bean,根据该Bean的IDBeanFactory中获取的实际上是 FactoryBean的getObject()返回的特定 Bean 实例,而不是FactoryBean 本身,如果要获取FactoryBean对象,需要在Bean id 前加一个 & 符号来获取。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章