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

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

三级接口:ConfigurableBeanFactory 配置Bean工厂【巨大的工厂接口】


对二级接口HierarchicalBeanFactory进行了再次增强,它还继承了另一个外来的接口SingletonBeanRegistry(因此它也具有分层、注册单例Bean的能力了)。

SingletonBeanRegistry:Spring容器对单例bean实例的登记管理主要通过接口SingletonBeanRegistry建模抽象,我们可以称之为"单例bean实例注册表"。


public interface SingletonBeanRegistry {
  //以指定的名字将给定Object注册到BeanFactory中。
  //此接口相当于直接把Bean注册,所以都是准备好了的Bean。(动态的向容器里直接放置一个Bean)
  //什么BeanPostProcessor、InitializingBean、afterPropertiesSet等都不会被执行的,销毁的时候也不会收到destroy的信息
  void registerSingleton(String beanName, Object singletonObject);
  //以Object的形式返回指定名字的Bean,如果仅仅还是只有Bean定义信息,这里不会反悔
  // 需要注意的是:此方法不能直接通过别名获取Bean。若是别名,请通过BeanFactory的方法先获取到id
  @Nullable
  Object getSingleton(String beanName);
  //是否包含此单例Bean(不支持通过别名查找)
  boolean containsSingleton(String beanName);
  // 得到容器内所有的单例Bean的名字们
  String[] getSingletonNames();
  int getSingletonCount();
  // @since 4.2
  // 获取当前这个注册表的互斥量(mutex),使用者通过该互斥量协同访问当前注册表
  // 实现类DefaultSingletonBeanRegistry就一句话:return this.singletonObjects; 返回当前所有的单例Bean
  Object getSingletonMutex();
}



ConfigurableBeanFactory中定义了太多太多的api,比如类加载器,类型转化,属性编辑器,BeanPostProcessor,作用域,bean定义,处理bean依赖关系,合并其他ConfigurableBeanFactory,bean如何销毁【共55+个方法,虽然方法繁多,还算井井有条】


