Spring bean的生命周期-前篇

Spring bean生命周期12個環(huán)節(jié)

  • 1.階段1:Bean元信息配置階段

  • 2.階段2:Bean元信息解析階段

  • 3.階段3:將Bean注冊到容器中

  • 4.階段4:BeanDefinition合并階段

    1. 階段5:Bean Class加載階段
  • 6.階段6:Bean實例化階段(2個小階段)

    • Bean實例化前階段
    • Bean實例化階段
    1. 階段7:合并后的BeanDefinition處理
    1. 階段8:屬性賦值階段(3個小階段)
    • Bean實例化后階段
    • Bean屬性賦值前階段
    • Bean屬性賦值階段
  • 9.階段9:Bean初始化階段(4個小階段)

    • Bean Aware接口回調(diào)階段
    • Bean初始化前階段
    • Bean初始化階段
    • Bean初始化后階段
  • 10.階段10:所有單例bean初始化完成后階段

    1. 階段11:Bean的使用階段
  • 12.階段12:Bean銷毀前階段

    1. 階段13:Bean銷毀階段

階段1:Bean元信息配置階段

這個階段主要是bean信息的定義階段。

Bean信息定義4種方式
  • API的方式
  • Xml文件方式
  • properties文件的方式
  • 注解的方式
API的方式

先來說這種方式,因為其他幾種方式最終都會采用這種方式來定義bean配置信息。
Spring容器啟動的過程中,會將Bean解析成Spring內(nèi)部的BeanDefinition結(jié)構(gòu)。 不管是是通過xml配置文件的 <Bean> 標(biāo)簽,還是通過注解配置的 @Bean ,還是 @Compontent 標(biāo)注的類,還是掃描得到的類,它最終都會被解析成一個BeanDefinition對象,最后我們的Bean工廠就會根據(jù)這份Bean的定義信息,對bean進行實例化、初始化等等操作。你可以把BeanDefinition丟給Bean工廠,然后Bean工廠就會根據(jù)這個信息幫你生產(chǎn)一個Bean實例,拿去使用。BeanDefinition里面里面包含了bean定義的各種信息,如:bean對應(yīng)的class、scope、lazy信息、dependOn信息、autowireCandidate(是否是候選對象)、primary(是否是主要的候選者)等信息。BeanDefinition是個接口,有幾個實現(xiàn)類,看一下類圖:

image.png

BeanDefinition接口:bean定義信息接口

表示bean定義信息的接口,里面定義了一些獲取bean定義配置信息的各種方法,來看一下源碼:

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package org.springframework.beans.factory.config;

import org.springframework.beans.BeanMetadataElement;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.core.AttributeAccessor;
import org.springframework.core.ResolvableType;
import org.springframework.lang.Nullable;

