Spring-bean的生命周期-前篇

embedded/2024/9/23 14:36:27/
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是个接口,有几个实现类,看一下类图:
image.png

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);@NullableString getParentName();/*** 指定此bean定义的bean类名(对应xml中bean元素的class属性)**/void setBeanClassName(@Nullable String beanClassName);/*** 返回此bean定义的当前bean类名* 注意,如果子定义重写/继承其父类的类名,则这不一定是运行时使用的实际类名。此外,这可能只* 是调用工厂方法的类,或者在调用方法的工厂bean引用的情况下,它甚至可能是空的。因此,不要认为这是运* 行时的最终bean类型,而只将其用于单个bean定义级别的解析目的。* @return*/@NullableString getBeanClassName();/*** 设置此bean的生命周期,如:singleton、prototype(对应xml中bean元素的scope属性)* @param scope 设置此bean的生命周期*/void setScope(@Nullable String scope);/**** @return 返回此bean的生命周期,如:singleton、prototype*/@NullableString 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);@NullableString[] 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);@NullableString getFactoryBeanName();/*** 指定工厂方法(如果有)。此方法将使用构造函数参数调用,如果未指定任何参数,则不使用任何参* 数调用。该方法将在指定的工厂bean(如果有的话)上调用,或者作为本地bean类上的静态方法调用。* @param factoryMethodName 工厂方法名称*/void setFactoryMethodName(@Nullable String factoryMethodName);@NullableString 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);@NullableString getInitMethodName();/**** @param destroyMethodName 设置bean销毁方法的名称*/void setDestroyMethodName(@Nullable String destroyMethodName);@NullableString getDestroyMethodName();/**** @param role 设置bean的role信息*/void setRole(int role);int getRole();/**** @param description   设置bean描述信息*/void setDescription(@Nullable String description);@NullableString getDescription();/**** @return  获取bean类型解析器*/ResolvableType getResolvableType();boolean isSingleton();boolean isPrototype();/**** @return  对应xml中bean元素的abstract属性,用来指定是否是抽象的*/boolean isAbstract();/**** @return  返回此bean定义来自的资源的描述(以便在出现错误时显示上下文)*/@NullableString getResourceDescription();@NullableBeanDefinition 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*/@NullableObject getAttribute(String name);/**** @param name   移除某个属性* @return*/@NullableObject removeAttribute(String name);/**** @param name  是否包含某个属性* @return flag*/boolean hasAttribute(String name);/**** @return  返回所有的属性名称*/String[] attributeNames();
}

这个接口相当于key->value数据结构的一种操作,BeanDefinition继承这个,内部实际上是使用了
LinkedHashMap来实现这个接口中的所有方法,通常我们通过这些方法来保存BeanDefinition定义过程
中产生的一些附加信息。

BeanMetadataElement接口

java">public interface BeanMetadataElement {@Nullabledefault 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 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内容格式如下:

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注册器中。

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"));}
}

运行输出如下:

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


http://www.ppmy.cn/embedded/111410.html

相关文章

笔试强训day11

游游的水果大礼包 #include <iostream> #define int long longusing namespace std; int n, m, a, b;signed main() {cin>>n>>m>>a>>b;int ret 0;for(int x 0; x < min(n / 2, m); x) // 枚举 1 号礼包的个数{int y min(n - x * 2, (m - …

ASP.NET Core 入门教学二十九 DDD设计

在软件开发中&#xff0c;领域驱动设计&#xff08;Domain-Driven Design&#xff0c;简称DDD&#xff09;是一种重要的软件设计方法论&#xff0c;它强调通过深入理解业务领域来构建高质量的软件系统。DDD的核心思想是将复杂的业务逻辑集中在领域模型中&#xff0c;并通过分层…

计算机毕业设计选题推荐-农家乐综合服务系统-乡村游乐购系统-田园休闲生活系统-Java/Python项目实战

✨作者主页&#xff1a;IT毕设梦工厂✨ 个人简介&#xff1a;曾从事计算机专业培训教学&#xff0c;擅长Java、Python、微信小程序、Golang、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇⬇⬇ Java项目 Py…

软件开发人员的真实面

我相信我们都看过视频上那些名为“软件工程师的一天”的视频。这些视频通常只展示一些日常任务&#xff0c;比如吃饭、打字和参加会议。我对这些视频未能展示软件开发工作的真实内容感到失望。这些内容往往只关注表面活动&#xff0c;却忽略了工作中的思维挑战和解决问题的部分…

【C++开发中XML 文件的妙用】

在C中&#xff0c;XML&#xff08;可扩展标记语言&#xff09;文件通常用于存储配置数据、应用程序设置、数据交换格式等。由于其结构化和可读性强的特点&#xff0c;XML文件在配置管理、序列化、跨平台数据交换以及软件国际化等方面有着广泛的应用。 XML 文件的妙用 配置管理…

【python - 函数】

一、递归函数 如果函数体中直接或间接调用了函数本身&#xff0c;则函数称为递归&#xff08;recursive&#xff09;函数。也就是说&#xff0c;执行递归函数主体的过程中可能需要再次调用该函数。在 Python 中&#xff0c;递归函数不需要使用任何特殊语法&#xff0c;但它们确…

C#中的闭包

在 C# 中&#xff0c;闭包&#xff08;Closure&#xff09;是一种编程结构&#xff0c;它允许一个内部函数&#xff08;也称为闭包函数&#xff09;捕获和存储定义它的外部函数&#xff08;也称为外部函数或父函数&#xff09;的作用域中的变量。即使外部函数已经执行完毕并退出…

Rust 函数

Rust 函数 Rust 是一种系统编程语言,以其安全性、速度和并发性而闻名。在 Rust 中,函数是一等公民,是组织代码和实现功能的基本单位。本文将深入探讨 Rust 中的函数,包括其定义、特性、参数、返回值以及高级用法。 函数定义 在 Rust 中,函数使用 fn 关键字定义。函数可…