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。

5.1、BeanDefinition

一個 BeanDefinition 描述了一個 Bean 實例,實例包含屬性值、構造方法參數值以及更多實現信息。該 BeanDefinition 只是是一個最小的接口,主要目的是允許修改屬性值和其他 Bean 元數據,這里列出幾個核心方法。

public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement { // 單例、原型標識符
    String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON; String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE; // 標識 Bean 的類別,分別對應 用戶定義的 Bean、來源於配置文件的 Bean、Spring 內部的 Bean
    int ROLE_APPLICATION = 0; int ROLE_SUPPORT = 1; int ROLE_INFRASTRUCTURE = 2; // 設置、返回 Bean 的父類名稱
    void setParentName(@Nullable String parentName); String getParentName(); // 設置、返回 Bean 的 className
    void setBeanClassName(@Nullable String beanClassName); String getBeanClassName(); // 設置、返回 Bean 的作用域
    void setScope(@Nullable String scope); String getScope(); // 設置、返回 Bean 是否懶加載
    void setLazyInit(boolean lazyInit); boolean isLazyInit(); // 設置、返回當前 Bean 所依賴的其它 Bean 名稱。
    void setDependsOn(@Nullable String... dependsOn); String[] getDependsOn(); // 設置、返回 Bean 是否可以自動注入。只對 @Autowired 注解有效
    void setAutowireCandidate(boolean autowireCandidate); boolean isAutowireCandidate(); // 設置、返回當前 Bean 是否為主要候選 Bean 。 // 當同一個接口有多個實現類時,通過該屬性來配置某個 Bean 為主候選 Bean。
    void setPrimary(boolean primary); boolean isPrimary(); // 設置、返回創建該 Bean 的工廠類。
    void setFactoryBeanName(@Nullable String factoryBeanName); String getFactoryBeanName(); // 設置、返回創建該 Bean 的工廠方法
    void setFactoryMethodName(@Nullable String factoryMethodName); String getFactoryMethodName(); // 返回該 Bean 構造方法參數值、所有屬性
 ConstructorArgumentValues getConstructorArgumentValues(); MutablePropertyValues getPropertyValues(); // 返回該 Bean 是否是單例、是否是非單例、是否是抽象的
    boolean isSingleton(); boolean isPrototype(); boolean isAbstract(); // 返回 Bean 的類別。類別對應上面的三個屬性值。
    int getRole(); ... }

可以看到 BeanDefinition 接口提供了一系列操作 Bean 元數據的set、get方法,這些操作為 Bean 的描述定義了一套模板,具體的實現則交由子類。

5.2、AnnotatedBeanDefinition

AnnotatedBeanDefinition 是 BeanDefinition 子接口之一,該接口擴展了 BeanDefinition 的功能,其用來操作注解元數據。一般情況下,通過注解方式得到的 Bean(@Component、@Bean),其 BeanDefinition 類型都是該接口的實現類。

public interface AnnotatedBeanDefinition extends BeanDefinition { // 獲得當前 Bean 的注解元數據
 AnnotationMetadata getMetadata(); // 獲得當前 Bean 的工廠方法上的元數據
 MethodMetadata getFactoryMethodMetadata(); }

該接口可以返回兩個元數據的類:

  • AnnotationMetadata:主要對 Bean 的注解信息進行操作,如:獲取當前 Bean 標注的所有注解、判斷是否包含指定注解。
  • MethodMetadata:方法的元數據類。提供獲取方法名稱、此方法所屬類的全類名、是否是抽象方法、判斷是否是靜態方法、判斷是否是final方法等 ;

5.3、AbstractBeanDefinition

AbstractBeanDefinition 是 BeanDefinition 的子抽象類,也是其他 BeanDefinition 類型的基類,其實現了接口中定義的一系列操作方法,並定義了一系列的常量屬性,這些常量會直接影響到 Spring 實例化 Bean 時的策略。核心屬性如下。 

