Spring-bean的生命周期-前篇

Spring bean生命周期12个环节
  • 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接口回调阶段
    • 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内部的BeanDefinition结构 。 不管是是通过xml配置文件的 标签,还是通过注解配置的 @Bean ,还是 @Compontent 标注的类,还是扫描得到的类,它最终都会被解析成一个BeanDefinition对象,最后我们的Bean工厂就会根据这份Bean的定义信息,对bean进行实例化、初始化等等操作。你可以把BeanDefinition丢给Bean工厂,然后Bean工厂就会根据这个信息帮你生产一个Bean实例,拿去使用。BeanDefinition里面里面包含了bean定义的各种信息,如:bean对应的class、scope、lazy信息、dependOn信息、autowireCandidate(是否是候选对象)、primary(是否是主要的候选者)等信息。BeanDefinition是个接口,有几个实现类,看一下类图:

BeanDefinition接口:bean定义信息接口

表示bean定义信息的接口,里面定义了一些获取bean定义配置信息的各种方法,来看一下源码:

java 复制代码
//
// 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;

    /**
     *设置此bean的父bean名称(对应xml中bean元素的parent属性)
    */
    void setParentName(@Nullable String var1);

    @Nullable
    String getParentName();
     /**
     * 指定此bean定义的bean类名(对应xml中bean元素的class属性)
     *
     */
    void setBeanClassName(@Nullable String beanClassName);


    /**
     * 返回此bean定义的当前bean类名
     * 注意,如果子定义重写/继承其父类的类名,则这不一定是运行时使用的实际类名。此外,这可能只
     * 是调用工厂方法的类,或者在调用方法的工厂bean引用的情况下,它甚至可能是空的。因此,不要认为这是运
     * 行时的最终bean类型,而只将其用于单个bean定义级别的解析目的。
     * @return
     */
    @Nullable
    String getBeanClassName();

    /**
     * 设置此bean的生命周期,如:singleton、prototype(对应xml中bean元素的scope属性)
     * @param scope 设置此bean的生命周期
     */
    void setScope(@Nullable String scope);

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

    /**
     *  设置是否应延迟初始化此bean(对应xml中bean元素的lazy属性)
     * @param lazyInit
     */
    void setLazyInit(boolean lazyInit);

    boolean isLazyInit();

    /**
     * 设置此bean依赖于初始化的bean的名称,bean工厂将保证dependsOn指定的bean会在当前bean初
     * 始化之前先初始化好
     * @param depends
     */
    void setDependsOn(@Nullable String... depends);

    @Nullable
    String[] getDependsOn();

    /**
     *  设置此bean是否作为其他bean自动注入时的候选者
     * @param autowireCandidate
     */
    void setAutowireCandidate(boolean autowireCandidate);

    boolean isAutowireCandidate();


    /**
     * 设置此bean是否为自动注入的主要候选者
     * @param primary 是否为主要候选者
     */
    void setPrimary(boolean primary);

    boolean isPrimary();

    /**
     * 指定要使用的工厂bean(如果有)。这是要对其调用指定工厂方法的bean的名称。
     * @param factoryBeanName   工厂bean名称
     */
    void setFactoryBeanName(@Nullable String factoryBeanName);

    @Nullable
    String getFactoryBeanName();

    /**
     * 指定工厂方法(如果有)。此方法将使用构造函数参数调用,如果未指定任何参数,则不使用任何参
     * 数调用。该方法将在指定的工厂bean(如果有的话)上调用,或者作为本地bean类上的静态方法调用。
     * @param factoryMethodName 工厂方法名称
     */
    void setFactoryMethodName(@Nullable String factoryMethodName);

    @Nullable
    String getFactoryMethodName();

    /**
     *
     * @return   返回此bean的构造函数参数值
     */
    ConstructorArgumentValues getConstructorArgumentValues();

    /**
     *
     * @return 是否有构造器参数值设置信息(对应xml中bean元素的<constructor-arg />子元素)
     */
    default boolean hasConstructorArgumentValues() {
        return !this.getConstructorArgumentValues().isEmpty();
    }

    /**
     *
     * @return 获取bean定义是配置的属性值设置信息
     */
    MutablePropertyValues getPropertyValues();

    /**
     *
     * @return  这个bean定义中是否有属性设置信息(对应xml中bean元素的<property />子元素)
     */
    default boolean hasPropertyValues() {
        return !this.getPropertyValues().isEmpty();
    }

    /**
     *
     * @param initMethodName 设置bean初始化方法名称
     */
    void setInitMethodName(@Nullable String initMethodName);

    @Nullable
    String getInitMethodName();

    /**
     *
     * @param destroyMethodName 设置bean销毁方法的名称
     */
    void setDestroyMethodName(@Nullable String destroyMethodName);

    @Nullable
    String getDestroyMethodName();


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

    int getRole();

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

    @Nullable
    String getDescription();

    /**
     *
     * @return  获取bean类型解析器
     */
    ResolvableType getResolvableType();

    boolean isSingleton();

    boolean isPrototype();

    /**
     *
     * @return  对应xml中bean元素的abstract属性,用来指定是否是抽象的
     */
    boolean isAbstract();

    /**
     *
     * @return  返回此bean定义来自的资源的描述(以便在出现错误时显示上下文)
     */
    @Nullable
    String getResourceDescription();

    @Nullable
    BeanDefinition getOriginatingBeanDefinition();
}

