Spring IoC之BeanFactory

hresh 557 0

Spring IoC之BeanFactory

概述

在上一章节 Spring IoC之ClassPathXmlApplicationContext 关于 ClassPathXmlApplicationContext 的使用流程进行了简单的分析,其中关于 bean 的加载我们也有了大概的了解。Spring 通过资源加载器加载相应的 XML 文件,使用读取器读取资源加载器中的文件到读取器中,在读取的过程中,解析相应的 XML 文件元素,转换为 Spring 定义的数据结构 BeanDefinition,把相应的 BeanDefinition 注册到注册表中。注册表中包含的 BeanDefinition 的数据结构,没有经过加工处理过,无法得到我们想要的 bean 对象。我们如何得到 bean 对象,Spring 都做了哪些工作?BeanFactory 提供了多种方式得到 bean 对象,所以接下来就学习一下 BeanFactory。

BeanFactory

org.springframework.beans.factory.BeanFactory 是一个工厂类(接口),它负责生产和管理 bean。在 Spring 中,BeanFactory 是 IoC 容器的核心接口,它的职责包括:实例化、定位、配置应用程序中的对象以及建立这些对象间的依赖。其定义如下:

public interface BeanFactory {
    String FACTORY_BEAN_PREFIX = "&";

    //返回给定名称注册的bean实例。
    Object getBean(String var1) throws BeansException;

    <T> T getBean(String var1, Class<T> var2) throws BeansException;

    //返回以给定名称注册的bean实例,并转换为给定class类型
    Object getBean(String var1, Object... var2) throws BeansException;

    <T> T getBean(Class<T> var1) throws BeansException;

    <T> T getBean(Class<T> var1, Object... var2) throws BeansException;

    <T> ObjectProvider<T> getBeanProvider(Class<T> var1);

    <T> ObjectProvider<T> getBeanProvider(ResolvableType var1);

    //判断工厂中是否包含给定名称的bean定义,若有则返回true
    boolean containsBean(String var1);

    //判断给定名称的bean定义是否为单例模式
    boolean isSingleton(String var1) throws NoSuchBeanDefinitionException;

    //判断给定名称的bean定义是否为原型类型
    boolean isPrototype(String var1) throws NoSuchBeanDefinitionException;

    // 类型是否匹配
    boolean isTypeMatch(String var1, ResolvableType var2) throws NoSuchBeanDefinitionException;

    boolean isTypeMatch(String var1, Class<?> var2) throws NoSuchBeanDefinitionException;

    // 获取一个bean的数据类型
    @Nullable
    Class<?> getType(String var1) throws NoSuchBeanDefinitionException;

    @Nullable
    Class<?> getType(String var1, boolean var2) throws NoSuchBeanDefinitionException;

    //返回给定bean名称的所有别名 
    String[] getAliases(String var1);
}

接口里定义了一个变量 FACTORY_BEAN_PREFIX,用来区分是获取 FactoryBean 还是 FactoryBean 的 createBean 创建的实例。如果&开始则获取 FactoryBean;否则获取 createBean 创建的实例。

BeanFactory 体系结构,如下图所示:

Spring IoC之BeanFactory

从图中可以看到:

  • BeanFactory 作为一个主接口不继承任何接口,暂且称为一级接口。

  • 有 3个子接口继承了它,进行功能上的增强。这3个子接口称为二级接口。 ListableBeanFactory 接口表示这些 Bean 是可列表的,而 HierarchicalBeanFactory表示的是这些 Bean 是有继承关系的,也就是每个 Bean 有可能有父 Bean。AutowireCapableBeanFactory接口定义 Bean 的自动装配规则。

  • ConfigurableBeanFactory可以被称为三级接口,对二级接口HierarchicalBeanFactory进行了再次增强 ;ApplicationContext 继承 HierarchicalBeanFactory 和 ListableBeanFactory,包含 BeanFactory 的所有功能,通常建议比 BeanFactory 优先使用。。
  • ConfigurableListableBeanFactory是一个更强大的接口,继承了上述的所有接口,无所不包,称为四级接口。
  • AbstractBeanFactory 作为一个抽象类,实现了三级接口 ConfigurableBeanFactory 大部分功能。
  • AbstractAutowireCapableBeanFactory 同样是抽象类,继承自 AbstractBeanFactory,并额外实现了二级接口 AutowireCapableBeanFactory。
  • DefaultListableBeanFactory 继承自 AbstractAutowireCapableBeanFactory,实现了最强大的四级接口 ConfigurableListableBeanFactory,并实现了一个外来接口BeanDefinitionRegistry,它并非抽象类。
  • XmlBeanFactory,继承自 DefaultListableBeanFactory,重写了一些功能,使自己更强大。 注意:从 Spring3.1开始该类不推荐使用。

