通过 applicationcontext 获取value_SpringFramework之ApplicationContext和BeanFactory

目标:共同学习、共同进步、告别码农,成为受人敬仰的、有态度的程序猿。拒绝不知其所以然的复制粘贴、拒绝人云亦云。用最严谨的态度、最专业的方法、最可靠的知识来源,探究技术内幕,死磕到底!!!

内容简介

今天开设一个新的栏目——SpringFramework。根据源码讲解SpringFramework各种功能,以及官方推荐的最佳实践。依然是那句话,拒绝不知其所以然的复制粘贴。今天我们首先来了解下SpringFramework中最核心的接口之一——ApplicationContext,我们的重点是围绕该接口的继承关系,弄清ApplicationContext中每个方法的来源,及其所提供的能力。

注意:本系列会持续跟踪SpringFramework的最新版本。当前的最新版本为:5.2.8.RELEASE

注意:文中的类图为了简介,图中的方法都没有标出返回值和参数,不同参数的多个重载方法只写了一个

目录:

  1. 使用Jar包依赖引入SpringFramework

  2. 初看ApplicationContext

  3. 小结一

  4. 再看ApplicationContext

  5. 深入BeanFactory

  6. 小结二

  7. ApplicationContext实现类和DefaultListableBeanFactory

  8. 总结

1. 使用Jar包依赖引入SpringFramework

        目前,SpringFramework官方文档中已经没有用Jar包依赖来引入SpringFramework的部分了,取而代之的是使用SpringBoot来引入。但我们这个系列主要是说SpringFramework,因此我们不使用SpringBoot。

  • 安装maven:下载地址https://maven.apache.org/download.cgi,下载好解压到相应的目录,具体安装方法见https://maven.apache.org/install.html。

  • 配置maven仓库:这一步是可选的。maven默认使用中央仓库,但由于网络问题,拉取依赖可能会比较慢,因此可以构建私服来缓存jar包。一些公司会开放自己的私服供大家使用。这里使用腾讯云的私服。具体方法参见https://cloud.tencent.com/document/product/649/20231。

  • 在IDE中配置maven:这里介绍的是在IntelliJ IDEA中配置,如下图

通过 applicationcontext 获取value_SpringFramework之ApplicationContext和BeanFactory_第1张图片

  • 创建maven工程:这一步就不细说了。

  • 配置POM文件中的依赖:配置编译版本和依赖,如下图

通过 applicationcontext 获取value_SpringFramework之ApplicationContext和BeanFactory_第2张图片

  • 编写main方法:如下

24125f78fa11f07c17d060152fda6e8e.png

  • 做完以上的工作,SpringFramework就引入到代码中了。

2. 初看ApplicationContext

        在上面最后一步的main方法中只有一行代码,其中就会看到ApplicationContext,那么这是个什么东西呢?我们来看一下它是什么,它又继承自什么?

通过 applicationcontext 获取value_SpringFramework之ApplicationContext和BeanFactory_第3张图片

        上图是我画的ApplicationContext继承关系的类图。从图上可以看出,ApplicationContext是一个接口,它之上的顶层接口有BeanFactory、EnvironmentCapable、ApplicationEventPublisher、MessageSource和ResourceLoader。接下来我们就逐一的看看它们都是做什么的。

2.1 我们从简单的开始,首先看一下EnvironmentCapable

b184ea355c1d929a4a40ddc90deb3fd1.png

        该接口提供获取环境变量的能力,Spring中所有的上下文都实现了这个接口。这个接口只有一个方法:

  • Environment getEnvironment():返回代表环境变量的对象。需要注意的是,ApplicationContext的子类ConfigurableApplicationContext对这个方法的返回值进行了重定义,提供了更具体的返回值ConfigurableEnvironment。

2.2 下面来看ApplicationEventPublisher

d5a3313f8db2e127511ced96ecf70bea.png

        这个接口的作用是封装了发布事件的功能。SpringFramework内部使用这套事件发布机制实现了观察者模式,通过为相应的事件注册对应的监听者,可以将操作通过事件的形式传播到所有监听者中进行相应处理。该接口也只有一个方法:

  • void publishEvent(Object event):通知所有监听该事件的监听器。接口本身不要求监听器是异步还是同步处理。当传入的参数不是ApplicationEvent接口的子类时,SpringFramework自动将其封装到一个PayloadApplicationEvent类型的对象中。

  • default void publishEvent(ApplicationEvent event):这是接口中的一个默认方法,内部就简单的调用了publishEvent((Object) event),该方法的目的就是能够将event限定为ApplicationEvent类型。

2.3 MessageSource

fe6cf2b754cf52ac4cf47b62f28a7573.png

        该接口是一个策略接口,用于处理参数化和国际化的消息。Spring内置两个实现类,ResourceBundleMessageSource底层使用Java自带的ResourceBundle;ReloadableResourceBundleMessageSource拥有更高的可配置性,尤其支持重新加载消息定义。该接口有三个重载的getMessage方法:

  • String getMessage(String code, @Nullable Object[] args, @Nullable String defaultMessage, Locale locale):第一参数code用于查找消息定义。如果没找到就用第三参数指定的默认消息。code推荐使用类的完全限定名或者包名。

  • String getMessage(String code, @Nullable Object[] args, Locale locale) throws NoSuchMessageException:同上。找不到code会抛异常。

  • String getMessage(MessageSourceResolvable resolvable, Locale locale) throws NoSuchMessageException:同上。用MessageSourceResolvable封装了其它三个参数。

2.4 下面看一个稍微复杂点的接口ResourcePatternResolver

通过 applicationcontext 获取value_SpringFramework之ApplicationContext和BeanFactory_第4张图片        

       主要的作用是检索符合条件的资源,这里定义了一个常量“classpath*:”,作为表示类路径的前缀,检索范围包括jar包中的条目。这个接口继承自ResourceLoader,其中定义常量“classpath:”用来表示类路径的url前缀。ResourcePatternResolver接口中只有一个方法,但从父接口中继承了两个,统一列在下面:

  • Resource getResource(String location):继承自ResourceLoader。从指定路径加载资源。返回的Resource对象可以重用(可以多次调用getInputStream方法)。路径可以是标准的URL、classpath和相对路径。返回的Resource不保证物理存在,需要使用exists方法确认。

  • ClassLoader getClassLoader():继承自ResourceLoader。返回加载资源的ClassLoader。应用程序应统一使用该ClassLoader,而不是依赖线程上下文的ClassLoader。

  • Resource[] getResources(String locationPattern) throws IOException:ResourcePatternResolver接口自己的方法。返回符合模式的所有资源。应尽可能避免指向同一物理资源的条目重叠。返回结果会去重。

2.5 最复杂的来了!

  ApplicationContext继承了HierarchicalBeanFactory和ListableBeanFactory接口,而这两个接口又继承自BeanFactory。这就引出了SpringFramework中另一个核心接口BeanFactory。

通过 applicationcontext 获取value_SpringFramework之ApplicationContext和BeanFactory_第5张图片

        ApplicationContext会将Bean的创建和检索等操作委托给BeanFactory来处理。这里的细节我们留到下一部分细说。

2.6 ApplicationContext自己

通过 applicationcontext 获取value_SpringFramework之ApplicationContext和BeanFactory_第6张图片

        一个ApplicationContext可以看作就是一个SpringFramework环境。程序中可能会有多个上下文环境。因此这个接口提供了针对该环境的功能,具体方法如下:

  • String getId():获得上下文环境的ID。由子类具体定义ID规则。

  • String getApplicationName():返回该上下文所属的应用名称。

  • String getDisplayName():返回该上下文的显示名称。

  • long getStartupDate():返回该上下文首次被加载时的时间戳。

  • ApplicationContext getParent():返回父上下文。

  • AutowireCapableBeanFactory getAutowireCapableBeanFactory() throws IllegalStateException:可用于向Spring管理外的对象注入Bean实例。

3. 小结一

        至此,我们分析了ApplicationContext接口的继承关系。从继承关系中我们可以看到。ApplicationContext从EnvironmentCapable继承了获取环境变量的能力;从ApplicationEventPublisher继承了发布事件的能力;从MessageSource继承了消息参数化和国际化的能力;从ResourcePatternResolver中继承了从URL、类路径和Jar包中获取资源的能力;并通过继承ListableBeanFactory和HierarchicalBeanFactory获得了BeanFactory中检索Bean实例的能力。而ApplicationContext自身具有维护上下文属性的能力。

4. 再看ApplicationContext

        我们已经从ApplicationContext的父接口中分析了它都具有什么样的能力。那么我们继续向继承关系的另一个方向出发,看看又有哪些接口继承了ApplicationContext,以及它们又提供了什么能力。

通过 applicationcontext 获取value_SpringFramework之ApplicationContext和BeanFactory_第7张图片

        从上图我们可以看到,ConfigurableApplicationContext继承了ApplicationContext,这个接口同时还继承了Lifecycle和Closeable接口。依照惯例,我们先从简单的接口看起。

4.1 Closeable

        Closeable接口是Java中的接口,只有一个close方法,该接口继承自AutoCloseable接口,其实现类可以使用Java7开始支持的try-with-resources方式关闭资源。比较简单,不做过多解释了。

4.2 Lifecycle

        提供启动和关闭这两个生命周期控制。可以被组件和容器实现,如果是容器(什么是容器?本文最后会将)实现,则该容器中所有的组件都会收到启动和停止信号。只有顶层的Singleton的Bean支持该声明周期。该接口的子接口SmartLifecycle提供更复杂的控制,比如支持异步停止、自动启动、启动顺序等。这个接口也不过多解释了,就三个方法,看名字都能知道是干什么的。

4.3 重点来了:ConfigurableApplicationContext

        从上方的类图可以看出,从这个接口开始,出现了设值方法,对上下文属性进行设置。上面介绍的其它接口都为取值方法。下面我们来逐一看看这些方法的作用:

  • void setId(String id):设置为上下文唯一标识。

  • void setParent(@Nullable ApplicationContext parent):设置上下文的父上下文。

  • void setEnvironment(ConfigurableEnvironment environment):为上下文设置Environment。

  • ConfigurableEnvironment getEnvironment():上面提到过,在
    ConfigurableApplicationContext中对其父接口EnvironmentCapable中的getEnvironment()方法返回值进行了窄化。

  • void addBeanFactoryPostProcessor(BeanFactoryPostProcessor postProcessor):为上下文添加一个BeanFactoryPostProcessor,该处理器可以在刷新时且解析Bean定义之前被使用。做框架或工具包的时候常用

  • void addApplicationListener(ApplicationListener> listener):添加一个监听器,用来接收上下文事件,比如上下文刷新和上下文关闭。这里与之配合的就是ApplicationEvent。

  • void setClassLoader(ClassLoader classLoader):设值加载资源的ClassLoader。

  • void addProtocolResolver(ProtocolResolver resolver):添加额外的协议解析器,主要用于解析URL或其它类型的资源地址。这里添加的解析器会放在所有解析器的前面,因此可以用来覆盖默认的。

  • void refresh() throws BeansException, IllegalStateException:从持久化的配置中加载和刷新上下文。配置可以是基于java的配置类、xml、properties文件和关系型数据库等。

  • void registerShutdownHook():该方法注册一个Hook,可以在jvm关闭的时候关闭该上下文。

  • void close():关闭该上下文,释放该上下文持有的所有资源,包括缓存的所有Singleton的Bean。

  • boolean isActive():判断上下文的状态是否是激活的。激活的含义是至少有一次refresh操作且没有close。

  • ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException:这里又引入了另一个非常重要的接口。这里暗示着,ConfigurableApplicationContext的实现类内会引用一个ConfigurableListableBeanFactory的实现类,用来托管所有Bean的创建和管理功能。

5. 深入BeanFactory

    上面最后提到ConfigurableApplicationContext接口内的getBeanFactory方法返回ConfigurableListableBeanFactory。下面我们来看看ConfigurableListableBeanFactory的继承关系:

通过 applicationcontext 获取value_SpringFramework之ApplicationContext和BeanFactory_第8张图片

        由于ConfigurableBeanFactory接口中的方法太多,上图没有显示这些方法。对比之前ApplicationContext的继承关系,我们可以看到顶层接口都是BeanFactory。

        因此这里再次强调一下,BeanFactory本身可以理解为是Bean的容器,负责创建和管理。而ApplicationContext继承了BeanFactory中检索Bean的能力,并且内部持有一个BeanFactory的实现类引用,将Bean的检索和管理都委托给了BeanFactory的实现类。

5.1 BeanFactory

        2001年4月13日创建的接口,就是这个20年前创建的接口,撑起了SpringFramework,可见优良设计的重要性。该接口是用于访问Spring Bean容器的最顶层接口。这个工厂的实现类内部保存了Bean的定义,每个Bean都通过一个字符串名称来唯一标识。工厂会根据Bean的定义来返回一个独立的实例(Prototype)或者返回一个在工厂范围内共享的实例(Singleton)。BeanFactory是所有component的注册中心和配置中心。虽然可以通过BeanFactory中的相关方法对指定的Bean进行检索(pull模式),但是更推荐的方式是使用依赖注入(push模式)。Spring的依赖注入的实现使用了BeanFactory和其子接口的能力。BeanFactory从配置源(如:xml)或Java代码中读取Bean定义,然后对其进行配置,BeanFactory本身不关注定义的存储形式,如LDAP,RDBMS,XML,properties文件等。BeanFactory创建的Bean会经过Spring标准的初始化生命周期,如下:

  • BeanNameAware接口的setBeanName方法;

  • BeanClassLoaderAware接口的setBeanClassLoader方法;

  • BeanFactoryAware接口的setBeanFactory方法;

  • EnvironmentAware接口的setEnvironment方法;

  • EmbeddedValueResolverAware接口的setEmbeddedValueResolver方法;

  • ResourceLoaderAware接口的setResourceLoader方法。(只有运行在一个ApplicationContext中时会应用这一步);

  • ApplicationEventPublisherAware接口的setApplicationEventPublisher方法。(只有运行在一个ApplicationContext中时会应用这一步);

  • MessageSourceAware接口的setMessageSource方法。(只有运行在一个ApplicationContext中时会应用这一步);

  • ApplicationContextAware接口的setApplicationContext方法。(只有运行在一个ApplicationContext中时会应用这一步);

  • ServletContextAware接口的setServletContext方法。(只有运行在一个Web类型的ApplicationContext中时会应用这一步);

  • 所有注册的BeanPostProcessor的postProcessBeforeInitialization方法;

  • InitializingBean接口的afterPropertiesSet方法;

  • 自定义init-method方法;

  • 所有注册的BeanPostProcessor的postProcessAfterInitialization方法。

        当BeanFactory关闭的时候会经过如下生命周期

  • 所有注册的DestructionAwareBeanPostProcessor的postProcessBeforeDestruction方法;

  • DisposableBean接口的destroy方法;

  • 自定义destroy-method方法。

        介绍完BeanFactory初始化Bean的过程后,我们来看看这个接口中的方法(这里有个需要注意的点,SpringFramework中获取Bean的时候,如果参数名是name,通常既可以是Bean的名称又可以是Bean的别名,如果参数名是beanName,则只能是Bean的名称):

  • Object getBean(String name) throws BeansException:根据Bean的名字在BeanFactory中查找对应的Bean定义,返回找到的示例。返回的实例可能是单例也可能是Prototype实例。如果传入的name是别名,会翻译成对应的标准Bean名称(下同,不再赘述)

通过 applicationcontext 获取value_SpringFramework之ApplicationContext和BeanFactory_第9张图片

  • T getBean(String name, Class requiredType) throws BeansException:提供类型检查并返回对应类型的Bean实例。返回的实例可能是Singleton也可能是Prototype实例。

  • Object getBean(String name, Object... args) throws BeansException:根据传入的参数查找有匹配构造函数的Bean定义。只能用于返回Prototype实例。如果不是Prototype会抛出异常BeanDefinitionStoreException。

  • ObjectProvider getBeanProvider(Class requiredType):根据传入的类型返回对应的ObjectProvider。ObjectProvider是ObjectFactory的子类,他们可以用于在程序中注入Scope生命周期比当前短的Bean。如在一个Singleton的实例中注入一个Scope是request的Bean。

  • ObjectProvider getBeanProvider(ResolvableType requiredType):ResolvableType封装了Java中的Type类型,提供访问父类、接口、泛型等功能。

  • boolean containsBean(String name):根据名称在BeanFactory中查找对应的Bean,找到返回true否则返回false。查找包含Bean定义是抽象、懒加载,且包含全部范围,因此即使该方法返回true,也不意味着getBean方法一定能返回正确的实例。

  • boolean isSingleton(String name) throws NoSuchBeanDefinitionException:根据传入的名字返回对应的Bean是否是一个共享实例。

  • boolean isPrototype(String name) throws NoSuchBeanDefinitionException:根据传入的名字返回对应的Bean是否是一个独立实例。

  • boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException:根据传入的名字判断BeanFactory中对应的Bean定义类型是否匹配指定的类型。

  • boolean isTypeMatch(String name, Class> typeToMatch) throws NoSuchBeanDefinitionException:同上。

  • Class> getType(String name) throws NoSuchBeanDefinitionException:返回名称所对应的Bean的类型,如果无法确定类型则返回null。如果传入的是一个FactoryBean,则返回FactoryBean创建的类型,即FactoryBean.getObjectType()的返回值。该方法为了确定类型,会初始化之前未初始化过的FactoryBean。

  • Class> getType(String name, boolean allowFactoryBeanInit) throws NoSuchBeanDefinitionException:同上。第二参数决定是否初始化之前未初始化过的FactoryBean。

  • String[] getAliases(String name):如果存在,则根据名字返回Bean的别名,如果传入的是一个别名,则数组的第一个元素是Bean的标准名称。

5.2 ListableBeanFactory

        继承自BeanFactory。该接口提供内部管理的Bean的遍历功能,不需要客户端根据指定的name进行查找。该接口中的方法只关注本层管理的Bean定义,不会去父层查找,会忽略其它方式注册过的Singleton范围的Bean,除了getBeanNamesForType和getBeansOfType方法。该接口中的方法不应频繁调用,执行速度可能会较慢。内部方法如下:

  • boolean containsBeanDefinition(String beanName):检查该BeanFactory中是否存在指定的bean定义。

  • int getBeanDefinitionCount():返回该BeanFactory中的Bean定义数量。

  • String[] getBeanDefinitionNames():返回该BeanFactory中的所有Bean名称。

  • String[] getBeanNamesForType(ResolvableType type):返回匹配指定类型的bean名称(匹配包含子类)。不会检查内部嵌套声明的Bean的类型。等同于getBeanNamesForType(type, true, true)。

  • String[] getBeanNamesForType(@Nullable Class> type):同上。

  • String[] getBeanNamesForType(ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit):同上。第二参数表示是否包括prototype和有范围的Bean。第三参数表示否是允许初始化懒初始化的Bean和FactoryBean创建的对象。

  • String[] getBeanNamesForType(@Nullable Class> type, boolean includeNonSingletons, boolean allowEagerInit):同上。

  • Map getBeansOfType(@Nullable Class type) throws BeansException:返回匹配指定类型的Bean。(匹配包括子类)

  • Map getBeansOfType(@Nullable Class type, boolean includeNonSingletons, boolean allowEagerInit)  throws BeansException:同上。

  • String[] getBeanNamesForAnnotation(Class extends Annotation> annotationType):返回被指定注解所注释的Bean实例。

  • Map getBeansWithAnnotation(Class extends Annotation> annotationType) throws BeansException:回被指定注解所注释的Bean实例。

  • A findAnnotationOnBean(String beanName, Class annotationType)  throws NoSuchBeanDefinitionException:查找Bean上的指定注解,如果未找到继续在接口和父接口中查找。

5.3 HierarchicalBeanFactory

        继承自BeanFactory。该接口的BeanFactory会处在一个分层体系中。在查找Bean的时候,先找本层BeanFactory,如果没有找到会继续找父BeanFactory中的。方法如下:

  • BeanFactory getParentBeanFactory():返回父BeanFactory。设置父BeanFactory在ConfigurableBeanFactory接口中。

  • boolean containsLocalBean(String name):只在本层查找是否存在指定名称的Bean。

5.4 AutowireCapableBeanFactory

        继承自BeanFactory。这个接口可以向Spring管理之外的对象注入Bean。这里暂时先略过,后面说ConfigurableListableBeanFactory时重点说。

5.5 SingletonBeanRegistry

        该接口为Singleton范围的bean提供注册能力。具体方法如下:

  • void registerSingleton(String beanName, Object singletonObject):向注册表中注册一个已存在的对象实例,并表示该Bean是一个Singleton。由于注册时实例已经初始化完成,因此不会调用Spring的初始化回调方法和销毁回调方法。

  • Object getSingleton(String beanName):返回beanName对应的Bean,返回的Bean一定是初始化完成的,并且该方法不处理别名。

  • boolean containsSingleton(String beanName):返回是否存在一个已经实例化好的且名称为指定名称的bean。

  • String[] getSingletonNames():返回所有实例化好的Singleton范围的Bean的名字。

  • int getSingletonCount():返回所有实例化好的单例Bean的个数。

  • Object getSingletonMutex():这个方法暂时不知道是干什么的,后面遇到再说

5.6 ConfigurableBeanFactory

通过 applicationcontext 获取value_SpringFramework之ApplicationContext和BeanFactory_第10张图片

        如上图所示,ConfigurableBeanFactory接口继承了SingletonBeanRegistry和HierarchicalBeanFactory。因此具有注册Singleton范围的Bean和拥有分层关系的能力。该接口提供对BeanFactory的配置能力,通常业务代码不应使用该接口的能力。接口中定义了singleton和prototype的范围常量。接口中的方法有些多,和ConfigurableApplicationContext类似,接口中开始出现设值方法,具体如下:

  • void setParentBeanFactory(BeanFactory parentBeanFactory) throws IllegalStateException:设置父BeanFactory,设置后就不能改变。

  • void setBeanClassLoader(@Nullable ClassLoader beanClassLoader):设置Bean的类加载器,默认是线程上下文的类加载器。该类加载器只对尚未被解析的Bean定义生效。

  • ClassLoader getBeanClassLoader():获取Bean的类加载器。

  • void setTempClassLoader(@Nullable ClassLoader tempClassLoader):设置一个临时的类加载器,默认是null。通常在装载时织入时,为了尽可能晚的加载Bean的类会设置这个类加载器。一旦BeanFactory完成启动,该类加载器会被移除。

  • ClassLoader getTempClassLoader():获取临时类加载器。

  • void setCacheBeanMetadata(boolean cacheBeanMetadata):设置是否缓存Bean的元数据。默认是true。设置为false时可以对bean定义做热重载。

  • boolean isCacheBeanMetadata():是否开启元数据缓存。

  • void setBeanExpressionResolver(@Nullable BeanExpressionResolver resolver):设置Bean定义中表达式的解析器,默认为null。由子类选择实现,如EL表达式。

  • BeanExpressionResolver getBeanExpressionResolver():获取表达式解析器。

  • void setConversionService(@Nullable ConversionService conversionService):设置一个ConversionService用来对Bean属性值进行转换。转换的另一个方法是使用Java自带的PropertyEditor。

  • ConversionService getConversionService():返回设置的ConversionService。

  • void addPropertyEditorRegistrar(PropertyEditorRegistrar registrar):设置一个PropertyEditorRegistrar应用于所有Bean的创建过程,该registrar会创建一个PropertyEditor实例,并且将它注册到注册表中,因此通常比registerCustomEditor方法便捷。

  • void registerCustomEditor(Class> requiredType, Class extends PropertyEditor> propertyEditorClass):为指定的类型注册一个PropertyEditor。

  • void copyRegisteredEditorsTo(PropertyEditorRegistry registry):使用该BeanFactory中已经配置好的PropertyEditor初始化指定的PropertyEditorRegistry。

  • void setTypeConverter(TypeConverter typeConverter):设置一个TypeConverter来为Bean属性进行类型转换。该TypeConverter会覆盖PropertyEditor机制。

  • TypeConverter getTypeConverter():返回设置的TypeConverter。

  • void addEmbeddedValueResolver(StringValueResolver valueResolver):为内嵌值设置字符串解析器。内嵌值的例子比如注解的属性等。

  • boolean hasEmbeddedValueResolver():返回该BeanFactory是否设置了内嵌值字符串转换器。

  • String resolveEmbeddedValue(String value):解析指定的内嵌值。

  • void addBeanPostProcessor(BeanPostProcessor beanPostProcessor):添加一个BeanPostProcessor,用于在每个Bean的创建时可以进行额外的处理。添加多个会默认根据添加顺序调用,可使用Ordered接口指定顺序。

  • int getBeanPostProcessorCount():返回当前注册的BeanPostProcessor的个数。

  • void registerScope(String scopeName, Scope scope):注册一个Scope。

  • String[] getRegisteredScopeNames():返回注册的Scope,不包含内置的。

  • Scope getRegisteredScope(String scopeName):根据名称返回注册的Scope,不包含内置的。

  • AccessControlContext getAccessControlContext():返回当前BeanFactory的安全访问上下文。

  • void copyConfigurationFrom(ConfigurableBeanFactory otherFactory):从一个指定的BeanFactory中拷贝配置,不包含bean定义。

  • void registerAlias(String beanName, String alias) throws BeanDefinitionStoreException:为beanName注册一个别名。

  • void resolveAliases(StringValueResolver valueResolver):设置一个字符串解析器来对别名进行解析,如占位符。

  • BeanDefinition getMergedBeanDefinition(String beanName) throws NoSuchBeanDefinitionException:如果Bean由父,则返回合并后的Bean定义。

  • boolean isFactoryBean(String name) throws NoSuchBeanDefinitionException:判断给定的名字是否是一个FactoryBean。

  • void setCurrentlyInCreation(String beanName, boolean inCreation):为Bean设置正在创建中的状态,仅应该容器内使用。

  • boolean isCurrentlyInCreation(String beanName):判断Bean是否正在创建。

  • void registerDependentBean(String beanName, String dependentBeanName):为指定bean注册一个依赖bean,当指定的bean被销毁之前,依赖bean会被先销毁。

  • String[] getDependentBeans(String beanName):返回bean的依赖bean名称。

  • String[] getDependenciesForBean(String beanName):返回指定bean依赖的bean名称。

  • void destroyBean(String beanName, Object beanInstance):销毁Bean实例,通常是Prototype的Bean。

  • void destroyScopedBean(String beanName):销毁Bean实例,改Bean是一个有范围的Bean。

  • void destroySingletons():销毁该BeanFactory中的所有Singleton范围的Bean。

5.7 ConfigurableListableBeanFactory

通过 applicationcontext 获取value_SpringFramework之ApplicationContext和BeanFactory_第11张图片

        从上图可以看出,ConfigurableListableBeanFactory继承了ConfigurableBeanFactory、AutowireCapableBeanFactory和ListableBeanFactory。其中ListableBeanFactory和ConfigurableListableBeanFactory上面已经分析过了。AutowireCapableBeanFactory提供对一个Java对象进行自动装配的能力,不应在业务代码中使用

        AutowireCapableBeanFactory方法如下

  • T createBean(Class beanClass) throws BeansException:创建一个Bean实例。不会应用byName或byType的自动装配,会应用注解注入。该方法会调用所有注册的BeanPostProcessor中的相关方法,这在编写框架和类库中非常有用。同时也会调用相关的初始化方法。

  • Object createBean(Class> beanClass, int autowireMode, boolean dependencyCheck) throws BeansException:创建一个Bean实例,第二参数指定自动装配使用byName还是byType。第三参数表示是否执行依赖检查。

  • void autowireBean(Object existingBean) throws BeansException:自动装配一个已存在的Bean实例。不会应用BeanPostProcessor

  • Object autowire(Class> beanClass, int autowireMode, boolean dependencyCheck) throws BeansException:另外两个参数的含义和三参数的create方法一样。

  • Object configureBean(Object existingBean, String beanName) throws BeansException:使用一个已存在的对象配置一个Bean

  • void autowireBeanProperties(Object existingBean, int autowireMode, boolean dependencyCheck)  throws BeansException:为已存在的Bean实例自动装配属性。不会应用BeanPostProcessor

  • void applyBeanPropertyValues(Object existingBean, String beanName) throws BeansException:这个方法不会对属性进行自动装配,而是显示的指定。也不会应用标准的BeanPostProcessors回调方法。

  • Object initializeBean(Object existingBean, String beanName) throws BeansException:初始化Bean。会调用所有注册的BeanPostProcessor中的相关方法。

  • Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)  throws BeansException:在已存在的Bean实例上,调用所有BeanPostProcessor的postProcessBeforeInitialization方法。

  • Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)  throws BeansException:在已存在的Bean实例上,调用所有BeanPostProcessor的postProcessorsAfterInitialization方法。

  • NamedBeanHolder resolveNamedBean(Class requiredType) throws BeansException:解析唯一匹配给定类型的Bean实例。

  • Object resolveBeanByName(String name, DependencyDescriptor descriptor) throws BeansException:解析给定名称的Bean实例。

  • Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName) throws BeansException:解析依赖。

  • Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName, @Nullable Set autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException:解析依赖并应用类型转换和自动装配。

        ConfigurableListableBeanFactory中的方法:

通过 applicationcontext 获取value_SpringFramework之ApplicationContext和BeanFactory_第12张图片

  • void ignoreDependencyType(Class> type):在自动装配时忽略指定的类型。默认是null。

  • void ignoreDependencyInterface(Class> ifc):在自动装配时忽略指定的接口。默认只有BeanFactoryAware被忽略。

  • void registerResolvableDependency(Class> dependencyType, @Nullable Object autowiredValue):当一个类型有多个实现类,且注入的是这个类型时,可以使用这个方法来为该接口设置默认的注入值。

  • boolean isAutowireCandidate(String beanName, DependencyDescriptor descriptor)  throws NoSuchBeanDefinitionException:判断制定的Bean是否是一个依赖的候选Bean,用于注入到别的Bean中。

  • BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException:返回指定的Bean定义,并可以访问其属性和构造参数。

  • Iterator getBeanNamesIterator():返回所有Bean名称的视图,包括手动注册的Singleton的Bean。

  • void clearMetadataCache():清空元数据缓存。

  • void freezeConfiguration():冻结所有Bean定义,不允许再被修改。

  • boolean isConfigurationFrozen():Bean定义是否已经被冻结。

  • void preInstantiateSingletons() throws BeansException:确保所有非延迟初始化的Singleton的Bean被初始化。该方法通常在BeanFactory完成初始化之前被调用。

6. 小结二

        到此为止,我们可以看出。最核心的接口是BeanFactory。ApplicationContext主要继承了BeanFactory接口的HierarchicalBeanFactory和ListableBeanFactory子类,因此ApplicationContext拥有检索Bean、遍历Bean和构建层次化Bean结构的能力。ConfigurableApplicationContext继承了ApplicationContext、Lifecycle和Closeable,额外提供生命周期相关的能力和设置上下文属性的能力。而ConfigurableBeanFactory,继承了SingletonBeanRegistry和AutowireCapableBeanFactory,提供针对BeanFactory的设值能力,并且提供设置Bean初始化时的一些额外配置,如类型转换等。ConfigurableListableBeanFactory继承自ConfigurableBeanFactory、AutowireCapableBeanFactory和ListableBeanFactory,提供了依赖管理、自动装配和遍历的能力。

        可以看出,ApplicationContext继承BeanFactory主要是提供检索能力,那么是什么把ApplicationContext和BeanFactory的子接口联系到一起呢。这就是ApplicationContext的实现类,上面也提到过,在实现类中会有BeanFactory子类的引用,任何和Bean相关的创建和检索等都会委托给这个引用来处理。

7. ApplicationContext实现类和DefaultListableBeanFactory

        我们先来看一下ApplicationContext的实现类。注意:ApplicationContext的实现类非常多,这里只列出SpringFramework的context包中的典型实现类。

通过 applicationcontext 获取value_SpringFramework之ApplicationContext和BeanFactory_第13张图片

        可以看出,自抽象类AbstractApplicationContext之下分为了GenericApplicationContext和AbstractRefreshableApplicationContext,两者内部都有一个DefaultListableBeanFactory对象,后者的每个子类上下文只能从一种格式的配置文件中加载bean定义文件,如xml,refresh方法可以执行多次,每次都会创建一个新的内部beanFactory。前者可以从多种格式的配置中读取bean定义,读取后只能调用一次refresh来解析这些bean定义。我们熟悉的ClassPathXmlApplicationContext是AbstractRefreshableApplicationContext体系下的一个子类。而我们开篇使用的AnnotationConfigApplicationContext则是GenericApplicationContext的子类。

        上一段中提到的DefaultListableBeanFactory则是目前ConfigurableListableBeanFactory接口的唯一实现类。类图如下:

通过 applicationcontext 获取value_SpringFramework之ApplicationContext和BeanFactory_第14张图片

        上图中可以看出,DefaultListableBeanFactory实现了所有BeanFactory相关接口,拥有所有能力。

8. 总结

        通过上面的分析,我们可以看出。在SpringFramework中最顶层的核心接口是BeanFactory。ApplicationContext继承了部分上层的BeanFactory子接口,主要用于Bean的检索,而自身则主要提供上下文生命周期、上下文属性、资源管理、国际化、事件管理等功能。ApplicationContext的具体实现类中都会持有DefaultListableBeanFactory类的实例,该实例实现了所有BeanFactory及其子接口的能力,ApplicationContext将所有Bean的创建和检索等操作都委托给这个实例进行实际处理。因此我们通常所说的SpringFramework容器就指的是BeanFactory接口的实现类,实际上就是DefaultListableBeanFactory。

     简而言之,最顶层的BeanFactory代表了Bean的容器,ApplicationContext将Bean的创建和检索等功能委托给BeanFactory来处理。对应用程序而言,由于ApplicationContext继承了BeanFactory,因此将BeanFactory放置在了后端,这样对于开发人员来说,SpringFramework的入口只需要关注ApplicationContext就可以了。

        而在继承恭喜中我们也可以看出,顶层的BeanFactory只有取值方法,下面每一层子类都提供一种能力,比如第一层子类提供遍历、分层关系等能力(如ListableBeanFactory和HierarchicalBeanFactory),第二层提供配置能力,出现设值方法(如ConfigurableBeanFactory和ConfigurableApplicationContext),接着就是实现类,由抽象到具体。这种接口和抽象类的设计方式,是值得学习的。

        由于ConfigurableBeanFactory和ApplicationContext都支持分层,因此,在一个代码工程中可能会出现多个上下文环境,这些上下文可能是并列关系也可能是父子关系,每个上下文中都会有一个DefaultListableBeanFactory作为容器,而个容器也可能具有父容器。这就为模块化提供了便利。

        在SpringFramework的包结构中,BeanFactory位于spring-beans模块中的org.springframework.beans.factory包下。ApplicationContext位于spring-context模块下的org.springframework.context和org.springframework.context.support包下。

        本次我们主要介绍了SpringFramework中的ApplicationContext和BeanFactory的继承关系及各个子接口的能力。今天的介绍将会作为之后其它部分介绍的基础,有助于更加系统的分析源码、理解源码。下次我们会从启动开始真正深入到SpringFramework的源码逻辑中。

        下面附上本次介绍的完整类图(使用的是开源版的StarUML画的图,导出的图片有水印):

通过 applicationcontext 获取value_SpringFramework之ApplicationContext和BeanFactory_第15张图片

3bb436e8fe89d8c8007e5a16fd2dfd0f.png

关于作者

简介:10年JAVA开发经验,多年架构师经验。获得国家“系统架构设计师”、“PMP”、“MySQL DBA OCP”、“TOGAF9鉴定级”、“K8s CKA”、“Scrum Master PSM”等证书。擅长Java全栈开发、DevOps、架构设计、领域驱动、研发管理等。

邮箱[email protected]

博客:https://blog.csdn.net/genie2014(刚刚开始写博客,内容不多)

写在最后

如果大家在工作或学习中遇到技术问题,可以通过邮箱或留言联系我,若问题具有代表性,我可以录制专门的视频对问题的成因和解决方案进行讲解。

为什么不是视频了?因为懒。。。(录制视频需要的时间太长,而且不方便后期的快速回顾,因此后面都会优先使用图文)

关注公众号查看更多内容!!!

你可能感兴趣的:(通过,获取value)