public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {
    String SCOPE_SINGLETON = "singleton";
    String SCOPE_PROTOTYPE = "prototype";
    int ROLE_APPLICATION = 0;
    int ROLE_SUPPORT = 1;
    int ROLE_INFRASTRUCTURE = 2;

    /**
     *設(shè)置此bean的父bean名稱(對應(yīng)xml中bean元素的parent屬性)
    */
    void setParentName(@Nullable String var1);

    @Nullable
    String getParentName();
     /**
     * 指定此bean定義的bean類名(對應(yīng)xml中bean元素的class屬性)
     *
     */
    void setBeanClassName(@Nullable String beanClassName);


    /**
     * 返回此bean定義的當(dāng)前bean類名
     * 注意,如果子定義重寫/繼承其父類的類名,則這不一定是運行時使用的實際類名。此外,這可能只
     * 是調(diào)用工廠方法的類,或者在調(diào)用方法的工廠bean引用的情況下,它甚至可能是空的。因此,不要認為這是運
     * 行時的最終bean類型,而只將其用于單個bean定義級別的解析目的。
     * @return
     */
    @Nullable
    String getBeanClassName();

    /**
     * 設(shè)置此bean的生命周期,如:singleton、prototype(對應(yīng)xml中bean元素的scope屬性)
     * @param scope 設(shè)置此bean的生命周期
     */
    void setScope(@Nullable String scope);

    /**
     *
     * @return 返回此bean的生命周期,如:singleton、prototype
     */
    @Nullable
    String getScope();

    /**
     *  設(shè)置是否應(yīng)延遲初始化此bean(對應(yīng)xml中bean元素的lazy屬性)
     * @param lazyInit
     */
    void setLazyInit(boolean lazyInit);

    boolean isLazyInit();

    /**
     * 設(shè)置此bean依賴于初始化的bean的名稱,bean工廠將保證dependsOn指定的bean會在當(dāng)前bean初
     * 始化之前先初始化好
     * @param depends
     */
    void setDependsOn(@Nullable String... depends);

    @Nullable
    String[] getDependsOn();

    /**
     *  設(shè)置此bean是否作為其他bean自動注入時的候選者
     * @param autowireCandidate
     */
    void setAutowireCandidate(boolean autowireCandidate);

    boolean isAutowireCandidate();


    /**
     * 設(shè)置此bean是否為自動注入的主要候選者
     * @param primary 是否為主要候選者
     */
    void setPrimary(boolean primary);

    boolean isPrimary();

    /**
     * 指定要使用的工廠bean(如果有)。這是要對其調(diào)用指定工廠方法的bean的名稱。
     * @param factoryBeanName   工廠bean名稱
     */
    void setFactoryBeanName(@Nullable String factoryBeanName);

    @Nullable
    String getFactoryBeanName();

    /**
     * 指定工廠方法(如果有)。此方法將使用構(gòu)造函數(shù)參數(shù)調(diào)用,如果未指定任何參數(shù),則不使用任何參
     * 數(shù)調(diào)用。該方法將在指定的工廠bean(如果有的話)上調(diào)用,或者作為本地bean類上的靜態(tài)方法調(diào)用。
     * @param factoryMethodName 工廠方法名稱
     */
    void setFactoryMethodName(@Nullable String factoryMethodName);

    @Nullable
    String getFactoryMethodName();

    /**
     *
     * @return   返回此bean的構(gòu)造函數(shù)參數(shù)值
     */
    ConstructorArgumentValues getConstructorArgumentValues();

    /**
     *
     * @return 是否有構(gòu)造器參數(shù)值設(shè)置信息(對應(yīng)xml中bean元素的<constructor-arg />子元素)
     */
    default boolean hasConstructorArgumentValues() {
        return !this.getConstructorArgumentValues().isEmpty();
    }

    /**
     *
     * @return 獲取bean定義是配置的屬性值設(shè)置信息
     */
    MutablePropertyValues getPropertyValues();

    /**
     *
     * @return  這個bean定義中是否有屬性設(shè)置信息(對應(yīng)xml中bean元素的<property />子元素)
     */
    default boolean hasPropertyValues() {
        return !this.getPropertyValues().isEmpty();
    }

    /**
     *
     * @param initMethodName 設(shè)置bean初始化方法名稱
     */
    void setInitMethodName(@Nullable String initMethodName);

    @Nullable
    String getInitMethodName();

    /**
     *
     * @param destroyMethodName 設(shè)置bean銷毀方法的名稱
     */
    void setDestroyMethodName(@Nullable String destroyMethodName);

    @Nullable
    String getDestroyMethodName();


    /**
     *
     * @param role 設(shè)置bean的role信息
     */
    void setRole(int role);

    int getRole();

    /**
     *
     * @param description   設(shè)置bean描述信息
     */
    void setDescription(@Nullable String description);

    @Nullable
    String getDescription();

    /**
     *
     * @return  獲取bean類型解析器
     */
    ResolvableType getResolvableType();

    boolean isSingleton();

    boolean isPrototype();

    /**
     *
     * @return  對應(yīng)xml中bean元素的abstract屬性,用來指定是否是抽象的
     */
    boolean isAbstract();

    /**
     *
     * @return  返回此bean定義來自的資源的描述(以便在出現(xiàn)錯誤時顯示上下文)
     */
    @Nullable
    String getResourceDescription();

    @Nullable
    BeanDefinition getOriginatingBeanDefinition();
}

