【小家Spring】BeanFactory体系和ApplicationContext体系,两大体系各接口分析、区别和联系(上)

简介: 【小家Spring】BeanFactory体系和ApplicationContext体系,两大体系各接口分析、区别和联系(上)

前言

前面已经讲述了很多Spring容器启动、解析、依赖注入等等源码层面的东西了,但是小伙伴有没有一种感觉就是:Spring的设计者把面向对象使用到了极致(使用得非常的好),并且它吧职责单一原则也是使用到了极致。


它各个功能区块,通过接口都进行隔离得很开,这是让Spring能组件化开发,可插拔,变得如此优秀、普适的重要原因。


它的IOC和AOP主要围绕两大阵营展开的,也就是咱们今天的主题:BeanFactory体系和ApplicationContext体系,里面接口众多、抽象实现也众多,因此到了这个节点,我们是时候去宏观的看看这两大阵营的内容了。


Spring源码基于的Spring版本为:5.0.6.RELEASE(下同)

Spring源码基于的Spring版本为:5.0.6.RELEASE(下同)

Spring源码基于的Spring版本为:5.0.6.RELEASE(下同)


BeanFactory和ApplicationContext 区别


基本区别


BeanFactory:BeanFacotry是Spring中最原始的Factory,里面最低层的接口,提供了最简单的容器的功能,只提供了实例化对象和拿对象的功能。它没有AOP功能、Web应用功能等等

ApplicationContext:应用上下文,继承BeanFactory接口(因而提供BeanFactory所有的功能),ApplicationContext以一种更向面向框架的方式工作以及对上下文进行分层和实现继承。它是Spring的一各更高级的容器,提供了更多的有用的功能:


  1. 国际化(MessageSource)(ApplicationContext.getMessage()拿到国际化消息)
  2. 访问资源,如URL和文件(ResourceLoader) (ApplicationContext acxt =new ClassPathXmlApplicationContext("/applicationContext.xml");能直接读取文件内容)
  3. 载入多个(有继承关系)上下文 ,使得每一个上下文都专注于一个特定的层次,比如应用的web层
  4. 消息发送、响应机制(ApplicationEventPublisher)
  5. AOP(拦截器)


相同点:BeanFactory和ApplicationContext都支持BeanPostProcessor、BeanFactoryPostProcessor的使用,但两者之间的区别是:BeanFactory需要手动注册,而ApplicationContext则是自动注册


两者装载bean的区别


BeanFactory在启动的时候不会去实例化Bean,中有从容器中拿Bean的时候才会去实例化;(它只去加载Bean的定义信息,显示调用getBean()才会真正去实例化),这样懒加载的优点是:启动快,启动时占用资源少,但具有第一次惩罚的特点


ApplicationContext在启动的时候就把所有的Bean全部实例化了。它还可以为Bean配置lazy-init=true来让Bean延迟实例化(所有的单例、非懒加载的Bean都会容器启动时候立马实例化);

立马加载好的优点有(缺点你懂的,这里不提了):

1、启动时都初始化完成了,所以运行时会更快。

2、我们就能在系统启动的时候,尽早的发现系统中的配置问题 (因为启动时就得实例化处理)

3、可以(建议)把费时的操作放到系统启动中完成(比如初始化本地缓存、获取连接池的链接等等操作)


BeanFactory体系


先贴一张BeanFactory的继承图表,直观展示该家族的成员们

image.png


现在把这些接口分层级,进行逐一说明。


这个里给结论:只要 context 上下文未关闭,ContextRefreshedEvent事件可以多次触发刷新动作, 某些ApplicationContext支持”热”刷新。

比如,XmlWebApplicationContext 支持热刷新, GenericApplicationContext就不支持。

简单的说AbstractRefreshableApplicationContext都支持热刷新(所以它命名为Refreshable嘛),而GenericApplicationContext以及它的子类都是不能支持热舒心的


一级接口:BeanFactory(IOC的始祖)


只有一个,那就是BeanFactory,它提供如下基本方法:

public interface BeanFactory {
  String FACTORY_BEAN_PREFIX = "&";
  Object getBean(String name) throws BeansException;
  <T> T getBean(String name, @Nullable Class<T> requiredType) throws BeansException;
  Object getBean(String name, Object... args) throws BeansException;
  <T> T getBean(Class<T> requiredType) throws BeansException;
  <T> T getBean(Class<T> requiredType, Object... args) throws BeansException;
  //@since 4.1
  // 包含Bean定义或者包含单例Bean实例,都会返回true(不管这个Bean是具体的还是抽象的、lazy的还是eager的,in scope or not 都会返回true)
  boolean containsBean(String name);
  // 若是单例,getBean()每次都会返回同一个实例
  boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
  boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
  //@since 4.2
  // 名称为name的Bean的类型,是否和给定的类型匹配(4.2新增的重载接口,传的是ResolvableType ,更加强大了)
  boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;
  boolean isTypeMatch(String name, @Nullable Class<?> typeToMatch) throws NoSuchBeanDefinitionException;
  // name对应的Bean的类型
  Class<?> getType(String name) throws NoSuchBeanDefinitionException;
  // name对应的Bean的别名们(通过别名也可以依赖注入哦~~~)  通过alia别名,也可以getBean()
  String[] getAliases(String name);
}


这10来个方法,很明显,这是一个典型的工厂模式的工厂接口

需要注意的是,Spring5.1之后在此接口上又加入了如下两个接口:根据类型获取一个provider


// 返回指定bean的提供程序(Provider),允许延迟(这是重点)按需检索实例,包括可用性和唯一性选项
// @since 5.1
<T> ObjectProvider<T> getBeanProvider(Class<T> requiredType);
// @since 5.1
<T> ObjectProvider<T> getBeanProvider(ResolvableType requiredType);


二级接口:HierarchicalBeanFactory、ListableBeanFactory、AutowireCapableBeanFactory


3个子接口,进行了一定功能上的增强


HierarchicalBeanFactory:分层的Bean工厂


提供父容器的访问功能.至于父容器的设置,需要找三级接口ConfigurableBeanFactory的setParentBeanFactory(接口把设置跟获取给拆开了,这是为何呢?Spring早期设计的Bug?).

public interface HierarchicalBeanFactory extends BeanFactory {
  //返回本Bean工厂的父工厂(至于父工厂怎么设置进去的,却放在了三级接口(个人感觉是Spring的Bug哈哈))
  //这个方法实现了工厂的分层
  @Nullable
  BeanFactory getParentBeanFactory();
  //本地工厂是否包含这个Bean(忽略其他所有父工厂)。这也是分层思想的体现。
  boolean containsLocalBean(String name);
}

ListableBeanFactory:可将Bean逐一列出的工厂


它提供了提供容器中bean迭代的功能,不再需要一个个bean地查找.比如可以一次获取全部的bean(太暴力了),根据类型获取bean等等。它的这个功能在Spirng内部有大量的应用。


选哟注意的是:如果同时实现了HierarchicalBeanFactory,返回值不会考虑父类BeanFactory,只考虑当前factory定义的类.当然也可以使用BeanFactoryUtils辅助类来查找祖先工厂中的类。除了getBeanNamesOfType和getBeansOfType这两个方法,其余方法的逻辑都不会考虑父容器的Bean,只会考虑本容器自己的Bean


注意:getBeanDefinitionCount和containsBeanDefinition的实现方法因为效率比较低,还是频繁使用为好.