public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccessor implements BeanDefinition, Cloneable { // 默認的 SCOPE,默認是單例
    public static final String SCOPE_DEFAULT = ""; // 不進行自動裝配
    public static final int AUTOWIRE_NO = AutowireCapableBeanFactory.AUTOWIRE_NO; // 根據 Bean 的名字進行自動裝配,byName
    public static final int AUTOWIRE_BY_NAME = AutowireCapableBeanFactory.AUTOWIRE_BY_NAME; // 根據 Bean 的類型進行自動裝配,byType
    public static final int AUTOWIRE_BY_TYPE = AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE; // 根據構造器進行自動裝配
    public static final int AUTOWIRE_CONSTRUCTOR = AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR; // 首先嘗試按構造器自動裝配。如果失敗,再嘗試使用 byType 進行自動裝配。(Spring 3.0 之后已廢除)
    public static final int AUTOWIRE_AUTODETECT = AutowireCapableBeanFactory.AUTOWIRE_AUTODETECT; // 通過依賴檢查來查看 Bean 的每個屬性是否都設置完成 // 以下常量分別對應:不檢查、對依賴對象檢查、對基本類型,字符串和集合進行檢查、對全部屬性進行檢查
    public static final int DEPENDENCY_CHECK_NONE = 0; public static final int DEPENDENCY_CHECK_OBJECTS = 1; public static final int DEPENDENCY_CHECK_SIMPLE = 2; public static final int DEPENDENCY_CHECK_ALL = 3; // 關閉應用上下文時需調用的方法名稱
    public static final String INFER_METHOD = "(inferred)"; // 存放 Bean 的 Class 對象
    private volatile Object beanClass; // Bean 的作用范圍
    private String scope = SCOPE_DEFAULT; // 非抽象
    private boolean abstractFlag = false; // 非延遲加載
    private boolean lazyInit = false; // 默認不自動裝配
    private int autowireMode = AUTOWIRE_NO; // 默認不依賴檢查
    private int dependencyCheck = DEPENDENCY_CHECK_NONE; // 依賴的 Bean 列表
    private String[] dependsOn; // 可以作為自動裝配的候選者,意味着可以自動裝配到其他 Bean 的某個屬性中
    private boolean autowireCandidate = true; // 創建當前 Bean 實例工廠類名稱
    private String factoryBeanName; // 創建當前 Bean 實例工廠類中方法名稱
    private String factoryMethodName; // 存儲構造方法的參數
    private ConstructorArgumentValues constructorArgumentValues; // 存儲 Bean 屬性名稱以及對應的值
    private MutablePropertyValues propertyValues; // 存儲被覆蓋的方法信息
    private MethodOverrides methodOverrides; // init、destroy 方法名稱
    private String initMethodName; private String destroyMethodName; // 是否執行 init 和 destroy 方法
    private boolean enforceInitMethod = true; private boolean enforceDestroyMethod = true; // Bean 是否是用戶定義的而不是應用程序本身定義的
    private boolean synthetic = false; // Bean 的身份類別,默認是用戶定義的 Bean
    private int role = BeanDefinition.ROLE_APPLICATION; // Bean 的描述信息
    private String description; // Bean 定義的資源
    private Resource resource; ... }

以上是 AbstractBeanDefinition 中定義的一些常量和屬性,該類中還有一部分是操作這些屬性的 set 和 get 方法,這些方法都由子類來操作,且應用程序中真正使用的也是這些子類 BeanDefinition。 先來看 AbstractBeanDefinition 直接實現類:RootBeanDefinition、GenericBeanDefinition、ChildBeanDefinition。

5.4、RootBeanDefinition

該類繼承自 AbstractBeanDefinition,它可以單獨作為一個 BeanDefinition,也可以作為其他 BeanDefinition 的父類。 RootBeanDefinition 在 AbstractBeanDefinition 的基礎上定義了更多屬性。 