BeanDefinition接口上面還繼承了2個接口:

  • org.springframework.core.AttributeAccessor
  • org.springframework.beans.BeanMetadataElement

AttributeAccessor接口:屬性訪問接口

public interface AttributeAccessor {
   /**
    *  設(shè)置屬性->值
    * @param name   屬性
    * @param value 值
    */
   void setAttribute(String name, @Nullable Object value);


   /**
    *
    * @param name  獲取某個屬性對應(yīng)的值
    * @return  value
    */
   @Nullable
   Object getAttribute(String name);


   /**
    *
    * @param name   移除某個屬性
    * @return
    */
   @Nullable
   Object removeAttribute(String name);

   /**
    *
    * @param name  是否包含某個屬性
    * @return flag
    */
   boolean hasAttribute(String name);

   /**
    *
    * @return  返回所有的屬性名稱
    */
   String[] attributeNames();
}

這個接口相當(dāng)于key->value數(shù)據(jù)結(jié)構(gòu)的一種操作,BeanDefinition繼承這個,內(nèi)部實際上是使用了
LinkedHashMap來實現(xiàn)這個接口中的所有方法,通常我們通過這些方法來保存BeanDefinition定義過程
中產(chǎn)生的一些附加信息。

BeanMetadataElement接口

public interface BeanMetadataElement {
    @Nullable
    default Object getSource() {
        return null;
    }
}

BeanDefinition繼承這個接口,getSource返回BeanDefinition定義的來源,比如我們通過xml定義
BeanDefinition的,此時getSource就表示定義bean的xml資源;若我們通過api的方式定義
BeanDefinition,我們可以將source設(shè)置為定義BeanDefinition時所在的類,出錯時,可以根據(jù)這個來
源方便排錯

RootBeanDefinition類:表示根bean定義信息
通常bean中沒有父bean的就使用這種表示

ChildBeanDefinition類:表示子bean定義信息
如果需要指定父bean的,可以使用ChildBeanDefinition來定義子bean的配置信息,里面有個parentName 屬性,用來指定父bean的名稱。

GenericBeanDefinition類:通用的bean定義信息
既可以表示沒有父bean的bean配置信息,也可以表示有父bean的子bean配置信息,這個類里面也有parentName屬性,用來指定父bean的名稱。

ConfigurationClassBeanDefinition類:表示通過配置類中@Bean方法定義bean信息
可以通過配置類中使用@Bean來標(biāo)注一些方法,通過這些方法來定義bean,這些方法配置的bean信息最后會轉(zhuǎn)換為ConfigurationClassBeanDefinition類型的對象

AnnotatedBeanDefinition接口:表示通過注解的方式定義的bean信息
里面有個方法

AnnotationMetadata getMetadata();

用來獲取定義這個bean的類上的所有注解信息。

BeanDefinitionBuilder:構(gòu)建BeanDefinition的工具類
spring中為了方便操作BeanDefinition,提供了一個類: BeanDefinitionBuilder ,內(nèi)部提供了很多靜態(tài)方法,通過這些方法可以非常方便的組裝BeanDefinition對象。

綜合案例

@Data
public class Pig {

    private String name;
    private Integer age;

    private String description;

    public Pig() {
    }


    public Pig(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    public Pig(String name, Integer age, String description) {
        this.name = name;
        this.age = age;
        this.description = description;
    }
}

再來一個依賴于上面的類

@Data
public class User {
    private Pig pig;
    private String name;

    private List<Pig> pigList;
    private Set<Pig> pigSet;