public interface ListableBeanFactory extends BeanFactory {
  // 这三个都是和Bean定义信息有关的方法
  boolean containsBeanDefinition(String beanName);
  int getBeanDefinitionCount();
  String[] getBeanDefinitionNames();
  //返回匹配给定类型(包括子类)的所有bean的名字,如果是普通bean,则是bean定义的名字,如果是 FactoryBean,则是其getObjectType方法返回的对象的名字
  // 这个方法只考虑最顶层的bean(top-level beans),内部嵌套的bean(nested beans)即便可能匹配指定的类型也不考虑(不支持内部类)
  // 在许多实现中,此方法返回的结果与调用getBeansOfType(type, true, true)一样
  // 这个方法返回的bean名称应该尽可能与后台配置的bean定义顺序一样
  // 此方法只会
  // 若没有符合条件的,返回的空数组,而不是null
  @since 4.2
  String[] getBeanNamesForType(ResolvableType type);
  // 同上
  String[] getBeanNamesForType(@Nullable Class<?> type);
  // includeNonSingletons:false表示只查单例Bean。true表示包含prototype或者其它Scope的Bean们
  // allowEagerInit:主要是解决FactoryBean的情况。若为false,只会去检查FactoryBean本身,若为true,FactoryBean本身和它的产生的对象都会被检查匹配
  // 上面的方法底层调用的为:return getBeanNamesForType(type, true, true); 所以上面方法是全拿(一般不建议调用)
  String[] getBeanNamesForType(@Nullable Class<?> type, boolean includeNonSingletons, boolean allowEagerInit);
  //返回匹配给定类型(包含子类)的实例,可能是通过bean定义创建,也可以是FactoryBean时其getObjectType返回(注意:此处返回的是实例了,不再是Bean定义了)
  //此方法仅考虑最顶层bean,不含其内部嵌套的bean,即使内部嵌套的bean匹配给定类型
  //此方法返回的结果与调用getBeansOfType(type, true, true)一样
  // 实现者:Map的顺序要尽最大可能的与配置时一样
  // 备注:此方法但凡一调用,即使有些Bean只是Bean定义的话,也会被立马初始化的~~~~~
  <T> Map<String, T> getBeansOfType(@Nullable Class<T> type) throws BeansException;
  <T> Map<String, T> getBeansOfType(@Nullable Class<T> type, boolean includeNonSingletons, boolean allowEagerInit) throws BeansException;
  // 这个接口会把所有标注有指定注解的Bean的定义信息的BeanName返回
  //@since 4.0
  String[] getBeanNamesForAnnotation(Class<? extends Annotation> annotationType);
  // 返回的实例~~~~
  Map<String, Object> getBeansWithAnnotation(Class<? extends Annotation> annotationType) throws BeansException;
  //查找指定bean的指定类型的注解。
  // 注意:如果本类没找到,还会去它的接口、它的父类里面找,这个厉害了我的哥
  // getBeanNamesForAnnotation依赖于此接口
  @Nullable
  <A extends Annotation> A findAnnotationOnBean(String beanName, Class<A> annotationType) throws NoSuchBeanDefinitionException;
}



正如这个工厂接口的名字所示,这个工厂接口最大的特点就是可以列出工厂可以生产的所有实例。

这个工厂作为二级接口,有多个个独有的方法,扩展了跟BeanDefinition的功能,提供了BeanDefinition、BeanName、注解有关的各种操作

AutowireCapableBeanFactory:自动装配的Bean工厂


(该接口特别重要,扩展出来的方法也非常的多)对于想要拥有自动装配能力,并且想把这种能力暴露给外部应用的BeanFactory类需要实现此接口。


正常情况下,不要使用此接口,应该更倾向于使用BeanFactory或者ListableBeanFactory接口。此接口主要是针对框架之外,没有向Spring托管Bean的应用。通过暴露此功能,Spring框架之外的程序,具有自动装配等Spring的功能


需要注意的是,ApplicationContext接口并没有实现此接口,因为应用代码很少用到此功能,如果确实需要的话,可以调用ApplicationContext的getAutowireCapableBeanFactory方法,来获取此接口的实例。


另外,如果一个类实现了此接口,那么很大程度上它还需要实现BeanFactoryAware接口。它可以在应用上下文中返回BeanFactory

public interface AutowireCapableBeanFactory extends BeanFactory {
  // 用于标识外部自动装配功能是否可用。但是此标识不影响正常的(基于注解的等)自动装配功能的使用
  int AUTOWIRE_NO = 0; // 不注入
  int AUTOWIRE_BY_NAME = 1; // 根据名称注入
  int AUTOWIRE_BY_TYPE = 2; // 根据类型注入
  int AUTOWIRE_CONSTRUCTOR = 3; // 根据构造器注入
  @Deprecated
  int AUTOWIRE_AUTODETECT = 4; // 标识自动识别一种装配策略来实现自动装配(Spring3.0后废弃)
  //创建一个给定Class的实例。它会处理各种带有注解的域和方法,并且会调用所有Bean初始化时所需要调用的回调函数
  //它会执行所有的关于Bean生命周期的接口方法如BeanPostProcessor
  //此方法并不意味着by-name或者by-type方式的自动装配,如果需要使用这写功能,可以使用其下面的重载方法
  <T> T createBean(Class<T> beanClass) throws BeansException;
  // 和上面的区别为:创建这个Bean的时候可以指定autowireMode,然后可以把它需要注入的Bean都注入进来(这个Mode会放在Bean定义里,在依赖注入的时候会有用)
  // Bean定义的默认值为:autowireMode = AUTOWIRE_NO;显然是不会开启自动装配的
  // 在populateBean()给属性赋值(依赖注入的时候,会使用到此模式)
  Object createBean(Class<?> beanClass, int autowireMode, boolean dependencyCheck) throws BeansException;
  //通过调用给定Bean的after-instantiation及post-processing接口,对bean进行装配值
  // 此方法主要是用于处理Bean中带有注解的字段和方法。
  // 此方法并不意味着by-name或者by-type方式的自动装配,如果需要使用这些功能,可以使用其重载方法autowireBeanProperties
  // 只会调用populateBean
  void autowireBean(Object existingBean) throws BeansException;
  //通过指定的自动装配策略来初始化一个Bean 注意:他会创建一个新的Bean
  //需要注意的是:此方法不会调用Bean上注册的诸如BeanPostProcessors的回调方法
  // 只会调用populateBean
  Object autowire(Class<?> beanClass, int autowireMode, boolean dependencyCheck) throws BeansException;
  //通过指定的自动装配方式来对给定的已经存在的Bean进行自动装配
  //不过会调用指定Bean注册的BeanPostProcessors等回调函数来初始化Bean。
  //如果指定装配方式为AUTOWIRE_NO的话,不会自动装配属性,但是,但是,但是依然会调用BeanPiostProcesser等回调方法。
  //只会调用populateBean
  void autowireBeanProperties(Object existingBean, int autowireMode, boolean dependencyCheck) throws BeansException;
  //配置参数中指定的bean,包括自动装配其域,对其应用如setBeanName功能的回调函数。并且会调用其所有注册的post processor.
  // beanName表示在Bean定义中的名称。
  // populateBean和initializeBean都会被调用
  Object configureBean(Object existingBean, String beanName) throws BeansException;
  //简单的说,就是把Bean定义信息里面的一些东西,赋值到已经存在的Bean里面
  // 除了InstantiationAwareBeanPostProcessor的回调方法外,此方法不会在Bean上应用其它的例如BeanPostProcessors
  void applyBeanPropertyValues(Object existingBean, String beanName) throws BeansException;
  // 实例化这个Bean,会调用所有的postProcessors 方法
  Object initializeBean(Object existingBean, String beanName) throws BeansException;
  //调用参数中指定Bean的postProcessBeforeInitialization/postProcessorsAfterInitialization方法  初始化之前、之后
  Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName) throws BeansException;
  Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName) throws BeansException;
  //销毁参数中指定的Bean,同时调用此Bean上的DisposableBean和DestructionAwareBeanPostProcessors方法
  //在销毁途中,任何的异常情况都只应该被直接捕获和记录,而不应该向外抛出。
  void destroyBean(Object existingBean);
  //查找唯一符合指定类的实例,如果有,则返回实例的名字和实例本身
  //底层依赖于:BeanFactory中的getBean(Class)方法
  <T> NamedBeanHolder<T> resolveNamedBean(Class<T> requiredType) throws BeansException;
  //解析出在Factory中与指定Bean有指定依赖关系的Bean(@Autowired依赖注入的核心方法)
  @Nullable
  Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName) throws BeansException;
  //descriptor 依赖描述 (field/method/constructor)
  //requestingBeanName 依赖描述所属的Bean
  //autowiredBeanNames 与指定Bean有依赖关系的Bean
  //typeConverter 用以转换数组和连表的转换器
  //备注:结果可能为null,毕竟容器中可能不存在这个依赖嘛~~~~~~~~~~~~~~~~
  @Nullable
  Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName, @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException;
}