public interface ConfigurableBeanFactory extends HierarchicalBeanFactory, SingletonBeanRegistry {
  //定义了两个作用域: 单例和原型.可以通过registerScope来添加.
  String SCOPE_SINGLETON = "singleton";
  String SCOPE_PROTOTYPE = "prototype";
  //父容器设置.而且一旦设置了就不让修改(改就抛错)
  // 配合父接口HierarchicalBeanFactory的getParentBeanFactory方法
  void setParentBeanFactory(BeanFactory parentBeanFactory) throws IllegalStateException;
  //类加载器设置与获取.默认使用当前线程中的类加载器
  void setBeanClassLoader(@Nullable ClassLoader beanClassLoader);
  @Nullable
  ClassLoader getBeanClassLoader();
  //为了类型匹配,搞个临时类加载器.好在一般情况为null,使用上面定义的标准加载器
  void setTempClassLoader(@Nullable ClassLoader tempClassLoader);
  @Nullable
  ClassLoader getTempClassLoader();
  //设置、是否缓存元数据,如果false,那么每次请求实例,都会从类加载器重新加载(热加载)
  // 在字段mergedBeanDefinitions里存着,和getMergedBeanDefinition方法有关
  void setCacheBeanMetadata(boolean cacheBeanMetadata);
  boolean isCacheBeanMetadata();
  //定义用于解析bean definition的表达式解析器
  void setBeanExpressionResolver(@Nullable BeanExpressionResolver resolver);
  @Nullable
  BeanExpressionResolver getBeanExpressionResolver();
  //类型转化器
  void setConversionService(@Nullable ConversionService conversionService);
  @Nullable
  ConversionService getConversionService();
  //添加一个属性编辑器的登记员:Registrar
  void addPropertyEditorRegistrar(PropertyEditorRegistrar registrar);
  //注册常用属性编辑器
  void registerCustomEditor(Class<?> requiredType, Class<? extends PropertyEditor> propertyEditorClass);
  //用工厂中注册的通用的编辑器初始化指定的属性编辑注册器
  void copyRegisteredEditorsTo(PropertyEditorRegistry registry);
  //BeanFactory用来转换bean属性值或者参数值的自定义转换器
  void setTypeConverter(TypeConverter typeConverter);
  TypeConverter getTypeConverter();
  //string值解析器(想起mvc中的ArgumentResolver了)
  //增加一个嵌入式的StringValueResolver
  void addEmbeddedValueResolver(StringValueResolver valueResolver);
  // 上面增加过,这里就是true嘛
  boolean hasEmbeddedValueResolver();
  // 用注册的值解析器,依次解析这个value(注意是依次解析)。谁先解析出为null了,后面就不再解析了
  @Nullable
  String resolveEmbeddedValue(String value);
  // 向工厂里添加Bean的后置处理器BeanPostProcessor 
  // 需要注意的是:内部实现是先执行remove,再add的设计技巧
  void addBeanPostProcessor(BeanPostProcessor beanPostProcessor);
  int getBeanPostProcessorCount();
  // 作用域定义:注册范围
  void registerScope(String scopeName, Scope scope);
  String[] getRegisteredScopeNames();
  @Nullable
  Scope getRegisteredScope(String scopeName);
  //访问权限控制:返回本工厂的一个安全访问上下文  和java.security有关的
  AccessControlContext getAccessControlContext();
  //从其他的工厂复制相关的所有配置
  void copyConfigurationFrom(ConfigurableBeanFactory otherFactory);
  //给指定的Bean注册别名  内部还会checkForAliasCircle(name, alias);
  void registerAlias(String beanName, String alias) throws BeanDefinitionStoreException;
  void resolveAliases(StringValueResolver valueResolver);
  //合并bean定义,包括父容器的 返回合并后的Bean定义信息
  BeanDefinition getMergedBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
  //是否是FactoryBean类型  判断指定Bean是否为一个工厂Bean
  boolean isFactoryBean(String name) throws NoSuchBeanDefinitionException;
  //bean创建状态控制.在解决循环依赖时有使用   设置一个Bean是否正在创建
  void setCurrentlyInCreation(String beanName, boolean inCreation);
  boolean isCurrentlyInCreation(String beanName);
  //处理bean依赖问题
  //注册一个依赖于指定bean的Bean
  void registerDependentBean(String beanName, String dependentBeanName);
  //返回依赖于指定Bean的所欲Bean名
  String[] getDependentBeans(String beanName);
  //返回指定Bean依赖的所有Bean名(注意和上面的区别,是反过来的)
  String[] getDependenciesForBean(String beanName);
  // 销毁的相关方法
  void destroyBean(String beanName, Object beanInstance);
  void destroyScopedBean(String beanName);
  //销毁所有的单例们
  void destroySingletons();
}


这个工厂名为ConfigurableBeanFactory,真是名不虚传。功能也不可为不强大


四级接口:ConfigurableListableBeanFactory Bean工厂的集大成者


它是一个更强大的接口,继承了上述的所有接口,无所不包。


public interface ConfigurableListableBeanFactory extends ListableBeanFactory, AutowireCapableBeanFactory, ConfigurableBeanFactory {
  // 忽略的自动注入的类型。也就是说这些类型不能@Autowired了
  void ignoreDependencyType(Class<?> type);
  // 忽略自动装配的接口
  void ignoreDependencyInterface(Class<?> ifc);
  // 注册一个可以给解析的依赖。这样子注入进去的,在Autowired的时候就可以被自动注入进去了,即使不在容器里面
  void registerResolvableDependency(Class<?> dependencyType, @Nullable Object autowiredValue);
  //判断指定的Bean是否有资格作为自动装配的候选者
  boolean isAutowireCandidate(String beanName, DependencyDescriptor descriptor) throws NoSuchBeanDefinitionException;
  //返回注册的Bean定义(这个比较常用)  它可以拿到单独的某个Bean定义信息
  // ListableBeanFactory都是批量的返回
  BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
  Iterator<String> getBeanNamesIterator();
  // 清理元数据的缓存
  void clearMetadataCache();
  //暂时冻结所有的Bean配置
  void freezeConfiguration();
  boolean isConfigurationFrozen();
  // 这个厉害了:实例化当前所有的剩下的单实例Bean们
  void preInstantiateSingletons() throws BeansException;
}



