diff --git a/README.md b/README.md index 13f12b2..7685f74 100644 --- a/README.md +++ b/README.md @@ -123,9 +123,9 @@ - [`BeanFactory`](spring-factory/spring-factory-beanFactory/README.md):Spring的核心接口,提供对Bean的配置、创建、管理的基本功能。 - - [`ListableBeanFactory`](spring-factory/spring-factory-hierarchicalBeanFactory/README.md):支持按类型获取Bean的集合。 + - [`ListableBeanFactory`](spring-factory/spring-factory-listableBeanFactory/README.md):支持按类型获取Bean的集合。 - - `HierarchicalBeanFactory`:支持父子容器关系,实现Bean定义的层次结构。 + - [`HierarchicalBeanFactory`](spring-factory/spring-factory-hierarchicalBeanFactory/README.md):支持父子容器关系,实现Bean定义的层次结构。 - `ConfigurableBeanFactory`:提供对BeanFactory配置的扩展,如属性编辑器、作用域等。 diff --git a/spring-factory/spring-factory-listableBeanFactory/README.md b/spring-factory/spring-factory-listableBeanFactory/README.md new file mode 100644 index 0000000..3974607 --- /dev/null +++ b/spring-factory/spring-factory-listableBeanFactory/README.md @@ -0,0 +1,493 @@ +## ListableBeanFactory + + +### 一、基本信息 + +✒️ **作者** - Lex 📝 **博客** - [掘金](https://juejin.cn/user/4251135018533068/posts) 📚 **源码地址** - [github](https://github.com/xuchengsheng/spring-reading) + +### 二、基本描述 + +`ListableBeanFactory` 接口是 Spring 框架中的一个子接口,扩展了 `BeanFactory`,用于表示能够以列表形式获取 bean 定义的容器。它提供了方法来检索容器中所有 bean 的数量、名称,以及按类型或注解过滤的 bean 实例。通过这个接口,我们可以方便地获取有关容器中 bean 的信息,如动态查找 bean 名称、按类型检索 bean 实例等,为运行时动态管理和处理 bean 提供了灵活性和便利性。 + +### 三、主要功能 + +1. **获取 Bean 定义数量** + + - 该方法返回容器中定义的 bean 的数量,允许我们了解容器中注册的所有 bean 的总数。 + +2. **获取所有 Bean 的名称** + + - 通过此方法,可以获取容器中所有 bean 的名称,提供了一个 bean 名称的列表。这对于遍历和检查容器中的所有 bean 是很有用的。 + +3. **按类型获取 Bean 的名称** + + - 通过指定类型,可以获取容器中所有与该类型兼容的 bean 的名称。这对于按照特定类型查找和处理 bean 是非常方便的。 + +4. **按类型获取 Bean 实例** + + - 该方法返回指定类型的所有 bean 实例,以 bean 的名称和实例的映射形式。这是一个强大的功能,特别是在需要按类型进行动态处理的情况下。 + +5. **按注解获取 Bean 实例** + + - 允许我们根据指定的注解获取所有带有该注解的 bean 实例,以 bean 的名称和实例的映射形式返回。这在基于注解的配置和处理中非常有用。 + +### 四、接口源码 + +```java +/** + * {@link BeanFactory}接口的扩展,由可以枚举其所有bean实例而不是按名称一个个查找bean的工厂实现。 + * 预加载所有bean定义(例如基于XML的工厂)的BeanFactory可以实现此接口。 + * + *

如果这是一个{@link HierarchicalBeanFactory},返回值将不会考虑任何BeanFactory层次结构, + * 而只会与当前工厂中定义的bean相关联。使用{@link BeanFactoryUtils}助手类来考虑祖先工厂中的bean。 + * + *

此接口中的方法只会尊重此工厂的bean定义。它们将忽略通过其他手段注册的任何单例bean, + * 例如{@link org.springframework.beans.factory.config.ConfigurableBeanFactory}的 + * {@code registerSingleton}方法,但 {@code getBeanNamesForType} 和 {@code getBeansOfType} + * 将检查这样手动注册的单例。当然,BeanFactory的 {@code getBean} 也允许透明访问这样的特殊bean。 + * 但是,在典型情况下,所有bean都将由外部bean定义来定义,因此大多数应用程序不需要担心这种区分。 + * + *

