程序项目代做,有需求私信(小程序、网站、爬虫、电路板设计、驱动、应用程序开发、毕设疑难问题处理等)

Spring Boot -- 启动流程分析之ApplicationContext 上

我们总经常听说Spring容器,那Spring容器到底是什么,在介绍创建Spring应用程序上下文之前,我们先来聊一聊Spring容器到底是什么。

一、容器简介

容器顾名思义就是用来装东西的,装的是什么?装的是Bean。

Bean是Spring的基本单位,在基于Spring的web应用中,所有的组件都被当做Bean处理、包括数据源、Hiberate的SessionFactory、事务管理器等。在Spring中,Bean是一个非常广义的概念,任何Java对象,Java组件都被当做Bean处理。

那容器仅仅是用来保存Bean这么简单么?不是。

当我们需要某个Bean时,容器会自动帮我们创建,并在适当时销毁。当某个 Bean 中需创建另一个 Bean 时,也就是 Bean 之间有依赖关系,这种依赖的 Bean 也是由容器自动创建。在外界有一个标准的名词,前者称呼为 IOC,也就是控制反转,后者称呼为 DI,也就是依赖注入。 

1.1、IOC/DI

IOC (Inversion of Control) 控制反转:所谓控制反转,就是当我们需要某个 Bean 时,将 Bean 的名称告知容器,由容器去创建该 Bean,而不是我们手动 new 一个,这里 Bean 创建管理的控制权都交给了容器,所以这是一种控制权的反转。其通俗点讲就是需要什么东西让别人送过来,而不是自己去拿。

DI (Dependency Injection) 依赖注入:就是指当 A Bean 里面需创建 B Bean 时,会在创建 A Bean 的时候,自动将依赖的 B Bean 注入进去,其 B Bean 是被动接受注入而不是自己主动去找。换句话说就是指 A Bean 不是从容器中查找它依赖的 B Bean,而是在容器创建 A Bean 候主动将它依赖的 B Bean 注入给它。

IOC 和 DI 其实归根结底实现的功能是相同的,只是同样的功能站在不同的角度来阐述罢了。当然,在真实场景中,交由 Spring 容器创建的 Bean 泛指在应用程序中的表现层、业务层、持久层等各层对应的 Bean,如 Controller、Service 等;进行数据交互的模型,如 DTO、VO 等就不需交由 Spring 来创建。 

所以,容器本质上可以也可以看作是 Bean 工厂,该工厂管理 Bean 的生命周期,以及 Bean 之间的依赖关系。外界也将 Spring 容器称为 IOC 容器。当然,这里容器仅仅是 Spring 的抽象概念,代码中将其具象化为 BeanFactory 或 ApplicationContext,容器功能也由具象化的类进行处理。 

1.2、容器的结构

容器的实现类并不是唯一的,Spring 框架提供了多个容器的实现,这些容器分为两套体系:一套是早期的 BeanFactory 体系;还有一套是现在常用的 ApplicationContext,也可称为应用上下文,它继承了 BeanFactory,它除了有 BeanFactory 的功能外 ,还提供了其他服务,例如事务和 AOP 服务、国际化(il8n)的消息源以及应用程序事件处理等企业级的服务。

说到这,就不得不说 Spring 的两种配置方式,在早期都是 XML 配置文件的方式,而现在使用的是注解配置的方式。BeanFactory 体系的容器一般用来处理 XML 配置文件的方式,而 ApplicationContext 体系则都可以处理。 

下表列出了BeanFactory 和 ApplicationContext 接口和实现所提供的功能:

功能/特点 BeanFactory ApplicationContext
Bean 实例化/装配
BeanPostProcessor 自动注册 没有
BeanFactoryPostProcessor 自动注册 没有
MessageSource 便捷访问(针对i18n) 没有
ApplicationEvent 发布 没有

两者还有一个区别是:

  • ApplicationContext 在容器启动时,一次性创建了所有的 Bean。
  • BeanFactory 在容器启动时,并未创建 Bean,直到第一次访问某个 Bean 时才创建目标 Bean。

1.3、BeanFactory

BeanFactory 是容器最基础的类,它定义了容器的基本功能规范:

复制代码
public interface BeanFactory {

    // 对 FactoryBean 的转义定义,因为如果使用 bean 的名字检索 FactoryBean 得到的对象是工厂生成的对象,
    // 如果需要得到工厂本身,需要转义(FactoryBean 在后续会详细介绍)
    String FACTORY_BEAN_PREFIX = "&";
    
    // 根据 bean 的名字,获取在容器中 bean 实例
    Object getBean(String name) throws BeansException;
    
    //根据 bean 的名字和 Class 类型来得到 bean 实例,增加了类型安全验证机制。
    <T> T getBean(String name, @Nullable Class<T> requiredType) throws BeansException;
    Object getBean(String name, Object... args) throws BeansException;
    <T> T getBean(Class<T> requiredType) throws BeansException;
    <T> T getBean(Class<T> requiredType, Object... args) throws BeansException;
    
    // 提供对 bean 的检索,看看是否在容器有这个名字的 bean
    boolean containsBean(String name);
    
    // 根据 bean 名字,判断这个 bean 是不是单例
    boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
    
    // 根据 bean 名字,判断这个 bean 是不是原型
    boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
    
    // 根据 bean 名字,判断是否与指定的类型匹配
    boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;
    boolean isTypeMatch(String name, @Nullable Class<?> typeToMatch) throws NoSuchBeanDefinitionException;
    
    // 得到 bean 实例的 Class 类型
    Class<?> getType(String name) throws NoSuchBeanDefinitionException;
    
    // 得到bean 的别名,如果根据别名检索,那么其原名也会被检索出来
    String[] getAliases(String name);
}
复制代码

在 BeanFactory 里只对容器的基本行为作了定义,其根本不关心你的 Bean 是如何定义怎样加载的。 正如我们只关心工厂里得到什么的产品对象,至于工厂是怎么生产这些对象的,这个基本的接口不关心。而要知道工厂是如何产生对象的,我们就需要看具体的容器了,也就是 BeanFactory 的子类。

BeanFactory 大致的继承关系如下:

BeanFactory 体系中常用的实现类有:

  • ListableBeanFactory:提供容器中 bean 迭代的功能。如返回所有 Bean 的名字、容器中 Bean 的数量等。
  • HierarchicalBeanFactory:提供父容器的访问功能,可通过 ConfigurableBeanFactory 的 setParentBeanFactory 方法设置父容器。
  • AutowireCapableBeanFactory:为 Spring 容器之外的 Bean ,也就是未交由 Spring 管理的 Bean ,提供依赖注入的功能。

以上三个是 BeanFactory 的直系亲属,这个三个直系亲属下面又派生了两个复杂的容器:

  • ConfigurableBeanFactory:其继承了 HierarchicalBeanFactory 和 SingletonBeanRegistry 这两个接口,其提供了很多方法,如:定义类加载器、类型转化、属性编辑器、注册依赖 Bean 、销毁 bean 等,且该接口被大多数的容器继承、实现。
  • ConfigurableListableBeanFactory:这个接口继承了 ListableBeanFactory、 AutowireCapableBeanFactory、ConfigurableBeanFactory,自身主要提供用于分析和修改 bean 定义以及预先实例化单例 Bean 的方法。 

最后是核心容器:

DefaultListableBeanFactory:它实现了以上所有的接口,在 BeanFactory 体系中可以作为一个独立的容器使用。这个类特别重要,后面我们介绍到的Spring应用上下文启动都是围绕该类展开的,这个类中有几个字段我们后面会反复使用到:

复制代码
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
        implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
       ...

    /** Map from serialized id to factory instance. */
    private static final Map<String, Reference<DefaultListableBeanFactory>> serializableFactories =
            new ConcurrentHashMap<>(8);

    /** Optional id for this factory, for serialization purposes. */
    @Nullable
    private String serializationId;

    /** Whether to allow re-registration of a different definition with the same name. */
    private boolean allowBeanDefinitionOverriding = true;

    /** Whether to allow eager class loading even for lazy-init beans. */
    private boolean allowEagerClassLoading = true;

    /** Optional OrderComparator for dependency Lists and arrays. */
    @Nullable
    private Comparator<Object> dependencyComparator;

    /** Resolver to use for checking if a bean definition is an autowire candidate. */
    private AutowireCandidateResolver autowireCandidateResolver = new SimpleAutowireCandidateResolver();

    /** Map from dependency type to corresponding autowired value. */
    private final Map<Class<?>, Object> resolvableDependencies = new ConcurrentHashMap<>(16);

    /** Map of bean definition objects, keyed by bean name. */
    private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);

    /** Map of singleton and non-singleton bean names, keyed by dependency type. */
    private final Map<Class<?>, String[]> allBeanNamesByType = new ConcurrentHashMap<>(64);

    /** Map of singleton-only bean names, keyed by dependency type. */
    private final Map<Class<?>, String[]> singletonBeanNamesByType = new ConcurrentHashMap<>(64);

    /** List of bean definition names, in registration order. */
    private volatile List<String> beanDefinitionNames = new ArrayList<>(256);

    /** List of names of manually registered singletons, in registration order. */
    private volatile Set<String> manualSingletonNames = new LinkedHashSet<>(16);

    /** Cached array of bean definition names in case of frozen configuration. */
    @Nullable
    private volatile String[] frozenBeanDefinitionNames;

    /** Whether bean definition metadata may be cached for all beans. */
    private volatile boolean configurationFrozen = false;
       ...
}
复制代码

此外还有继承自DefaultSingletonBeanRegistry的字段:

复制代码
public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {

    /** Cache of singleton objects: bean name to bean instance. */
    private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

    /** Cache of singleton factories: bean name to ObjectFactory. */
    private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

    /** Cache of early singleton objects: bean name to bean instance. */
    private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);

    /** Set of registered singletons, containing the bean names in registration order. */
    private final Set<String> registeredSingletons = new LinkedHashSet<>(256);

    /** Names of beans that are currently in creation. */
    private final Set<String> singletonsCurrentlyInCreation =
            Collections.newSetFromMap(new ConcurrentHashMap<>(16));

    /** Names of beans currently excluded from in creation checks. */
    private final Set<String> inCreationCheckExclusions =
            Collections.newSetFromMap(new ConcurrentHashMap<>(16));

    /** List of suppressed Exceptions, available for associating related causes. */
    @Nullable
    private Set<Exception> suppressedExceptions;

    /** Flag that indicates whether we're currently within destroySingletons. */
    private boolean singletonsCurrentlyInDestruction = false;

    /** Disposable bean instances: bean name to disposable instance. */
    private final Map<String, Object> disposableBeans = new LinkedHashMap<>();

    /** Map between containing bean names: bean name to Set of bean names that the bean contains. */
    private final Map<String, Set<String>> containedBeanMap = new ConcurrentHashMap<>(16);

    /** Map between dependent bean names: bean name to Set of dependent bean names. */
    private final Map<String, Set<String>> dependentBeanMap = new ConcurrentHashMap<>(64);

    /** Map between depending bean names: bean name to Set of bean names for the bean's dependencies. */
    private final Map<String, Set<String>> dependenciesForBeanMap = new ConcurrentHashMap<>(64);
    ...
}
复制代码

下面重点介绍一下ApplicationContext,主要是因为ApplicationContext 包含了 BeanFactory,实际中基本不单独使用 BeanFactory。

1.4、ApplicationContext

上面说过 ApplicationContext 是 BeanFactory 子类,它不仅包含 BeanFactory 所有功能,还对其进行了扩展,而我们喜欢将 ApplicationContext 称为应用上下文,因为容器只是它的基本功能。 

复制代码
public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,
        MessageSource, ApplicationEventPublisher, ResourcePatternResolver {

    // 返回此应用程序上下文的唯一ID
    @Nullable
    String getId();

    // 返回此上下文所属的应用程序名称
    String getApplicationName();

    // 返回应用上下文具像化的类名
    String getDisplayName();

    // 返回第一次加载此上下文时的时间戳
    long getStartupDate();

    // 获取父级应用上下文
    @Nullable
    ApplicationContext getParent();

    // 将 AutowireCapableBeanFactory 接口暴露给外部使用
    AutowireCapableBeanFactory getAutowireCapableBeanFactory() throws IllegalStateException;
}
复制代码

ApplicationContext 自身提供的方法非常简单,但它继承了六个接口,来扩展自身功能:

  • EnvironmentCapable:获取 Environment。
  • ListableBeanFactory、HierarchicalBeanFactory:这是 BeanFactory 体系接口,分别提供 Bean 迭代和访问父容器的功能。
  • MessageSource:支持国际化功能。
  • ApplicationEventPublisher:应用事件发布器,封装事件发布功能的接口。
  • ResourcePatternResolver:该接口继承至 ResourceLoader ,作用是加载多个 Resource。