    private Map<String, String> stringMap;
    private Map<String, Pig> stringPigMap;

    private List<String> strings;

    private Set<String> stringSet;
}

先用xml方式定義user bean

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--bean生命周期那一節(jié)的內(nèi)容 -->

    <!--先定義兩頭豬 喬治和佩奇 -->
    <bean id="pig" class="com.shiguiwu.springmybatis.spring.lifecycle.definition.Pig">
        <property name="name" value="jose" />
        <property name="description" value="名字是喬治"/>
     </bean>

    <bean id="patch" class="com.shiguiwu.springmybatis.spring.lifecycle.definition.Pig">
        <property name="name" value="patch" />
        <property name="description" value="名字是佩奇"/>
    </bean>

    <!-- end -->

    <!-- 定義個user bean -->

    <bean id="user" class="com.shiguiwu.springmybatis.spring.lifecycle.definition.User">
        <!-- 設(shè)置自定義屬性 -->
        <property name="pig" ref="patch" />

        <!-- 設(shè)置 string 屬性 -->
        <property name="name" value="小明" />

        <!-- 設(shè)置 pig 對象的list集合 -->
        <property name="pigList">
            <list>
                <ref bean="pig"/>
                <ref bean="patch"/>
            </list>
        </property>

        <!-- 設(shè)置 pig 對象的set集合 -->
        <property name="pigSet">
            <set>
                <ref bean="pig"/>
                <ref bean="patch"/>
            </set>
        </property>

        <!-- 設(shè)置 string -> string對象的map集合 -->
        <property name="stringMap">
            <map>
                <entry key="name" value="佩奇" />
                <entry key="age" value="15.5"/>
            </map>
        </property>

        <!-- 設(shè)置 string -> pig對象的map集合 -->
        <property name="stringPigMap">
            <map>
                <entry key="pig" value-ref="pig" />
                <entry key="patch" value-ref="patch"/>
            </map>
        </property>

        <!-- 設(shè)置 string 對象的list集合 -->
        <property name="strings" >
            <list>
                <value>小豬佩奇</value>
                <value>喬治</value>
            </list>
        </property>

        <!-- 設(shè)置 string 對象的set集合 -->
        <property name="stringSet" >
            <set>
                <value>小豬佩奇1</value>
                <value>喬治1</value>
            </set>
        </property>
    </bean>
    <!-- user bean end -->
</beans>

xml中的bean配置信息會被解析器解析為BeanDefinition對象,一會在第二階段詳解。

下面我們采用純api的方式實現(xiàn),如下

@1:調(diào)用addPropertyValue給Car中的name設(shè)置值
@2:創(chuàng)建了一個spring容器
@3:將carBeanDefinition這個bean配置信息注冊到spring容器中,bean的名稱為car
@4:從容器中獲取car這個bean,最后進行輸出
package com.shiguiwu.springmybatis.spring.lifecycle.definition;

import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.beans.factory.support.ManagedList;
import org.springframework.beans.factory.support.ManagedMap;
import org.springframework.beans.factory.support.ManagedSet;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * @description:
 * :通過api設(shè)置(Map、Set、List)屬性
 * 下面我們來演示注入List、Map、Set,內(nèi)部元素為普通類型及其他bean元素。
 * @author: stone
 * @date: Created by 2021/3/17 15:36
 * @version: 1.0.0
 * @pakeage: com.shiguiwu.springmybatis.spring.lifecycle.definition
 */
public class DefinitionApiTests {