注意:除了 {@code getBeanDefinitionCount} 和 {@code containsBeanDefinition}, + * 此接口中的方法并非设计用于频繁调用。实现可能会很慢。 + * + * @author Rod Johnson + * @author Juergen Hoeller + * @since 2001年4月16日 + * @see HierarchicalBeanFactory + * @see BeanFactoryUtils + */ +public interface ListableBeanFactory extends BeanFactory { + + /** + * 检查此bean工厂是否包含给定名称的bean定义。 + *

不考虑此工厂可能参与的任何层次结构,并忽略通过bean定义之外的其他手段注册的任何单例bean。 + * @param beanName 要查找的bean的名称 + * @return 如果此bean工厂包含给定名称的bean定义,则为true + * @see #containsBean + */ + boolean containsBeanDefinition(String beanName); + + /** + * 返回工厂中定义的bean的数量。 + *

不考虑此工厂可能参与的任何层次结构,并忽略通过bean定义之外的其他手段注册的任何单例bean。 + * @return 工厂中定义的bean的数量 + */ + int getBeanDefinitionCount(); + + /** + * 返回此工厂中定义的所有bean的名称。 + *

不考虑此工厂可能参与的任何层次结构,并忽略通过bean定义之外的其他手段注册的任何单例bean。 + * @return 此工厂中定义的所有bean的名称,如果没有定义,则为空数组 + */ + String[] getBeanDefinitionNames(); + + /** + * 返回指定bean的提供程序,允许按需延迟检索实例,包括可用性和唯一性选项。 + * @param requiredType bean必须匹配的类型;可以是接口或超类 + * @param allowEagerInit 是否允许基于流的访问初始化懒加载单例由FactoryBeans创建的对象 + * (或通过带有 "factory-bean" 引用的工厂方法创建的对象)进行类型检查 + * @return 相应的提供程序处理 + * @since 5.3 + * @see #getBeanProvider(ResolvableType, boolean) + * @see #getBeanProvider(Class) + * @see #getBeansOfType(Class, boolean, boolean) + * @see #getBeanNamesForType(Class, boolean, boolean) + */ + ObjectProvider getBeanProvider(Class requiredType, boolean allowEagerInit); + + /** + * 返回指定bean的提供程序,允许按需延迟检索实例,包括可用性和唯一性选项。 + * @param requiredType bean必须匹配的类型;可以是泛型类型声明。 + * 请注意,此处不支持集合类型,与反射注入点形成对比。要以编程方式检索匹配特定类型的bean列表,请在此处指定实际的bean类型, + * 然后随后使用{@link ObjectProvider#orderedStream()}或其延迟流/迭代选项。 + * @param allowEagerInit 是否允许基于流的访问初始化懒加载单例由FactoryBeans创建的对象 + * (或通过带有 "factory-bean" 引用的工厂方法创建的对象)进行类型检查 + * @return 相应的提供程序处理 + * @since 5.3 + * @see #getBeanProvider(ResolvableType) + * @see ObjectProvider#iterator() + * @see ObjectProvider#stream() + * @see ObjectProvider#orderedStream() + * @see #getBeanNamesForType(ResolvableType, boolean, boolean) + */ + ObjectProvider getBeanProvider(ResolvableType requiredType, boolean allowEagerInit); + + /** + * 返回使用提供的{@link Annotation}类型进行注释的所有bean的名称,而不会实际创建相应的bean实例。 + *

请注意,此方法会考虑由FactoryBeans创建的对象,这意味着将初始化FactoryBeans以确定其对象类型。 + * @param annotationType 要查找的注释类型 + * (在指定bean的类、接口或工厂方法级别) + * @return 所有匹配的bean的名称 + * @since 4.0 + * @see #findAnnotationOnBean + */ + String[] getBeanNamesForAnnotation(Class annotationType); + + /** + * 查找使用提供的{@link Annotation}类型进行注释的所有bean,返回具有相应的bean名称和相应bean实例的Map。 + *

请注意,此方法会考虑由FactoryBeans创建的对象,这意味着将初始化FactoryBeans以确定其对象类型。 + * @param annotationType 要查找的注释类型 + * (在指定bean的类、接口或工厂方法级别) + * @return 包含匹配bean的Map,其中包含bean名称作为键和相应的bean实例作为值 + * @throws BeansException 如果无法创建bean + * @since 3.0 + * @see #findAnnotationOnBean + */ + Map getBeansWithAnnotation(Class annotationType) throws BeansException; + + /** + * 在指定的bean上查找{@code annotationType}的{@link Annotation}, + * 遍历其接口和超类如果在给定类本身上找不到注释,则检查bean的工厂方法(如果有的话)。 + * @param beanName 要查找注释的bean的名称 + * @param annotationType 要查找的注释类型 + * (在指定bean的类、接口或工厂方法级别) + * @return 如果找到给定类型的注释,则为该注释;否则为{@code null} + * @throws NoSuchBeanDefinitionException 如果没有给定名称的bean + * @since 3.0 + * @see #getBeanNamesForAnnotation + * @see #getBeansWithAnnotation + */ + @Nullable + A findAnnotationOnBean(String beanName, Class annotationType) + throws NoSuchBeanDefinitionException; + + /** + * 返回使用提供的{@link Annotation}类型进行注释的所有bean的名称, + * 返回具有相应的bean名称和相应bean实例的Map。 + *

请注意,此方法会考虑由FactoryBeans创建的对象,这意味着将初始化FactoryBeans以确定其对象类型。 + * @param annotationType 要查找的注释类型 + * (在指定bean的类、接口或工厂方法级别) + * @return 包含匹配bean的Map,其中包含bean名称作为键和相应的bean实例作为值 + * @throws BeansException 如果无法创建bean + * @since 3.0 + * @see #findAnnotationOnBean + */ + Map getBeansWithAnnotation(Class annotationType) throws BeansException; + + /** + * 在指定的bean上查找{@code annotationType}的{@link Annotation}, + * 遍历其接口和超类如果在给定类本身上找不到注释,则检查bean的工厂方法(如果有的话)。 + * @param beanName 要查找注释的bean的名称 + * @param annotationType 要查找的注释类型 + * (在指定bean的类、接口或工厂方法级别) + * @return 如果找到给定类型的注释,则为该注释;否则为{@code null} + * @throws NoSuchBeanDefinitionException 如果没有给定名称的bean + * @since 3.0 + * @see #getBeanNamesForAnnotation + * @see #getBeansWithAnnotation + */ + @Nullable + A findAnnotationOnBean(String beanName, Class annotationType) + throws NoSuchBeanDefinitionException; + + /** + * 返回与给定对象类型(包括子类)匹配的所有bean的名称,从bean定义或FactoryBeans的{@code getObjectType}的值判断。 + *

注意:此方法仅内省顶级bean。它不会检查可能也匹配指定类型的嵌套bean。 + *

如果FactoryBeans创建的对象符合条件,它将得到初始化。如果FactoryBean创建的对象不匹配, + * 则原始FactoryBean本身将与类型匹配。 + *

不考虑此工厂可能参与的任何层次结构。使用BeanFactoryUtils的{@code beanNamesForTypeIncludingAncestors} + * 将祖先工厂中的bean包括在内。 + *

注意:不会忽略通过bean定义之外的其他手段注册的任何单例bean。 + *

此版本的{@code getBeanNamesForType}匹配所有类型的bean,无论是单例、原型还是FactoryBeans。 + * 在大多数实现中,结果与{@code getBeanNamesForType(type, true, true)}相同。 + *

此方法返回的bean名称应始终尽可能以后端配置中的定义顺序返回bean名称。 + * @param type 要匹配的泛型类型或接口 + * @return 匹配的对象类型(包括子类)的所有bean的名称,如果没有则为空数组 + * @since 4.2 + * @see #isTypeMatch(String, ResolvableType) + * @see FactoryBean#getObjectType + * @see BeanFactoryUtils#beanNamesForTypeIncludingAncestors(ListableBeanFactory, ResolvableType) + */ + String[] getBeanNamesForType(ResolvableType type); + + /** + * 根据给定的类型(包括子类),从bean定义或FactoryBeans的{@code getObjectType}的值判断,返回匹配的bean的名称数组。 + *

注意:此方法仅内省顶级bean。它不检查可能与指定类型匹配的嵌套bean。 + *

如果设置了“allowEagerInit”标志,会考虑由FactoryBeans创建的对象,这意味着FactoryBeans将被初始化。 + * 如果由FactoryBean创建的对象不匹配,则原始FactoryBean本身将与类型匹配。 + * 如果未设置“allowEagerInit”,则仅检查原始FactoryBeans(这不需要初始化每个FactoryBean)。 + *

不考虑此工厂可能参与的任何层次结构。 + * 使用BeanFactoryUtils的{@code beanNamesForTypeIncludingAncestors}以包括祖先工厂中的bean。 + *

注意:不会忽略以非bean定义的方式注册的单例bean。 + *

此方法返回的bean名称数组应尽可能以后端配置中定义的顺序返回bean名称。 + * + * @param type 要匹配的泛型类型或接口 + * @param includeNonSingletons 是否包括原型或作用域bean,或仅包括单例(也适用于FactoryBeans) + * @param allowEagerInit 是否初始化延迟初始化的单例和 + * 由FactoryBeans创建的对象(或带有 + * "factory-bean"引用的工厂方法)以进行类型检查。 + * 请注意,需要急切地初始化FactoryBeans和"factory-bean"引用,因此 + * 请注意,为此标志传递“true”将初始化FactoryBeans和“factory-bean”引用。 + * @return 匹配给定对象类型(包括子类)的bean的名称数组,如果没有则为空数组 + * @since 5.2 + * @see FactoryBean#getObjectType + * @see BeanFactoryUtils#beanNamesForTypeIncludingAncestors(ListableBeanFactory, ResolvableType, boolean, boolean) + */ + String[] getBeanNamesForType(ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit); + + /** + * 根据给定类型(包括子类)返回匹配的bean的名称数组,根据bean定义或FactoryBeans的{@code getObjectType}的值判断。 + *

注意:此方法仅内省顶级bean。它不检查可能与指定类型匹配的嵌套bean。 + *

会考虑由FactoryBeans创建的对象,这意味着FactoryBeans将被初始化。 + * 如果由FactoryBean创建的对象不匹配,则原始FactoryBean本身将与类型匹配。 + *

不考虑此工厂可能参与的任何层次结构。 + * 使用BeanFactoryUtils的{@code beanNamesForTypeIncludingAncestors}以包括祖先工厂中的bean。 + *

注意:不会忽略以非bean定义的方式注册的单例bean。 + *

此版本的{@code getBeanNamesForType}匹配所有类型的bean,无论是单例,原型还是FactoryBeans。 + * 在大多数实现中,结果将与{@code getBeanNamesForType(type, true, true)}的结果相同。 + *

此方法返回的bean名称数组应尽可能以后端配置中定义的顺序返回bean名称。 + * + * @param type 要匹配的类或接口,或{@code null}表示所有bean名称 + * @return 匹配给定对象类型(包括子类)的bean的名称数组,如果没有则为空数组 + * @see FactoryBean#getObjectType + * @see BeanFactoryUtils#beanNamesForTypeIncludingAncestors(ListableBeanFactory, Class) + */ + String[] getBeanNamesForType(@Nullable Class type); + + /** + * 根据给定类型(包括子类)返回匹配的bean的名称数组,根据bean定义或FactoryBeans的{@code getObjectType}的值判断。 + *

注意:此方法仅内省顶级bean。它不检查可能与指定类型匹配的嵌套bean。 + *

如果设置了“allowEagerInit”标志,会考虑由FactoryBeans创建的对象,这意味着FactoryBeans将被初始化。 + * 如果由FactoryBean创建的对象不匹配,则原始FactoryBean本身将与类型匹配。 + * 如果未设置“allowEagerInit”,则仅检查原始FactoryBeans(这不需要初始化每个FactoryBean)。 + *

不考虑此工厂可能参与的任何层次结构。 + * 使用BeanFactoryUtils的{@code beanNamesForTypeIncludingAncestors}以包括祖先工厂中的bean。 + *

注意:不会忽略以非bean定义的方式注册的单例bean。 + *

此方法返回的bean名称数组应尽可能以后端配置中定义的顺序返回bean名称。 + * + * @param type 要匹配的类或接口,或{@code null}表示所有bean名称 + * @param includeNonSingletons 是否包括原型或作用域bean,或仅包括单例(也适用于FactoryBeans) + * @param allowEagerInit 是否初始化延迟初始化的单例和 + * 由FactoryBeans创建的对象(或带有 + * "factory-bean"引用的工厂方法)以进行类型检查。 + * 请注意,需要急切地初始化FactoryBeans和"factory-bean"引用,因此 + * 请注意,为此标志传递“true”将初始化FactoryBeans和“factory-bean”引用。 + * @return 匹配给定对象类型(包括子类)的bean的名称数组,如果没有则为空数组 + * @see FactoryBean#getObjectType + * @see BeanFactoryUtils#beanNamesForTypeIncludingAncestors(ListableBeanFactory, Class, boolean, boolean) + */ + String[] getBeanNamesForType(@Nullable Class type, boolean includeNonSingletons, boolean allowEagerInit); + + /** + * 根据给定的对象类型(包括子类),从bean定义或FactoryBeans的{@code getObjectType}的值判断, + * 返回匹配的bean实例Map。 + *

注意:此方法仅内省顶级bean。它不检查可能与指定类型匹配的嵌套bean。 + *

会考虑由FactoryBeans创建的对象,这意味着FactoryBeans将被初始化。 + * 如果由FactoryBean创建的对象不匹配,则原始FactoryBean本身将与类型匹配。 + *

不考虑此工厂可能参与的任何层次结构。 + * 使用BeanFactoryUtils的{@code beansOfTypeIncludingAncestors}以包括祖先工厂中的bean。 + *

注意:不会忽略以非bean定义的方式注册的单例bean。 + *

此版本的getBeansOfType匹配所有类型的bean,无论是单例,原型还是FactoryBeans。 + * 在大多数实现中,结果将与{@code getBeansOfType(type, true, true)}的结果相同。 + *

此方法返回的Map应尽可能以后端配置中定义的顺序返回bean名称和相应的bean实例。 + * + * @param type 要匹配的类或接口,或{@code null}表示所有具体bean + * @return 匹配的bean的Map,其中包含bean名称作为键,相应的bean实例作为值 + * @throws BeansException 如果无法创建bean + * @since 1.1.2 + * @see FactoryBean#getObjectType + * @see BeanFactoryUtils#beansOfTypeIncludingAncestors(ListableBeanFactory, Class) + */ + Map getBeansOfType(@Nullable Class type) throws BeansException; + + /** + * 根据给定对象类型(包括子类),从bean定义或FactoryBeans的{@code getObjectType}的值判断, + * 返回匹配的bean实例Map。 + *

注意:此方法仅内省顶级bean。它不检查可能与指定类型匹配的嵌套bean。 + *

如果设置了“allowEagerInit”标志,会考虑由FactoryBeans创建的对象, + * 这意味着FactoryBeans将被初始化。如果由FactoryBean创建的对象不匹配, + * 则原始FactoryBean本身将与类型匹配。 + *

不考虑此工厂可能参与的任何层次结构。 + * 使用BeanFactoryUtils的{@code beansOfTypeIncludingAncestors}以包括祖先工厂中的bean。 + *

注意:不会忽略以非bean定义的方式注册的单例bean。 + *

此方法返回的Map应尽可能以后端配置中定义的顺序返回bean名称和相应的bean实例。 + * + * @param type 要匹配的类或接口,或{@code null}表示所有具体bean + * @param includeNonSingletons 是否包括原型或作用域bean,或仅包括单例(也适用于FactoryBeans) + * @param allowEagerInit 是否初始化延迟初始化的单例和 + * 由FactoryBeans创建的对象(或带有 + * "factory-bean"引用的工厂方法)以进行类型检查。 + * 请注意,需要急切地初始化FactoryBeans和"factory-bean"引用,因此 + * 请注意,为此标志传递“true”将初始化FactoryBeans和“factory-bean”引用。 + * @return 匹配的bean的Map,其中包含bean名称作为键,相应的bean实例作为值 + * @throws BeansException 如果无法创建bean + * @see FactoryBean#getObjectType + * @see BeanFactoryUtils#beansOfTypeIncludingAncestors(ListableBeanFactory, Class, boolean, boolean) + */ + Map getBeansOfType(@Nullable Class type, boolean includeNonSingletons, boolean allowEagerInit) + throws BeansException; + + /** + * 查找所有具有提供的{@link Annotation}类型注释的bean的名称,尚未创建相应的bean实例。 + *

请注意,此方法考虑由FactoryBeans创建的对象,这意味着FactoryBeans将初始化以确定其对象类型。 + * + * @param annotationType 要查找的注解类型 + * (在指定bean的类、接口或工厂方法级别) + * @return 所有匹配bean的名称 + * @since 4.0 + * @see #findAnnotationOnBean + */ + String[] getBeanNamesForAnnotation(Class annotationType); + + /** + * 查找所有具有提供的{@link Annotation}类型注释的bean,返回包含bean名称作为键和相应bean实例作为值的Map。 + *

请注意,此方法考虑由FactoryBeans创建的对象,这意味着FactoryBeans将初始化以确定其对象类型。 + * + * @param annotationType 要查找的注解类型 + * (在指定bean的类、接口或工厂方法级别) + * @return 包含匹配的bean的Map,其中包含bean名称作为键,相应的bean实例作为值 + * @throws BeansException 如果无法创建bean + * @since 3.0 + * @see #findAnnotationOnBean + */ + Map getBeansWithAnnotation(Class annotationType) throws BeansException; + + /** + * 在指定的bean上查找{@code annotationType}类型的{@link Annotation}, + * 如果在给定类本身找不到注解,还会遍历其接口和超类,以及检查bean的工厂方法(如果有)。 + * + * @param beanName 要查找注解的bean的名称 + * @param annotationType 要查找的注解类型 + * (在指定bean的类、接口或工厂方法级别) + * @return 如果找到,返回给定类型的注解,否则返回{@code null} + * @throws NoSuchBeanDefinitionException 如果没有给定名称的bean + * @since 3.0 + * @see #getBeanNamesForAnnotation + * @see #getBeansWithAnnotation + */ + @Nullable + A findAnnotationOnBean(String beanName, Class annotationType) + throws NoSuchBeanDefinitionException; + +} +``` + +### 五、主要实现 + +- `DefaultListableBeanFactory` + - `DefaultListableBeanFactory`是Spring框架中实现`BeanFactory`接口的关键类之一,负责注册、管理和初始化应用程序中的所有Bean定义。它支持依赖注入、不同作用域的Bean管理、处理`FactoryBean`、层次性容器、以及各种生命周期回调等功能,是Spring IoC容器的核心实现,提供了灵活而强大的Bean管理和配置机制。 + +### 六、最佳实践 + +使用`ListableBeanFactory`接口的方法,通过Spring容器获取和检查bean定义和实例。给大家展示了如何判断是否包含特定名称的bean定义,获取所有bean定义的数量和名称,懒加载获取bean实例,根据类型和注解获取bean名称和实例,以及在指定bean上查找指定类型的注解。 + +```java +public class ListableBeanFactoryDemo { + + public static void main(String[] args) { + // 创建 ListableBeanFactory + ListableBeanFactory beanFactory = new AnnotationConfigApplicationContext(MyConfiguration.class).getBeanFactory(); + + // 判断是否包含指定名称的 bean 定义 + boolean containsBeanDefinition = beanFactory.containsBeanDefinition("myService"); + System.out.println("判断是否包含指定名称的Bean定义: " + containsBeanDefinition); + + // 获取工厂中所有 bean 定义的数量 + int beanDefinitionCount = beanFactory.getBeanDefinitionCount(); + System.out.println("获取工厂中所有Bean定义数量: " + beanDefinitionCount); + + // 获取工厂中所有 bean 定义的名称数组 + String[] beanDefinitionNames = beanFactory.getBeanDefinitionNames(); + System.out.println("获取工厂中所有Bean定义名称: " + String.join(", ", beanDefinitionNames)); + + // 获取 ObjectProvider,并懒加载获取 bean 实例 + ObjectProvider objectProvider = beanFactory.getBeanProvider(MyService.class, true); + System.out.println("获取Bean的ObjectProvider: " + objectProvider.getObject()); + + // 根据类型获取所有 bean 的名称 + String[] beanNamesForType = beanFactory.getBeanNamesForType(ResolvableType.forClass(MyService.class)); + System.out.println("根据类型获取Bean名称: " + String.join(", ", beanNamesForType)); + + // 根据注解类型获取所有 bean 的名称 + String[] beanNamesForAnnotation = beanFactory.getBeanNamesForAnnotation(Service.class); + System.out.println("根据注解获取Bean名称: " + String.join(", ", beanNamesForAnnotation)); + + // 根据注解类型获取所有 bean 实例 + Map beansWithAnnotation = beanFactory.getBeansWithAnnotation(Service.class); + System.out.println("根据注解类型获取所有Bean实例: " + beansWithAnnotation); + + // 在指定 bean 上查找指定类型的注解 + Service annotation = beanFactory.findAnnotationOnBean("myService", Service.class); + System.out.println("指定Bean上查找指定类型的注解: " + annotation); + } +} +``` + +`MyConfiguration` 类扫描包 "`com.xcs.spring.service`" 以查找Spring组件,如 `@Component`、`@Service`、`@Repository` 和 `@Controller`。Spring将识别带有这些注解的类,并在应用程序上下文中将它们注册为Bean。 + +```java +@Configuration +@ComponentScan("com.xcs.spring.service") +public class MyConfiguration { + +} +``` + +通过 `@Service` 注解告诉Spring框架它是一个被管理的组件。 + +```java +@Service +public class MyService { +} +``` + +运行结果发现,Spring容器中Bean的定义、数量、名称,以及通过不同方式获取Bean的相关信息。 + +```java +判断是否包含指定名称的Bean定义: true +获取工厂中所有Bean定义数量: 6 +获取工厂中所有Bean定义名称: org.springframework.context.annotation.internalConfigurationAnnotationProcessor, org.springframework.context.annotation.internalAutowiredAnnotationProcessor, org.springframework.context.event.internalEventListenerProcessor, org.springframework.context.event.internalEventListenerFactory, myConfiguration, myService +获取Bean的ObjectProvider: com.xcs.spring.service.MyService@4b0d79fc +根据类型获取Bean名称: myService +根据注解获取Bean名称: myService +根据注解类型获取所有Bean实例: {myService=com.xcs.spring.service.MyService@4b0d79fc} +指定Bean上查找指定类型的注解: @org.springframework.stereotype.Service(value=) +``` + +### 七、与其他组件的关系 + +1. **`BeanFactory` 接口** + + - `ListableBeanFactory` 继承自 `BeanFactory` 接口,因此拥有 `BeanFactory` 的基本功能,包括获取 Bean、判断 Bean 是否存在等。 + +2. **`ApplicationContext` 接口** + + - `ApplicationContext` 是 `BeanFactory` 的子接口,它继承了 `ListableBeanFactory`,因此拥有了 `ListableBeanFactory` 的所有功能。`ApplicationContext` 还提供了更多的应用级别的功能,例如国际化、事件发布等。 + +3. **`ConfigurableListableBeanFactory` 接口** + + - `ConfigurableListableBeanFactory` 是 `ListableBeanFactory` 的子接口,继承了 `ListableBeanFactory` 的功能,并在此基础上提供了配置修改的方法,例如注册 Bean 定义、销毁 Bean 等。 + +4. **`AbstractApplicationContext` 抽象类** + + - `AbstractApplicationContext` 是 `ApplicationContext` 接口的一个抽象实现,它实现了 `ConfigurableListableBeanFactory` 接口,包含了 `ListableBeanFactory` 和 `ConfigurableListableBeanFactory` 的功能。 + +5. **`GenericApplicationContext` 类** + + - `GenericApplicationContext` 是 `AbstractApplicationContext` 的具体实现,它可以通过配置文件、注解等方式进行配置,同时提供了 `ListableBeanFactory` 和 `ConfigurableListableBeanFactory` 的功能。 + +6. **`AnnotationConfigApplicationContext` 类:** + + - `AnnotationConfigApplicationContext` 是 `GenericApplicationContext` 的一个具体实现,它通过基于注解的配置类来初始化 Spring 容器,同时支持 `ListableBeanFactory` 和 `ConfigurableListableBeanFactory` 接口。 + +### 八、常见问题 + +1. **无法获取到指定类型的Bean** + + - Bean 的定义未被扫描或注册到 Spring 容器中。确保相关包或类被包含在组件扫描的范围内,或手动配置相关的 Bean 定义。 + +2. **Bean数量不符合预期** + + - 组件扫描范围、条件过滤不准确,或者配置类中存在错误。仔细检查组件扫描的配置、条件过滤条件,确保配置类正确无误。 + +3. **`ObjectProvider` 无法获取到实例** + + - 目标类型的 Bean 不存在,或者存在多个符合条件的 Bean。确保目标类型的 Bean 在容器中存在且符合条件,或者使用 `ObjectProvider` 的其他方法进行更灵活的操作。 + +4. **`getBeansOfType` 返回的结果为空** + + - 目标类型的 Bean 在容器中不存在。确保目标类型的 Bean 在容器中存在,并检查是否符合条件。 + +5. **Bean名称顺序不符合期望** + + - Spring 容器中的 Bean 注册顺序和期望的不一致。对于有顺序要求的情况,可以考虑使用 `@Order` 注解或其他方式指定 Bean 注册顺序。 \ No newline at end of file diff --git a/spring-factory/spring-factory-listableBeanFactory/src/main/java/com/xcs/spring/ListableBeanFactoryDemo.java b/spring-factory/spring-factory-listableBeanFactory/src/main/java/com/xcs/spring/ListableBeanFactoryDemo.java index c74e7fb..96df09c 100644 --- a/spring-factory/spring-factory-listableBeanFactory/src/main/java/com/xcs/spring/ListableBeanFactoryDemo.java +++ b/spring-factory/spring-factory-listableBeanFactory/src/main/java/com/xcs/spring/ListableBeanFactoryDemo.java @@ -20,36 +20,36 @@ public class ListableBeanFactoryDemo { // 创建 ListableBeanFactory ListableBeanFactory beanFactory = new AnnotationConfigApplicationContext(MyConfiguration.class).getBeanFactory(); - // 示例:判断是否包含指定名称的 bean 定义 + // 判断是否包含指定名称的 bean 定义 boolean containsBeanDefinition = beanFactory.containsBeanDefinition("myService"); - System.out.println("1.包含Bean定义: " + containsBeanDefinition); + System.out.println("判断是否包含指定名称的Bean定义: " + containsBeanDefinition); - // 示例:获取工厂中所有 bean 定义的数量 + // 获取工厂中所有 bean 定义的数量 int beanDefinitionCount = beanFactory.getBeanDefinitionCount(); - System.out.println("2.Bean定义数量: " + beanDefinitionCount); + System.out.println("获取工厂中所有Bean定义数量: " + beanDefinitionCount); - // 示例:获取工厂中所有 bean 定义的名称数组 + // 获取工厂中所有 bean 定义的名称数组 String[] beanDefinitionNames = beanFactory.getBeanDefinitionNames(); - System.out.println("3.Bean定义名称: " + String.join(", ", beanDefinitionNames)); + System.out.println("获取工厂中所有Bean定义名称: " + String.join(", ", beanDefinitionNames)); - // 示例:获取 ObjectProvider,并懒加载获取 bean 实例 + // 获取 ObjectProvider,并懒加载获取 bean 实例 ObjectProvider objectProvider = beanFactory.getBeanProvider(MyService.class, true); - System.out.println("4.Bean的ObjectProvider: " + objectProvider.getObject()); + System.out.println("获取Bean的ObjectProvider: " + objectProvider.getObject()); - // 示例:根据类型获取所有 bean 的名称 + // 根据类型获取所有 bean 的名称 String[] beanNamesForType = beanFactory.getBeanNamesForType(ResolvableType.forClass(MyService.class)); - System.out.println("5.根据类型获取Bean名称: " + String.join(", ", beanNamesForType)); + System.out.println("根据类型获取Bean名称: " + String.join(", ", beanNamesForType)); - // 示例:根据注解类型获取所有 bean 的名称 + // 根据注解类型获取所有 bean 的名称 String[] beanNamesForAnnotation = beanFactory.getBeanNamesForAnnotation(Service.class); - System.out.println("6.根据注解获取Bean名称: " + String.join(", ", beanNamesForAnnotation)); + System.out.println("根据注解获取Bean名称: " + String.join(", ", beanNamesForAnnotation)); - // 示例:根据注解类型获取所有 bean 实例 + // 根据注解类型获取所有 bean 实例 Map beansWithAnnotation = beanFactory.getBeansWithAnnotation(Service.class); - System.out.println("7.根据注解类型获取所有Bean实例: " + beansWithAnnotation); + System.out.println("根据注解类型获取所有Bean实例: " + beansWithAnnotation); - // 示例:在指定 bean 上查找指定类型的注解 + // 在指定 bean 上查找指定类型的注解 Service annotation = beanFactory.findAnnotationOnBean("myService", Service.class); - System.out.println("8.Bean上的注解: " + annotation); + System.out.println("指定Bean上查找指定类型的注解: " + annotation); } }