ApplicationContext 同样提供了非常多的实现类,其又可细分为两大类, ConfigurableApplicationContext 和 WebApplicationContext。

1.5、ConfigurableApplicationContext 

该接口是比较重要的一个接口,几乎所有的应用上下文都实现了该接口。该接口在ApplicationContext的基础上提供了配置应用上下文的能力,此外提供了生命周期的控制能力。

复制代码
public

interface ConfigurableApplicationContext extends ApplicationContext, Lifecycle, Closeable { // 应用上下文配置时,这些符号用于分割多个配置路径 String CONFIG_LOCATION_DELIMITERS = ",; \t\n"; // BeanFactory中,ConversionService类所对应的bean的名字。如果没有此类的实例的话吗,则使用默认的转换规则 String CONVERSION_SERVICE_BEAN_NAME = "conversionService"; //LoadTimeWaver类所对应的Bean在容器中的名字。如果提供了该实例,上下文会使用临时的 ClassLoader ,这样,LoadTimeWaver就可以使用bean确切的类型了 String LOAD_TIME_WEAVER_BEAN_NAME = "loadTimeWeaver"; // Environment 类在容器中实例的名字 String ENVIRONMENT_BEAN_NAME = "environment"; // System 系统变量在容器中对应的Bean的名字 String SYSTEM_PROPERTIES_BEAN_NAME = "systemProperties"; // System 环境变量在容器中对应的Bean的名字 String SYSTEM_ENVIRONMENT_BEAN_NAME = "systemEnvironment"; // 设置容器的唯一ID void setId(String id); // 设置此容器的父容器 void setParent(@Nullable ApplicationContext parent); // 设置容器的 Environment 变量 void setEnvironment(ConfigurableEnvironment environment); // 以 ConfigurableEnvironment 的形式返回此容器的环境变量。以使用户更好的进行配置 @Override ConfigurableEnvironment getEnvironment(); // 此方法一般在读取应用上下文配置的时候调用,用以向此容器中增加BeanFactoryPostProcessor。增加的Processor会在容器refresh的时候使用。 void addBeanFactoryPostProcessor(BeanFactoryPostProcessor postProcessor); // 向容器增加一个 ApplicationListener,增加的 Listener 用于发布上下文事件,如 refresh 和 shutdown 等 void addApplicationListener(ApplicationListener<?> listener); // 向容器中注入给定的 Protocol resolver void addProtocolResolver(ProtocolResolver resolver); // 这是初始化方法,因此如果调用此方法失败的情况下,要将其已经创建的 Bean 销毁。 // 换句话说,调用此方法以后,要么所有的Bean都实例化好了,要么就一个都没有实例化 void refresh() throws BeansException, IllegalStateException; // 向JVM注册一个回调函数,用以在JVM关闭时,销毁此应用上下文 void registerShutdownHook(); // 关闭此应用上下文,释放其所占有的所有资源和锁。并销毁其所有创建好的 singleton Beans @Override void close(); // 检测此 FactoryBean 是否被启动过 boolean isActive(); // 返回此应用上下文的容器。 // 千万不要使用此方法来对 BeanFactory 生成的 Bean 做后置处理,因为单例 Bean 在此之前已经生成。 // 这种情况下应该使用 BeanFactoryPostProcessor 来在 Bean 生成之前对其进行处理 ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException; }
复制代码

该接口下又有几个重要的实现类:

  • AbstractApplicationContext:这是个抽象类,仅实现了公共的上下文特性。这个抽象类使用了模板方法设计模式,需要具体的实现类去实现这些抽象的方法。
  • GenericApplicationContext:该类继承自 AbstractApplicationContext,是为通用目的设计的,它能加载各种配置文件,例如 xml,properties 等等。它的内部持有一个 DefaultListableBeanFactory 的实例,实现了 BeanDefinitionRegistry 接口,以便允许向其应用任何 bean 的定义的读取器。
  • AnnotationConfigApplicationContext:该类继承自 GenericApplicationContext ,提供了注解配置(例如:@Configuration、@Component等)和类路径扫描(scan方法)的支持。

1.6、WebApplicationContext

该接口是专门为 Web 应用准备的,其允许从相对于 Web 根目录的路径中装载配置文件完成初始化。

复制代码
public interface WebApplicationContext extends ApplicationContext {

    // 整个 Web 应用上下文是作为属性放置在 ServletContext 中的,该常量就是应用上下文在 ServletContext 属性列表中的 key
    String ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE = WebApplicationContext.class.getName() + ".ROOT";

    // 定义了三个作用域的名称
    String SCOPE_REQUEST = "request";
    String SCOPE_SESSION = "session";
    String SCOPE_APPLICATION = "application";

    // 在工厂中的 bean 名称
    String SERVLET_CONTEXT_BEAN_NAME = "servletContext";

    // ServletContext 初始化参数名称
    String CONTEXT_PARAMETERS_BEAN_NAME = "contextParameters";

    // 在工厂中 ServletContext 属性值环境bean的名称
    String CONTEXT_ATTRIBUTES_BEAN_NAME = "contextAttributes";

    // 用来获取 ServletContext 对象
    @Nullable
    ServletContext getServletContext();
}
复制代码

该接口的核心实现类有:

  • ConfigurableWebApplicationContext:该接口同时继承了 WebApplicationContext 和 ConfigurableApplicationContext,提供了 Web 应用上下文的可配置的能力。
  • GenericWebApplicationContext:该类继承自 GenericApplicationContext,实现了 ConfigurableWebApplicationContext。
  • XmlWebApplicationContext:该上下文是使用 Xml 配置文件的方式,不过是在 Web 环境中使用的。
  • AnnotationConfigServletWebServerApplicationContext:该类是被 SpringBoot 扩展而来的,SpringBoot 使用的就是该上下文。 

二、创建Spring应用上下文(createApplicationContext)

我们接着上一篇博客继续分析SpringApplication run方法中的核心部分代码:应用上下文的创建。

复制代码
public class SpringApplication {

    public static final String DEFAULT_CONTEXT_CLASS = "org.springframework.context."
            + "annotation.AnnotationConfigApplicationContext";