    public static void main(String[] args) {
        BeanDefinitionBuilder builder1 = BeanDefinitionBuilder.genericBeanDefinition(Pig.class.getName());
        BeanDefinitionBuilder builder2 = BeanDefinitionBuilder.genericBeanDefinition(Pig.class);
        BeanDefinition pig1 = builder1.addPropertyValue("name", "小豬佩奇")
                .addPropertyValue("age", 12)
                .getBeanDefinition();

        BeanDefinition pig2 = builder2.addPropertyValue("name", "喬治111")
                .addPropertyValue("age", 6)
                .getBeanDefinition();

        ManagedList<String> strings = new ManagedList<>();
        strings.addAll(Arrays.asList("字符串1", "strings","list"));
        ManagedSet<String> stringSet = new ManagedSet<>();
        stringSet.add("set");
        stringSet.add("注入set集合");

        ManagedMap<String, String> stringMap = new ManagedMap<>();
        stringMap.put("name", "小豬佩奇");
        stringMap.put("age", "13");

        List<RuntimeBeanReference> pigList = new ManagedList<>();
        pigList.addAll(Arrays.asList(new RuntimeBeanReference("pig1"), new RuntimeBeanReference("pig2")));

        Set<RuntimeBeanReference> pigSet = new ManagedSet<>();
        pigSet.add(new RuntimeBeanReference("pig1"));
        pigSet.add(new RuntimeBeanReference("pig2"));

        Map<String, RuntimeBeanReference> stringPigMap = new ManagedMap<>();
        stringPigMap.put("pig1", new RuntimeBeanReference("pig1"));
        stringPigMap.put("pig2", new RuntimeBeanReference("pig2"));

        BeanDefinition userDefinition = new GenericBeanDefinition();
        userDefinition.setBeanClassName(User.class.getName());
        userDefinition.getPropertyValues()
                .add("pig", new RuntimeBeanReference("pig1"))
                .add("name", "shiguiwu")
                .add("pigList", pigList)
                .add("pigSet", pigSet)
                .add("stringMap", stringMap)
                .add("stringPigMap", stringPigMap)
                .add("strings", strings)
                .add("stringSet", stringSet);
        DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
        factory.registerBeanDefinition("pig1", pig1);
        factory.registerBeanDefinition("pig2", pig2);
        factory.registerBeanDefinition("user", userDefinition);

        String[] beanDefinitionNames = factory.getBeanDefinitionNames();
        for (String beanDefinitionName : beanDefinitionNames) {
            System.out.println(factory.getBean(beanDefinitionName));

        }

    }
}

有幾點需要說一下:
RuntimeBeanReference:用來表示bean引用類型,類似于xml中的ref
ManagedList:屬性如果是List類型的,t需要用到這個類進行操作,這個類繼承了ArrayList
ManagedSet:屬性如果是Set類型的,t需要用到這個類進行操作,這個類繼承了LinkedHashSet
ManagedMap:屬性如果是Map類型的,t需要用到這個類進行操作,這個類繼承了
LinkedHashMap
上面也就是這幾個類結(jié)合的結(jié)果。

properties文件的方式
這種方式估計大家比較陌生,將bean定義信息放在properties文件中,然后通過解析器將配置信息解析為BeanDefinition對象。
properties內(nèi)容格式如下:

pig.(class)=com.shiguiwu.springmybatis.spring.lifecycle.definition.Pig
pig.name=shiguiwu
pig.age=18

注解的方式

常見的2種:

  1. 類上標(biāo)注@Compontent注解來定義一個bean
  2. 配置類中使用@Bean注解來定義bean

小結(jié)
bean注冊者只識別BeanDefinition對象,不管什么方式最后都會將這些bean定義的信息轉(zhuǎn)換為BeanDefinition對象,然后注冊到spring容器中。

階段2:Bean元信息解析階段

Bean元信息的解析就是將各種方式定義的bean配置信息解析BeanDefinition對象。

Bean元信息的解析主要有3種方式

    1. xml文件定義bean的解析
    1. properties文件定義bean的解析
    1. 注解方式定義bean的解析

XML方式解析:XmlBeanDefinitionReader
spring中提供了一個類 XmlBeanDefinitionReader ,將xml中定義的bean解析為BeanDefinition對象。
xml文件為上一個階段的user.xml,這里我們直接解析他。

package com.shiguiwu.springmybatis.spring.lifecycle.parse;

import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;

/**
 * @description: 解析階段
 * @author: stone
 * @date: Created by 2021/3/21 18:41
 * @version: 1.0.0
 * @pakeage: com.shiguiwu.springmybatis.spring.lifecycle.definition.parse
 */
public class XmlParseTests {