BeanDefinition接口上面还继承了2个接口:

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

AttributeAccessor接口:属性访问接口

java 复制代码
public interface AttributeAccessor {
   /**
    *  设置属性->值
    * @param name   属性
    * @param value 值
    */
   void setAttribute(String name, @Nullable Object value);


   /**
    *
    * @param name  获取某个属性对应的值
    * @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();
}

这个接口相当于key->value数据结构的一种操作,BeanDefinition继承这个,内部实际上是使用了

LinkedHashMap来实现这个接口中的所有方法,通常我们通过这些方法来保存BeanDefinition定义过程

中产生的一些附加信息。

BeanMetadataElement接口

java 复制代码
public interface BeanMetadataElement {
    @Nullable
    default Object getSource() {
        return null;
    }
}

BeanDefinition继承这个接口,getSource返回BeanDefinition定义的来源,比如我们通过xml定义

BeanDefinition的,此时getSource就表示定义bean的xml资源;若我们通过api的方式定义

BeanDefinition,我们可以将source设置为定义BeanDefinition时所在的类,出错时,可以根据这个来

源方便排错

RootBeanDefinition类:表示根bean定义信息

通常bean中没有父bean的就使用这种表示

ChildBeanDefinition类:表示子bean定义信息

如果需要指定父bean的,可以使用ChildBeanDefinition来定义子bean的配置信息,里面有个parentName 属性,用来指定父bean的名称。

GenericBeanDefinition类:通用的bean定义信息

既可以表示没有父bean的bean配置信息,也可以表示有父bean的子bean配置信息,这个类里面也有parentName属性,用来指定父bean的名称。

ConfigurationClassBeanDefinition类:表示通过配置类中@Bean方法定义bean信息

可以通过配置类中使用@Bean来标注一些方法,通过这些方法来定义bean,这些方法配置的bean信息最后会转换为ConfigurationClassBeanDefinition类型的对象

AnnotatedBeanDefinition接口:表示通过注解的方式定义的bean信息

里面有个方法

java 复制代码
AnnotationMetadata getMetadata();

用来获取定义这个bean的类上的所有注解信息。

BeanDefinitionBuilder:构建BeanDefinition的工具类

spring中为了方便操作BeanDefinition,提供了一个类: BeanDefinitionBuilder ,内部提供了很多静态方法,通过这些方法可以非常方便的组装BeanDefinition对象。

综合案例

java 复制代码
@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;
    }
}

再来一个依赖于上面的类

java 复制代码
@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 复制代码
<?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生命周期那一节的内容 -->

    <!--先定义两头猪 乔治和佩奇 -->
    <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">
        <!-- 设置自定义属性 -->
        <property name="pig" ref="patch" />

        <!-- 设置 string 属性 -->
        <property name="name" value="小明" />

        <!-- 设置 pig 对象的list集合 -->
        <property name="pigList">
            <list>
                <ref bean="pig"/>
                <ref bean="patch"/>
            </list>
        </property>

        <!-- 设置 pig 对象的set集合 -->
        <property name="pigSet">
            <set>
                <ref bean="pig"/>
                <ref bean="patch"/>
            </set>
        </property>

        <!-- 设置 string -> string对象的map集合 -->
        <property name="stringMap">
            <map>
                <entry key="name" value="佩奇" />
                <entry key="age" value="15.5"/>
            </map>
        </property>

        <!-- 设置 string -> pig对象的map集合 -->
        <property name="stringPigMap">
            <map>
                <entry key="pig" value-ref="pig" />
                <entry key="patch" value-ref="patch"/>
            </map>
        </property>

        <!-- 设置 string 对象的list集合 -->
        <property name="strings" >
            <list>
                <value>小猪佩奇</value>
                <value>乔治</value>
            </list>
        </property>

        <!-- 设置 string 对象的set集合 -->
        <property name="stringSet" >
            <set>
                <value>小猪佩奇1</value>
                <value>乔治1</value>
            </set>
        </property>
    </bean>
    <!-- user bean end -->
</beans>

xml中的bean配置信息会被解析器解析为BeanDefinition对象,一会在第二阶段详解。

下面我们采用纯api的方式实现,如下

@1:调用addPropertyValue给Car中的name设置值
@2:创建了一个spring容器
@3:将carBeanDefinition这个bean配置信息注册到spring容器中,bean的名称为car
@4:从容器中获取car这个bean,最后进行输出
java 复制代码
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设置(Map、Set、List)属性
 * 下面我们来演示注入List、Map、Set,内部元素为普通类型及其他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

上面也就是这几个类结合的结果。

properties文件的方式

这种方式估计大家比较陌生,将bean定义信息放在properties文件中,然后通过解析器将配置信息解析为BeanDefinition对象。

properties内容格式如下:

properties 复制代码
pig.(class)=com.shiguiwu.springmybatis.spring.lifecycle.definition.Pig
pig.name=shiguiwu
pig.age=18

注解的方式

常见的2种:

  1. 类上标注@Compontent注解来定义一个bean
  2. 配置类中使用@Bean注解来定义bean

小结
bean注册者只识别BeanDefinition对象,不管什么方式最后都会将这些bean定义的信息转换为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,这里我们直接解析他。

java 复制代码
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容器,这个容器默认实现了BeanDefinitionRegistry,所以本身就是一个bean
        //注册器
        DefaultListableBeanFactory factory = new DefaultListableBeanFactory();

        //定义一个xml的BeanDefinition读取器,需要传递一个BeanDefinitionRegistry(bean注册器)对象
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
        //通过XmlBeanDefinitionReader加载bean xml文件,然后将解析产生的BeanDefinition注册容器容器中
        int count = reader.loadBeanDefinitions("spring/user.xml");

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

        for (String name : factory.getBeanDefinitionNames()) {
            //根据名称获取定义
            BeanDefinition beanDefinition = factory.getBeanDefinition(name);

            //根据具体哪个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);
        }




    }

}

上面注释比较详细,这里就不解释了。

注意一点:创建XmlBeanDefinitionReader的时候需要传递一个bean注册器

(BeanDefinitionRegistry),解析过程中生成的BeanDefinition会丢到bean注册器中。

log 复制代码
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

java 复制代码
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 {
}

测试代码如下:

java 复制代码
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常用到的一些方法,源码如下:

java 复制代码
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);

    /**
     * 获取已经定义(注册)的bean名称列表
     * @return  bean名称列表
     */
    String[] getBeanDefinitionNames();