public class RootBeanDefinition extends AbstractBeanDefinition { // BeanDefinitionHolder 存儲 Bean 的名稱、別名、BeanDefinition
    private BeanDefinitionHolder decoratedDefinition; // AnnotatedElement 是java反射包的接口,通過它可以查看 Bean 的注解信息
    private AnnotatedElement qualifiedElement; // 允許緩存
    boolean allowCaching = true; // 工廠方法是否唯一
    boolean isFactoryMethodUnique = false; // 封裝了 java.lang.reflect.Type,提供了泛型相關的操作
    volatile ResolvableType targetType; // 緩存 Class,表示 RootBeanDefinition 存儲哪個類的信息
    volatile Class<?> resolvedTargetType; // 緩存工廠方法的返回類型
    volatile ResolvableType factoryMethodReturnType; // 這是以下四個構造方法字段的通用鎖
    final Object constructorArgumentLock = new Object(); // 用於緩存已解析的構造方法或工廠方法
 Executable resolvedConstructorOrFactoryMethod; // 將構造方法參數標記為已解析
    boolean constructorArgumentsResolved = false; // 用於緩存完全解析的構造方法參數
 Object[] resolvedConstructorArguments; // 緩存待解析的構造方法參數
 Object[] preparedConstructorArguments; // 這是以下兩個后處理字段的通用鎖
    final Object postProcessingLock = new Object(); // 表明是否被 MergedBeanDefinitionPostProcessor 處理過
    boolean postProcessed = false; // 在生成代理的時候會使用,表明是否已經生成代理
    volatile Boolean beforeInstantiationResolved; // 實際緩存的類型是 Constructor、Field、Method 類型
    private Set<Member> externallyManagedConfigMembers; // InitializingBean中 的 init 回調函數名 afterPropertiesSet 會在這里記錄,以便進行生命周期回調
    private Set<String> externallyManagedInitMethods; // DisposableBean 的 destroy 回調函數名 destroy 會在這里記錄,以便進生命周期回調
    private Set<String> externallyManagedDestroyMethods; ... }

5.5、ChildBeanDefinition

該類繼承自 AbstractBeanDefinition。其相當於一個子類,不可以單獨存在,必須依賴一個父 BeanDetintion,構造 ChildBeanDefinition 時,通過構造方法傳入父 BeanDetintion 的名稱或通過 setParentName 設置父名稱。它可以從父類繼承方法參數、屬性值,並可以重寫父類的方法,同時也可以增加新的屬性或者方法。若重新定義 init 方法,destroy 方法或者靜態工廠方法,ChildBeanDefinition 會重寫父類的設置。

從 Spring 2.5 開始,以編程方式注冊 Bean 定義的首選方法是 GenericBeanDefinition,GenericBeanDefinition 可以有效替代 ChildBeanDefinition 的絕大分部使用場合。

5.6、GenericBeanDefinition

GenericBeanDefinition 是 Spring 2.5 以后新引入的 BeanDefinition,是 ChildBeanDefinition 更好的替代者,它同樣可以通過 setParentName 方法設置父 BeanDefinition。

5.7、 ConfigurationClassBeanDefinition

該類繼承自 RootBeanDefinition ,並實現了 AnnotatedBeanDefinition 接口。這個 BeanDefinition 用來描述在標注 @Configuration 注解的類中,通過 @Bean 注解實例化的 Bean。

其功能特點如下:

1、如果 @Bean 注解沒有指定 Bean 的名字,默認會用方法的名字命名 Bean。

2、標注 @Configuration 注解的類會成為一個工廠類,而標注 @Bean 注解的方法會成為工廠方法,通過工廠方法實例化 Bean,而不是直接通過構造方法初始化。

3、標注 @Bean 注解的類會使用構造方法自動裝配;

5.8、AnnotatedGenericBeanDefinition

該類繼承自 GenericBeanDefinition ,並實現了 AnnotatedBeanDefinition 接口。這個 BeanDefinition 用來描述標注 @Configuration 注解的 Bean。

5.9、ScannedGenericBeanDefinition

該類繼承自 GenericBeanDefinition ,並實現了 AnnotatedBeanDefinition 接口。 這個 BeanDefinition 用來描述標注 @Component 注解的 Bean,其派生注解如 @Service、@Controller 也同理。

最后,我們來做個總結。BeanDefinition 主要是用來描述 Bean,其存儲了 Bean 的相關信息,Spring 實例化 Bean 時需讀取該 Bean 對應的 BeanDefinition。BeanDefinition 整體可以分為兩類,一類是描述通用的 Bean,還有一類是描述注解形式的 Bean。一般前者在 XML 時期定義 <bean> 標簽以及在 Spring 內部使用較多,而現今我們大都使用后者,通過注解形式加載 Bean。

六、BeanDefinitionRegistry(注冊BeanDefinition)

上面我們已經對 BeanDefinition 進行了討論,BeanDefinition 是對 Bean 的定義,其保存了 Bean 的各種信息,如屬性、構造方法參數、是否單例、是否延遲加載等。這里將會介紹如何將Bean定義成BeanDefinition,之后放入Spring容器中,我們常說的Spring容器其實就是我們上面介紹到的BeanFactory中的beanDefinitionMap,這是一個Map,key為Bean的名稱,value是Bean的BeanDefinition。

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

