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

本文涉及的产品
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 【小家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



相关文章
|
2月前
|
XML Java 数据格式
探索Spring之利剑:ApplicationContext接口
本文深入介绍了Spring框架中的核心接口ApplicationContext,解释了其作为应用容器的功能,包括事件发布、国际化支持等,并通过基于XML和注解的配置示例展示了如何使用ApplicationContext管理Bean实例。
113 6
|
2月前
|
Java 关系型数据库 数据库
京东面试:聊聊Spring事务?Spring事务的10种失效场景?加入型传播和嵌套型传播有什么区别?
45岁老架构师尼恩分享了Spring事务的核心知识点,包括事务的两种管理方式(编程式和声明式)、@Transactional注解的五大属性(transactionManager、propagation、isolation、timeout、readOnly、rollbackFor)、事务的七种传播行为、事务隔离级别及其与数据库隔离级别的关系,以及Spring事务的10种失效场景。尼恩还强调了面试中如何给出高质量答案,推荐阅读《尼恩Java面试宝典PDF》以提升面试表现。更多技术资料可在公众号【技术自由圈】获取。
|
4月前
|
存储 安全 Java
|
4月前
|
自然语言处理 JavaScript Java
Spring 实现 3 种异步流式接口,干掉接口超时烦恼
本文介绍了处理耗时接口的几种异步流式技术,包括 `ResponseBodyEmitter`、`SseEmitter` 和 `StreamingResponseBody`。这些工具可在执行耗时操作时不断向客户端响应处理结果,提升用户体验和系统性能。`ResponseBodyEmitter` 适用于动态生成内容场景,如文件上传进度;`SseEmitter` 用于实时消息推送,如状态更新;`StreamingResponseBody` 则适合大数据量传输,避免内存溢出。文中提供了具体示例和 GitHub 地址,帮助读者更好地理解和应用这些技术。
693 0
|
4月前
|
Java 编译器 Spring
Spring AOP 和 AspectJ 的区别
Spring AOP和AspectJ AOP都是面向切面编程(AOP)的实现,但它们在实现方式、灵活性、依赖性、性能和使用场景等方面存在显著区别。‌
151 2
|
4月前
|
监控 Java 应用服务中间件
Spring和Spring Boot的区别
Spring和Spring Boot的主要区别,包括项目配置、开发模式、项目依赖、内嵌服务器和监控管理等方面,强调Spring Boot基于Spring框架,通过约定优于配置、自动配置和快速启动器等特性,简化了Spring应用的开发和部署过程。
108 19
|
4月前
|
XML 前端开发 Java
Spring,SpringBoot和SpringMVC的关系以及区别 —— 超准确,可当面试题!!!也可供零基础学习
本文阐述了Spring、Spring Boot和Spring MVC的关系与区别,指出Spring是一个轻量级、一站式、模块化的应用程序开发框架,Spring MVC是Spring的一个子框架,专注于Web应用和网络接口开发,而Spring Boot则是对Spring的封装,用于简化Spring应用的开发。
324 0
Spring,SpringBoot和SpringMVC的关系以及区别 —— 超准确,可当面试题!!!也可供零基础学习
|
29天前
|
XML Java 应用服务中间件
Spring Boot 两种部署到服务器的方式
本文介绍了Spring Boot项目的两种部署方式:jar包和war包。Jar包方式使用内置Tomcat,只需配置JDK 1.8及以上环境,通过`nohup java -jar`命令后台运行,并开放服务器端口即可访问。War包则需将项目打包后放入外部Tomcat的webapps目录,修改启动类继承`SpringBootServletInitializer`并调整pom.xml中的打包类型为war,最后启动Tomcat访问应用。两者各有优劣,jar包更简单便捷,而war包适合传统部署场景。需要注意的是,war包部署时,内置Tomcat的端口配置不会生效。
233 17
Spring Boot 两种部署到服务器的方式
|
29天前
|
Dart 前端开发 JavaScript
springboot自动配置原理
Spring Boot 自动配置原理:通过 `@EnableAutoConfiguration` 开启自动配置,扫描 `META-INF/spring.factories` 下的配置类,省去手动编写配置文件。使用 `@ConditionalXXX` 注解判断配置类是否生效,导入对应的 starter 后自动配置生效。通过 `@EnableConfigurationProperties` 加载配置属性,默认值与配置文件中的值结合使用。总结来说,Spring Boot 通过这些机制简化了开发配置流程,提升了开发效率。
61 17
springboot自动配置原理
|
1月前
|
XML JavaScript Java
SpringBoot集成Shiro权限+Jwt认证
本文主要描述如何快速基于SpringBoot 2.5.X版本集成Shiro+JWT框架,让大家快速实现无状态登陆和接口权限认证主体框架,具体业务细节未实现,大家按照实际项目补充。
87 11