    public static final String DEFAULT_SERVLET_WEB_CONTEXT_CLASS = "org.springframework.boot."
            + "web.servlet.context.AnnotationConfigServletWebServerApplicationContext";
            
    public static final String DEFAULT_REACTIVE_WEB_CONTEXT_CLASS = "org.springframework."
            + "boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext";
            
    ...
    
    private WebApplicationType webApplicationType;
    
    ...
    
    public ConfigurableApplicationContext run(String... args) {
        ...
        
        ConfigurableApplicationContext context = null;
        
        try {
            ...
            // createApplicationContext 方法创建对应的 ApplicationContext 应用上下文
            context = createApplicationContext();
            
            exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
                    new Class[] { ConfigurableApplicationContext.class }, context);
            prepareContext(context, environment, listeners, applicationArguments, printedBanner);
            
            // 该方法实质是启动 Spring 应用上下文的,但 Spring Boot 嵌入式容器也在该过程中被启动,入参是上下文对象
            refreshContext(context);
            
            ...
        }
        ...
    }
    ...
}
复制代码

2.1、创建ConfigurableApplicationContext 

复制代码
   protected ConfigurableApplicationContext createApplicationContext() {
        Class<?> contextClass = this.applicationContextClass;
        if (contextClass == null) {
            try {
            
                // 这里就是通过 webApplicationType 属性,判断应用类型,来创建不同的 ApplicationContext 应用上下文
                switch (this.webApplicationType) {
                case SERVLET:
                    
                    // 返回的是 Servlet Web ,具体对象为 AnnotationConfigServletWebServerApplicationContext, 
                    contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
                    break;
                case REACTIVE:
                
                    // 返回的是 Reactive Web,具体对象为 AnnotationConfigReactiveWebServerApplicationContext
                    contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
                    break;
                default:
                
                    // 应用类型是非 Web 时,返回 AnnotationConfigApplicationContext
                    contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
                }
            }
            ...
        }
        return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
    }
    
复制代码

这里也是通过 webApplicationType 属性来确定应用类型从而创建 String 上下文,上篇文章说到该属性值是在 Spring Boot 准备阶段推导出来的。这里我们的应用类型是 Servlet ,所以创建的是 AnnotationConfigServletWebServerApplicationContext 对象。

2.1、AnnotationConfigServletWebServerApplicationContext 构造函数

通过 BeanUtils.instantiateClass会调用AnnotationConfigServletWebServerApplicationContext 的无参构造函数,而在Java的继承中,会先调用父类的构造方法。所以会先调用AnnotationConfigServletWebServerApplicationContext 的父类GeniricApplicationContext的构造方法:

复制代码
public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry {

    private final DefaultListableBeanFactory beanFactory;

    @Nullable
    private ResourceLoader resourceLoader;

    private boolean customClassLoader = false;

    private final AtomicBoolean refreshed = new AtomicBoolean();


    /**
     * Create a new GenericApplicationContext.
     * @see #registerBeanDefinition
     * @see #refresh
     */
    public GenericApplicationContext() {
        this.beanFactory = new DefaultListableBeanFactory();
    }
     ...
}
复制代码

在父类中初始化beanFactory,即直接new了一个DefaultListableBeanFactory:

复制代码
    /**
     * Create a new {@link AnnotationConfigServletWebServerApplicationContext} that needs
     * to be populated through {@link #register} calls and then manually
     * {@linkplain #refresh refreshed}.
     */
    public AnnotationConfigServletWebServerApplicationContext() {
        this.reader = new AnnotatedBeanDefinitionReader(this);
        this.scanner = new ClassPathBeanDefinitionScanner(this);
    }
复制代码

在构造函数中通过new AnnotatedBeanDefinitionReader(this)实例化了一个Bean读取器:

复制代码
    /**
     * Create a new {@code AnnotatedBeanDefinitionReader} for the given registry.
     * <p>If the registry is {@link EnvironmentCapable}, e.g. is an {@code ApplicationContext},
     * the {@link Environment} will be inherited, otherwise a new
     * {@link StandardEnvironment} will be created and used.
     * @param registry the {@code BeanFactory} to load bean definitions into,
     * in the form of a {@code BeanDefinitionRegistry}
     * @see #AnnotatedBeanDefinitionReader(BeanDefinitionRegistry, Environment)
     * @see #setEnvironment(Environment)
     */
    public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry) {
        this(registry, getOrCreateEnvironment(registry));
    }

    /**
     * Create a new {@code AnnotatedBeanDefinitionReader} for the given registry,
     * using the given {@link Environment}.
     * @param registry the {@code BeanFactory} to load bean definitions into,
     * in the form of a {@code BeanDefinitionRegistry}
     * @param environment the {@code Environment} to use when evaluating bean definition
     * profiles.
     * @since 3.1
     */
    public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
        Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
        Assert.notNull(environment, "Environment must not be null");
        this.registry = registry;
        this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
        AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
    }
复制代码

最后会调用到AnnotationConfigUtils.registerAnnotationConfigProcessors(BeanDefinitionRegistry registry,Object source)方法:

复制代码
    /**
     * Register all relevant annotation post processors in the given registry.
     * @param registry the registry to operate on
     * @param source the configuration source element (already extracted)
     * that this registration was triggered from. May be {@code null}.
     * @return a Set of BeanDefinitionHolders, containing all bean definitions
     * that have actually been registered by this call
     */
    public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
            BeanDefinitionRegistry registry, @Nullable Object source) {

        DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
        if (beanFactory != null) {
            if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
                beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
            }
            if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
                beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
            }
        }

        Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);

        if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
            RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
            def.setSource(source);
            beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
        }

        if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
            RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
            def.setSource(source);
            beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
        }

        // Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.
        if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
            RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
            def.setSource(source);
            beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
        }

        // Check for JPA support, and if present add the PersistenceAnnotationBeanPostProcessor.
        if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {
            RootBeanDefinition def = new RootBeanDefinition();
            try {
                def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,
                        AnnotationConfigUtils.class.getClassLoader()));
            }
            catch (ClassNotFoundException ex) {
                throw new IllegalStateException(
                        "Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);
            }
            def.setSource(source);
            beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));
        }

        if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
            RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
            def.setSource(source);
            beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
        }

        if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {
            RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);
            def.setSource(source);
            beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));
        }

        return beanDefs;
    }