我們已經知道應用上下文中的BeanFactory的實現類是DefaultListableBeanFactory,是一個具有注冊功能的完整 Bean 工廠,注冊 Bean 的方法是 registerBeanDefinition,DefaultListableBeanFactory 通過實現 BeanDefinitionRegistry 接口,重寫該方法。 

public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable { ... @Override public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException { ... } ... }

討論 registerBeanDefinition 方法之前,先來簡單介紹 BeanDefinitionRegistry 接口。

6.1、BeanDefinitionRegistry

BeanDefinitionRegistry 是一個接口,它定義了關於 BeanDefinition 的注冊、移除、查詢等一系列的操作。

public interface BeanDefinitionRegistry extends AliasRegistry { // 注冊 BeanDefinition
    void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException; // 移除 BeanDefinition
    void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException; // 獲取 BeanDefinition
    BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException; // 根據 beanName 判斷容器是否存在對應的 BeanDefinition 
    boolean containsBeanDefinition(String beanName); // 獲取所有的 BeanDefinition
 String[] getBeanDefinitionNames(); // 獲取 BeanDefinition 數量
    int getBeanDefinitionCount(); // 判斷 beanName 是否被占用
    boolean isBeanNameInUse(String beanName); }

該接口有三個實現類:DefaultListableBeanFactory、GenericApplicationContext、SimpleBeanDefinitionRegistry,其中 GenericApplicationContext 底層調用的是 DefaultListableBeanFactory 中的實現方法,所以嚴格意義上來說,只有兩個實現類。這里,我們主要討論 DefaultListableBeanFactory 中的方法實現。 

6.2、registerBeanDefinition 方法注冊 Bean

前面說過 registerBeanDefinition 方法的主要實現類是 DefaultListableBeanFactory :

public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable { ... // 存儲所有的 BeanDefinition ,key 是 Bean 的名稱。我們一直稱呼的容器,底層就是這個 Map
    private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256); // 存儲所有 Bean 名稱
    private volatile List<String> beanDefinitionNames = new ArrayList<>(256); // 存儲手動注冊的單例 Bean 名稱
    private volatile Set<String> manualSingletonNames = new LinkedHashSet<>(16); // 存儲凍結的 BeanDefinition,留作后面緩存用
    private volatile String[] frozenBeanDefinitionNames; ... // 方法的入參為 Bean 名稱和對應的 BeanDefinition
 @Override public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException { Assert.hasText(beanName, "Bean name must not be empty"); Assert.notNull(beanDefinition, "BeanDefinition must not be null"); // 如果 beanDefinition 的實例為 AbstractBeanDefinition,則進行驗證
        if (beanDefinition instanceof AbstractBeanDefinition) { try { // 驗證: // 如果有重寫方法,但是是工廠方法,則拋出異常,因為重寫方法需要代理,而工廠方法無法代理; // 通過方法名稱,判斷 Bean 中該名稱方法存在的數量,0:方法不存在,報錯;1:方法非重載,overloaded 屬性設為 false;
 ((AbstractBeanDefinition) beanDefinition).validate(); } catch (BeanDefinitionValidationException ex) { throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Validation of bean definition failed", ex); } } BeanDefinition oldBeanDefinition; // 先從 beanDefinitionMap 中嘗試獲取 beanName 對應 BeanDefinition
        oldBeanDefinition = this.beanDefinitionMap.get(beanName); // 不為 null,則 beanName 對應的 BeanDefinition 已經存在
        if (oldBeanDefinition != null) { // 是否應允許覆蓋 BeanDefinition,不允許則拋異常
            if (!isAllowBeanDefinitionOverriding()) { throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
                        "': There is already [" + oldBeanDefinition + "] bound."); } /***************************** 若允許覆蓋 *****************************/
            
            // 判斷 Bean 的角色大小: // 0:用戶定義的 Bean、1:來源於配置文件的 Bean、2:Spring 內部的 Bean; // 當原 BeanDefinition 角色小於新的 BeanDefinition 角色時,輸出一個 warn 日志,提示 BeanDefinition 被覆蓋
            else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) { // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
                if (this.logger.isWarnEnabled()) { this.logger.warn("Overriding user-defined bean definition for bean '" + beanName +
                            "' with a framework-generated bean definition: replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]"); } } // 當新 BeanDefinition 屬性值不等於原 BeanDefinition 屬性值時,輸出 info 提示信息
            else if (!beanDefinition.equals(oldBeanDefinition)) { if (this.logger.isInfoEnabled()) { this.logger.info("Overriding bean definition for bean '" + beanName +
                            "' with a different definition: replacing [" + oldBeanDefinition +
                            "] with [" + beanDefinition + "]"); } } // 最后,輸出 debug 日志信息:用等效的新 BeanDefinition 覆蓋原 BeanDefinition
            else { if (this.logger.isDebugEnabled()) { this.logger.debug("Overriding bean definition for bean '" + beanName +
                            "' with an equivalent definition: replacing [" + oldBeanDefinition +
                            "] with [" + beanDefinition + "]"); } } // 添加至 BeanDefinition 集合,並覆蓋原 BeanDefinition
            this.beanDefinitionMap.put(beanName, beanDefinition); } // Map 中無對應的 BeanDefinition,則直接注冊
        else { // 已開始創建 Bean 
            if (hasBeanCreationStarted()) { synchronized (this.beanDefinitionMap) { // 將 Bean 對應的 BeanDefinition 放入 beanDefinitionMap 中
                    this.beanDefinitionMap.put(beanName, beanDefinition); // 創建新的 beanNames 集合,並將已緩存的 beanName 和新的 beanName 加入該集合
                    List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1); updatedDefinitions.addAll(this.beanDefinitionNames); updatedDefinitions.add(beanName); this.beanDefinitionNames = updatedDefinitions; // 在手動注冊 Bean 的集合中,如果存在同名的 beanName,則將集合中同名的 beanName 刪除
                    if (this.manualSingletonNames.contains(beanName)) { Set<String> updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames); updatedSingletons.remove(beanName); this.manualSingletonNames = updatedSingletons; } } } // 仍處於啟動注冊階段
            else { // 將當前 Bean 對應的 BeanDefinition 放入 beanDefinitionMap 中
                this.beanDefinitionMap.put(beanName, beanDefinition); // 將當前 beanName 放入 beanDefinitionNames
                this.beanDefinitionNames.add(beanName); // 刪除手動注冊 Bean 集合中同名的 beanName
                this.manualSingletonNames.remove(beanName); } // 將存儲凍結 BeanDefinition 的 Map 置為 null
            this.frozenBeanDefinitionNames = null; } // 當前注冊的 BeanDefinition 已在 beanDefinitionMap 中存在,或者其實例已在存儲單例 Bean 的 Map 中存在
        if (oldBeanDefinition != null || containsSingleton(beanName)) { // 重置 BeanDefinition,主要做一些清理工作
 resetBeanDefinition(beanName); } } }

