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的生命周期前篇结束,由于篇幅较多,我把它分开前,中,后篇。

相关推荐
一元咖啡1 分钟前
SpringCloud Gateway转发请求到同一个服务的不同端口
spring·spring cloud·gateway
儿时可乖了8 分钟前
使用 Java 操作 SQLite 数据库
java·数据库·sqlite
ruleslol9 分钟前
java基础概念37:正则表达式2-爬虫
java
xmh-sxh-131426 分钟前
jdk各个版本介绍
java
天天扭码1 小时前
五天SpringCloud计划——DAY2之单体架构和微服务架构的选择和转换原则
java·spring cloud·微服务·架构
程序猿进阶1 小时前
堆外内存泄露排查经历
java·jvm·后端·面试·性能优化·oom·内存泄露
FIN技术铺1 小时前
Spring Boot框架Starter组件整理
java·spring boot·后端
小曲程序1 小时前
vue3 封装request请求
java·前端·typescript·vue
陈王卜1 小时前
django+boostrap实现发布博客权限控制
java·前端·django
小码的头发丝、1 小时前
Spring Boot 注解
java·spring boot