加上自有的这8个方法,这个工厂接口总共有80+个方法,实在是巨大到不行了,所以它是集大成者。


上面介绍的全部是工厂接口,那么接下俩,就开始介绍接口的抽象类实现了。========

抽象类工厂(一级):AbstractBeanFactory


AbstractBeanFactory作为一个抽象类,实现了三级接口ConfigurableBeanFactory(方法50+的接口)大部分功能。


而且继承自FactoryBeanRegistrySupport,所以它也具备了SingletonBeanRegistry和SimpleAliasRegistry的能力


public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory {
  ... 实现了大部分的方法,其中最终的实现为getBean()/doGetBean()方法的实现,提供了模版。其实createBean抽象方法,还是子类去实现的
  ... isSingleton(String name) / isPrototype(String name) / containsBean(String name) 也能实现精准的判断了
  // ===其中,它自己提供了三个抽象方法,子类必要去实现的===
  // 效果同:ListableBeanFactory#containsBeanDefinition  实现类:DefaultListableBeanFactory
  protected abstract boolean containsBeanDefinition(String beanName);
  // 效果同:ConfigurableListableBeanFactory#getBeanDefinition  实现类:DefaultListableBeanFactory
  protected abstract BeanDefinition getBeanDefinition(String beanName) throws BeansException;
  // 创建Bean的复杂逻辑,子类去实现。(子类:AbstractAutowireCapableBeanFactory)
  protected abstract Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
      throws BeanCreationException;
}

此处Spring其实用了一个小技巧:采用抽象方法和接口方法签名一模一样。比如这里的containsBeanDefinition和getBeanDefinition等。这样的好处是,子类若同时实现对应接口、抽象类等,能够达到类似:跨级实现的效果~~~(我明明没有实现它这个接口,但我却复写了这个接口的方法…)

image.png


抽象类工厂(二级):AbstractAutowireCapableBeanFactory


实例化bean和依赖注入是在AbstractBeanFactory的入口,但是实际还是在AbstractAutowireCapableBeanFactory这个类中实现。(入口是getBean()方法)

// 继承自抽象实现:AbstractBeanFactory 
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory implements AutowireCapableBeanFactory {
  // 它有很多属性,我觉得还是很有意义的
  // Bean的实例化需要借助它,策略接口
  private InstantiationStrategy instantiationStrategy = new CglibSubclassingInstantiationStrategy();
  // 解析方法参数的名字
  @Nullable
  private ParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer();
  // 这两个保存的类型,是ignore on dependency check and autowire(字段装配时,如果在这里面的类型讲被忽略)
  // 使用:我们可以自己忽略类型:beanFactory.ignoreDependencyType(ArrayList.class); 比如在BeanFactoryPostProcessor 这里可以这么做
  // 他们有些区别:因为平时使用较少,却别这里就不详细介绍了
  // 总之,若你自己想忽略特定类型的自动注入的话,推荐使用ignoredDependencyTypes 
  private final Set<Class<?>> ignoredDependencyTypes = new HashSet<>();
  private final Set<Class<?>> ignoredDependencyInterfaces = new HashSet<>();
  ... 最重要的是实现了doCreateBean()的创建逻辑,然后执行队形的BeanPostProcessor
  ... applyPropertyValues():这里做的大部分工作就是依赖的准备工作
  ... 然后对bean实例化、初始化、并完成了它的依赖注入入口(具体逻辑由子类DefaultListableBeanFactory具体去实现)
  ... 它实现了对Bean的实例化、populateBean()、以及initializeBean(),会对Bean进行注入等操作
  ... 当然也管理了一些ignoredDependencyTypes,忽略的依赖等等
}