BeanFactory 只是个接口,并不是 IoC 容器的具体实现,但是 Spring 容器给出了很多种实现,如 AbstractBeanFactory、DefaultListableBeanFactory、XmlBeanFactory、ApplicationContext 等,其中 XmlBeanFactory 就是常用的一个,该实现将以 XML 方式描述组成应用的对象及对象间的依赖关系。XmlBeanFactory 类将持有此 XML 配置元数据,并用它来构建一个完全可配置的系统或应用。 ApplicationContext 包含 BeanFactory 的所有功能,同时还进行了扩展,后期我们会单独对其进行讲解学习。

BeanFactory 提供了多种方式得到 bean 对象,getBean()方法是最核心得到 bean 对象 getBean 主要由 AbstractBeanFactory、AbstractAutowireCapableBeanFactory、以及 DefaultListableBeanFactory 实现。

FactoryBean

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

以 Bean 结尾,表示它是一个 Bean,不同于普通 Bean 的是:它是实现了 FactoryBean接口的 Bean,根据该 Bean 的 ID 从 BeanFactory 中获取的实际上是 FactoryBean 的 getObject() 返回的对象,而不是 FactoryBean 本身,如果要获取 FactoryBean 对象,请在 ID 前面加一个&符号来获取。 后面我们会从源码来分析这一块。

public interface FactoryBean<T> {
    String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";

    @Nullable
    T getObject() throws Exception;

    @Nullable
    Class<?> getObjectType();

    default boolean isSingleton() {
        return true;
    }
}

在该接口中定义了以下3个方法:

  • T getObject():返回由 FactoryBean 创建的 Bean 实例,如果 isSingleton()返回 true,则该实例会放到 Spring 容器中的单实例缓冲池中。
  • boolean isSingleton():返回由 FactoryBean 创建的 Bean 实例的作用域是 singleton 还是 prototype。
  • Class<?> getObjectType():返回 FactoryBean 创建的 Bean 类型。

当配置文件中的 class 属性配置的实现类是 FactoryBean 时,通过 getBean() 方法返回的不是 FactoryBean 本身,而是 FactoryBean#getObject() 方法返回的对象,相当于 FactoryBean#getObject()代理了 getBean()方法。

例如:如果使用传统方式配置下面 Car 的时,Car 的每个属性分别对应一个元素标签。

public class Car {
    private int maxSpeed ;
    private String brand ;
    private double price ;

    //get//set 方法

    @Override
    public String toString() {
        return "Car{" +
                "maxSpeed=" + maxSpeed +
                ", brand='" + brand + '\'' +
                ", price=" + price +
                '}';
    }
}

此时 beans.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"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="car" class="com.msdn.bean.Car">
        <property name="maxSpeed" value="120" />
        <property name="brand" value="BMW" />
        <property name="price" value="2500.5" />
    </bean>

</beans>

测试代码如下:

@Test
public void getCar(){
    ClassPathResource resource = new ClassPathResource("beans.xml");
    BeanFactory beanFactory = new XmlBeanFactory(resource);

    Car car = (Car) beanFactory.getBean("car");
    System.out.println(car);
}

上述实现方式是我们比较常用的,就是在 bean 定义的时候,如果该 bean 类有多个属性的时候,设置 property 比较麻烦。此时如果用 FactoryBean 的方式实现就灵活点,下例通过逗号分割符的方式一次性的为 Ca r的所有属性指定配置值:

import  org.springframework.beans.factory.FactoryBean;  
public class CarFactoryBean implements FactoryBean<Car> {
    private String carInfo;
    @Override
    public Car getObject() throws Exception {
        Car car = new Car();
        String[] infos = carInfo.split(",");
        car.setBrand(infos[0]);
        car.setMaxSpeed(Integer.valueOf(infos[1]));
        car.setPrice(Double.valueOf(infos[2]));
        return car;
    }

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

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

    public String getCarInfo() {
        return carInfo;
    }

    public void setCarInfo(String carInfo) {
        this.carInfo = carInfo;
    }
}

有了这个 CarFactoryBean 后,就可以在配置文件中使用下面这种自定义的配置方式配置 CarBean 了:

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

    <bean id="carFactoryBean" class="com.msdn.bean.CarFactoryBean" p:carInfo="BMW,234,45000" />

</beans>

测试代码如下:

@Test
public void getCar() throws Exception {
    ClassPathResource resource = new ClassPathResource("beans.xml");
    BeanFactory beanFactory = new XmlBeanFactory(resource);

    Car car = (Car) beanFactory.getBean("carFactoryBean");
    System.out.println(car);
    CarFactoryBean carFactoryBean = (CarFactoryBean) beanFactory.getBean("&carFactoryBean");
    System.out.println(carFactoryBean.getObject());
    System.out.println(carFactoryBean);
}

执行结果为:

Car{maxSpeed=234, brand='BMW', price=45000.0}
Car{maxSpeed=234, brand='BMW', price=45000.0}
com.msdn.bean.CarFactoryBean@5383967b

当调用 getBean("carFactoryBean")时,Spring 通过反射机制发现 CarFactoryBean 实现了 FactoryBean 的接口,这时 Spring 容器就调用接口方法 CarFactoryBean#getObject()方法返回。如果希望获取 CarFactoryBean 的实例,则需要在使用 getBean(beanName)方法时在 beanName 前显示的加上"&"前缀:如getBean("&carFactoryBean");

AbstractBeanFactory

AbstractBeanFactory 实现了依赖关系处理,它 继承了 DefaultSingletonBeanRegistry 类,并进一步丰富了已有的功能,这个类提供了 singleton/prototype 的选择,单例 cache,对于 FactoryBean 的处理,bean 定义的处理以及 bean 的销毁等。关于该类的分析由于篇幅过长,所以会单独出一章节内容,欢迎大家阅读 Spring IoC之AbstractBeanFactory

DefaultListableBeanFactory

由于 XmlBeanFactory 继承了 DefaultListableBeanFactory 类,因此我们接下来学习 DefaultListableBeanFactory 中的知识点。

该实现类中的内容太多了,没法都讲解到,因此这里就前一章节分析过程中使用到的内容进行讲述。

属性

@Nullable
private static Class<?> javaxInjectProviderClass;
//序列化ID映射到工厂实例的Map
private static final Map<String, Reference<DefaultListableBeanFactory>> serializableFactories;
// 可选ID,用于序列化
@Nullable
private String serializationId;
//是否允许同名字不同定义的bean重新注册
private boolean allowBeanDefinitionOverriding = true;
// 是否允许bean基至是延迟加载的bean马上加载
private boolean allowEagerClassLoading = true;
//可选的用于依赖集合和数组的比较器
@Nullable
private Comparator<Object> dependencyComparator;
//用于检查一个类定义是否有自动注入请求的解析器
private AutowireCandidateResolver autowireCandidateResolver = new SimpleAutowireCandidateResolver();
//依赖类型到对应的注入值的映射
private final Map<Class<?>, Object> resolvableDependencies = new ConcurrentHashMap(16);
//bean名称和bean数据实体的映射
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap(256);
//依赖类型到对应bean名字的映射,包括单例和非单例
private final Map<Class<?>, String[]> allBeanNamesByType = new ConcurrentHashMap(64);
//依赖类型到对应bean名字的映射,仅包含单例
private final Map<Class<?>, String[]> singletonBeanNamesByType = new ConcurrentHashMap(64);
//所有bean定义的名字的集合,按注册次序
private volatile List<String> beanDefinitionNames = new ArrayList(256);
//手工注册的单例bean定义的名字的集合,按注册次序
private volatile Set<String> manualSingletonNames = new LinkedHashSet(16);
//缓存bean定义名字的数组
@Nullable
private volatile String[] frozenBeanDefinitionNames;
//是否允许bean定义的元数据被缓存,以用于所有的bean
private volatile boolean configurationFrozen = false;

构造函数

public DefaultListableBeanFactory() {
}

public DefaultListableBeanFactory(@Nullable BeanFactory parentBeanFactory) {
    super(parentBeanFactory);
}

有参构造函数实际调用的是 AbstractAutowireCapableBeanFactory 类中的构造函数,其定义如下:

public AbstractAutowireCapableBeanFactory() {
    this.instantiationStrategy = new CglibSubclassingInstantiationStrategy();
    this.parameterNameDiscoverer = new DefaultParameterNameDiscoverer();
    this.allowCircularReferences = true;
    this.allowRawInjectionDespiteWrapping = false;
    this.ignoredDependencyTypes = new HashSet();
    this.ignoredDependencyInterfaces = new HashSet();
    this.currentlyCreatedBean = new NamedThreadLocal("Currently created bean");
    this.factoryBeanInstanceCache = new ConcurrentHashMap();
    this.factoryMethodCandidateCache = new ConcurrentHashMap();
    this.filteredPropertyDescriptorsCache = new ConcurrentHashMap();
    this.ignoreDependencyInterface(BeanNameAware.class);
    this.ignoreDependencyInterface(BeanFactoryAware.class);
    this.ignoreDependencyInterface(BeanClassLoaderAware.class);
}

public AbstractAutowireCapableBeanFactory(@Nullable BeanFactory parentBeanFactory) {
    this();
    this.setParentBeanFactory(parentBeanFactory);
}

该构造方法用来初始化一些必要的参数信息,然后设置 bean 工厂超类。

setSerializationId

public void setSerializationId(@Nullable String serializationId) {
    if (serializationId != null) {
        serializableFactories.put(serializationId, new WeakReference(this));
    } else if (this.serializationId != null) {
        serializableFactories.remove(this.serializationId);
    }

    this.serializationId = serializationId;
}