一共8个跟自动装配有关的方法,实在是繁杂,2个执行BeanPostProcessors的方法,2个分解指定依赖的方法(依赖注入)


从宏观上看,AutowireCapableBeanFactory提供了如下能力:


  1. 为已经实例化的对象装配属性,这些属性对象都是Spring管理的;
  2. 实例化一个类型,并自动装配,这些属性对象都是Spring管理的,实例化的类可以不被Spring管理(这点特别重要)。所以这个接口提供功能就是自动装配bean相关的,具体实现方式,其实我们在之前的getBean()解析时候已经有了,请参考:【小家Spring】AbstractBeanFactory#getBean()、doGetBean完成Bean的初始化、实例化,以及BeanPostProcessor后置处理器源码级详细分析


此接口主要是针对框架之外,没有向Spring托管Bean的应用。通过暴露此功能,Spring框架之外的程序,y也能具有自动装配的能力(此接口赋予它的)。


可以使用这个接口集成其它框架。捆绑并填充(注入)并不由Spring管理生命周期并已存在的实例.像集成WebWork的Actions 和Tapestry Page就很实用

一般应用开发者不会使用这个接口,所以像ApplicationContext这样的外观实现类不会实现这个接口


为了更深入的了解本接口的使用,请参照我专门写的一篇博文,脱离Spring容器来实现依赖注入(脱离容器):

【小家Spring】为脱离Spring IOC容器管理的Bean赋能【依赖注入】的能力,并分析原理(借助AutowireCapableBeanFactory赋能)



相关文章
|
16天前
|
监控 Java 应用服务中间件
spring和springboot的区别
spring和springboot的区别
20 1
|
22天前
|
Java API 微服务
【Spring Boot系列】通过OpenAPI规范构建微服务服务接口
【4月更文挑战第5天】通过OpenAPI接口构建Spring Boot服务RestAPI接口
|
2月前
|
XML 存储 缓存
【深入浅出Spring原理及实战】「缓存Cache开发系列」带你深入分析Spring所提供的缓存Cache管理器的实战开发指南(修正篇)
【深入浅出Spring原理及实战】「缓存Cache开发系列」带你深入分析Spring所提供的缓存Cache管理器的实战开发指南(修正篇)
32 0
|
1天前
|
XML Java 数据库连接
Spring框架与Spring Boot的区别和联系
Spring框架与Spring Boot的区别和联系
8 0
|
5天前
|
Java Spring
spring boot访问接口报500
spring boot访问接口报500
11 2
|
16天前
|
存储 缓存 Java
【spring】06 循环依赖的分析与解决
【spring】06 循环依赖的分析与解决
9 1
|
16天前
|
Java 数据库连接 数据库
spring+mybatis_编写一个简单的增删改查接口
spring+mybatis_编写一个简单的增删改查接口
16 2
|
25天前
|
XML Java C++
【Spring系列】Sping VS Sping Boot区别与联系
【4月更文挑战第2天】Spring系列第一课:Spring Boot 能力介绍及简单实践
【Spring系列】Sping VS Sping Boot区别与联系
|
29天前
|
XML Java 数据格式
Bean工厂探秘:解析Spring底层工厂体系BeanFactory的神奇之道
Bean工厂探秘:解析Spring底层工厂体系BeanFactory的神奇之道
24 0
Bean工厂探秘:解析Spring底层工厂体系BeanFactory的神奇之道