    /**
     *
     * @return 返回注册器中已注册的bean数量
     */
    int getBeanDefinitionCount();

    /**
     * 确定给定的bean名称或者别名是否已在此注册表中使用
     * beanName:可以是bean名称或者bean的别名
     * @param beanName  bean名称
     * @return  是否已经注册过
     */
    boolean isBeanNameInUse(String beanName);
}

别名注册接口:AliasRegistry

BeanDefinitionRegistry 接口继承了 AliasRegistry 接口,这个接口中定义了操作bean别名的一些方法,看一下其源码:

java 复制代码
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是否作为别名已经被使用了
     * @return 返回
     */
    boolean isAlias(String name);

    /**
     * 
     * @param name bean的名称
     * @return 返回name对应的所有别名
     */
    String[] getAliases(String name);
}

BeanDefinitionRegistry唯一实现:DefaultListableBeanFactory

spring中BeanDefinitionRegistry接口有一个唯一的实现类:

java 复制代码
org.springframework.beans.factory.support.DefaultListableBeanFactory

大家可能看到有很多类也实现了 BeanDefinitionRegistry 接口,比如我们经常用到的

AnnotationConfigApplicationContext ,但实际上其内部是转发给了

DefaultListableBeanFactory 进行处理的,所以真正实现这个接口的类是

DefaultListableBeanFactory 。

大家再回头看一下开头的几个案例,都使用的是 DefaultListableBeanFactory 作为bean注册器,此时你们应该可以理解为什么了。

下面我们来个案例演示一下上面常用的一些方法。

java 复制代码
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定义的数量
        System.out.println(factory.getBeanDefinitionCount());

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

        System.out.println("别名相关操作。。。。。。。。。。。。。。。。。");

        //注册两个别名
        factory.registerAlias("name","alias-name-1");
        factory.registerAlias("name", "alias-name-2");

        //判断别名是否已经使用
        System.out.println(factory.isAlias("alias-name-2"));

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

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

    }
}

运行输出如下:

log 复制代码
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
别名相关操作。。。。。。。。。。。。。。。。。
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的生命周期前篇结束,由于篇幅较多,我把它分开前,中,后篇。

相关推荐
guangzhi06334 分钟前
JAVA执行引擎详细介绍
java·jvm
解孔明36 分钟前
IDEA2023.1添加java虚拟机启动参数,打开断言
java·开发语言
关关不烦恼38 分钟前
【Java数据结构】二叉树
java·开发语言·数据结构
苹果酱056739 分钟前
使用 React Testing Library 测试自定义 React Hooks
java·开发语言·spring boot·后端·中间件
好奇的菜鸟1 小时前
Java技术体系:深入理解JDK与JRE及其产品线
java·开发语言
api771 小时前
1688商品详情API返回值中的售后保障与服务信息
java·服务器·前端·javascript·python·spring·pygame
疑惑的杰瑞1 小时前
[乱码]确保命令行窗口与主流集成开发环境(IDE)统一采用UTF-8编码,以规避乱码问题
java·c++·vscode·python·eclipse·sublime text·visual studio
自身就是太阳1 小时前
深入理解 Spring 事务管理及其配置
java·开发语言·数据库·spring
喵手1 小时前
Java零基础-多态详解
java·开发语言·python
麋鹿会飞但不飘2 小时前
EasyExcel拿表头(二级表头)爬坑,invokeHeadMap方法
java·spring boot·excel