Spring系列-03-BeanFactory和Application接口和相关实现

news2024/11/25 2:49:26

BeanFactory

BeanFactory和它的子接口们

BeanFactory 接口的所有子接口, 如下图

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

BeanFactory(根容器)-掌握

BeanFactory是根容器

The root interface for accessing a Spring bean container. This is the basic client view of a bean container; further interfaces such as ListableBeanFactory and org.springframework.beans.factory.config.ConfigurableBeanFactory are available for specific purposes.

翻译:

用于访问 SpringFramework bean 容器的根接口。这是 bean 容器的基本客户端视图。诸如 ListableBeanFactoryorg.springframework.beans.factory.config.ConfigurableBeanFactory 之类的扩展接口可用于特定的用途。

  • 结论: 解释BeanFactory 是 SpringFramework 中管理 Bean 的容器, 它是最最基本的根接口, 下面的扩展都是为了实现某些额外的特性(层次性、可搜索性、可配置性等)
BeanFactory中定义的作用域概念

This interface is implemented by objects that hold a number of bean definitions, each uniquely identified by a String name. Depending on the bean definition, the factory will return either an independent instance of a contained object (the Prototype design pattern), or a single shared instance (a superior alternative to the Singleton design pattern, in which the instance is a singleton in the scope of the factory). Which type of instance will be returned depends on the bean factory configuration: the API is the same. Since Spring 2.0, further scopes are available depending on the concrete application context (e.g. “request” and “session” scopes in a web environment).

翻译:

BeanFactory接口由包含多个 bean 定义的对象实现, 每个 bean 的定义信息均由 "name"进行唯一标识。根据 bean 的定义, SpringFramework 中的工厂会返回所包含对象的独立实例 ( prototype , 原型模式 ) , 或者返回单个共享实例 ( singleton , 单例模式的替代方案, 其中实例是工厂作用域中的单例 ) 。返回 bean 的实例类型取决于 bean 工厂的配置:API是相同的。从 SpringFramework 2.0 开始, 根据具体的应用程序context ( 例如 Web 环境中的 request 和 session 作用域 ) , 可以使用更多作用域。

  • 结论: 解释了 BeanFactory 中设计的作用域概念, 默认情况下, BeanFactory 中的 Bean 只有单实例 Bean(singleton)原型 Bean(prototype) , 自打 SpringFramework2.0 开始, 出现了 Web 系列的作用域 "request""session" , 后续的又出现了 "global session""websocket" 作用域
BeanFactory集成了环境配置

The point of this approach is that the BeanFactory is a central registry of application components, and centralizes configuration of application components (no more do individual objects need to read properties files, for example). See chapters 4 and 11 of “Expert One-on-One J2EE Design and Development” for a discussion of the benefits of this approach.

翻译:

这种方法的重点是 BeanFactory 是应用程序组件的注册中心, 并且它集成了应用程序组件的配置(例如不再需要单个对象读取属性文件)。有关此方法的好处的讨论, 请参见《Expert One-on-One J2EE Design and Development》的第4章和第11章

  • 结论: 解释了 BeanFactory 它本身是所有 Bean 的注册中心, 所有的 Bean 最终都在 BeanFactory 中创建和保存。另外 BeanFactory 中还集成了配置信息。通过加载外部的 properties 文件, 借助 SpringFramework 的方式将配置文件的属性值设置到 Bean 对象中
BeanFactory推荐使用DI而不是DL

Note that it is generally better to rely on Dependency Injection (“push” configuration) to configure application objects through setters or constructors, rather than use any form of “pull” configuration like a BeanFactory lookup. Spring’s Dependency Injection functionality is implemented using this BeanFactory interface and its subinterfaces.

翻译:

请注意, 通常最好使用依赖注入(""的配置), 通过setter方法或构造器注入的方式, 配置应用程序对象, 而不是使用任何形式的"拉"的配置(例如借助 BeanFactory 进行依赖查找)。 SpringFramework 的 Dependency Injection 功能是使用 BeanFactory 接口及其子接口实现的

  • 结论: SpringFramework 官方在 IOC 的两种实现上的权衡:推荐使用 DI , 尽可能不要使用 DLDI 的思想是"推", 它主张把组件需要的依赖"推"到组件的成员上;DL 的思想是"拉", 组件需要哪些依赖需要组件自己去 IOC 容器中"拉取"
BeanFactory支持多种类型的配置源

Normally a BeanFactory will load bean definitions stored in a configuration source (such as an XML document), and use the org.springframework.beans package to configure the beans. However, an implementation could simply return Java objects it creates as necessary directly in Java code. There are no constraints on how the definitions could be stored: LDAP, RDBMS, XML, properties file, etc. Implementations are encouraged to support references amongst beans (Dependency Injection).

翻译:

通常情况下, BeanFactory 会加载存储在配置源(例如 XML 文档)中 bean 的定义, 并使用 org.springframework.beans 包中的 API 来配置 bean 。然而, BeanFactory 的实现可以根据需要直接在 Java 代码中返回它创建的 Java 对象。bean 定义的存储方式没有任何限制, 它可以是 LDAP (轻型文件目录访问协议), RDBMS(关系型数据库系统), XML, properties 文件等。鼓励实现以支持 Bean 之间的引用(依赖注入)。

  • 结论: SpringFramework 可以支持的配置源类型有很多种, 当然咱最常用的还是 xml 和注解驱动啦 ~ 这些配置源中存储的信息是一些 Bean 的定义(BeanDefinition)
BeanFactory可实现层次性

In contrast to the methods in ListableBeanFactory, all of the operations in this interface will also check parent factories if this is a HierarchicalBeanFactory. If a bean is not found in this factory instance, the immediate parent factory will be asked. Beans in this factory instance are supposed to override beans of the same name in any parent factory.

翻译:

ListableBeanFactory 中的方法相比, BeanFactory 中的所有操作还将检查父工厂(如果这是 HierarchicalBeanFactory )。如果在 BeanFactory 实例中没有找到指定的 bean , 则会向父工厂中搜索查找。BeanFactory 实例中的 Bean 应该覆盖任何父工厂中的同名 Bean 。

  • 结论: Spring想告诉我们的是, BeanFactory 本身可以支持父子结构, 这个父子结构的概念和实现由 HierarchicalBeanFactory 实现, 在 BeanFactory 中它也只是提了一下
BeanFactory中设有完整的生命周期控制机制

Bean factory implementations should support the standard bean lifecycle interfaces as far as possible. The full set of initialization methods and their standard order is:

  • BeanNameAware’s setBeanName
  • BeanClassLoaderAware’s setBeanClassLoader
  • BeanFactoryAware’s setBeanFactory
  • EnvironmentAware’s setEnvironment
  • EmbeddedValueResolverAware’s setEmbeddedValueResolver
  • ResourceLoaderAware’s setResourceLoader (only applicable when running in an application context)
  • ApplicationEventPublisherAware’s setApplicationEventPublisher (only applicable when running in an application context)
  • MessageSourceAware’s setMessageSource (only applicable when running in an application context)
  • ApplicationContextAware’s setApplicationContext (only applicable when running in an application context)
  • ServletContextAware’s setServletContext (only applicable when running in a web application context)
  • postProcessBeforeInitialization methods of BeanPostProcessors
  • InitializingBean’s afterPropertiesSet
  • a custom init-method definition
  • postProcessAfterInitialization methods of BeanPostProcessors

On shutdown of a bean factory, the following lifecycle methods apply:

  • postProcessBeforeDestruction methods of DestructionAwareBeanPostProcessors
  • DisposableBean’s destroy
  • a custom destroy-method definition

翻译:

BeanFactory 接口实现了尽可能支持标准 Bean 的生命周期接口。全套初始化方法及其标准顺序为:

在关闭 BeanFactory 时, 以下生命周期方法适用:

结论: Bean 的生命周期是在 BeanFactory 中就有设计的, 而且官方文档也提供了全套的初始化和销毁流程

总结

总的来说, BeanFactory提供了一下的特性

  • BeanFactory是根容器
  • 定义的作用域概念
  • 集成环境配置
  • 支持多种类型的配置源
  • 层次性的设计
  • 完整的生命周期控制机制

HierarchicalBeanFactory(层次性)-熟悉

Hierarchical翻译过来就是等级制度的, 分等级的, 很明显的体现了层次性, 所谓的父子结构就是从这里体现出来的

JavaDoc描述

Sub-interface implemented by bean factories that can be part of a hierarchy.
The corresponding setParentBeanFactory method for bean factories that allow setting the parent in a configurable fashion can be found in the ConfigurableBeanFactory interface

翻译:

BeanFactory 实现的子接口, 它可以理解为是层次结构的一部分。可以在 ConfigurableBeanFactory 接口中找到用于 BeanFactory 的相应 setParentBeanFactory 方法, 该方法允许以可配置的方式设置父对象

结论: getParentBeanFactory() , 它就可以获取到父 BeanFactory 对象