    public static void main(String[] args) {

        //定義一個spring容器,這個容器默認實現(xiàn)了BeanDefinitionRegistry,所以本身就是一個bean
        //注冊器
        DefaultListableBeanFactory factory = new DefaultListableBeanFactory();

        //定義一個xml的BeanDefinition讀取器,需要傳遞一個BeanDefinitionRegistry(bean注冊器)對象
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
        //通過XmlBeanDefinitionReader加載bean xml文件,然后將解析產(chǎn)生的BeanDefinition注冊容器容器中
        int count = reader.loadBeanDefinitions("spring/user.xml");

        System.out.println("一共注冊多少bean ===>" + count);

        for (String name : factory.getBeanDefinitionNames()) {
            //根據(jù)名稱獲取定義
            BeanDefinition beanDefinition = factory.getBeanDefinition(name);

            //根據(jù)具體哪個bean定義
            String className = beanDefinition.getClass().getName();

            //獲取對象
            Object bean = factory.getBean(name);

            System.out.println(name +"===========================>");

            System.out.println("beanDefinition = " + beanDefinition);

            System.out.println("className = " + className);

            System.out.println("bean = " + bean);
        }




    }

}

上面注釋比較詳細,這里就不解釋了。
注意一點:創(chuàng)建XmlBeanDefinitionReader的時候需要傳遞一個bean注冊器
(BeanDefinitionRegistry),解析過程中生成的BeanDefinition會丟到bean注冊器中。

00:01:26.660 [main] DEBUG org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Loaded 3 bean definitions from class path resource [spring/user.xml]
一共注冊多少bean ===>3
00:01:26.676 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'pig'
pig===========================>
beanDefinition = Generic bean: class [com.shiguiwu.springmybatis.spring.lifecycle.definition.Pig]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in class path resource [spring/user.xml]
className = org.springframework.beans.factory.support.GenericBeanDefinition
bean = Pig(name=jose, age=null, description=名字是喬治)
00:01:26.873 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'patch'
patch===========================>
beanDefinition = Generic bean: class [com.shiguiwu.springmybatis.spring.lifecycle.definition.Pig]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in class path resource [spring/user.xml]
className = org.springframework.beans.factory.support.GenericBeanDefinition
bean = Pig(name=patch, age=null, description=名字是佩奇)
00:01:26.874 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'user'
user===========================>
beanDefinition = Generic bean: class [com.shiguiwu.springmybatis.spring.lifecycle.definition.User]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in class path resource [spring/user.xml]
className = org.springframework.beans.factory.support.GenericBeanDefinition
bean = User(pig=Pig(name=patch, age=null, description=名字是佩奇), name=小明, pigList=[Pig(name=jose, age=null, description=名字是喬治), Pig(name=patch, age=null, description=名字是佩奇)], pigSet=[Pig(name=jose, age=null, description=名字是喬治), Pig(name=patch, age=null, description=名字是佩奇)], stringMap={name=佩奇, age=15.5}, stringPigMap={pig=Pig(name=jose, age=null, description=名字是喬治), patch=Pig(name=patch, age=null, description=名字是佩奇)}, strings=[小豬佩奇, 喬治], stringSet=[小豬佩奇1, 喬治1])

上面的輸出認真看一下,這幾個BeanDefinition都是 GenericBeanDefinition 這種類型的,也就是說xml中定義的bean被解析之后都是通過GenericBeanDefinition 這種類型表示的。
properties文件定義bean的解析:
主要是PropertiesBeanDefinitionReader類,這里主要是使用過程比較少,所以這里不做講解,感興趣的可以自行研究

注解方式:AnnotatedBeanDefinitionReader
注解的方式定義的bean,需要使用AnnotatedBeanDefinitionReader這個類來進行解析,方式也和上面2種方式類似,直接來看案例。
注冊的bean

package com.shiguiwu.springmybatis.spring.autowired;

import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

/**
 * @description:
 * @author: stone
 * @date: Created by 2021/3/15 14:39
 * @version: 1.0.0
 * @pakeage: com.shiguiwu.springmybatis.spring.autowired
 */
@Service
public class B implements C {
}

測試代碼如下:

package com.shiguiwu.springmybatis.spring.lifecycle.parse;

import com.shiguiwu.springmybatis.spring.autowired.B;
import com.shiguiwu.springmybatis.spring.autowired.resource.Rb;
import com.shiguiwu.springmybatis.spring.autowired.resource.Rc;
import com.shiguiwu.springmybatis.spring.lazy.A;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.annotation.AnnotatedBeanDefinitionReader;

/**
 * @description: 2,注解解析類
 * @author: stone
 * @date: Created by 2021/3/23 10:16
 * @version: 1.0.0
 * @pakeage: com.shiguiwu.springmybatis.spring.lifecycle.parse
 */
public class  AnnotatedParseTests {

