写点什么

spring 的 BeanFactory 和 ApplicationContext

作者:程序员欣宸
  • 2022 年 6 月 11 日
  • 本文字数:3388 字

    阅读完需:约 11 分钟

spring的BeanFactory和ApplicationContext

欢迎访问我的 GitHub

这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos


  • 文中涉及的 spring 版本号为 4.1.8.RELEASE;

BeanFactory 接口

  • 在 spring 容器中,BeanFactory 接口是 IOC 容器要实现的最基础的接口,定义了管理 bean 的最基本的方法,例如获取实例、基本的判断等,如下图:



  • BeanFactory 有多个子接口来进一步扩展 bean 相关的功能,以下两个与本文有直接关系,需要关注:

  • HierarchicalBeanFactory:beanFactory 可以设置 ParentBeanFactory,这个接口的两个方法都是和 ParentBeanFactory 相关的,getParentBeanFactory 方法返回 ParentBeanFactory,containsLocalBean 方法是相对 containsBean 方法而言的,containsBean 方法找不到 bean 的时候会通过 ParentBeanFactory 去找,而 containsLocalBean 只在当前 beanFactory 找;

  • ListableBeanFactory:主要用于获取 bean 相关信息,例如获取所有 bean 名称,查找指定类型的所有 bean 等,如下图:


ApplicationContext 接口

  • 关于 ApplicationContext 和 BeanFactory 的关系,看类图即可一目了然:



  • 原来 ApplicationContext 继承了 HierarchicalBeanFactory 和 ListableBeanFactory,也就是说前面看到的接口特性都被 ApplicationContext 继承下来了,另外通过类图可以发现,ApplicationContext 还继承了诸如 Environment、Resource、Message、Event

  • 等相关的接口,也就是说除了 bean 的管理配置相关的能力,ApplicationContext 还拥有了 Environment(环境)、MessageSource(国际化)、ResourceLoader(资源)、ApplicationEventPublisher(应用事件)等服务相关的接口,简单的说 ApplicationContext 是以 bean 管理为基础的综合能力扩展,用于满足业务对 Spring 综合能力的需要;

  • 再看看 ApplicationContext 源码,除了继承,它自身也提供了一些扩展的能力:


public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,    MessageSource, ApplicationEventPublisher, ResourcePatternResolver {
//标识当前context实例的id,最终会通过native方法来生成:System.identityHashCode String getId();
//返回该context所属的应用名称,默认为空字符串,在web应用中返回的是servlet的contextpath String getApplicationName();
//返回当前context的名称 String getDisplayName();
//返回context第一次被加载的时间 long getStartupDate();
//返回该context的parent ApplicationContext getParent();
//返回具有自动装配能力的beanFactory,默认返回的就是初始化时实例化的beanFactory AutowireCapableBeanFactory getAutowireCapableBeanFactory() throws IllegalStateException;}
复制代码


  • 小结:


  1. BeanFactory 是基础,BeanFactory 和它的子接口定义的 API 满足了 spring 环境中对 bean 管理和配置的需求;

  2. ApplicationContext 是扩展,以 BeanFactory 为主线,通过继承的方式综合了环境、国际化、资源、事件等多条支线,自己又规定了一些扩展服务(如返回 context 的 id,应用名称等),而所有支线都以 bean 服务为基础;

实现类解析

  • 如果有个类实现了 ApplicationContext 接口,就必须实现上述多个接口定义的方法,这个类岂不是很复杂?我们看看 AbstractApplicationContext 类的源码,这是个基础抽象类,常用的 ClassPathXmlApplicationContext、AnnotationConfigServletWebServerApplicationContext 等都继承自 AbstractApplicationContext;

  • 先看看是如何实现 BeanFactory 接口中定义的方法的:


  @Override  public Object getBean(String name) throws BeansException {    assertBeanFactoryActive();    return getBeanFactory().getBean(name);  }
@Override public <T> T getBean(String name, Class<T> requiredType) throws BeansException { assertBeanFactoryActive(); return getBeanFactory().getBean(name, requiredType); }
@Override public <T> T getBean(Class<T> requiredType) throws BeansException { assertBeanFactoryActive(); return getBeanFactory().getBean(requiredType); }
@Override public Object getBean(String name, Object... args) throws BeansException { assertBeanFactoryActive(); return getBeanFactory().getBean(name, args); }
@Override public <T> T getBean(Class<T> requiredType, Object... args) throws BeansException { assertBeanFactoryActive(); return getBeanFactory().getBean(requiredType, args); }
@Override public boolean containsBean(String name) { return getBeanFactory().containsBean(name); }
@Override public boolean isSingleton(String name) throws NoSuchBeanDefinitionException { assertBeanFactoryActive(); return getBeanFactory().isSingleton(name); }
@Override public boolean isPrototype(String name) throws NoSuchBeanDefinitionException { assertBeanFactoryActive(); return getBeanFactory().isPrototype(name); }
@Override public boolean isTypeMatch(String name, Class<?> targetType) throws NoSuchBeanDefinitionException { assertBeanFactoryActive(); return getBeanFactory().isTypeMatch(name, targetType); }
@Override public Class<?> getType(String name) throws NoSuchBeanDefinitionException { assertBeanFactoryActive(); return getBeanFactory().getType(name); }
@Override public String[] getAliases(String name) { return getBeanFactory().getAliases(name); }
复制代码


  • 看过上述代码后恍然大悟,原来 AbstractApplicationContext 并没有自己来完成 bean 的管理配置,而是全部委托给了 getBeanFactory()方法返回的这个实例,接口是组合,实现也是组合,这种清晰的设计是学习典范;

  • 再来看看 getBeanFactory()方法,解释究竟是谁在真正的提供 bean 的管理配置服务,该方法的实现在 AbstractApplicationContext 的子类 AbstractRefreshableApplicationContext 中,代码很简单,返回了成员变量 beanFactory:


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");      }      return this.beanFactory;    }  }
复制代码


  • 该成员变量在 refreshBeanFactory 方法中实例化,而 refreshBeanFactory 方法又是在 spring 容器初始化的时候调用的,所以容器初始化之后,AbstractApplicationContext 就具备了 bean 管理配置的能力;

扩展思考

  • 看了 AbstractApplicationContext 类中 beanFactory 相关的代码,我就猜想:**莫非 Message 支线也是这个套路,委托给 Message 服务相关的实例来完成?**看代码吧:


  @Override  public String getMessage(String code, Object args[], String defaultMessage, Locale locale) {    return getMessageSource().getMessage(code, args, defaultMessage, locale);  }
@Override public String getMessage(String code, Object args[], Locale locale) throws NoSuchMessageException { return getMessageSource().getMessage(code, args, locale); }
@Override public String getMessage(MessageSourceResolvable resolvable, Locale locale) throws NoSuchMessageException { return getMessageSource().getMessage(resolvable, locale); }
复制代码


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

  • 至此,通过查看源码,我们对 spring 的 BeanFactory 和 ApplicationContext 有了更清晰的认识,又经历了一次结合类图分析源码的实践,在您学习 spring 的路上,希望本文能助您一臂之力,一起学习、共同进步;

欢迎关注 InfoQ:程序员欣宸

学习路上,你不孤单,欣宸原创一路相伴...

发布于: 2022 年 06 月 11 日阅读数: 24
用户头像

搜索"程序员欣宸",一起畅游Java宇宙 2018.04.19 加入

前腾讯、前阿里员工,从事Java后台工作,对Docker和Kubernetes充满热爱,所有文章均为作者原创,个人Github:https://github.com/zq2599/blog_demos

评论

发布
暂无评论
spring的BeanFactory和ApplicationContext_Java_程序员欣宸_InfoQ写作社区