image.png


实例工厂类:DefaultListableBeanFactory Spring内部的唯一使用的工厂实现(XmlBeanFactory已废弃)基于bean definition对象,是一个成熟的bean factroy


默认实现了ListableBeanFactory和BeanDefinitionRegistry接口,基于bean definition对象,**是一个成熟的bean factroy。**它是整个bean加载的核心部分,也是spring注册加载bean的默认实现


DefaultListableBeanFactory既可以作为一个单独的beanFactory,也可以作为自定义beanFactory的父类。

至于特定格式的Bean定义信息(比如常见的有xml、注解等)的解析器可以自己实现,也可以使用原有的解析器,如: PropertiesBeanDefinitionReader和XmLBeanDefinitionReader、AnnotatedBeanDefinitionReader

// extends:相当于继承了抽象类所有的实现,并且是已经具有注入功能了(含有ListableBeanFactory、ConfigurableListableBeanFactory的所有接口)
// implements:直接实现ConfigurableListableBeanFactory,表示它具有了批量处理Bean、配置Bean等等功能
// BeanDefinitionRegistry:该接口目前还仅有这个类实现(它父接口为:AliasRegistry )
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
    implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
}


BeanDefinitionRegistry接口简介: 定义了一些对 bean的常用操作


public interface BeanDefinitionRegistry extends AliasRegistry {
  // 注册一个Bean定义信息(下面的方法都非常的简单,就不一一介绍了)
  void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException;
  void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
  BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
  boolean containsBeanDefinition(String beanName);
  String[] getBeanDefinitionNames();
  int getBeanDefinitionCount();
  boolean isBeanNameInUse(String beanName);
// 需要注意的是:这里面有写方法和ListableBeanFactory接口里定义的三个关于Bean定义的方法一样的:
//getBeanDefinitionNames/getBeanDefinitionCount等等
}


为什么要拆成这么多的类和接口呢。这里面可能基于几点考虑:


  1. 功能的不同维度,分不同的接口,方便以后的维护和其他人的阅读。(代码的可读性异常的重要,特别像Spring这种持久性的项目)
  2. 不同接口的实现,分布在不同的之类里,方便以后不同接口多种实现的扩展(单一职责,才好扩展。否则造成臃肿后,后面无法发展)
  3. 从整个类图的分布,可以看出spring在这块是面向接口编程,后面类的实现,他们认为只是接口功能实现的一种,随时可以拓展成多种实现 (面向接口编程,能极大的解耦各模块之间的互相影响)

ApplicationContext体系


如果说BeanFactory是Spring的心脏,那么ApplicationContext就是完整的躯体了,ApplicationContext由BeanFactory派生而来,提供了更多面向实际应用的功能。在BeanFactory中,很多功能需要以编程的方式实现,而在ApplicationContext中则可以通过配置实现


ApplicationContext接口继承众多接口,集众多接口功能与一身,为Spring的运行提供基本的功能支撑。

根据程序设计的“单一职责原则”,其实每个较顶层接口都是“单一职责的”,只提供某一方面的功能,而ApplicationContext接口继承了众多接口,相当于拥有了众多接口的功能


image.png


下面我们看看ApplicationContext体系的家族图标(提供一个web环境的和一个非web环境的):

web环境的如下(XmlWebApplicationContext、GroovyWebApplicationContext、AnnotationConfigWebApplicationContext):

image.png


非web环境下如:AnnotationConfigApplicationContextFileSystemXmlApplicationContextClassPathXmlApplicationContext


image.png