复制代码

这里通过调用registerPostProcessor向BeanDefinitionMap中注册了5个BeanDefinition,BeanDefinition保存 Bean 的相关信息,我们在后面会详细介绍。

    private static BeanDefinitionHolder registerPostProcessor(
            BeanDefinitionRegistry registry, RootBeanDefinition definition, String beanName) {

        definition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
        registry.registerBeanDefinition(beanName, definition);
        return new BeanDefinitionHolder(definition, beanName);
    }

这里的register就是我们的应用上下文,这里调用的就是GenericApplicationContext的registerBeanDefinition:

/** Map of bean definition objects, keyed by bean name. */
    private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);

GenericApplicationContext 底层调用的是 DefaultListableBeanFactory(BeanFactory的实现类)中的实现方法:

    public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
            throws BeanDefinitionStoreException {

        this.beanFactory.registerBeanDefinition(beanName, beanDefinition);
    }

这里注册的BeanDefinition分别为ConfigurationClassPostProcessor、DefaultEventListenerFactory、EventListenerMethodProcessor、AutowiredAnnotationBeanPostProcessor、CommonAnnotationBeanPostProcessor。

接着 调用this.scanner = new ClassPathBeanDefinitionScanner(this)来初始化一个扫描器,这个扫描器在后面扫描包的时候,并没有用到。

三、准备Spring应用上下文(prepareContext)

prepareContext(context, environment, listeners, applicationArguments, printedBanner);

创建完 Spring 应用上下文之后,执行 prepareContext 方法进入准备上下文阶段,我们来看看主要做了哪些操作。

复制代码
    private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
            SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
        context.setEnvironment(environment);
        postProcessApplicationContext(context);
        applyInitializers(context);
        listeners.contextPrepared(context);
        if (this.logStartupInfo) {
            logStartupInfo(context.getParent() == null);
            logStartupProfileInfo(context);
        }
        // Add boot specific singleton beans
        ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
        beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
        if (printedBanner != null) {
            beanFactory.registerSingleton("springBootBanner", printedBanner);
        }
        if (beanFactory instanceof DefaultListableBeanFactory) {
            ((DefaultListableBeanFactory) beanFactory)
                    .setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
        }
        if (this.lazyInitialization) {
            context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
        }
        // Load the sources
        Set<Object> sources = getAllSources();
        Assert.notEmpty(sources, "Sources must not be empty");
        load(context, sources.toArray(new Object[0]));
        listeners.contextLoaded(context);
    }
复制代码

3.1、设置Spring 应用上下文的 environment 

3.2、Spring 应用上下文后置处理(postProcessApplicationContext)

主要是覆盖当前 Spring 应用上下文默认所关联的 ResourceLoader 和 ClassLoader,以及初始化beanFactory的conversionService。

3.3、类型转换器

为了统一调用Converter进行类型转换,spring为我们提供了一个ConversionService接口。通过实现这个接口我们可以实现自己的Converter调用逻辑:

复制代码
package org.springframework.core.convert;

import org.springframework.lang.Nullable;

/**
 * 类型转换服务
 */
public interface ConversionService {

    /**
     * 是否支持原类型到目标类型的转换
     */
    boolean canConvert(@Nullable Class<?> sourceType, Class<?> targetType);

    /**
     * 是否支持原类型到目标类型的转换
     */
    boolean canConvert(@Nullable TypeDescriptor sourceType, TypeDescriptor targetType);

    /**
     * 将source实例转成目标类型,如果转换过程出错,抛出 ConversionException,
     * 如果 targetType 为null,抛出 IllegalArgumentException
     */
    @Nullable
    <T> T convert(@Nullable Object source, Class<T> targetType);

    /**
     * 将source实例转成目标类型,如果转换过程出错,抛出 ConversionException,
     * 如果 targetType 为null,抛出 IllegalArgumentException
     */
    @Nullable
    Object convert(@Nullable Object source, @Nullable TypeDescriptor sourceType, TypeDescriptor targetType);

}
复制代码

我们可以看到ConversionService接口里面定义了两个canConvert方法和两个convert方法,canConvert方法用于判断当前的ConversionService是否能够对原类型和目标类型进行转换,convert方法则是用于进行类型转换的。 

比如我们想实现String类型到IBaseEnum类型的转换可以怎么办呢,我们可以自己实现一个类型转换器:

复制代码
package com.goldwind.bigdataplat.core.config;

import com.goldwind.ngsp.auth.api.constant.enums.IBaseEnum;
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.convert.converter.ConverterFactory;
import org.springframework.stereotype.Component;

import javax.validation.constraints.NotBlank;

/**
 * Author: zy
 * Description: String->IbaseEnum类型转换器
 * Date: 2020/5/21
 */
public class EnumConverterFactory implements ConverterFactory<String, IBaseEnum> {

    /**
     * @author: zy
     * @description: 获取String->targetType类型的转换器 用于支持自己IBaseEnum类型(Spring支持常规的枚举类型)
     * @date: 2020/5/21 10:17
     * @param targetType: 目标类型
     * @return Converter<String,T>:
     */
    @Override
    public <T extends IBaseEnum> Converter<String, T> getConverter(Class<T> targetType) {
        //获取给定类型对应的转换器
        return new StrToEnum(targetType);
    }

    /*
     * 整型字符串转换为T枚举类型的转换器
     */
    private class StrToEnum<T extends Enum<T> & IBaseEnum> implements Converter<String, T> {
        /*
         * 保存枚举类型
         */
        private final Class<T> enumType;

        /*
         * 构造函数
         */
        private StrToEnum(Class<T> enumType) {
            this.enumType = enumType;
        }


        /*
         * 将给定的字符串转换成对应的枚举类型
         */
        @Override
        public T convert(@NotBlank String source) {
            try{
                return (T)IBaseEnum.valueOf(this.enumType, Integer.parseInt(source));
            }catch(NumberFormatException e) {
                return (T)IBaseEnum.valueOf(this.enumType, source);
            }
        }
    }
}
复制代码

其中IBaseEnum定义如下:

复制代码
package com.goldwind.ngsp.auth.api.constant.enums;

/**
 * Author: zy
 * Description: 用户支持将http请求参数中传入的数字转换为对应的枚举值
 * Date: 2020/5/21
 */
public interface IBaseEnum{
    /*
     * 与数据库进行映射的值
     */
    int getValue();

