Spring bean生命周期12个环节
-
1.阶段1:Bean元信息配置阶段
-
2.阶段2:Bean元信息解析阶段
-
3.阶段3:将Bean注册到容器中
-
4.阶段4:BeanDefinition合并阶段
-
- 阶段5:Bean Class加载阶段
-
6.阶段6:Bean实例化阶段(2个小阶段)
- Bean实例化前阶段
- Bean实例化阶段
-
- 阶段7:合并后的BeanDefinition处理
-
- 阶段8:属性赋值阶段(3个小阶段)
- Bean实例化后阶段
- Bean属性赋值前阶段
- Bean属性赋值阶段
-
9.阶段9:Bean初始化阶段(4个小阶段)
- Bean Aware接口回调阶段
- Bean初始化前阶段
- Bean初始化阶段
- Bean初始化后阶段
-
10.阶段10:所有单例bean初始化完成后阶段
-
- 阶段11:Bean的使用阶段
-
12.阶段12:Bean销毁前阶段
-
- 阶段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定义配置信息的各种方法,来看一下源码:
//
// 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接口:属性访问接口
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接口
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信息
里面有个方法
AnnotationMetadata getMetadata();
用来获取定义这个bean的类上的所有注解信息。
BeanDefinitionBuilder:构建BeanDefinition的工具类
spring中为了方便操作BeanDefinition,提供了一个类: BeanDefinitionBuilder ,内部提供了很多静态方法,通过这些方法可以非常方便的组装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生命周期那一节的内容 -->
<!--先定义两头猪 乔治和佩奇 -->
<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,最后进行输出
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种:
- 类上标注@Compontent注解来定义一个bean
- 配置类中使用@Bean注解来定义bean
小结
bean注册者只识别BeanDefinition对象,不管什么方式最后都会将这些bean定义的信息转换为BeanDefinition对象,然后注册到spring容器中。
阶段2:Bean元信息解析阶段
Bean元信息的解析就是将各种方式定义的bean配置信息解析BeanDefinition对象。
Bean元信息的解析主要有3种方式
-
- xml文件定义bean的解析
-
- properties文件定义bean的解析
-
- 注解方式定义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容器,这个容器默认实现了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
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);
/**
* 获取已经定义(注册)的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别名的一些方法,看一下其源码:
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接口有一个唯一的实现类:
org.springframework.beans.factory.support.DefaultListableBeanFactory
大家可能看到有很多类也实现了 BeanDefinitionRegistry 接口,比如我们经常用到的
AnnotationConfigApplicationContext ,但实际上其内部是转发给了
DefaultListableBeanFactory 进行处理的,所以真正实现这个接口的类是
DefaultListableBeanFactory 。
大家再回头看一下开头的几个案例,都使用的是 DefaultListableBeanFactory 作为bean注册器,此时你们应该可以理解为什么了。
下面我们来个案例演示一下上面常用的一些方法。
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的生命周期前篇结束,由于篇幅较多,我把它分开前,中,后篇。
本站资源均来自互联网,仅供研究学习,禁止违法使用和商用,产生法律纠纷本站概不负责!如果侵犯了您的权益请与我们联系!
转载请注明出处: 免费源码网-免费的源码资源网站 » Spring-bean的生命周期-前篇
发表评论 取消回复