相关文章
|
9月前
|
XML Java 数据格式
探索Spring之利剑:ApplicationContext接口
本文深入介绍了Spring框架中的核心接口ApplicationContext,解释了其作为应用容器的功能,包括事件发布、国际化支持等,并通过基于XML和注解的配置示例展示了如何使用ApplicationContext管理Bean实例。
392 6
|
3月前
|
负载均衡 Java API
基于 Spring Cloud 的微服务架构分析
Spring Cloud 是一个基于 Spring Boot 的微服务框架,提供全套分布式系统解决方案。它整合了 Netflix、Zookeeper 等成熟技术,通过简化配置和开发流程,支持服务发现(Eureka)、负载均衡(Ribbon)、断路器(Hystrix)、API网关(Zuul)、配置管理(Config)等功能。此外,Spring Cloud 还兼容 Nacos、Consul、Etcd 等注册中心,满足不同场景需求。其核心组件如 Feign 和 Stream,进一步增强了服务调用与消息处理能力,为开发者提供了一站式微服务开发工具包。
428 0
|
6月前
|
负载均衡 Dubbo Java
Spring Cloud Alibaba与Spring Cloud区别和联系?
Spring Cloud Alibaba与Spring Cloud区别和联系?
|
5月前
|
SQL 前端开发 Java
深入分析 Spring Boot 项目开发中的常见问题与解决方案
本文深入分析了Spring Boot项目开发中的常见问题与解决方案,涵盖视图路径冲突(Circular View Path)、ECharts图表数据异常及SQL唯一约束冲突等典型场景。通过实际案例剖析问题成因,并提供具体解决方法,如优化视图解析器配置、改进数据查询逻辑以及合理使用外键约束。同时复习了Spring MVC视图解析原理与数据库完整性知识,强调细节处理和数据验证的重要性,为开发者提供实用参考。
216 0
|
9月前
|
XML Java 数据格式
Spring Core核心类库的功能与应用实践分析
【12月更文挑战第1天】大家好,今天我们来聊聊Spring Core这个强大的核心类库。Spring Core作为Spring框架的基础,提供了控制反转(IOC)和依赖注入(DI)等核心功能,以及企业级功能,如JNDI和定时任务等。通过本文,我们将从概述、功能点、背景、业务点、底层原理等多个方面深入剖析Spring Core,并通过多个Java示例展示其应用实践,同时指出对应实践的优缺点。
129 14
|
9月前
|
Java 关系型数据库 数据库
京东面试:聊聊Spring事务?Spring事务的10种失效场景?加入型传播和嵌套型传播有什么区别?
45岁老架构师尼恩分享了Spring事务的核心知识点,包括事务的两种管理方式(编程式和声明式)、@Transactional注解的五大属性(transactionManager、propagation、isolation、timeout、readOnly、rollbackFor)、事务的七种传播行为、事务隔离级别及其与数据库隔离级别的关系,以及Spring事务的10种失效场景。尼恩还强调了面试中如何给出高质量答案,推荐阅读《尼恩Java面试宝典PDF》以提升面试表现。更多技术资料可在公众号【技术自由圈】获取。
|
11月前
|
Java BI API
spring boot 整合 itextpdf 导出 PDF,写入大文本,写入HTML代码,分析当下导出PDF的几个工具
这篇文章介绍了如何在Spring Boot项目中整合iTextPDF库来导出PDF文件,包括写入大文本和HTML代码,并分析了几种常用的Java PDF导出工具。
2280 0
spring boot 整合 itextpdf 导出 PDF,写入大文本,写入HTML代码,分析当下导出PDF的几个工具
|
11月前
|
Java 编译器 Spring
Spring AOP 和 AspectJ 的区别
Spring AOP和AspectJ AOP都是面向切面编程(AOP)的实现,但它们在实现方式、灵活性、依赖性、性能和使用场景等方面存在显著区别。‌
341 2
|
11月前
|
XML Java 应用服务中间件
【Spring】运行Spring Boot项目,请求响应流程分析以及404和500报错
【Spring】运行Spring Boot项目,请求响应流程分析以及404和500报错
860 2
|
Java Spring 容器
获取Spring的ApplicationContext的几种方式
简单来说就是Spring中的高级容器,可以获取容器中的各种bean组件,注册监听事件,加载资源文件等功能。
225 0
获取Spring的ApplicationContext的几种方式