    public static void main(String[] args) {
        //1定義一個容器,一個注冊器
        DefaultListableBeanFactory factory = new DefaultListableBeanFactory();

        //2定義一個注解讀取器
        AnnotatedBeanDefinitionReader reader = new AnnotatedBeanDefinitionReader(factory);

        //3注冊到注解解析器中
        reader.register(B.class);

        System.out.println(factory.getBean("b"));
        System.out.println(factory.getBeanDefinition("b").getClass().getName());
        System.out.println("========================");


        factory.getBeansOfType(BeanPostProcessor.class).values().forEach(factory::addBeanPostProcessor); // @1

//        String[] beanDefinitionNames = factory.getBeanDefinitionNames();
//        for (String name : beanDefinitionNames) {
//            System.out.println(factory.getBean(name));
//            System.out.println("========================");
//        }
    }
}

階段3:Spring Bean注冊階段

bean注冊階段需要用到一個非常重要的接口:BeanDefinitionRegistry

Bean注冊接口:BeanDefinitionRegistry

這個接口中定義了注冊bean常用到的一些方法,源碼如下:

public interface BeanDefinitionRegistry extends AliasRegistry {
    /**
     *
     * 注冊一個新的bean定義
     * @param beanName  bean的名稱
     * @param beanDefinition    bean定義信息
     * @throws BeanDefinitionStoreException
     */
    void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException;

    /**
     *  通過bean名稱移除已注冊的bean
     * @param beanName  bean的名稱
     * @throws NoSuchBeanDefinitionException
     */
    void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;

    /**
     *  通過名稱獲取bean的定義信息
     * @param beanName  bean的名稱
     * @return  bean定義信息
     * @throws NoSuchBeanDefinitionException
     */
    BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;

    /**
     *  查看beanName是否注冊過
     * @param beanName  bean的名稱
     * @return  是否注冊過
     */
    boolean containsBeanDefinition(String beanName);

    /**
     * 獲取已經(jīng)定義(注冊)的bean名稱列表
     * @return  bean名稱列表
     */
    String[] getBeanDefinitionNames();

    /**
     *
     * @return 返回注冊器中已注冊的bean數(shù)量
     */
    int getBeanDefinitionCount();

    /**
     * 確定給定的bean名稱或者別名是否已在此注冊表中使用
     * beanName:可以是bean名稱或者bean的別名
     * @param beanName  bean名稱
     * @return  是否已經(jīng)注冊過
     */
    boolean isBeanNameInUse(String beanName);
}

別名注冊接口:AliasRegistry
BeanDefinitionRegistry 接口繼承了 AliasRegistry 接口,這個接口中定義了操作bean別名的一些方法,看一下其源碼:

public interface AliasRegistry {