    /*
     * 描述信息
     */
    String getDesc();

    /*
     * 将状态码装换为枚举类型
     */
    static <E extends IBaseEnum> IBaseEnum valueOf(Class<E> enumClass,int value){
        try {
            E[] enumConstants = enumClass.getEnumConstants();
            for (E e : enumConstants) {
                if (e.getValue() == value)
                    return e;
            }
            return null;
        } catch (Exception ex) {
            throw new IllegalArgumentException("Cannot convert " + value + " to " + enumClass.getSimpleName() + " by code value.", ex);
        }
    }

    /*
     * 将枚举字符串装换为枚举类型
     */
    static <E extends Enum<E>> IBaseEnum valueOf(Class<E> enumClass,String value) {
        return (IBaseEnum) Enum.valueOf(enumClass, value);
    }
}
View Code
复制代码

然后,我们采用@Bean注解,将这个类型转换器注入到Spring容器中:

    /*
     * 注入自定义类型转换器ConversionService
     */
    @Bean
    public GenericConversionService getDefaultConversionService(@Autowired GenericConversionService conversionService) {
        conversionService.addConverterFactory(new EnumConverterFactory());
        return conversionService;
    }

可以看到这里是拿到了Spring容器中的GenericConversionService对象,然后调用addConverterFactory加入我们的类型转换器工厂。

顾名思义,ConverterRegistry接口就是用来注册各种转换器的:

复制代码
/*
 * Copyright 2002-2016 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.core.convert.converter;

/**
 * For registering converters with a type conversion system.
 *
 * @author Keith Donald
 * @author Juergen Hoeller
 * @since 3.0
 */
public interface ConverterRegistry {

    /**
     * Add a plain converter to this registry.
     * The convertible source/target type pair is derived from the Converter's parameterized types.
     * @throws IllegalArgumentException if the parameterized types could not be resolved
     */
    void addConverter(Converter<?, ?> converter);

    /**
     * Add a plain converter to this registry.
     * The convertible source/target type pair is specified explicitly.
     * <p>Allows for a Converter to be reused for multiple distinct pairs without
     * having to create a Converter class for each pair.
     * @since 3.1
     */
    <S, T> void addConverter(Class<S> sourceType, Class<T> targetType, Converter<? super S, ? extends T> converter);

    /**
     * Add a generic converter to this registry.
     */
    void addConverter(GenericConverter converter);

    /**
     * Add a ranged converter factory to this registry.
     * The convertible source/target type pair is derived from the ConverterFactory's parameterized types.
     * @throws IllegalArgumentException if the parameterized types could not be resolved
     */
    void addConverterFactory(ConverterFactory<?, ?> factory);

    /**
     * Remove any converters from {@code sourceType} to {@code targetType}.
     * @param sourceType the source type
     * @param targetType the target type
     */
    void removeConvertible(Class<?> sourceType, Class<?> targetType);

}
复制代码

3.4、执行 Spring 的初始化器ApplicationContextInitializer 

上篇文章说过在 Spring Boot 准备阶段初始化了一批在 spring.factories 文件中定义好的 ApplicationContextInitializer ,这里就是执行它们的 initialize 方法,同时向应用上下文beanFactoryPostProcessors列表添加两个对象:

protected void applyInitializers(ConfigurableApplicationContext context) {
        for (ApplicationContextInitializer initializer : getInitializers()) {
            Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(),
                    ApplicationContextInitializer.class);
            Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
            initializer.initialize(context);
        }
    }
/** BeanFactoryPostProcessors to apply on refresh. */
    private final List<BeanFactoryPostProcessor> beanFactoryPostProcessors = new ArrayList<>();

3.5、触发ApplicationContextInitializedEvent事件

执行 SpringApplicationRunListeners 的 contextPrepared 阶段方法,表示 ApplicationContext 准备完成,同时向 Spring Boot 监听器发布 ApplicationContextInitializedEvent 事件 。

3.6、注册单例Bean实例

将 springApplicationArguments 和 springBootBanner注册为单例Bean实例,至于为什么注册为单例Bean、可以参考博客:Spring 为啥默认把bean设计成单例的?Spring对象类型——单例和多例

/** Cache of singleton objects: bean name to bean instance. */
    private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

3.7、加载 Spring 应用上下文的配置源到BeanDefinitionMap

讲SpringApplication准备阶段获取的 primarySources注册到Spring容器 ,primarySources 来源于 SpringApplication 构造器参数;

 

3.8、触发ApplicationPreparedEvent事件

最后执行 SpringApplicationRunListeners 的 contextLoaded 阶段方法,表示 ApplicationContext 完成加载但还未启动,同时向 Spring Boot 监听器发布 ApplicationPreparedEvent 事件 。

四、刷新Spring应用上下文(refreshContext )

接下来就是真正启动阶段,执行的是 refreshContext 方法:

复制代码
    private void refreshContext(ConfigurableApplicationContext context) {
        refresh(context);
        if (this.registerShutdownHook) {
            try {
                context.registerShutdownHook();
            }
            catch (AccessControlException ex) {
                // Not allowed in some environments.
            }
        }
    }
复制代码

然后调用refresh方法:

protected void refresh(ApplicationContext applicationContext) {
        Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
        
        // 最终调用了 所有应用上下文的统一抽象类 AbstractApplicationContext 中的 refresh 方法,进入 
        ((AbstractApplicationContext) applicationContext).refresh();
    }
    

AbstractApplicationContext 的 refresh 方法如下:

复制代码
public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
        // 1. 初始化 refresh 的上下文环境,就是记录下容器的启动时间、标记已启动状态、处理配置文件中的占位符
        prepareRefresh();

        // 2. 初始化 BeanFactory,加载并解析配置
        ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();

        /* ---至此,已经完成了简单容器的所有功能,下面开始对简单容器进行增强--- */

        // 3. 对 BeanFactory 进行功能增强,如设置BeanFactory的类加载器,添加几个 BeanPostProcessor,手动注册几个特殊的 bean
        prepareBeanFactory(beanFactory);

        try {
            // 4. 后置处理 beanFactory,添加后置处理器
            postProcessBeanFactory(beanFactory);

            // 5. 调用已注册的 BeanFactoryPostProcessor
            invokeBeanFactoryPostProcessors(beanFactory);

            // 6. 注册 BeanPostProcessor,仅仅是注册,调用在getBean的时候
            registerBeanPostProcessors(beanFactory);

            // 7. 初始化国际化资源
            initMessageSource();

            // 8. 初始化事件广播器
            initApplicationEventMulticaster();

            // 9. 留给子类实现的模板方法
            onRefresh();

            // 10. 注册事件监听器
            registerListeners();

            // 11. 实例化所有非延迟加载的单例
            finishBeanFactoryInitialization(beanFactory);

            // 12. 完成刷新过程,发布应用事件
            finishRefresh();
            
        } catch (BeansException ex) {
            if (logger.isWarnEnabled()) {
                logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + ex);
            }
            
            // 13.销毁已经初始化的 singleton 的 Beans,以免有些 bean 会一直占用资源
            this.destroyBeans();
            
            // Reset 'active' flag.
            this.cancelRefresh(ex);
            // Propagate exception to caller.
            throw ex;
        } finally {
            // Reset common introspection caches in Spring's core, since we
            // might not ever need metadata for singleton beans anymore...
            this.resetCommonCaches();
        }
    }
}
复制代码

4.1、prepareRefresh

我们先从 refresh 中的 prepareRefresh 方法开始讨论:

复制代码
public class AnnotationConfigServletWebServerApplicationContext
        extends ServletWebServerApplicationContext implements AnnotationConfigRegistry {

    ...
    
    @Override
    protected void prepareRefresh() {
    
        // 清除 Class 的元数据缓存。底层用 Map 保存元数据,执行 Map 的 clear 方法
           this.scanner.clearCache();
        
        // 调用父类,也就是 AbstractApplicationContext 的 prepareRefresh 方法
        super.prepareRefresh();
    }
    ...     
}
复制代码

这里调用父类的prepareRefresh方法:

复制代码
public abstract class AbstractApplicationContext {
    
    ...
    
    private long startupDate;
    
    private final AtomicBoolean active = new AtomicBoolean();

    private final AtomicBoolean closed = new AtomicBoolean();

    private Set<ApplicationEvent> earlyApplicationEvents;

    ...

    protected void prepareRefresh() {
        
        // 记录此上下文开始时的系统时间(以毫秒为单位)
        this.startupDate = System.currentTimeMillis();
        
        // 记录此上下文是否已关闭,这里设置为未关闭
        this.closed.set(false);
        
        // 记录此上下文是否处于活动状态,这里设置为活动状态
        this.active.set(true);
    
        if (logger.isInfoEnabled()) {
            logger.info("Refreshing " + this);
        }
    
        // 这也是交由子类扩展的方法。具体子类为 GenericWebApplicationContext,主要是初始化属性源,
        // 将 ServletContext 和 ServletConfig 属性配置添加到 Environment 环境上下文中
        initPropertySources();
    
        // 校验 Environment 中那些必备的属性配置是否存在,不存在则抛异常。
        getEnvironment().validateRequiredProperties();
    
        // 创建 ApplicationEvent 事件集合
        this.earlyApplicationEvents = new LinkedHashSet<>();
    }

}
复制代码

refresh 中的 prepareRefresh 方法执行结束,主要是记录容器的启动时间、活动状态、检查必备属性是否存在。

4.2、obtainFreshBeanFactory

接着进入 refresh 中的 obtainFreshBeanFactory 方法:

复制代码
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
        // 该方法也是由子类扩展,其子类有 AbstractRefreshableApplicationContext 和 GenericApplicationContext,
        // 因当前是 Servlet Web 应用,所以执行的是 GenericApplicationContext 中的 refreshBeanFactory 方法。
        // 该方法主要设置 BeanFactory 的 serializationId 属性值,也就是序列化id
        refreshBeanFactory();
        
        // 通过 getBeanFactory 返回 BeanFactory 对象。同样也是由子类扩展,调用的是 GenericApplicationContext 类中的 getBeanFactory 方法。
        // 返回的是 DefaultListableBeanFactory 。
        ConfigurableListableBeanFactory beanFactory = getBeanFactory();
        if (logger.isDebugEnabled()) {
            logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
        }
        return beanFactory;
    }
复制代码

之后,该方法还返回了 BeanFactory 对象,从这也可以看出 ApplicationContext 底层是以 BeanFactory 为基础,逐步扩展 Spring 容器功能。

4.3、prepareBeanFactory

接着进入 refresh 中的 prepareBeanFactory 方法。prepareBeanFactory 方法主要是对 BeanFactory 做一些配置,包含各种类加载器、需要忽略的依赖以及后置处理器、解析器等:

复制代码
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    // 设置类加载器
    beanFactory.setBeanClassLoader(getClassLoader());
    // 设置表达式解析器,主要用来解析 EL 表达式; Bean 初始化完成后填充属性时会用到
    beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
    // 设置属性注册解析器,主要用来解析 Bean 中的各种属性类型,如 String、int 等
    beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
    // 添加一个后置处理器:ApplicationContextAwareProcessor。
    // 该后置处理器用于向实现了 Aware 系列接口的 bean 设置相应属性。
    // (后置处理器和 Aware 接口也是比较核心的概念)
    beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
    
    // 以下接口,在自动注入时会被忽略,其都是 Aware 系列接口
    beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
    beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
    beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
    beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
    beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
    beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);

    // 当以下特殊的 Bean 需自动注入时,指定其注入的类型 。
    // 如:注入 BeanFactory 时,注入的类型对象为 ConfigurableListableBeanFactory 。
    beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
    beanFactory.registerResolvableDependency(ResourceLoader.class, this);
    beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
    beanFactory.registerResolvableDependency(ApplicationContext.class, this);

    // 添加 ApplicationListenerDetector 后置处理器。
    // 该后置处理器用来检测那些实现了 ApplicationListener 接口的 bean,并将其添加到应用上下文的事件广播器上。
    beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));

    // 判断容器中是否存在 loadTimeWeaver Bean,如果存在则上下文使用临时的 ClassLoader 进行类型匹配。
    // 集成 AspectJ 时会用到 loadTimeWeaver 对象。
    if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
        beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
        beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
    }

    // 注册和环境相关的 Bean,如 environment、systemProperties、systemEnvironment
    if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
        beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
    }
    if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
        beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
    }
    if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
        beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
    }
}
复制代码