執行完 registerBeanDefinition 方法后,Bean 的名稱和對應的 BeanDefinition 就被放入了容器中,后續獲取 Bean 也是從這個容器中獲取。

當然,DefaultListableBeanFactory 還實現了 BeanDefinitionRegistry 接口的其它方法,如對 BeanDefinition 進行移除、判斷是否存在、獲取數量等操作,其實都是圍繞 beanDefinitionMap 這個 Map 進行的,這里就不詳細介紹。

除了BeanDefinitionRegister的,Spring還提供了一個統一操作單例Bean的類SingletonBeanRegistry,通過該類可直接對單例 Bean 的實例進行存儲、注冊等操作。

七、SingletonBeanRegistry(注冊單例Bean實例)

SingletonBeanRegistry 是一個接口,其定義了操作單例 Bean 實例的一些基礎方法:

public interface SingletonBeanRegistry { // 注冊單例 Bean。其實就是將該 Bean 保存到一個專門存儲單例 Bean 實例的Map中,Key是 beanName,Value是對應的單例 Bean 實例
    void registerSingleton(String beanName, Object singletonObject); // 通過 beanName 獲取該單例 Bean 實例
 Object getSingleton(String beanName); // 通過 beanName 判斷該單例 Bean 實例是否存在
    boolean containsSingleton(String beanName); // 返回所有單例 Bean 的名稱
 String[] getSingletonNames(); // 返回已注冊的單例 Bean 實例數量
    int getSingletonCount(); // 返回當前使用的單例鎖,主要提供給外部協作者使用
 Object getSingletonMutex(); }

這個接口的核心實現類是 DefaultSingletonBeanRegistry,該類不僅實現了這些基礎方法,還針對單例 Bean 擴展了許多功能,如:存儲 Bean 之間的依賴關系、存儲 Bean 的包含關系(外部類包含內部類)、獲取 Bean 所處的狀態(正在創建、創建完畢等)、回調銷毀 Bean 時觸發的 destroy 方法等。