DefaultListableBeanFactory 实现了序列化接口,该方法指定一个ID以进行序列化,如果需要的话,允许将该 BeanFactory 从该ID反序列化回 BeanFactory 对象。

getBean

返回与给定对象类型唯一匹配的bean实例(如果有)

public <T> T getBean(Class<T> requiredType) throws BeansException {
    return this.getBean(requiredType, (Object[])null);
}

public <T> T getBean(Class<T> requiredType, @Nullable Object... args) throws BeansException {
    Assert.notNull(requiredType, "Required type must not be null");
    Object resolved = this.resolveBean(ResolvableType.forRawClass(requiredType), args, false);
    if (resolved == null) {
        throw new NoSuchBeanDefinitionException(requiredType);
    } else {
        return resolved;
    }
}

其中关键的是 resolveBean()方法,该方法用于生成一个 bean 的实例,其定义如下:

private <T> T resolveBean(ResolvableType requiredType, @Nullable Object[] args, boolean nonUniqueAsNull) {
    //该方法为核心方法,用于生成bean实例
    NamedBeanHolder<T> namedBean = this.resolveNamedBean(requiredType, args, nonUniqueAsNull);
    if (namedBean != null) {
        return namedBean.getBeanInstance();
    } else {
        BeanFactory parent = this.getParentBeanFactory();
        if (parent instanceof DefaultListableBeanFactory) {
            return ((DefaultListableBeanFactory)parent).resolveBean(requiredType, args, nonUniqueAsNull);
        } else if (parent != null) {
            ObjectProvider<T> parentProvider = parent.getBeanProvider(requiredType);
            if (args != null) {
                return parentProvider.getObject(args);
            } else {
                return nonUniqueAsNull ? parentProvider.getIfUnique() : parentProvider.getIfAvailable();
            }
        } else {
            return null;
        }
    }
}

其中具体的实现还是集中在 resolveNamedBean()方法上,其定义如下:

    private <T> NamedBeanHolder<T> resolveNamedBean(ResolvableType requiredType, @Nullable Object[] args, boolean nonUniqueAsNull) throws BeansException {
        Assert.notNull(requiredType, "Required type must not be null");
        //遍历xml文件,获取相应的bean名称
        String[] candidateNames = this.getBeanNamesForType(requiredType);
        String[] var6;
        int var7;
        int var8;
        String beanName;
        if (candidateNames.length > 1) {
            List<String> autowireCandidates = new ArrayList(candidateNames.length);
            var6 = candidateNames;
            var7 = candidateNames.length;

            for(var8 = 0; var8 < var7; ++var8) {
                beanName = var6[var8];
                if (!this.containsBeanDefinition(beanName) || this.getBeanDefinition(beanName).isAutowireCandidate()) {
                    autowireCandidates.add(beanName);
                }
            }

            if (!autowireCandidates.isEmpty()) {
                candidateNames = StringUtils.toStringArray(autowireCandidates);
            }
        }

        if (candidateNames.length == 1) {
            String beanName = candidateNames[0];
            //调用AbstractBeanFactory类中的getBean方法
            return new NamedBeanHolder(beanName, this.getBean(beanName, requiredType.toClass(), args));
        } else {
            if (candidateNames.length > 1) {
                Map<String, Object> candidates = new LinkedHashMap(candidateNames.length);
                var6 = candidateNames;
                var7 = candidateNames.length;

                for(var8 = 0; var8 < var7; ++var8) {
                    beanName = var6[var8];
                    if (this.containsSingleton(beanName) && args == null) {
                        Object beanInstance = this.getBean(beanName);
                        candidates.put(beanName, beanInstance instanceof NullBean ? null : beanInstance);
                    } else {
                        candidates.put(beanName, this.getType(beanName));
                    }
                }

                String candidateName = this.determinePrimaryCandidate(candidates, requiredType.toClass());
                if (candidateName == null) {
                    candidateName = this.determineHighestPriorityCandidate(candidates, requiredType.toClass());
                }

                if (candidateName != null) {
                    Object beanInstance = candidates.get(candidateName);
                    if (beanInstance == null || beanInstance instanceof Class) {
                        beanInstance = this.getBean(candidateName, requiredType.toClass(), args);
                    }

                    return new NamedBeanHolder(candidateName, beanInstance);
                }

                if (!nonUniqueAsNull) {
                    throw new NoUniqueBeanDefinitionException(requiredType, candidates.keySet());
                }
            }

            return null;
        }
    }

结合代码可知,当 getBean()传入的是 bean 的 class 类型时,会通过 getBeanNamesForType()方法转换为 beanName,接着再调用 AbstractBeanFactory 类中的 getBean 方法。

发表评论 取消回复
表情 图片 链接 代码

分享