在 prepareBeanFactory 方法中,主要对 BeanFactory 添加了一系列属性项,如添加忽略自动注入的接口、添加 BeanPostProcessor 后置处理器、手动注册部分特殊的 Bean及环境相关的 Bean,值得注意的是这些Bean都是单例的 ,因此直接保存单例Bean实例。

    /**
     * Dependency interfaces to ignore on dependency check and autowire, as Set of
     * Class objects. By default, only the BeanFactory interface is ignored.
     */
    private final Set<Class<?>> ignoredDependencyInterfaces = new HashSet<>();

 

    /** BeanPostProcessors to apply in createBean. */
    private final List<BeanPostProcessor> beanPostProcessors = new CopyOnWriteArrayList<>();

/** Cache of singleton objects: bean name to bean instance. */
    private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

 

4.4、postProcessBeanFactory

postProcessBeanFactory 方法是上下文准备的最后一步,主要用来注册 Web 请求相关的处理器、Bean及配置。

复制代码
public class AnnotationConfigServletWebServerApplicationContext
        extends ServletWebServerApplicationContext implements AnnotationConfigRegistry {

    private final AnnotatedBeanDefinitionReader reader;

    private final ClassPathBeanDefinitionScanner scanner;

    private final Set<Class<?>> annotatedClasses = new LinkedHashSet<>();

    private String[] basePackages;
    
    ...
    
    @Override
    protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        // 先执行父类 ServletWebServerApplicationContext 的 postProcessBeanFactory 方法。
        // 跳转到 1 查看父类实现
        super.postProcessBeanFactory(beanFactory);
        
        // basePackages 存储的是类路径。先判断是否为 null,不为 null 则通过 ClassPathBeanDefinitionScanner 的 scan 方法
        // 扫描该路径下符合条件的 Class,并将 Class 信息包装成 BeanDefinition 注册到容器中,
        // 当然,这里没有指定扫描路径,所以不会进入这个 if。
        // (BeanDefinition 概念会在后面章节详细讨论)
     if (this.basePackages != null && this.basePackages.length > 0) {
            this.scanner.scan(this.basePackages);
        }
        
        // annotatedClasses 存储的 Class 集合。先判断该集合是否为空,不为空则通过
        // AnnotatedBeanDefinitionReader 的 register 方法将 Class 信息包装成 BeanDefinition 注册到容器中,
        // 这里同样没有设置 Class 集合内容,所以不会进入这个 if。
         if (!this.annotatedClasses.isEmpty()) {
            this.reader.register(ClassUtils.toClassArray(this.annotatedClasses));
        }
    }       
}

//1
public class ServletWebServerApplicationContext extends GenericWebApplicationContext
        implements ConfigurableWebServerApplicationContext {
    ...

    @Override
    protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        // 添加 BeanPostProcessor 后置处理器:WebApplicationContextServletContextAwareProcessor,
        // 该后置处理器主要是从 ConfigurableWebApplicationContext 上下文中获取 ServletContext 和 ServletConfig 对象
       beanFactory.addBeanPostProcessor(new WebApplicationContextServletContextAwareProcessor(this));
        // 添加一个 忽略自动注入的接口                     
 beanFactory.ignoreDependencyInterface(ServletContextAware.class);
    }
    ...         
}
复制代码

postProcessBeanFactory 方法执行的操作和前面类似,也是添加了后置处理器和忽略自动注入的接口。

 

五、BeanDefinition

原计划是对接下来的 invokeBeanFactoryPostProcessors 方法进行讨论,但该方法涉及 Spring 中一个非常重要的概念: BeanDefinition,其实上面我们也提到了,只是没有具体的介绍,所以,这里先对 BeanDefinition 进行讨论,这样也有利于完善 Spring 的知识体系。 

现如今,我们一般获取对象的方式有两种:

  • 一种是手动直接 new;
  • 另一种是交给 Spring 管理,Spring 将管理的对象称之为 Bean,容器会先实例化 Bean,然后自动注入,实例化的过程就需要依赖 BeanDefinition。

BeanDefinition 用于保存 Bean 的相关信息,包括属性、构造方法参数、依赖的 Bean 名称及是否单例、延迟加载等,它是实例化 Bean 的原材料,Spring 就是根据 BeanDefinition 中的信息实例化 Bean。

BeanDefinition 是一个接口,它有多个实现类,这些实现类分别描述不同类型的 Bean。

亲爱的读者和支持者们,自动博客加入了打赏功能,陆陆续续收到了各位老铁的打赏。在此,我想由衷地感谢每一位对我们博客的支持和打赏。你们的慷慨与支持,是我们前行的动力与源泉。

日期姓名金额
2023-09-06*源19
2023-09-11*朝科88
2023-09-21*号5
2023-09-16*真60
2023-10-26*通9.9
2023-11-04*慎0.66
2023-11-24*恩0.01
2023-12-30I*B1
2024-01-28*兴20
2024-02-01QYing20
2024-02-11*督6
2024-02-18一*x1
2024-02-20c*l18.88
2024-01-01*I5
2024-04-08*程150
2024-04-18*超20
2024-04-26.*V30
2024-05-08D*W5
2024-05-29*辉20
2024-05-30*雄10
2024-06-08*:10
2024-06-23小狮子666
2024-06-28*s6.66
2024-06-29*炼1
2024-06-30*!1
2024-07-08*方20
2024-07-18A*16.66
2024-07-31*北12
2024-08-13*基1
2024-08-23n*s2
2024-09-02*源50
2024-09-04*J2
2024-09-06*强8.8
2024-09-09*波1
2024-09-10*口1
2024-09-10*波1
2024-09-12*波10
2024-09-18*明1.68
2024-09-26B*h10
2024-09-3010
2024-10-02M*i1
2024-10-14*朋10
2024-10-22*海10
2024-10-23*南10
2024-10-26*节6.66
2024-10-27*o5
2024-10-28W*F6.66
2024-10-29R*n6.66
2024-11-02*球6
2024-11-021*鑫6.66
2024-11-25*沙5
2024-11-29C*n2.88
posted @   大奥特曼打小怪兽  阅读(2411)  评论(0编辑  收藏  举报
编辑推荐:
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
如果有任何技术小问题,欢迎大家交流沟通,共同进步

公告 & 打赏

>>

欢迎打赏支持我 ^_^

最新公告

程序项目代做,有需求私信(小程序、网站、爬虫、电路板设计、驱动、应用程序开发、毕设疑难问题处理等)。

了解更多

点击右上角即可分享
微信分享提示