    /**
     * 給name指定別名alias
     * @param name beanName
     * @param alias alias
     */
    void registerAlias(String name, String alias);

    /**
     *
     * @param alias 從此注冊表中刪除指定的別名
     */
    void removeAlias(String alias);

    /**
     *
     * @param name   判斷name是否作為別名已經(jīng)被使用了
     * @return 返回
     */
    boolean isAlias(String name);

    /**
     * 
     * @param name bean的名稱
     * @return 返回name對應(yīng)的所有別名
     */
    String[] getAliases(String name);
}

BeanDefinitionRegistry唯一實現(xiàn):DefaultListableBeanFactory
spring中BeanDefinitionRegistry接口有一個唯一的實現(xiàn)類:

org.springframework.beans.factory.support.DefaultListableBeanFactory

大家可能看到有很多類也實現(xiàn)了 BeanDefinitionRegistry 接口,比如我們經(jīng)常用到的
AnnotationConfigApplicationContext ,但實際上其內(nèi)部是轉(zhuǎn)發(fā)給了
DefaultListableBeanFactory 進行處理的,所以真正實現(xiàn)這個接口的類是
DefaultListableBeanFactory 。
大家再回頭看一下開頭的幾個案例,都使用的是 DefaultListableBeanFactory 作為bean注冊器,此時你們應(yīng)該可以理解為什么了。
下面我們來個案例演示一下上面常用的一些方法。

package com.shiguiwu.springmybatis.spring.lifecycle.register;

import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.GenericBeanDefinition;

import java.util.Arrays;

/**
 * @description: 3,注冊階段。。。
 * @author: stone
 * @date: Created by 2021/3/23 12:45
 * @version: 1.0.0
 * @pakeage: com.shiguiwu.springmybatis.spring.lifecycle.register
 */
public class RegisterTests {

    public static void main(String[] args) {
        //1 定義個注冊器
        DefaultListableBeanFactory factory = new DefaultListableBeanFactory();

        //定義一個bean定義信息
        GenericBeanDefinition definition = new GenericBeanDefinition();
        definition.setBeanClass(String.class);
        definition.getConstructorArgumentValues().addIndexedArgumentValue(0, "shiguiwu");
        //注冊一個組件
        factory.registerBeanDefinition("name", definition);

        //是否包括某組件
        System.out.println(factory.containsBean("name"));

        //獲取定義信息
        System.out.println(factory.getBeanDefinition("name"));

        //是否注冊過bean定義
        System.out.println(factory.containsBeanDefinition("name"));

        //獲取所有注冊信息
        System.out.println(Arrays.asList(factory.getBeanDefinitionNames()));

        //獲取bean定義的數(shù)量
        System.out.println(factory.getBeanDefinitionCount());

        //是否使用過名稱
        System.out.println(factory.isBeanNameInUse("name"));

        System.out.println("別名相關(guān)操作。。。。。。。。。。。。。。。。。");

        //注冊兩個別名
        factory.registerAlias("name","alias-name-1");
        factory.registerAlias("name", "alias-name-2");

        //判斷別名是否已經(jīng)使用
        System.out.println(factory.isAlias("alias-name-2"));

        //獲取所以別名
        System.out.println(Arrays.asList(factory.getAliases("name")));

        System.out.println(factory.getBean("name"));

    }
}

運行輸出如下:

Connected to the target VM, address: '127.0.0.1:55842', transport: 'socket'
true
Generic bean: class [java.lang.String]; scope=; abstract=false; lazyInit=null; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null
true
[name]
1
true
別名相關(guān)操作。。。。。。。。。。。。。。。。。
true
[alias-name-2, alias-name-1]
17:34:32.427 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'name'
shiguiwu

自此,Spring bean的生命周期前篇結(jié)束,由于篇幅較多,我把它分開前,中,后篇。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容