核心方法解析
  • getParentBeanFactory() : 获取当前BeanFactory的父BeanFactory

  • containsLocalBean(): 检查当前BeanFacotry是否有指定名称的Bean, 不会往父BeanFactory中进行查找

    • 即是父容器中有这个Bean, 那么也返回false
  • ``containsBean()`: 检查当前BeanFacotry是否有指定名称的Bean, 如果没有, 那么会往父容器中继续查找

  • getBean(): 从当前 BeanFactory 开始查找是否存在指定的 Bean , 如果当前找不到就依次向上找父 BeanFactory , 直到找到为止返回, 或者都找不到最终抛出 NoSuchBeanDefinitionException

    • 注意这里的说法:如果当前找不到就往上找, 那如果找到了就不往上找了。思考一个问题:如果当前 BeanFactory 中有指定的Bean了, 父 BeanFactory 中可能有吗?

      答案是有, 因为即便存在父子关系, 但他们本质上是不同的BeanFactory, 所以有可能找到多个相同的 Bean 。换句话说, @Scope 中声明的Singleton只是在一个容器中是单实例的, 但有了层次性结构后, 对于整体的多个容器来看, 就不是单实例的了

运行示例

Bean类

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Cat {
    private String name;
}

xml配置

child.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="dog" class="com.linkedbear.spring.lifecycle.Dog">
        <constructor-arg index="0" value="childDog"/>
    </bean>
</beans>

parent.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="pig" class="com.linkedbear.spring.lifecycle.Pig">
        <constructor-arg index="0" value="parentPig"/>
    </bean>
</beans>

启动类

public class TestApplication {
    public static void main(String[] args) throws Exception {
        // 创建子 BeanFactory
        ConfigurableBeanFactory childContext = new XmlBeanFactory(new ClassPathResource("lifecycle/child.xml"));
        // 创建父 BeanFactory
        ConfigurableBeanFactory parentContext = new XmlBeanFactory(new ClassPathResource("lifecycle/parent.xml"));
        // 设置父子关系
        childContext.setParentBeanFactory(parentContext);
        // 控制台打印结果如下: org.springframework.beans.factory.xml.XmlBeanFactory@8b96fde: defining beans [cat,pig]; root of factory hierarchy
        System.out.println("childContext的父容器: " + childContext.getParentBeanFactory());

        // ------ getBean() 方法 ------
        Dog childDog = childContext.getBean("dog", Dog.class);
        // 控制台打印结果如下: Dog(name=childDog)
        System.out.println("childContext.getBean(): " + childDog);

        // 控制台抛出异常NoSuchBeanDefinitionException, 因为parent.xml中没有名为dog的Bean
        // Dog parentDog = parentContext.getBean("dog", Dog.class);

        System.out.println("------------------");

        Pig childPig = childContext.getBean("pig", Pig.class);
        // 控制台打印结果如下: Pig(name=parentPig), 输出的是parent.xml中pig, child.xml中并没有名为pig的Bean, 说明了本地容器没有这个Bean的时候, getBean()会继续往父容器找
        System.out.println("childContext.getBean(): " + childPig);

        Pig parentPig = parentContext.getBean("pig", Pig.class);
        // 控制台打印结果如下: Pig(name=parentPig)
        System.out.println("parentContext.getBean(): " + parentPig);

        // 结论: getBean只获取本地容器中的Bean, 如果本地容器中没有的这个Bean时, 并不会往父容器查找

        System.out.println("------------------");

        // ------ containsLocalBean() 方法 ------
        boolean childDogContainLocal = childContext.containsLocalBean("dog");
        // 控制台打印结果如下:  ture
        System.out.println("childContext.containsLocalBean(): " + childDogContainLocal);

        boolean parentPigContainLocal = parentContext.containsLocalBean("dog");
        // 控制台打印结果如下:  false, 此时child.xml中没有pig, 但是父容器parent.xml中有名为pig的Bean, 这里输出false说明
        System.out.println("parentContext.containsLocalBean(): " + parentPigContainLocal);

        System.out.println("------------------");

        // ------ containsBean() 方法 ------
        boolean childPigContain = childContext.containsBean("pig");
        // 控制台打印结果如下:  true, 此时child.xml中没有pig, 但是父容器parent.xml中有名为pig的Bean, 这里输出true, 说明了containsBean()在当本地容器没找到Bean时会往父容器中进行寻找
        System.out.println("childContext.containsBean(): " + childPigContain);

        boolean parentPigContain = parentContext.containsBean("pig");
        // 控制台打印结果如下:  true
        System.out.println("parentContext.containsBean(): " + parentPigContain);
    }
}

ListableBeanFactory(可列举性)-熟悉

Listable翻译过来就是可列举的, 那么ListableBeanFactory就可以理解为可列举的BeanFactory

ListableBeanFactory只列举当前容器中的Bean

Extension of the BeanFactory interface to be implemented by bean factories that can enumerate all their bean instances, rather than attempting bean lookup by name one by one as requested by clients. BeanFactory implementations that preload all their bean definitions (such as XML-based factories) may implement this interface.

翻译:

它是 BeanFactory 接口的扩展实现, 它可以列举出所有 bean 实例, 而不是按客户端调用的要求, 按照名称一一进行 bean 的依赖查找。具有"预加载其所有 bean 定义信息"的 BeanFactory 实现(例如基于XML的 BeanFactory )可以实现此接口

结论: ListableBeanFactory 只会列举当前容器的 Bean, 列举所有Bean可以使用BeanFactoryUtils中的方法获取

  • BeanFactory 可以具有层次性, 那这样再列举所有 Bean 的时候, 就需要斟酌到底是获取包括父容器在内的所有 Bean , 还是只获取当前容器中的 Bean , SpringFramework 在斟酌之后选择了只获取当前容器中的 Bean , 而如果真的想获取所有Bean , 可以借助 BeanFactoryUtils 工具类来实现(工具类中有不少以 "IncludingAncestors" 结尾的方法, 代表可以一起取父容器)
ListableBeanFactory会有选择性的列举

The methods in this interface will just respect bean definitions of this factory. They will ignore any singleton beans that have been registered by other means like org.springframework.beans.factory.config.ConfigurableBeanFactory’s registerSingleton method, with the exception of getBeanNamesForType and getBeansOfType which will check such manually registered singletons too. Of course, BeanFactory’s getBean does allow transparent access to such special beans as well. However, in typical scenarios, all beans will be defined by external bean definitions anyway, so most applications don’t need to worry about this differentiation.

翻译:

ListableBeanFactory 中的方法将仅遵循当前工厂的bean定义, 它们将忽略通过其他方式(例如 ConfigurableBeanFactoryregisterSingleton 方法)注册的任何单实例 bean (但 getBeanNamesForTypegetBeansOfType 除外), 它们也会检查这种手动注册的单实例 Bean 。当然, BeanFactorygetBean 确实也允许透明访问此类特殊 bean 。在一般情况下, 无论如何所有的 bean 都来自由外部的 bean 定义信息, 因此大多数应用程序不必担心这种区别。

结论: 作为一个"可迭代"的BeanFactory, 按理来讲应该最起码得把当前容器中的所有Bean都列出来, 结果你又告诉我有些Bean会被忽略掉不给列(比如手动注册的Bean)

  • ListableBeanFactory设计选择性列举的目的: 有些组件属于Spring内部使用的, Spring并不希望开发者平常直接操作它, 类比Win中隐藏受保护的操作系统文件, 默认情况下都是隐藏的, 避免用户操作(如果动了这些文件, 那么很可能Win就出问题了)
ListableBeanFactory的大部分方法不适合频繁调用

NOTE: With the exception of getBeanDefinitionCount and containsBeanDefinition, the methods in this interface are not designed for frequent invocation. Implementations may be slow.

翻译:

注意:除了getBeanDefinitionCountcontainsBeanDefinition之外, 此接口中的方法不适用于频繁调用, 方法的实现可能执行速度会很慢。

结论: 通常都不需要动不动去翻IOC容器的东西, 顶多是读完一遍就自己缓存起来. 一般情况下也不会有业务需求会深入到 IOC 容器的底部

AutowireCapableBeanFactory(可自动注入性)-了解

AutowireCapableBeanFactory可以支持外部Bean的自动装配

Extension of the BeanFactory interface to be implemented by bean factories that are capable of autowiring, provided that they want to expose this functionality for existing bean instances.

翻译:

它是 BeanFactory 接口的扩展实现, 它可以实现自动装配, 前提是开发者希望为现有的 bean实例公开此功能。

结论: AutowireCapableBeanFactory本身可以支持自动装配, 而且还可以为现有的一些 Bean 也能支持自动装配。而这个"现有"的概念, 实际上指的是那些不被Spring管理的 Bean

AutowireCapableBeanFactory用于框架集成

This subinterface of BeanFactory is not meant to be used in normal application code: stick to BeanFactory or ListableBeanFactory for typical use cases.

Integration code for other frameworks can leverage this interface to wire and populate existing bean instances that Spring does not control the lifecycle of. This is particularly useful for WebWork Actions and Tapestry Page objects, for example.

翻译:

AutowireCapableBeanFactory 这个子接口不能在常规的应用程序代码中使用:一般情况下, 请坚持使用 BeanFactoryListableBeanFactory 。 其他框架的集成代码可以利用此接口来连接和注入SpringFramework 无法控制其生命周期的现有bean实例。例如, 这对于 WebWork 操作和 Tapestry 页面对象特别有用。

结论: AutowireCapableBeanFactory平常业务代码不要用, 与其他框架进行集成时才使用利用此接口来连接和注入 SpringFramework 无法控制其生命周期的现有 bean 实例, 这其实已经把它的作用完整的描述出来了:你要是真想用它, 那也是在跟其它框架集成时, 如果其它框架的一些Bean实例无法让SpringFramework控制, 但又需要注入一些由SpringFramework管理的对象, 那就可以用它了

  • 框架可能会创建自己的Bean实例, 并管理它们的生命周期, 而这些 Bean 实例通常不受 Spring 容器的控制, 因此Spring不会自动地为它们注入依赖或管理它们的生命周期(表明了, 如果这个Bean要注入Spring中管理的Bean, 那么需要将Bean注册到Spring中)
  • AutowireCapableBeanFactory 接口提供了一个方法 autowireBean, 它可以用来手动为这些非 Spring Bean 实例注入依赖。这个方法允许你指定一个 Bean 实例, 以及一个需要注入的属性名称。Spring会根据这个属性的类型, 在其 Bean 定义中查找合适的 Bean, 并将其注入到非 Spring Bean 实例中

场景示例

示例一: 非Spring管理的对象需要注入Spring管理的Bean

// MyAction它不是由Spring管理的类
public class MyAction {
    // 需要注入MyService
    private MyService myService;
	
    // setter()注入依赖
    public void setMyService(MyService myService) {
        this.myService = myService;
    }

    public String execute() {
        // 使用注入的服务
        myService.doSomething();
        return "success";
    }
}

// Spring环境中, 在配置类中使用@Bean配置MyService, 
@Configuration
public class AppConfig {

    @Bean
    public MyService myService() {
        return new MyServiceImpl();
    }
}

// 在非 Spring 环境中, 需要手动注入依赖
public class Main {
    public static void main(String[] args) {
        // 创建 Spring 应用context
        ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

        // 获取 AutowireCapableBeanFactory
        AutowireCapableBeanFactory beanFactory = context.getAutowireCapableBeanFactory();

        // 创建MyAction对象
        MyAction action = new MyAction();

        // 手动注入依赖
        beanFactory.autowireBean(action);

        // 执行 Struts 动作
        action.execute();
    }
}

MyAction需要注入一个MyService实例。虽然 MyService 是由 Spring 容器管理的, 但是 MyAction 实例不是(即是非Spring管理的对象需要注入Spring管理的Bean), 所以我们不能在 MyAction 类中使用 Spring的@Autowired注解来注入MyService。相反, 我们需要在 Spring之外手动注入这个依赖

AutowireCapableBeanFactory不由ApplicationContext实现但可获取

Note that this interface is not implemented by ApplicationContext facades, as it is hardly ever used by application code. That said, it is available from an application context too, accessible through ApplicationContext’s getAutowireCapableBeanFactory() method.

翻译:

请注意, 该接口没有在 ApplicationContext 中实现, 因为应用程序代码几乎从未使用过此接口。也就是说, 它也可以从应用程序context中获得:可以通过 ApplicationContextgetAutowireCapableBeanFactory() 方法进行访问。

结论: 这个扩展你们一般用不到, 但我给你取的方式, 你们需要的时候自己拿

AutowireCapableBeanFactory可以借助BeanFactoryAware注入

You may also implement the org.springframework.beans.factory.BeanFactoryAware interface, which exposes the internal BeanFactory even when running in an ApplicationContext, to get access to an AutowireCapableBeanFactory: simply cast the passed-in BeanFactory to AutowireCapableBeanFactory.

翻译:

您还可以实现 BeanFactoryAware 接口, 该接口即使在 ApplicationContext 中运行时也公开内部 BeanFactory , 以访问 AutowireCapableBeanFactory :只需将传入的 BeanFactory 强制转换为 AutowireCapableBeanFactory

结论: 如果你实现了 BeanFactoryAware 接口, Spring 框架会在创建 Bean 的时候自动注入一个 BeanFactory 实例到你的 Bean 中。由于 BeanFactory 是一个接口, 实际注入的对象可能是 AutowireCapableBeanFactory 的实例, 当你需要访问 AutowireCapableBeanFactory 的特定方法, 你可以将 BeanFactory 强制转换为 AutowireCapableBeanFactory。, 因为如果你在ApplicationContext中运行, BeanFactory 实际上是 AutowireCapableBeanFactory 的实例

ConfigurableBeanFactory(可配置性)-熟悉

在 SpringFramework 的 BeanFactoryApplicationContext 中, 都会有这样的设计。普通的 BeanFactory 只有 get 相关的操作, 而 Configurable开头的 BeanFactory 或者 ApplicationContext 就具有了 set 的操作(对权限进行限制划分)

ConfigurableBeanFactory提供可配置的功能

Configuration interface to be implemented by most bean factories. Provides facilities to configure a bean factory, in addition to the bean factory client methods in the BeanFactory interface.

翻译:

大多数 BeanFactory 的实现类都会实现这个带配置的接口。除了 BeanFactory 接口中的基础获取方法之外, 还提供了配置 BeanFactory 的功能。

结论: 表明了ConfigurableBeanFactory带配置的功能, 可以用这里边的方法对BeanFactory进行修改, 拓展等

ConfigurableBeanFactory不推荐给开发者使用

This bean factory interface is not meant to be used in normal application code: Stick to BeanFactory or org.springframework.beans.factory.ListableBeanFactory for typical needs. This extended interface is just meant to allow for framework-internal plug’n’play and for special access to bean factory configuration methods.

翻译:

ConfigurableBeanFactory 接口并不希望开发者在应用程序代码中使用, 而是坚持使用 BeanFactoryListableBeanFactory 。此扩展接口仅用于允许在框架内部进行即插即用, 并允许对 BeanFactory 中的配置方法的特殊访问。

结论: SpringFramework 不希望开发者用 ConfigurableBeanFactory , 而用最根本的 BeanFactory, 因为程序在运行期间按理不应该对 BeanFactory 再进行频繁的变动, 此时只应该有读的动作, 而不应该出现写的动作

BeanFactory的实现类们

BeanFactory的最核心的实现类取出来, 如下图

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

AbstractBeanFactory-熟悉

在这里插入图片描述

从类名上就知道, 它是 BeanFactory 最基本的抽象实现, 当然作为一个抽象类, 一定是只具备了部分功能

AbstractBeanFactory是最终BeanFactory的基础实现

Abstract base class for BeanFactory implementations, providing the full capabilities of the ConfigurableBeanFactory SPI. Does not assume a listable bean factory: can therefore also be used as base class for bean factory implementations which obtain bean definitions from some backend resource (where bean definition access is an expensive operation).

翻译:

它是 BeanFactory 接口最基础的抽象实现类, 提供 ConfigurableBeanFactory SPI 的全部功能。我们不假定有一个可迭代的 BeanFactory , 因此也可以用作 BeanFactory 实现的父类, 该实现可以从某些后端资源(其中 bean 定义访问是一项昂贵的操作)获取 bean 的定义。

说人话: :AbstractBeanFactory 是作为 BeanFactory 接口下面的第一个抽象的实现类, 它具有最基础的功能, 并且它可以从配置源(之前看到的 xml 、LDAP 、RDBMS 等)获取 Bean 的定义信息, 而这个 Bean 的定义信息就是 BeanDefinition。SPI可参考博主的另外一篇博客JDK和Spring的SPI机制原理分析

AbstractBeanFactory对Bean的支持

This class provides a singleton cache (through its base class DefaultSingletonBeanRegistry), singleton/prototype determination, FactoryBean handling, aliases, bean definition merging for child bean definitions, and bean destruction (org.springframework.beans.factory.DisposableBean interface, custom destroy methods). Furthermore, it can manage a bean factory hierarchy (delegating to the parent in case of an unknown bean), through implementing the org.springframework.beans.factory.HierarchicalBeanFactory interface.

翻译:

此类可以提供单实例 Bean 的缓存(通过其父类 DefaultSingletonBeanRegistry ), 单例/原型 Bean 的决定, FactoryBean 处理, Bean 的别名, 用于子 bean 定义的 bean 定义合并以及 bean 销毁( DisposableBean 接口, 自定义 destroy 方法)。此外, 它可以通过实现 HierarchicalBeanFactory 接口来管理 BeanFactory 层次结构(在未知 bean 的情况下委托给父工厂)。

除了在之前 BeanFactory 中介绍的功能和特性之外, 它还扩展了另外一些功能:别名的处理(来源于 AliasRegistry 接口)、Bean 定义的合并、Bean 的销毁动作支持( DisposableBean )等

AbstractBeanFactory定义了模板方法

The main template methods to be implemented by subclasses are getBeanDefinition and createBean, retrieving a bean definition for a given bean name and creating a bean instance for a given bean definition, respectively. Default implementations of those operations can be found in DefaultListableBeanFactory and AbstractAutowireCapableBeanFactory.

翻译:

子类要实现的主要模板方法是 getBeanDefinitioncreateBean , 分别为给定的 bean 名称检索 bean 定义信息, 并根据给定的 bean 定义信息创建 bean 的实例。这些操作的默认实现可以在 DefaultListableBeanFactoryAbstractAutowireCapableBeanFactory 中找到。

结论: SpringFramework 中大量使用模板方法模式(相关介绍最有用的设计模式之一-模板方法)来设计核心组件, 它的思路是:父类提供逻辑规范, 子类提供具体步骤的实现。在文档注释中, 说到AbstractBeanFactory 中对 getBeanDefinitioncreateBean 两个方法进行了规范上的定义, 分别代表获取 Bean 的定义信息, 以及创建 Bean 的实例。这两个方法都会在 SpringFramework 的 IOC 容器初始化阶段起到至关重要的作用。 而createBean 是 SpringFramework 能管控的所有 Bean 的创建入口(注意了, 这里说的是入口, 不是最终实现Bean创建的地方)

AbstractAutowireCapableBeanFactory-掌握

AutowireCapableBeanFactory 接口的落地实现了, 那就意味着, 它可以实现组件的自动装配

AbstractAutowireCapableBeanFactory提供Bean的创建逻辑实现

Abstract bean factory superclass that implements default bean creation, with the full capabilities specified by the RootBeanDefinition class. Implements the AutowireCapableBeanFactory interface in addition to AbstractBeanFactory’s createBean method.

翻译:

它是实现了默认 bean 创建逻辑的的抽象的 BeanFactory 实现类, 它具有 RootBeanDefinition 类指定的全部功能。除了 AbstractBeanFactorycreateBean 方法之外, 还实现 AutowireCapableBeanFactory 接口。

说人话: AbstractAutowireCapableBeanFactory 继承了 AbstractBeanFactory 抽象类(默认 bean 创建逻辑的的抽象的 BeanFactory指的就是AbstractBeanFactory ), 还额外实现了 AutowireCapableBeanFactory 接口, 那么就说明了拥有了自动注入功能, 再者还实现了 AbstractBeanFactorycreateBean 方法, 那么就说明了它还具有创建Bean的功能

  • createBean 方法也不是最终实现 Bean 的创建, 而是有另外一个叫 doCreateBean 方法, 它同样在 AbstractAutowireCapableBeanFactory 中定义, 而且是 protected 方法, 没有子类重写它(以后细细分析, 埋个坑)
AbstractAutowireCapableBeanFactory实现了属性赋值和组件注入

Provides bean creation (with constructor resolution), property population, wiring (including autowiring), and initialization. Handles runtime bean references, resolves managed collections, calls initialization methods, etc. Supports autowiring constructors, properties by name, and properties by type.

翻译:

提供 Bean 的创建(具有构造方法的解析), 属性填充, 属性注入(包括自动装配)和初始化。处理运行时 Bean 的引用, 解析托管集合, 调用初始化方法等。支持自动装配构造函数, 按名称的属性和按类型的属性。

AbstractAutowireCapableBeanFactory 中实现的最最核心功能全部列出来了:Bean 的创建、属性填充和依赖的自动注入、Bean 的初始化。这部分是创建 Bean 最核心的三个步骤(注意了, 这里是脉络, 后续都以此铺开)

AbstractAutowireCapableBeanFactory保留了模板方法

The main template method to be implemented by subclasses is resolveDependency(DependencyDescriptor, String, Set, TypeConverter), used for autowiring by type. In case of a factory which is capable of searching its bean definitions, matching beans will typically be implemented through such a search. For other factory styles, simplified matching algorithms can be implemented.

翻译:

子类要实现的主要模板方法是 resolveDependency(DependencyDescriptor, String, Set, TypeConverter) , 用于按类型自动装配。如果工厂能够搜索其 bean 定义, 则通常将通过此类搜索来实现匹配的 bean 。对于其他工厂样式, 可以实现简化的匹配算法。

AbstractBeanFactory 不太一样, AbstractAutowireCapableBeanFactory 没有把全部模板方法都实现完, 它保留了文档注释中提到的 resolveDependency 方法, 这个方法的作用是解析 Bean 的成员中定义的属性依赖关系

从这里也可以看出, Spring组件的单一职责切割很好, 组件之间的功能不逾矩

AbstractAutowireCapableBeanFactory不负责BeanDefinition的注册

Note that this class does not assume or implement bean definition registry capabilities. See DefaultListableBeanFactory for an implementation of the org.springframework.beans.factory.ListableBeanFactory and BeanDefinitionRegistry interfaces, which represent the API and SPI view of such a factory, respectively.

翻译:

请注意, 此类不承担或实现 bean 定义注册的功能。有关 ListableBeanFactoryBeanDefinitionRegistry 接口的实现, 请参见DefaultListableBeanFactory , 它们分别表示该工厂的 API 和 SPI 视图。

Spring想表明的是, AbstractAutowireCapableBeanFactory 实现了对 Bean 的创建、赋值、注入、初始化的逻辑, 但对于BeanDefinition是如何进入 BeanFactory 的, 它不负责。这里面涉及到两个流程:Bean 的创建BeanDefinition的进入(后续BeanDefinition部分会解析)

DefaultListableBeanFactory-掌握

DefaultListableBeanFactory唯一一个目前使用的 BeanFactory 的落地实现了

DefaultListableBeanFactory是BeanFactory最终的默认实现

Spring’s default implementation of the ConfigurableListableBeanFactory and BeanDefinitionRegistry interfaces: a full-fledged bean factory based on bean definition metadata, extensible through post-processors.

翻译:

Spring 的 ConfigurableListableBeanFactoryBeanDefinitionRegistry 接口的默认实现, 它时基于 Bean 的定义信息的的成熟的 BeanFactory 实现, 它可通过后置处理器进行扩展。

结论: DefaultListableBeanFactory 已经没有 abstract 标注了, 说明它可以算作一个成熟的落地实现

DefaultListableBeanFactory会先注册Bean定义信息再创建Bean

Typical usage is registering all bean definitions first (possibly read from a bean definition file), before accessing beans. Bean lookup by name is therefore an inexpensive operation in a local bean definition table, operating on pre-resolved bean definition metadata objects.

翻译:

典型的用法是在访问 bean 之前先注册所有 bean 定义信息(可能是从有 bean 定义的文件中读取)。因此, 按名称查找 Bean 是对本地 Bean 定义表进行的合理操作, 该操作对预先解析的 Bean 定义元数据对象进行操作。

讲人话: DefaultListableBeanFactoryAbstractAutowireCapableBeanFactory 的基础上, 完成了注册 Bean 定义信息的动作, 而这个动作就是通过上面的 BeanDefinitionRegistry 来实现的。所以咱就可以知道一点, 完整的 BeanFactory 对 Bean 的管理, 应该是先注册 Bean 的定义信息, 再完成 Bean 的创建和初始化动作(注意, 重点句子)

DefaultListableBeanFactory不负责解析Bean定义文件

Note that readers for specific bean definition formats are typically implemented separately rather than as bean factory subclasses: see for example PropertiesBeanDefinitionReader and org.springframework.beans.factory.xml.XmlBeanDefinitionReader.

翻译:

请注意, 特定 bean 定义信息格式的解析器通常是单独实现的, 而不是作为 BeanFactory 的子类实现的, 有关这部分的内容参见 PropertiesBeanDefinitionReaderXmlBeanDefinitionReader

可以看出SpringFramework 对于组件的单一职责把控的非常好, BeanFactory 作为一个统一管理 Bean 组件的容器, 它的核心工作就是控制 Bean 在创建阶段的生命周期, 而对于 Bean 从哪里来, 如何被创建, 都有哪些依赖要被注入, 这些统统与它无关, 而是有专门的组件来处理(就是包括上面提到的 BeanDefinitionReader 在内的一些其它组件)

DefaultListableBeanFactory的替代实现

For an alternative implementation of the org.springframework.beans.factory.ListableBeanFactory interface, have a look at StaticListableBeanFactory, which manages existing bean instances rather than creating new ones based on bean definitions.

翻译:

对于 ListableBeanFactory 接口的替代实现, 请看一下 StaticListableBeanFactory , 它管理现有的 bean 实例, 而不是根据 bean 定义创建新的 bean 实例。

StaticListableBeanFactory 实现起来相对简单且功能也简单, 因为它只能管理现有的, 且单实例的Bean , 而且没有跟 Bean 定义等相关的高级概念在里面, 于是 SpringFramewor 默认也不用StaticListableBeanFactory

XmlBeanFactory-了解

在 SpringFramework 3.1 之后, XmlBeanFactory 正式被标注为过时, 代替的方案是使用 DefaultListableBeanFactory + XmlBeanDefinitionReader , 这种设计更符合组件的单一职责原则, 而且还有一点。自打 SpringFramework 3.0 之后出现了注解驱动的 IOC 容器, SpringFramework 就感觉这种 xml 驱动的方式不应该单独成为一种方案了, 倒不如咱都各退一步, 搞一个通用的容器, 都组合它来用, 这样就实现了配置源载体分离的目的了

ApplicationContext

推荐使用 ApplicationContext 而不是 BeanFactory , 因为 ApplicationContext 相比较 BeanFactory 扩展的实在是太多了

FeatureBeanFactoryApplicationContext
Bean instantiation/wiring—Bean的实例化和属性注入
Integrated lifecycle management —— 生命周期管理
Automatic BeanPostProcessor registration —— Bean后置处理器的支持
Automatic BeanFactoryPostProcessor registration —— BeanFactory后置处理器的支持
Convenient MessageSource access (for internalization) —— 消息转换服务(国际化)
Built-in ApplicationEvent publication mechanism —— 事件发布机制(事件驱动)

类关系图如下
在这里插入图片描述

ApplicationContext和它的子接口们

ApplicationContext-掌握

Central interface to provide configuration for an application. This is read-only while the application is running, but may be reloaded if the implementation supports this.

翻译:

它是为应用程序提供配置的中心接口。在应用程序运行时, 它是只读的, 但是如果受支持的话, 它可以重新加载。

结论: ApplicationContext 就是中央接口, 它就是 SpringFramework 的最最核心。另外它多提了一个概念:重新加载, 后续介绍

ApplicationContext组合多个功能接口

An ApplicationContext provides:

  • Bean factory methods for accessing application components. Inherited from ListableBeanFactory.
  • The ability to load file resources in a generic fashion. Inherited from the ResourceLoader interface.
  • The ability to publish events to registered listeners. Inherited from the ApplicationEventPublisher interface.
  • The ability to resolve messages, supporting internationalization. Inherited from the MessageSource interface.
  • Inheritance from a parent context. Definitions in a descendant context will always take priority. This means, for example, that a single parent context can be used by an entire web application, while each servlet has its own child context that is independent of that of any other servlet.

翻译:

ApplicationContext 提供:

  • 用于访问应用程序组件的 Bean 工厂方法。继承自 ListableBeanFactory
  • 以通用方式加载文件资源的能力。继承自 ResourceLoader 接口。
  • 能够将事件发布给注册的监听器。继承自 ApplicationEventPublisher 接口。
  • 解析消息的能力, 支持国际化。继承自 MessageSource 接口。
  • 从父context继承。在子容器中的定义将始终优先。例如, 这意味着整个 Web 应用程序都可以使用单个父context, 而每个 servlet 都有其自己的子context, 该子context独立于任何其他 servlet 的子context。

结论: 主要介绍功能和该功能的源自哪个接口。ApplicationContext 也是支持层级结构的, 但这里它的描述是父子context, 这个概念要区分理解。context中包含容器, 但又不仅仅是容器。容器只负责管理Bean(重点中的重点) , 但context中还包括动态增强、资源加载、事件监听机制等多方面扩展功能(这里也可以体现为什么Application的功能比BeanFactory强大)

Context和Beanfatory之间的关系
在这里插入图片描述

ApplicationContext负责部分回调注入

In addition to standard BeanFactory lifecycle capabilities, ApplicationContext implementations detect and invoke ApplicationContextAware beans as well as ResourceLoaderAware , ApplicationEventPublisherAware and MessageSourceAware beans.

翻译:

除了标准的 BeanFactory 生命周期功能外, ApplicationContext 实现还检测并调用 ApplicationContextAware bean 以及 ResourceLoaderAware bean, ApplicationEventPublisherAwareMessageSourceAware bean。

结论: 也就说除了BeanFactory的生命周期外, ApplicationContext还提供其它的拓展点, 用于执行额外操作。都是以Aware(Aware翻译过为感知)结尾的接口, *Aware 接口是 Spring 框架中一种回调机制, 允许 Bean 在创建过程中与 Spring 容器进行交互, 从而获取 Spring 容器提供的资源或服务

  • ApplicationContextAware 让 Bean 知道它所在的 ApplicationContext, 从而可以获取其他 Bean 或者进行一些 ApplicationContext 特有的操作。
  • ResourceLoaderAware 让 Bean 知道一个 ResourceLoader, 可以用来加载资源文件等。
  • ApplicationEventPublisherAware 让 Bean 知道一个 ApplicationEventPublisher, 可以用来发布应用程序事件。
  • MessageSourceAware 让 Bean 知道一个 MessageSource, 可以用来处理国际化(i18n)相关的消息

当实现了一个 *Aware 接口时, 实际上是在告诉 Spring 框架: “我需要这些资源或服务, 请在创建我的实例时帮我注入它们”, Spring 容器在创建 Bean 实例之后, 会通过调用这些接口的 set* 方法, 将相应的资源或服务注入到 Bean 中。这些资源或服务通常是 Spring 容器本身提供的, 比如 ApplicationContext, ResourceLoader, ApplicationEventPublisherMessageSource

例如, 在 Spring 中实现 ApplicationContextAware 接口时, 告诉 Spring 在创建你的 Bean 实例之后, 请调用 setApplicationContext 方法, 并将当前的 ApplicationContext 实例注入进去。这样, 你的Bean就能够访问到 Spring 的context环境, 从而能够做更多的事情(也就是说, 如果你实现*Aware接口, 那么Spring会将该接口对应的资源从容器中取出来供你使用)

ConfigurableApplicationContext-掌握

ConfigurableBeanFactory有点类似, 为ApplicationContext提供了可写功能(也就说有相关setter方法), 实现了该接口的实现类可以被客户端代码修改内部的某些配置

ConfigurableApplicationContext提供了可配置的可能

SPI interface to be implemented by most if not all application contexts. Provides facilities to configure an application context in addition to the application context client methods in the ApplicationContext interface.

翻译:

它是一个支持 SPI 的接口, 它会被大多数(如果不是全部)应用程序context的落地实现。除了 ApplicationContext 接口中的应用程序context客户端方法外, 还提供了用于配置应用程序context的功能。

ConfigurableApplicationContextApplicationContext 添加了用于配置的功能, 而且还扩展了 setParentsetEnvironmentaddBeanFactoryPostProcessoraddApplicationListener 等方法, 都是可以改变 ApplicationContext 本身的方法

ConfigurableApplicationContext只希望被调用启动和关闭

Configuration and lifecycle methods are encapsulated here to avoid making them obvious to ApplicationContext client code. The present methods should only be used by startup and shutdown code.

翻译:

配置和与生命周期相关的方法都封装在这里, 以避免暴露给 ApplicationContext 的调用者。本接口的方法仅应由启动和关闭代码使用。

ConfigurableApplicationContext 本身扩展了一些方法, 但是它一般情况下不希望让咱开发者调用, 而是只调用**启动(refresh)关闭(close)**方法。注意这个一般情况是在程序运行期间的业务代码中, 但如果是为了定制化 ApplicationContext 或者对其进行扩展, ConfigurableApplicationContext 的扩展则会成为切入的主目标

EnvironmentCapable-熟悉

capable本意为"有能力的", 在这里解释为**“携带/组合”**

在 SpringFramework 中, 以 Capable 结尾的接口, 通常意味着可以通过这个接口的某个特定的方法(通常是 getXXX())拿到特定的组件

也就说 EnvironmentCapable 接口中就应该通过一个 getEnvironment() 方法拿到 Environment

public interface EnvironmentCapable {
	Environment getEnvironment();
}
ApplicationContext都具有EnvironmentCapable的功能

Interface indicating a component that contains and exposes an Environment reference.

All Spring application contexts are EnvironmentCapable, and the interface is used primarily for performing instanceof checks in framework methods that accept BeanFactory instances that may or may not actually be ApplicationContext instances in order to interact with the environment if indeed it is available.

翻译:

它是具有获取并公开 Environment 引用的接口。

所有 Spring 的 ApplicationContext 都具有 EnvironmentCapable 功能, 并且该接口主要用于在接受 BeanFactory 实例的框架方法中执行 instanceof 检查, 以便可以与环境进行交互(如果实际上是 ApplicationContext 实例)。

ApplicationContext 都实现了这个 EnvironmentCapable 接口, 也就代表着所有的 ApplicationContext 的实现类都可以取到 Environment 抽象(Environment 是 Spring中抽象出来的类似于运行环境独立抽象, 它内部存放着应用程序运行的一些配置, Spring将运行时划分成了两部分: 应用程序本身, 应用程序运行时的环境)

ConfigurableApplicationContext可以获取ConfigurableEnvironment

As mentioned, ApplicationContext extends EnvironmentCapable, and thus exposes a getEnvironment() method; however, ConfigurableApplicationContext redefines getEnvironment() and narrows the signature to return a ConfigurableEnvironment. The effect is that an Environment object is ‘read-only’ until it is being accessed from a ConfigurableApplicationContext, at which point it too may be configured.

翻译:

如上面所述, ApplicationContext 扩展了 EnvironmentCapable , 因此公开了 getEnvironment() 方法;但是, ConfigurableApplicationContext 重新定义了 getEnvironment() 并缩小了签名范围, 以返回 ConfigurableEnvironment 。结果是环境对象是 “只读的” , 直到从 ConfigurableApplicationContext 访问它为止, 此时也可以对其进行配置。

指出了可配置的 ApplicationContext , 就可以获取到可配置的 Environment 抽象

MessageSource-熟悉

国际化, 是针对不同地区、不同国家的访问, 可以提供对应的符合用户阅读习惯(语言)的页面和数据。

Strategy interface for resolving messages, with support for the parameterization and internationalization of such messages. Spring provides two out-of-the-box implementations for production:

  • org.springframework.context.support.ResourceBundleMessageSource: built on top of the standard java.util.ResourceBundle, sharing its limitations.
  • org.springframework.context.support.ReloadableResourceBundleMessageSource: highly configurable, in particular with respect to reloading message definitions.

翻译:

用于解析消息的策略接口, 并支持消息的参数化和国际化。SpringFramework 为生产提供了两种现有的实现:

  • ResourceBundleMessageSource:建立在标准 java.util.ResourceBundle 之上, 共享其局限性。
  • ReloadableResourceBundleMessageSource:高度可配置, 尤其是在重新加载消息定义方面。

ApplicationEventPublisher-熟悉

类名可以理解为, 它是事件的发布器。SpringFramework 内部支持很强大的事件监听机制, 而 ApplicationContext 作为容器的最顶级, 自然也要实现观察者模式(见观察者模式, 发布-订阅模式, 监听器模式)中广播器的角色

JavaDoc对它总体概览如下

Interface that encapsulates event publication functionality. Serves as a super-interface for ApplicationContext.

封装事件发布功能的接口, 它作为 ApplicationContext 的父接口

ResourcePatternResolver-熟悉

类名理解可以解释为“资源模式解析器”, 实际上它是根据特定的路径去解析资源文件

ResourcePatternResolver是ResourceLoader的扩展

Strategy interface for resolving a location pattern (for example, an Ant-style path pattern) into Resource objects. This is an extension to the ResourceLoader interface. A passed-in ResourceLoader (for example, an org.springframework.context.ApplicationContext passed in via org.springframework.context.ResourceLoaderAware when running in a context) can be checked whether it implements this extended interface too.

翻译:

它是一个策略接口, 用于将位置模式(例如, Ant 样式的路径模式)解析为 Resource 对象。 这是 ResourceLoader 接口的扩展。可以检查传入的 ResourceLoader(例如, 在context中运行时通过 ResourceLoaderAware 传入的 ApplicationContext)是否也实现了此扩展接口。

ResourcePatternResolver本身还是 ResourceLoader 的扩展, ResourceLoader 实现最基本的解析, ResourcePatternResolver 可以支持 Ant 形式的带星号 ( * ) 的路径解析

ResourcePatternResolver的实现方式有多种

Can be used with any sort of location pattern (e.g. “/WEB-INF/*-context.xml”): Input patterns have to match the strategy implementation. This interface just specifies the conversion method rather than a specific pattern format.

翻译:

可以与任何类型的位置模式一起使用(例如 "/WEB-INF/*-context.xml"):输入模式必须与策略实现相匹配。该接口仅指定转换方法, 而不是特定的模式格式

Ant 风格的匹配模式有如下写法:

  • /WEB-INF/*.xml :匹配 /WEB-INF 目录下的任意 xml 文件
  • /WEB-INF/**/beans-*.xml :匹配 /WEB-INF 下面任意层级目录的 beans- 开头的 xml 文件
  • /**/*.xml :匹配任意 xml 文件
ResourcePatternResolver可以匹配类路径下的文件

This interface also suggests a new resource prefix “classpath*:” for all matching resources from the class path. Note that the resource location is expected to be a path without placeholders in this case (e.g. “/beans.xml”); JAR files or classes directories can contain multiple files of the same name.

翻译:

此接口还为类路径中的所有匹配资源建议一个新的资源前缀 "classpath*: "。请注意, 在这种情况下, 资源位置应该是没有占位符的路径(例如 "/beans.xml"); jar 文件或类目录可以包含多个相同名称的文件。

ResourcePatternResolver 不仅可以匹配 Web 工程中 webapps 的文件, 也可以匹配 classpath 下的文件。匹配类路径下的资源文件方式如下: 在资源路径中加一个 classpath*: 的前缀。

ApplicationContext的实现类们

类关系图如下:
在这里插入图片描述

AbstractApplicationContext-掌握

ApplicationContext最最最最核心的实现类, 没有之一AbstractApplicationContext 中定义和实现了绝大部分ApplicationContext的特性和功能

AbstractApplicationContext只构建功能抽象

Abstract implementation of the ApplicationContext interface. Doesn’t mandate the type of storage used for configuration; simply implements common context functionality. Uses the Template Method design pattern, requiring concrete subclasses to implement abstract methods.

翻译:

ApplicationContext 接口的抽象实现。不强制用于配置的存储类型;简单地实现通用context功能。使用模板方法模式, 需要具体的子类来实现抽象方法

和之前的AbstractBeanFactory一样, 借助模板方法规范功能, 实际逻辑由子类实现

AbstractApplicationContext可以处理特殊类型的Bean

In contrast to a plain BeanFactory, an ApplicationContext is supposed to detect special beans defined in its internal bean factory: Therefore, this class automatically registers BeanFactoryPostProcessors, BeanPostProcessors, and ApplicationListeners which are defined as beans in the context.

翻译:

与普通的 BeanFactory 相比, ApplicationContext 应该能够检测在其内部 Bean 工厂中定义的特殊 bean :因此, 此类自动注册在上下文中定义为 bean 的 BeanFactoryPostProcessors , BeanPostProcessorsApplicationListeners

ApplicationContextBeanFactory 强大的地方是支持更多的机制, 这里面就包括了后置处理器、监听器等, 而这些器, 说白了也都是一个一个的 Bean , BeanFactory 不会把它们区别对待, 但是 ApplicationContext 就可以区分出来, 并且赋予他们发挥特殊能力的机会

AbstractApplicationContext可以转换为多种类型

A MessageSource may also be supplied as a bean in the context, with the name “messageSource”; otherwise, message resolution is delegated to the parent context. Furthermore, a multicaster for application events can be supplied as an “applicationEventMulticaster” bean of type ApplicationEventMulticaster in the context; otherwise, a default multicaster of type SimpleApplicationEventMulticaster will be used.

翻译:

一个 MessageSource 也可以在上下文中作为一个普通的 bean 提供, 名称为 "messageSource" 。否则, 将消息解析委托给父上下文。此外, 可以在上下文中将用于应用程序事件的广播器作为类型为 ApplicationEventMulticaster"applicationEventMulticaster" bean 提供。否则, 将使用类型为 SimpleApplicationEventMulticaster 的默认事件广播器。

ApplicationContext 实现了国际化的接口 MessageSource 、事件广播器的接口 ApplicationEventMulticaster , 那作为容器, 它也会把自己看成一个 Bean , 以支持不同类型的组件注入需要

AbstractApplicationContext提供默认的加载资源文件策略

Implements resource loading by extending DefaultResourceLoader. Consequently treats non-URL resource paths as class path resources (supporting full class path resource names that include the package path, e.g. “mypackage/myresource.dat”), unless the getResourceByPath method is overridden in a subclass.

翻译:

通过扩展 DefaultResourceLoader 实现资源加载。因此, 除非在子类中覆盖了 getResourceByPath() 方法, 否则将非 URL 资源路径视为类路径资源(支持包含包路径的完整类路径资源名称, 例如 "mypackage/myresource.dat")。

默认情况下, AbstractApplicationContext 加载资源文件的策略是直接继承了 DefaultResourceLoader 的策略, 从类路径下加载;但在 Web 项目中, 可能策略就不一样了, 它可以从 ServletContext 中加载(扩展的子类 ServletContextResourceLoader 等)

AbstractApplicationContext 中定义了一个特别特别重要的方法, 它是控制 ApplicationContext 生命周期的核心方法:refresh, 整体流程如下(细节不扣)

public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
        // Prepare this context for refreshing.
        // 1. 初始化前的预处理
        prepareRefresh();

        // Tell the subclass to refresh the internal bean factory.
        // 2. 获取BeanFactory, 加载所有xml配置文件中bean的定义信息(未实例化)
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

        // Prepare the bean factory for use in this context.
        // 3. BeanFactory的预处理配置
        prepareBeanFactory(beanFactory);

        try {
            // Allows post-processing of the bean factory in context subclasses.
            // 4. 准备BeanFactory完成后进行的后置处理
            postProcessBeanFactory(beanFactory);

            // Invoke factory processors registered as beans in the context.
            // 5. 执行BeanFactory创建后的后置处理器
            invokeBeanFactoryPostProcessors(beanFactory);

            // Register bean processors that intercept bean creation.
            // 6. 注册Bean的后置处理器
            registerBeanPostProcessors(beanFactory);

            // Initialize message source for this context.
            // 7. 初始化MessageSource
            initMessageSource();

            // Initialize event multicaster for this context.
            // 8. 初始化事件派发器
            initApplicationEventMulticaster();

            // Initialize other special beans in specific context subclasses.
            // 9. 子类的多态onRefresh
            onRefresh();

            // Check for listener beans and register them.
            // 10. 注册监听器
            registerListeners();
          
            //到此为止, BeanFactory已创建完成

            // Instantiate all remaining (non-lazy-init) singletons.
            // 11. 初始化所有剩下的单例Bean
            finishBeanFactoryInitialization(beanFactory);

            // Last step: publish corresponding event.
            // 12. 完成容器的创建工作
            finishRefresh();
        } // catch ......

        finally {
            // Reset common introspection caches in Spring's core, since we
            // might not ever need metadata for singleton beans anymore...
            // 13. 清除缓存
            resetCommonCaches();
        }
    }
}

GenericApplicationContext-熟悉

GenericApplicationContext 已经是一个普通的类(非抽象类)了, 它里面已经具备了ApplicationContext基本的所有能力

GenericApplicationContext组合了BeanFactory

Generic ApplicationContext implementation that holds a single internal DefaultListableBeanFactory instance and does not assume a specific bean definition format. Implements the BeanDefinitionRegistry interface in order to allow for applying any bean definition readers to it.

翻译:

通用 ApplicationContext 的实现, 该实现拥有一个内部 DefaultListableBeanFactory 实例, 并且不采用特定的 bean 定义格式。另外它实现 BeanDefinitionRegistry 接口, 以便允许将任何 bean 定义读取器应用于该容器中。

重中之重: GenericApplicationContext 中组合了一个 DefaultListableBeanFactory !!!*由此可以得到一个非常非常重要的信息:*ApplicationContext 并不是继承了 BeanFactory 的容器, 而是组合了 BeanFactory

public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry {
	private final DefaultListableBeanFactory beanFactory;
	// 其它代码
}
GenericApplicationContext借助BeanDefinitionRegistry处理特殊Bean

Typical usage is to register a variety of bean definitions via the BeanDefinitionRegistry interface and then call refresh() to initialize those beans with application context semantics (handling org.springframework.context.ApplicationContextAware, auto-detecting BeanFactoryPostProcessors, etc).

翻译:

典型的用法是通过 BeanDefinitionRegistry 接口注册各种 Bean 的定义, 然后调用 refresh() 以使用应用程序上下文语义来初始化这些 Bean(处理 ApplicationContextAware , 自动检测 BeanFactoryPostProcessors 等)。

GenericApplicationContext 实现了**BeanDefinitionRegistry(Bean定义注册器)** , 可以自定义注册一些 Bean 。然而在 GenericApplicationContext 中, 它实现的定义注册方法 registerBeanDefinition , 在底层还是调用的 DefaultListableBeanFactory 执行 registerBeanDefinition 方法, 说明它也没有对此做什么扩展

public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry {
    private final DefaultListableBeanFactory beanFactory;

    public GenericApplicationContext() {
        // 内置的beanFactory在GenericApplicationContext创建时就已经初始化好了
        this.beanFactory = new DefaultListableBeanFactory();
    }

    @Override
    public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
        throws BeanDefinitionStoreException {
        this.beanFactory.registerBeanDefinition(beanName, beanDefinition);
    }
    // 省略其它代码
}
GenericApplicationContext只能刷新一次

In contrast to other ApplicationContext implementations that create a new internal BeanFactory instance for each refresh, the internal BeanFactory of this context is available right from the start, to be able to register bean definitions on it. refresh() may only be called once.

翻译:

与为每次刷新创建一个新的内部 BeanFactory 实例的其他 ApplicationContext 实现相反, 此上下文的内部 BeanFactory 从一开始就可用, 以便能够在其上注册 Bean 定义。 refresh() 只能被调用一次。

由于 GenericApplicationContext 中组合了一个 DefaultListableBeanFactory , 而这个 BeanFactory 是在 GenericApplicationContext构造方法中就已经初始化好了, 那么初始化好的 BeanFactory不允许在运行期间被重复刷新了, 源码如下

public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry {
    private final DefaultListableBeanFactory beanFactory;

    public GenericApplicationContext() {
        // 内置的beanFactory在GenericApplicationContext创建时就已经初始化好了
        this.beanFactory = new DefaultListableBeanFactory();
    }


    @Override
    protected final void refreshBeanFactory() throws IllegalStateException {
        if (!this.refreshed.compareAndSet(false, true)) {
            throw new IllegalStateException(
                "GenericApplicationContext does not support multiple refresh attempts: just call 'refresh' once");
        }
        this.beanFactory.setSerializationId(getId());
    }
    // 省略其它代码
}

文档注释提到"相反"这个词, 另外一类 ApplicationContext 它的设计不是这样的, 而是每次刷新创建一个新的内部 BeanFactory 实例, 如AbstractRefreshableApplicationContext

GenericApplicationContext的替代方案是用xml

For the typical case of XML bean definitions, simply use ClassPathXmlApplicationContext or FileSystemXmlApplicationContext, which are easier to set up - but less flexible, since you can just use standard resource locations for XML bean definitions, rather than mixing arbitrary bean definition formats. The equivalent in a web environment is org.springframework.web.context.support.XmlWebApplicationContext.

翻译:

对于 XML Bean 定义的典型情况, 只需使用 ClassPathXmlApplicationContextFileSystemXmlApplicationContext , 因为它们更易于设置(但灵活性较差, 因为只能将从标准的资源配置文件中读取 XML Bean 定义, 而不能混合使用任意 Bean 定义的格式)。在 Web 环境中, 替代方案是 XmlWebApplicationContext

注解驱动的 IOC 容器可以导入 xml 配置文件, 不过如果大多数都是 xml 配置的话, 官方建议还是直接用 ClassPathXmlApplicationContext 或者 FileSystemXmlApplicationContext 就好 。注解驱动的方式在开发时很灵活, 但如果需要修改配置时, 可能需要重新编译配置类;xml 驱动的方式在修改配置时直接修改即可, 不需要做任何额外的操作, 但能配置的内容实在是有些有限。所以这也建议咱开发者在实际开发中, 要权衡对比着使用

GenericApplicationContext不支持特殊Bean定义的可刷新读取

For custom application context implementations that are supposed to read special bean definition formats in a refreshable manner, consider deriving from the AbstractRefreshableApplicationContext base class.

翻译:

对于应该以可刷新方式读取特殊bean定义格式的自定义应用程序上下文实现, 请考虑从 AbstractRefreshableApplicationContext 基类派生。

AbstractRefreshableApplicationContext-熟悉

类名直译为 “可刷新的 ApplicationContext ”, 它跟上面 GenericApplicationContext 的最大区别之一就是它可以被重复刷新

AbstractRefreshableApplicationContext支持多次刷新

Base class for ApplicationContext implementations which are supposed to support multiple calls to refresh(), creating a new internal bean factory instance every time. Typically (but not necessarily), such a context will be driven by a set of config locations to load bean definitions from.

翻译:

它是 ApplicationContext 接口实现的抽象父类, 应该支持多次调用 refresh() 方法, 每次都创建一个新的内部 BeanFactory 实例。通常(但不是必须)这样的上下文将由一组配置文件驱动, 以从中加载 bean 的定义信息。

每次都会创建一个新的内部的 BeanFactory 实例(也就是 DefaultListableBeanFactory), 而整个 ApplicationContext 的初始化中不创建。通过源码来看, 它的内部也是组合 DefaultListableBeanFactory , 但构造方法中什么也没有干

public abstract class AbstractRefreshableApplicationContext extends AbstractApplicationContext {
    @Nullable
    private DefaultListableBeanFactory beanFactory;

    public AbstractRefreshableApplicationContext() {
    }
}

创建 BeanFactory的方法

protected DefaultListableBeanFactory createBeanFactory() {
    return new DefaultListableBeanFactory(getInternalParentBeanFactory());
}
AbstractRefreshableApplicationContext刷新的核心是加载Bean定义信息

The only method to be implemented by subclasses is loadBeanDefinitions, which gets invoked on each refresh. A concrete implementation is supposed to load bean definitions into the given DefaultListableBeanFactory, typically delegating to one or more specific bean definition readers. Note that there is a similar base class for WebApplicationContexts.

翻译:

子类唯一需要实现的方法是 loadBeanDefinitions , 它在每次刷新时都会被调用。一个具体的实现应该将 bean 的定义信息加载到给定的 DefaultListableBeanFactory 中, 通常委托给一个或多个特定的 bean 定义读取器。 注意, WebApplicationContexts 有一个类似的父类。

可刷新的ApplicationContext, 那它里面存放的Bean定义信息应该是可以被覆盖加载的。由于AbstractApplicationContext就已经实现了ConfigurableApplicationContext接口, 容器本身可以重复刷新, 那么每次刷新时就应该重新加载Bean的定义信息, 以及初始化Bean实例。在Web环境下也有一个类似的父类, 猜都能猜到肯定是名字里多了个Web:AbstractRefreshableWebApplicationContext, 它的特征与AbstractRefreshableApplicationContext基本一致, 不重复解释

AbstractRefreshableWebApplicationContext额外扩展了Web环境的功能

org.springframework.web.context.support.AbstractRefreshableWebApplicationContext provides the same subclassing strategy, but additionally pre-implements all context functionality for web environments. There is also a pre-defined way to receive config locations for a web context.

翻译:

AbstractRefreshableWebApplicationContext提供了相同的子类化策略,但是还预先实现了 Web 环境的所有上下文功能。还有一种预定义的方式来接收 Web 上下文的配置位置。

与普通的 ApplicationContext 相比,WebApplicationContext 额外扩展的是与Servlet相关的部分( request 、ServletContext 等)AbstractRefreshableWebApplicationContext 内部就组合了一个 ServletContext ,并且支持给Bean注入 ServletContextServletConfig 等 Servlet 中的组件

几个重要的最终实现类

Concrete standalone subclasses of this base class, reading in a specific bean definition format, are ClassPathXmlApplicationContext and FileSystemXmlApplicationContext, which both derive from the common AbstractXmlApplicationContext base class; org.springframework.context.annotation.AnnotationConfigApplicationContext supports @Configuration-annotated classes as a source of bean definitions.

翻译:

以特定的 bean 定义格式读取的该父类的具体独立子类是 ClassPathXmlApplicationContextFileSystemXmlApplicationContext ,它们均从 AbstractXmlApplicationContext 基类扩展。 AnnotationConfigApplicationContext 支持 @Configuration 注解的类作为 BeanDefinition 的源。

分别是基于 xml 配置的 ClassPathXmlApplicationContextFileSystemXmlApplicationContext ,以及基于注解启动的 AnnotationConfigApplicationContext

AbstractRefreshableConfigApplicationContext-了解

AbstractRefreshableApplicationContext 相比较,只是多了一个 Config ,说明它有扩展跟配置相关的特性。自己定义了 getConfigLocations 方法,意为“获取配置源路径

AbstractRefreshableApplicationContext subclass that adds common handling of specified config locations. Serves as base class for XML-based application context implementations such as ClassPathXmlApplicationContext and FileSystemXmlApplicationContext, as well as org.springframework.web.context.support.XmlWebApplicationContext.

翻译:

AbstractRefreshableApplicationContext 的子类,用于添加对指定配置位置的通用处理。作为基于 XML 的 ApplicationContext 实现(例如ClassPathXmlApplicationContextFileSystemXmlApplicationContext 以及 XmlWebApplicationContext )的父类。

通篇就抽出来一句话:用于添加对指定配置位置的通用处理。由于它是基于 xml 配置的 ApplicationContext 的父类,所以肯定需要传入配置源路径,那这个配置的动作就封装在这个 AbstractRefreshableConfigApplicationContext 中了

AbstractXmlApplicationContext-掌握

AbstractXmlApplicationContextClassPathXmlApplicationContextFileSystemXmlApplicationContext 的直接父类

AbstractXmlApplicationContext已具备基本全部功能

Convenient base class for ApplicationContext implementations, drawing configuration from XML documents containing bean definitions understood by an XmlBeanDefinitionReader. Subclasses just have to implement the getConfigResources and/or the getConfigLocations method. Furthermore, they might override the getResourceByPath hook to interpret relative paths in an environment-specific fashion, and/or getResourcePatternResolver for extended pattern resolution.

翻译:

方便的 ApplicationContext 父类,从包含 XmlBeanDefinitionReader 解析的 BeanDefinition 的 XML 文档中提取配置。

子类只需要实现 getConfigResources 和/或 getConfigLocations 方法。此外,它们可能会覆盖 getResourceByPath 的钩子回调,以特定于环境的方式解析相对路径,和/或 getResourcePatternResolver 来扩展模式解析。

由于 AbstractXmlApplicationContext 已经接近于最终的 xml 驱动 IOC 容器的实现了,所以它应该有基本上所有的功能。又根据子类的两种不同的配置文件加载方式,说明加载配置文件的策略是不一样的,所以文档注释中有说子类只需要实现 getConfigLocations 这样的方法就好。AbstractXmlApplicationContext加载到配置文件后如何处理

AbstractXmlApplicationContext中有loadBeanDefinitions的实现
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
    // Create a new XmlBeanDefinitionReader for the given BeanFactory.
    // 借助XmlBeanDefinitionReader解析xml配置文件
    XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

    // Configure the bean definition reader with this context's
    // resource loading environment.
    beanDefinitionReader.setEnvironment(this.getEnvironment());
    beanDefinitionReader.setResourceLoader(this);
    beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

    // Allow a subclass to provide custom initialization of the reader,
    // then proceed with actually loading the bean definitions.
    // 初始化BeanDefinitionReader,后加载BeanDefinition
    initBeanDefinitionReader(beanDefinitionReader);
    loadBeanDefinitions(beanDefinitionReader);
}

解析 xml 配置文件不是自己干活,是组合了一个 XmlBeanDefinitionReader ,让它去解析。而实际解析配置文件的动作

protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
    Resource[] configResources = getConfigResources();
    if (configResources != null) {
        reader.loadBeanDefinitions(configResources);
    }
    String[] configLocations = getConfigLocations();
    if (configLocations != null) {
        reader.loadBeanDefinitions(configLocations);
    }
}

这里就是调用上面文档注释中提到的 getConfigResourcesgetConfigLocations 方法,取到配置文件的路径 / 资源类,交给 BeanDefinitionReader 解析

ClassPathXmlApplicationContext-掌握

ClassPathXmlApplicationContext从classpath 下加载 xml 配置文件的 ApplicationContext

ClassPathXmlApplicationContext是一个最终落地实现

Standalone XML application context, taking the context definition files from the class path, interpreting plain paths as class path resource names that include the package path (e.g. “mypackage/myresource.txt”). Useful for test harnesses as well as for application contexts embedded within JARs.

翻译:

独立的基于 XML 的 ApplicationContext ,它从 classpath 中获取配置文件,将纯路径解释为包含包路径的 classpath 资源名称(例如 mypackage / myresource.txt )。对于测试工具以及 jar 包中嵌入的 ApplicationContext 很有用。

支持的配置文件加载位置都是 classpath 下取,这种方式的一个好处是:如果工程中依赖了一些其他的 jar 包,而工程启动时需要同时传入这些 jar 包中的配置文件,那 ClassPathXmlApplicationContext 就可以加载它们

ClassPathXmlApplicationContext使用Ant模式声明配置文件路径

The config location defaults can be overridden via getConfigLocations, Config locations can either denote concrete files like “/myfiles/context.xml” or Ant-style patterns like “/myfiles/*-context.xml” (see the org.springframework.util.AntPathMatcher javadoc for pattern details).

翻译:

可以通过 getConfigLocations 方法覆盖配置文件位置的默认值,配置位置可以表示具体的文件,例如 /myfiles/context.xml ,也可以表示Ant样式的模式,例如 /myfiles/*-context.xml(请参见 AntPathMatcher 的 javadoc 以获取模式详细信息)。

上面 AbstractXmlApplicationContext 中就说了,可以重写 getConfigLocations 方法来调整配置文件的默认读取位置,它这里又重复了一遍。除此之外它还提到了,加载配置文件的方式可以使用 Ant 模式匹配(比较经典的写法当属 web.xml 中声明的 application-*.xml

ClassPathXmlApplicationContext解析的配置文件有先后之分

Note: In case of multiple config locations, later bean definitions will override ones defined in earlier loaded files. This can be leveraged to deliberately override certain bean definitions via an extra XML file.

翻译:

注意:如果有多个配置位置,则较新的 BeanDefinition 会覆盖较早加载的文件中的 BeanDefinition ,可以利用它来通过一个额外的 XML 文件有意覆盖某些 BeanDefinition

这一点是配合第一点的多配置文件读取来的。通常情况下,如果在一个 jar 包的 xml 配置文件中声明了一个 Bean ,并且又在工程的 resources 目录下又声明了同样的 Bean ,则 jar 包中声明的 Bean 会被覆盖,这也就是配置文件加载优先级的设定

ApplicationContext可组合灵活使用

This is a simple, one-stop shop convenience ApplicationContext. Consider using the GenericApplicationContext class in combination with an org.springframework.beans.factory.xml.XmlBeanDefinitionReader for more flexible context setup.

翻译:

这是一个简单的一站式便利 ApplicationContext 。可以考虑将 GenericApplicationContext 类与 XmlBeanDefinitionReader 结合使用,以实现更灵活的上下文配置。

最后文档中并没有非常强调 ClassPathXmlApplicationContext 的作用,而是提了另外一个建议:由于 ClassPathXmlApplicationContext 继承了 AbstractXmlApplicationContext ,而 AbstractXmlApplicationContext 实际上是内部组合了一个 XmlBeanDefinitionReader ,所以就可以有一种组合的使用方式:利用 GenericApplicationContext 或者子类 AnnotationConfigApplicationContext ,配合 XmlBeanDefinitionReader ,就可以做到注解驱动和 xml 通吃了。

AnnotationConfigApplicationContext-掌握

注解驱动的 IOC 容器。它本身继承了 GenericApplicationContext ,那自然它也只能刷新一次。同样是最终的落地实现,它自然也应该跟 ClassPathXmlApplicationContext 类似的有一些特征

AnnotationConfigApplicationContext是一个最终落地实现

Standalone application context, accepting component classes as input — in particular @Configuration-annotated classes, but also plain @Component types and JSR-330 compliant classes using javax.inject annotations.

翻译:

独立的注解驱动的 ApplicationContext ,接受组件类作为输入,特别是使用 @Configuration 注解的类,还可以使用普通的 @Component 类型和符合 JSR-330 规范(使用 javax.inject 包的注解)的类。

注解驱动,除了 @Component 及其衍生出来的几个注解,更重要的是 @Configuration 注解,一个被 @Configuration 标注的类相当于一个 xml 文件。至于下面还提到的关于 JSR-330 的东西,它没有类似于 @Component 的东西(它只是定义了依赖注入的标准,与组件注册无关),它只是说如果一个组件 Bean 里面有 JSR-330 的注解,那它能给解析而已。

AnnotationConfigApplicationContext解析的配置类也有先后之分

Allows for registering classes one by one using register(Class…) as well as for classpath scanning using scan(String…). In case of multiple @Configuration classes, @Bean methods defined in later classes will override those defined in earlier classes. This can be leveraged to deliberately override certain bean definitions via an extra @Configuration class.

翻译:

允许使用 register(Class ...) 一对一注册类,以及使用 scan(String ...) 进行类路径的包扫描。 如果有多个 @Configuration 类,则在以后的类中定义的 @Bean 方法将覆盖在先前的类中定义的方法。这可以通过一个额外的 @Configuration 类来故意覆盖某些 BeanDefinition

ClassPathXmlApplicationContext 一样存在配置覆盖的概念。除此之外,它上面还说了初始化的两种方式:要么注册配置类,要么直接进行包扫描。由于注解驱动开发中可能没有一个主配置类,都是一上来就一堆 @Component ,这个时候完全可以直接声明根扫描包,进行组件扫描。

参考资料

从 0 开始深入学习 Spring

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1690695.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

GD32F103RCT6/GD32F303RCT6-UCOSIII底层移植(4)消息队列实验

本文章基于兆易创新GD32 MCU所提供的2.2.4版本库函数开发 后续项目主要在下面该专栏中发布&#xff1a; 手把手教你嵌入式国产化_不及你的温柔的博客-CSDN博客 感兴趣的点个关注收藏一下吧! 电机驱动开发可以跳转&#xff1a; 手把手教你嵌入式国产化-实战项目-无刷电机驱动&am…

【LeetCode算法】第58题:最后一个单词的长度

目录 一、题目描述 二、初次解答 三、官方解法 四、总结 一、题目描述 二、初次解答 1. 思路&#xff1a;双指针法。low指向单词头&#xff0c;high指向单词后的空格&#xff0c;则high-low就是每个单词的长度。算法步骤&#xff1a;①low从头往后查找第一个非空格的字符&…

分割文本文件

分割一个.txt文件&#xff0c;可以选择在命令行中使用split指令&#xff0c;或者编写一段脚本进行操作。以下是一个简单的Python脚本来分割文本文件&#xff1a; def split_file(file, lines):# Open source filewith open(file, r) as source:count 0atEOF Falsewhile not …

如果有多个文件夹,怎么快速获得文件夹的名字呢

上一篇写到怎么批量建立文件夹&#xff0c;那么怎么获取批量文件夹的名字呢&#xff1f; 一、啊这&#xff0c;这真是一个好问题二、这个得用Python&#xff08;文本末尾有打包程序&#xff0c;点击链接运行就可以了&#xff09;&#xff08;1&#xff09;首先建立一个py文件&a…

Python 将文件夹中的图片信息导入到 Excel 的表格

引言 在数据处理和管理的日常任务中&#xff0c;经常需要将文件夹中的图片文件信息&#xff08;如文件名、路径、创建日期、大小、分辨率等&#xff09;整理成一个 Excel 表格。这篇博客将介绍如何使用 Python 中的 wxPython 模块创建一个 GUI 应用&#xff0c;用户可以通过这…

jmeter保存测试计划报错——Couldn‘t save test plan to file:

jmeter保存测试计划报错——Couldnt save test plan to file:。。。。。拒绝访问 一、问题描述二、分析三、结果 一、问题描述 Couldn’t save test plan to file:D:\Program Files\apache-jmeter-5.6.2\bin\线程组.jmx D:\Program Files\apache-jmeter-5.6.2\bin\线程组.jmx(…

2024电工杯A题完整代码论文分析

2024年电工杯数学建模竞赛A题论文和代码已完成&#xff0c;代码为B题全部问题的代码&#xff0c;论文包括摘要、问题重述、问题分析、模型假设、符号说明、模型的建立和求解&#xff08;问题1模型的建立和求解、问题2模型的建立和求解、问题3模型的建立和求解&#xff09;、模型…

【Mac】电脑任何来源无法打开的问题解决办法

前言 有小伙伴在安装本站软件过程中&#xff0c;遇到过运行脚本1提示 sudo: /etc/sudoers is world writable的问题&#xff0c;其实就是电脑任何来源无法打开。今天就来说一下解决办法。 问题现象 电脑运行「脚本1」时提示&#xff1a; // 错误内容sudo: /etc/sudoers is w…

Navicat 连接 OceanBase 快速入门 | 社区版

Navicat Premium&#xff08;16.1.9或更高版本&#xff09;正式支持 OceanBase全线数据库产品。OceanBase为现代数据架构打造的开源分布式数据库。兼容 MySQL 的单机分布式一体化国产开源数据库&#xff0c;具有原生分布式架构&#xff0c;支持金融级高可用、透明水平扩展、分布…

KVM虚拟化基础

一、虚拟化基础 1.传统物理机部署方案 IDC机房优点&#xff1a; IDC机房是分布式的&#xff0c;是全国连锁的。我们将物理服务器部署到IDC机房&#xff0c;由IDC机房帮我们上架服务&#xff0c;管理其内部的网络以及路由转发、服务器资源的分发&#xff1b;而且IDC机房带宽接…

加入MongoDB AI创新者计划,携手MongoDB共同开创AI新纪元

加入MongoDB AI创新者计划&#xff01; MongoDB对AI创新和初创企业的支持既全面又广泛&#xff01;无论您是领先的AI初创企业还是刚刚起步&#xff0c;MongoDB Atlas都是支持您愿景的最佳平台。 AI 初创者计划The AI Startup Track AI初创者计划为早期初创企业提供专属福利&…

顺序表及其应用

掌握顺序表的初始化&#xff0c;初始化、查找、插入、删除、遍历、查看实际长度等操作 内容 从键盘输入n个整数&#xff0c;创建顺序表。【创建长度为n的顺序表】从键盘输入1个整数x&#xff0c;在顺序表中查找x所在的位置。若找到&#xff0c;输出该元素所在的位置(即数组下标…

YOLOV10实时端到端目标检测

代码地址&#xff1a;GitHub - THU-MIG/yolov10: YOLOv10: Real-Time End-to-End Object Detection 论文地址&#xff1a;https://arxiv.org/pdf/2405.14458 本文介绍了YOLO系列目标检测器在实时和高效方面的优势&#xff0c;但是仍然存在一些缺陷&#xff0c;包括依赖非极大值…

【Linux】icmp_seq=1 Destination Host Unreachable

执行ping 命令提示&#xff1a;From 192.168.XX.XX icmp_seq1 Destination Host Unreachable 这个错误消息通常表示以下几种情况之一&#xff1a; 网络连接问题&#xff1a;目标主机可能没有连接到网络&#xff0c;或者网络中的某个路由器无法将数据包转发到目标主机。 目标主…

08.1.jenkins安装方法

安装 配置官方下载源 #配置jenkins源 sudo wget -O /etc/yum.repos.d/jenkins.repo https://pkg.jenkins.io/redhat-stable/jenkins.repo sudo rpm --import https://pkg.jenkins.io/redhat-stable/jenkins.io.key下载jak、jenkins服务 #下载jdk11环境&#xff0c;并且配置yu…

软考之信息系统管理知识点(3)

流水线&#xff1a;是指在程序执行时多条指令重叠进行操作的一种准并行处理实现技术。各种部件同时处理是针对不同指令而言的&#xff0c;它们可同时为多条指令的不同部分进行工作&#xff0c;以提高各部件的利用率和指令的平均执行速度。 编译得过程 关系数据库是表的集合 …

基于yolov2深度学习网络的昆虫检测算法matlab仿真,并输出昆虫数量和大小判决

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版本 matlab2022A 3.部分核心程序 .......................................................... for i 1:12 % 遍历结…

声量 2024 | 从小到大,有哪些好产品曾出现在我们生活里?

点击文末“阅读原文”即可参与节目互动 剪辑、音频 / 老段 运营 / SandLiu 卷圈 监制 / 姝琦 封面 / 姝琦 产品统筹 / bobo 场地支持 / 阿那亚 联合制作 / 声量The Power of Voice 特别鸣谢 / 深夜谈谈播客网络 本期节目录制于第二届「声量The Power of Voice」现场。 在…

【SqL】数据库脚本编写规范和指南

编写本文档的目的是保证在开发过程中产出高效、格式统一、易阅读、易维护的SQL代码。 1 编写目的 2 SQL书写规范 3 SQL编写原则 软件全套资料获取进主页或者本文末个人名片直接获取。

读人工智能时代与人类未来笔记13_网络57

1. jun背控制 1.1. 威慑的目的是通过威胁发动盒站来防止盒站 1.2. jun背控制的目的是通过限制甚至废除57&#xff08;或57类别&#xff09;本身来防止盒站真 1.2.1. 与盒不扩散相配合&#xff0c;以一整套详尽的条约、技术保障措施、监管和其他控制机制为支撑&#xff0c;所…