所有分类
  • 所有分类
  • 未分类

Spring–BeanFactory–使用/原理/详解

简介

本文介绍Spring里的BeanFactory。包括:BeanFactory 和 FactoryBean的区别,ApplicationContext的委托逻辑。

BeanFactory 和 FactoryBean

BeanFactoryFactoryBean
工厂负责生产和管理bean的一个通用工厂。 基于工厂模式实现。也是一个工厂,但只创建一种对象。
作用实例化、定位、配置对象及建立其依赖。 IOC容器的核心接口。可以创建复杂的bean。 是一个接口。 Spring自身就提供了70多个FactoryBean的实现。它们隐藏了实例化一些复杂Bean的细节,给上层应用带来了便利。
实现DefaultListableBeanFactory、ApplicationContext、XmlBeanFactory等。 比如:XmlBeanFactory解析XML生成bean,处理对象间的依赖关系。

类的关系

Spring–Bean的创建过程/获取流程 – 自学精灵里可以发现,这几个BeanFactory比较重要:AbstractApplicationContext、DefaultListableBeanFactory、AbstractBeanFactory。那来看一下详细的类关系:

放眼望去,一脸懵逼。那介绍下这些类的作用:

  1. BeanDefinitionRegistry: Spring 配置文件中每一个节点元素在 Spring 容器里都通过一个 BeanDefinition 对象表示,它描述了 Bean 的配置信息。而 BeanDefinitionRegistry 接口提供了向容器手工注册 BeanDefinition 对象的方法。
  2. BeanFactory 接口位于类结构树的顶端 ,它最主要的方法就是 getBean(String beanName),该方法从容器中返回特定名称的 Bean,BeanFactory 的功能通过其他的接口得到不断扩展:
  3. ListableBeanFactory:该接口定义了访问容器中 Bean 基本信息的若干方法,如查看Bean 的个数、获取某一类型 Bean 的配置名、查看容器中是否包括某一 Bean 等方法;
  4. HierarchicalBeanFactory:父子级联 IOC 容器的接口。
    1. 子容器可通过接口方法访问父容器; 通过 HierarchicalBeanFactory 接口, Spring 的 IoC 容器可以建立父子层级关联的容器体系,子容器可以访问父容器中的 Bean,但父容器不能访问子容器的 Bean。
    2. Spring 使用父子容器实现了很多功能,比如在 Spring MVC 中,展现层 Bean 位于一个子容器中,而业务层和持久层的 Bean 位于父容器中。这样,展现层 Bean 就可引用业务层和持久层的 Bean,而业务层和持久层的 Bean 则看不到展现层的 Bean。
  5. ConfigurableBeanFactory:是一个重要的接口,增强了 IoC 容器的可定制性,它定义了设置类装载器、属性编辑器、容器初始化后置处理器等方法;
  6. AutowireCapableBeanFactory:定义了将容器中的 Bean 按某种规则(如按名字匹配、按类型匹配等)进行自动装配的方法;
  7. SingletonBeanRegistry:定义了允许在运行期间向容器注册单例 Bean 的方法;
  8. DefaultSingletonBeanRegistry:有缓存单例对象和单例工厂的属性(map),缓存已经注册的单例的属性(set);有注册单例bean的方法
    1. 属性
      1. singletonObjects:这个map缓存了单例对象,bean的名字为key,bean对象为value
      2. singletonFactories:这个map缓存了单例工厂,bean的名字为key,工厂对象为value
      3. registeredSingletons:这个set缓存了已经注册的单例。
    2. 方法
      1. registerSingleton(String beanName, Object singletonObject):会将单例对象放到singleFactories、registeredSingletons

ApplicationContext的委托

AbstractApplicationContext的委托逻辑

 AbstractApplicationContext部分源码

public Object getBean(String name) throws BeansException {
    this.assertBeanFactoryActive();
    return this.getBeanFactory().getBean(name);
}

public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
    this.assertBeanFactoryActive();
    return this.getBeanFactory().getBean(name, requiredType);
}

public Object getBean(String name, Object... args) throws BeansException {
    this.assertBeanFactoryActive();
    return this.getBeanFactory().getBean(name, args);
}

public <T> T getBean(Class<T> requiredType) throws BeansException {
    this.assertBeanFactoryActive();
    return this.getBeanFactory().getBean(requiredType);
}

可以看到,对BeanFactory的实现都是委托给了getBeanFactory这个方法返回的实例,接口是组合,实现也是组合,这种清晰的设计是学习典范。

getBeanFactory:它是AbstractApplicationContext自己定义的抽象方法,实现类为AbstractRefreshableApplicationContext.class,

public final ConfigurableListableBeanFactory getBeanFactory() {
    synchronized(this.beanFactoryMonitor) {
        if (this.beanFactory == null) {
            throw new IllegalStateException("BeanFactory not initialized or already closed - call 'refresh' before accessing beans via the ApplicationContext");
        } else {
            return this.beanFactory;
        }
    }
}

实现很简单,它返回了它的成员:beanFactory。Spring容器初始化的时候调用refreshBeanFactory方法,该成员变量在refreshBeanFactory方法中实例化。所以容器初始化之后,AbstractApplicationContext就具备了bean管理配置的能力。

看了上述委托的方式,猜测ApplicationContext继承的Message接口也是这么操作的?

查看代码:

public String getMessage(String code, @Nullable Object[] args, @Nullable String defaultMessage, Locale locale) {
    return this.getMessageSource().getMessage(code, args, defaultMessage, locale);
}

public String getMessage(String code, @Nullable Object[] args, Locale locale) throws NoSuchMessageException {
    return this.getMessageSource().getMessage(code, args, locale);
}

public String getMessage(MessageSourceResolvable resolvable, Locale locale) throws NoSuchMessageException {
    return this.getMessageSource().getMessage(resolvable, locale);
}

如上所示,果然如此,Message相关的接口实现,都是getMessageSource()方法返回的实例在承担,getMessageSource()方法返回的是成员变量messageSource,该成员变量也是在Spring容器初始化的时候,调用initMessageSource方法生成的。

0

评论0

请先

显示验证码
没有账号?注册  忘记密码?

社交账号快速登录