下面是 DefaultSingletonBeanRegistry 類中的核心屬性和方法:

public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry { /********** 1、定義的一些 Map 屬性,用來保存單例 Bean 實例、 Bean 的依賴關系 **********/

    // 緩存單例 Bean 實例,Key 是 beanName,Value 是單例 Bean 實例
    private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256); // 緩存 Bean 對應的 ObjectFactory // ObjectFactory 是獲取 Bean 實例的工廠,只不過這里獲取的 Bean 還未完全實例化,屬於提早暴露的 Bean // 該屬性在解決循環依賴時使用,后續會深入討論
    private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16); // 緩存 singletonFactories 屬性中通過 ObjectFactory 創建的 Bean // 該屬性也是在解決循環依賴時使用,后續會深入討論
    private final Map<String, Object> earlySingletonObjects = new HashMap<>(16); // 保存已注冊的單例 Bean 名稱
    private final Set<String> registeredSingletons = new LinkedHashSet<>(256); // 保存當前正在創建的 Bean 的名稱
    private final Set<String> singletonsCurrentlyInCreation = Collections.newSetFromMap(new ConcurrentHashMap<>(16)); // 保存當前從創建檢查中排除的 Bean 的名稱
    private final Set<String> inCreationCheckExclusions = Collections.newSetFromMap(new ConcurrentHashMap<>(16)); ... // 當前 Bean 是否處於銷毀狀態
    private boolean singletonsCurrentlyInDestruction = false; // 保存實現了 DisposableBean 接口的 Bean,在銷毀 Bean 時,會回調該 Bean 中的 destory 方法
    private final Map<String, Object> disposableBeans = new LinkedHashMap<>(); // 保存 Bean 的包含關系,key 是 Bean 的名稱,value 是 Bean 里面包含的其它 Bean 名稱集合
    private final Map<String, Set<String>> containedBeanMap = new ConcurrentHashMap<>(16); // 保存 Bean 的依賴關系:key 是 Bean 的名稱,value 是依賴於該 Bean 的其它 Bean 名稱集合
    private final Map<String, Set<String>> dependentBeanMap = new ConcurrentHashMap<>(64); // 保存 Bean 的依賴關系:key 是 Bean 的名稱,value 是該 Bean 所依賴的其它 Bean 名稱集合
    private final Map<String, Set<String>> dependenciesForBeanMap = new ConcurrentHashMap<>(64); /******************************** 2、注冊單例 Bean 實例及對應的實例工廠 ********************************/

    // 注冊單例 Bean 實例
 @Override public void registerSingleton(String beanName, Object singletonObject) throws IllegalStateException { Assert.notNull(beanName, "Bean name must not be null"); Assert.notNull(singletonObject, "Singleton object must not be null"); synchronized (this.singletonObjects) { // 通過 beanName 獲取 Map 中對應的單例 Bean 實例
            Object oldObject = this.singletonObjects.get(beanName); // 如果不為空,則拋出異常,因為單例已經存在,無法再次注冊
            if (oldObject != null) { throw new IllegalStateException("Could not register object [" + singletonObject +
                        "] under bean name '" + beanName + "': there is already object [" + oldObject + "] bound"); } // 為空,則進入 addSingleton 方法
 addSingleton(beanName, singletonObject); } } // 緩存單例 Bean 實例
    protected void addSingleton(String beanName, Object singletonObject) { synchronized (this.singletonObjects) { // 將單例 Bean 實例存放至 singletonObjects 集合
            this.singletonObjects.put(beanName, singletonObject); // 當 beanName 對應的 Bean 實例已被存放至 singletonObjects 集合時,singletonFactories // 和 earlySingletonObjects 集合則不能再持有 beanName 對應的 ObjectFactory 和實例 // 其中原因會在后續循環依賴的文章深入討論
            this.singletonFactories.remove(beanName); this.earlySingletonObjects.remove(beanName); // 存儲 Bean 名稱
            this.registeredSingletons.add(beanName); } } // 緩存 Bean 對應的 ObjectFactory
    protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) { Assert.notNull(singletonFactory, "Singleton factory must not be null"); synchronized (this.singletonObjects) { if (!this.singletonObjects.containsKey(beanName)) { this.singletonFactories.put(beanName, singletonFactory); this.earlySingletonObjects.remove(beanName); this.registeredSingletons.add(beanName); } } } /********************************* 3、獲取單例 Bean 實例 *********************************/ @Override public Object getSingleton(String beanName) { // 該方法較為復雜,在后續結合循環依賴的場景討論
 } ... /***************************** 4、對單例 Bean 實例的基礎操作 *****************************/

    // 刪除單例 Bean 實例
    protected void removeSingleton(String beanName) { synchronized (this.singletonObjects) { this.singletonObjects.remove(beanName); this.singletonFactories.remove(beanName); this.earlySingletonObjects.remove(beanName); this.registeredSingletons.remove(beanName); } } // 判斷 beanName 對應的單例 Bean 實例時候存在
 @Override public boolean containsSingleton(String beanName) { return this.singletonObjects.containsKey(beanName); } // 返回所有單例 Bean 的 beanName
 @Override public String[] getSingletonNames() { synchronized (this.singletonObjects) { return StringUtils.toStringArray(this.registeredSingletons); } } // 返回單例 Bean 實例數量
 @Override public int getSingletonCount() { synchronized (this.singletonObjects) { return this.registeredSingletons.size(); } } ... /*************************************** 5、 Bean 的狀態 **************************************/

    // beanName 對應的 Bean 是否處於實例化階段
    public boolean isCurrentlyInCreation(String beanName) { Assert.notNull(beanName, "Bean name must not be null"); return (!this.inCreationCheckExclusions.contains(beanName) && isActuallyInCreation(beanName)); } protected boolean isActuallyInCreation(String beanName) { return isSingletonCurrentlyInCreation(beanName); } public boolean isSingletonCurrentlyInCreation(String beanName) { return this.singletonsCurrentlyInCreation.contains(beanName); } // 單例 Bean 實例化前執行,將正要創建的 Bean 加入 singletonsCurrentlyInCreation 集合
    protected void beforeSingletonCreation(String beanName) { if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) { throw new BeanCurrentlyInCreationException(beanName); } } // 單例 Bean 實例化后執行,從 singletonsCurrentlyInCreation 集合中移除已創建的 Bean 
    protected void afterSingletonCreation(String beanName) { if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)) { throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation"); } } ... /********************* 6、 存儲 Bean 之間的關系、判斷 Bean 之間的關系 *********************/
    
    // 保存具有包含關系的 Bean(內部類與外部類)
    public void registerContainedBean(String containedBeanName, String containingBeanName) { synchronized (this.containedBeanMap) { Set<String> containedBeans =
                    this.containedBeanMap.computeIfAbsent(containingBeanName, k -> new LinkedHashSet<>(8)); if (!containedBeans.add(containedBeanName)) { return; } } registerDependentBean(containedBeanName, containingBeanName); } // 保存具有依賴關系的 Bean
    public void registerDependentBean(String beanName, String dependentBeanName) { String canonicalName = canonicalName(beanName); synchronized (this.dependentBeanMap) { Set<String> dependentBeans =
                    this.dependentBeanMap.computeIfAbsent(canonicalName, k -> new LinkedHashSet<>(8)); if (!dependentBeans.add(dependentBeanName)) { return; } } synchronized (this.dependenciesForBeanMap) { Set<String> dependenciesForBean =
                    this.dependenciesForBeanMap.computeIfAbsent(dependentBeanName, k -> new LinkedHashSet<>(8)); dependenciesForBean.add(canonicalName); } } ... /***************************** 7、 銷毀 Bean 的方法 *****************************/ ... }

DefaultSingletonBeanRegistry 類中的屬性及方法雖然很多,但也有規律可循的,大致分為對單例 Bean 實例的操作、管理 Bean 之間關系、針對Bean的不同狀態進行操作及銷毀 Bean 的操作。 該類中的核心還是那些 Map,類中的所有方法都是對這些 Map 進行操作,而這些 Map 中存儲的是不同場景下的單例 Bean 。 

參考文章:

[1]Spring(二)核心容器 - 簡介 、BeanFactory、ApplicationContext(轉載)

[2]Spring(三)核心容器 - ApplicationContext 上下文啟動准備(轉載)

[3]Spring(四)核心容器 - BeanDefinition 解析(轉載)

[4]Spring(五)核心容器 - 注冊 Bean、BeanDefinitionRegistry簡介(轉載)

[5]Spring(六)核心容器 - 注冊單例 Bean 實例、SingletonBeanRegistry 簡介(轉載)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM