Spring进阶(十六)之spring生命周期

这篇具有很好参考价值的文章主要介绍了Spring进阶(十六)之spring生命周期。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

Bean生命周期

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

Bean信息定义4种方式

API的方式

XML的方式

properties文件的方式

注解的方式

小结

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

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

XML方式解析:XmlBeanDefinitionReader

properties文件定义bean的解析: PropertiesBeanDefinitionReader

注解方式:AnnotatedBeanDefinitionReader

阶段3:Spring Bean注册阶段

Bean注册接口:BeanDefinitionRegistry

别名注册接口:AliasRegistry

DefaultListableBeanFactory类

阶段4:BeanDefinition合并阶段

案例

阶段5:Bean Class加载阶段


Bean生命周期

Spring bean 生命周期可以分为13个阶段:

  1. Bean元信息配置阶段
  2. Bean元信息解析阶段
  3. 将Bean注册到容器中
  4. BeanDefinition合并阶段
  5. Bean Class加载阶段
  6. Bean实例化阶段(2个小阶段)
    • Bean实例化前阶段
    • Bean实例化阶段
  7. 合并后的BeanDefinition处理
  8. 属性赋值阶段(3个小阶段)
    • Bean实例化后阶段
    • Bean属性赋值前阶段
    • Bean属性赋值阶段
  9. Bean初始化阶段(4个小阶段)
    • Bean Aware接口回调阶段
    • Bean初始化前阶段
    • Bean初始化阶段
    • Bean初始化后阶段
  10. 所有单例bean初始化完成后阶段
  11. Bean的使用阶段
  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是个接口,有几个实现类,看一下类图:

Spring进阶(十六)之spring生命周期

BeanDefinition接口

bean定义信息的接口,我们下来看看源码:

public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {

	/**
	 *singleton
	 */
	String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;

	/**
	 * prototype
	 */
	String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;


	
	int ROLE_APPLICATION = 0;

	int ROLE_SUPPORT = 1;

	int ROLE_INFRASTRUCTURE = 2;


	// Modifiable attributes

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

	/**
	 * 返回bean定义时指定的父bean的名称
	 */
	@Nullable
	String getParentName();

	/**
	 * 指定bean的全路径类名(对应xml中的bean的class属性)
	 */
	void setBeanClassName(@Nullable String beanClassName);

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

	/**
	 * 指定bean的范围(对应xml中bea定义时的scope属性)
	 */
	void setScope(@Nullable String scope);

	/**
	 * 返回bean的范围
	 */
	@Nullable
	String getScope();

	/**
	 * 设置是否延迟初始化该bean(对应xml中bean定义时的lazy属性)
	 */
	void setLazyInit(boolean lazyInit);

	/**
	 * 返回该bean是否是一个延迟初始化的bean(只对单例的bean有效,因为多例的bean肯定是使用时才会
     * 创建的)
	 */
	boolean isLazyInit();

	/**
	 * 设置该bean初始化时需要依赖的bean的名称,bean工厂会保证让这些bean在该bean之前初始化
	 */
	void setDependsOn(@Nullable String... dependsOn);

	/**
	 * 返回此bean依赖的bean的名称
	 */
	@Nullable
	String[] getDependsOn();

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

	/**
	 * 返回此bean是否作为其他bean自动注入时的候选者
	 */
	boolean isAutowireCandidate();

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

	/**
	 * 返回此bean是否作为自动注入的主要候选者
	 */
	boolean isPrimary();

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

	/**
	 * 返回工厂bean名称(如果有)(对应xml中bean元素的factory-bean属性)
	 */
	@Nullable
	String getFactoryBeanName();

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

	/**
	 * 返回工厂方法名称(对应xml中bean的factory-method属性)
	 */
	@Nullable
	String getFactoryMethodName();

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

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

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

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

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

	/**
	 * 返回bean初始化方法名称
	 */
	@Nullable
	String getInitMethodName();

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

	/**
	 * 返回bean销毁方法的名称
	 */
	@Nullable
	String getDestroyMethodName();

	/**
	 * 为此BeanDefinition设置角色提示。角色提示为框架和工具提供了特定BeanDefinition的角色和重
     * 要性的指示
	 */
	void setRole(int role);

	/**
	 * 获取此BeanDefinition的角色提示。角色提示为框架和工具提供了特定BeanDefinition的角色和重
     * 要性的指示
	 */
	int getRole();

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

	/**
	 * 返回Bean的描述信息
	 */
	@Nullable
	String getDescription();


	// Read-only attributes

	/**
	 * 返回此 bean 定义的可解析类型
	 */
	ResolvableType getResolvableType();

	/**
	 * 是否是单例
	 */
	boolean isSingleton();

	/**
	 * 是否是多例
	 */
	boolean isPrototype();

	/**
	 * 返回此 bean 是否是“抽象的”,即不打算实例化
	 */
	boolean isAbstract();

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

	/**
	 * 返回原始 BeanDefinition,如果没有则返回null 
	 */
	@Nullable
	BeanDefinition getOriginatingBeanDefinition();

}

另外,BeanDefinition还实现了两个接口:

  • AttributeAccessor
  • BeanMetadataElement

AttributeAccessor接口:属性访问接口

源码:

public interface AttributeAccessor {

	/**
	 * 设置 属性->值 键值对
	 */
	void setAttribute(String name, @Nullable Object value);

	/**
	 * 获取某个属性对应的值
	 */
	@Nullable
	Object getAttribute(String name);

	/**
	 * 移除某个属性
	 */
	@Nullable
	Object removeAttribute(String name);

	/**
	 * 是否包含某个属性
	 */
	boolean hasAttribute(String name);

	/**
	 * 列出所有属性
	 */
	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信息

里面有个方法getMetadata()用来获取定义这个bean的类上的所有注解信息。

BeanDefinitionBuilder:构建BeanDefinition的工具类 

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

案例1:组装一个简单的bean

public class User {

    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                '}';
    }
}
    @Test
    void test1() {

        BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.rootBeanDefinition(User.class.getName());
        AbstractBeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();
        System.out.println(beanDefinition);

    }

运行输出:

Root bean: class [com.example.User]; scope=; abstract=false; lazyInit=null; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null

案例2:组装一个有属性的bean 

public class User {

    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                '}';
    }
}
    @Test
    void test2(){
        BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.rootBeanDefinition(User.class.getName());
        //给该bean的name属性设置值
        beanDefinitionBuilder.addPropertyValue("name","张三");
        AbstractBeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();
        System.out.println(beanDefinition);

        System.out.println("---------------------");

        //创建一个Spring容器
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        //将该Bean注册到Spring容器中
        beanFactory.registerBeanDefinition("User",beanDefinition);

        //获取容器中的Bean
        User user = (User) beanFactory.getBean("User");
        System.out.println(user);
    }

运行输出:

Root bean: class [com.example.User]; scope=; abstract=false; lazyInit=null; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null
---------------------
User{name='张三'}

案例3:组装一个有依赖关系的bean

public class User {

    private String name;

    private Car car;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Car getCar() {
        return car;
    }

    public void setCar(Car car) {
        this.car = car;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", car=" + car +
                '}';
    }
}
public class Car {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Car{" +
                "name='" + name + '\'' +
                '}';
    }
}
    @Test
    void test3(){
        
        //创建Car对象,并为其赋值
        BeanDefinitionBuilder beanDefinitionBuilder2 = BeanDefinitionBuilder.rootBeanDefinition(Car.class.getName());
        beanDefinitionBuilder2.addPropertyValue("name","宝马");
        AbstractBeanDefinition CarBeanDefinition = beanDefinitionBuilder2.getBeanDefinition();

        //创建User对象,并为其赋值
        BeanDefinitionBuilder beanDefinitionBuilder1 = BeanDefinitionBuilder.rootBeanDefinition(User.class.getName());
        beanDefinitionBuilder1.addPropertyValue("name","张三");
        beanDefinitionBuilder1.addPropertyReference("car","car");//为该bean注入依赖的bean
        AbstractBeanDefinition UserBeanDefinition = beanDefinitionBuilder1.getBeanDefinition();

        //创建Spring容器,将这两个Bean注册到容器中
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        beanFactory.registerBeanDefinition("user",UserBeanDefinition);
        beanFactory.registerBeanDefinition("car",CarBeanDefinition);

        Car car = (Car) beanFactory.getBean("car");
        System.out.println(car);
        User user = (User) beanFactory.getBean("user");
        System.out.println(user);
    }

运行输出:

Car{name='宝马'}
User{name='张三', car=Car{name='宝马'}}

案例4:有父子关系的bean

public class User {

    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                '}';
    }
}
@Test
    void test4(){

        //创建一个bean
        BeanDefinitionBuilder beanDefinitionBuilder1 = BeanDefinitionBuilder.rootBeanDefinition(User.class.getName());
        beanDefinitionBuilder1.addPropertyValue("name","张三");
        AbstractBeanDefinition UserBeanDefinition = beanDefinitionBuilder1.getBeanDefinition();

        //再创建一个bean,指定该bean的父bean,这样该bean就拥有了父bean的所有属性
        BeanDefinitionBuilder beanDefinitionBuilder2 = BeanDefinitionBuilder.childBeanDefinition("user");
        AbstractBeanDefinition UserBeanDefinitionSon = beanDefinitionBuilder2.getBeanDefinition();

        //将两个bean都注册到容器
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        beanFactory.registerBeanDefinition("user",UserBeanDefinition);
        beanFactory.registerBeanDefinition("userSon",UserBeanDefinitionSon);

        User user = (User) beanFactory.getBean("user");
        System.out.println(user);
        User userSon = (User) beanFactory.getBean("userSon");
        System.out.println(userSon);
    }

运行输出:

User{name='张三'}
User{name='张三'}

注意:

  • 有父子关系的时候,我们的 子 创建的不再是rootBeanDifinition对象了,而是childBeanDefinition对象,或者genericBeanDefinition对象,因为只有他们内部才有指定父bean的方法
  • 我们知道,一个bean指定了父bean以后,该bean会拥有父bean的所有属性。但是我们再想一想,子bean拥有了父bean的所有属性,那属性值呢?这些属性会有值吗?我们再看看上面的输出,默认情况下子bean也拥有了相同的值。又有一个疑问,那我们可以为子bean的属性再赋值来覆盖之前的值吗,答案是可以的,如图:
  • Spring进阶(十六)之spring生命周期

案例5:通过api设置(Map、Set、List)属性

 主要是用到这几个对象:

  • ManagedList
  • ManagedSet
  • ManagedMap
  • ManagedProperties
  • RuntimeBeanReference(很重要!!!)
public class Car {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Car{" +
                "name='" + name + '\'' +
                '}';
    }
}
public class UserObj {

    private String name;
    private Integer salary;
    private Car car;
    private List<String> stringList;
    private List<Car> carList;
    private Set<String> stringSet;
    private Set<Car> carSet;
    private Map<String,String> stringMap;
    private Map<String,Car> stringCarMap;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getSalary() {
        return salary;
    }

    public void setSalary(Integer salary) {
        this.salary = salary;
    }

    public Car getCar() {
        return car;
    }

    public void setCar(Car car) {
        this.car = car;
    }

    public List<String> getStringList() {
        return stringList;
    }

    public void setStringList(List<String> stringList) {
        this.stringList = stringList;
    }

    public List<Car> getCarList() {
        return carList;
    }

    public void setCarList(List<Car> carList) {
        this.carList = carList;
    }

    public Set<String> getStringSet() {
        return stringSet;
    }

    public void setStringSet(Set<String> stringSet) {
        this.stringSet = stringSet;
    }

    public Set<Car> getCarSet() {
        return carSet;
    }

    public void setCarSet(Set<Car> carSet) {
        this.carSet = carSet;
    }

    public Map<String, String> getStringMap() {
        return stringMap;
    }

    public void setStringMap(Map<String, String> stringMap) {
        this.stringMap = stringMap;
    }

    public Map<String, Car> getStringCarMap() {
        return stringCarMap;
    }

    public void setStringCarMap(Map<String, Car> stringCarMap) {
        this.stringCarMap = stringCarMap;
    }

    @Override
    public String toString() {
        return "UserObj{" +
                "name='" + name + '\'' +
                ", salary=" + salary +
                ", car=" + car +
                ", stringList=" + stringList +
                ", carList=" + carList +
                ", stringSet=" + stringSet +
                ", carSet=" + carSet +
                ", stringMap=" + stringMap +
                ", stringCarMap=" + stringCarMap +
                '}';
    }
}
    @Test
    void test5(){

        BeanDefinitionBuilder beanDefinitionBuilder1 = BeanDefinitionBuilder.rootBeanDefinition(Car.class.getName());
        beanDefinitionBuilder1.addPropertyValue("name","奥迪");
        AbstractBeanDefinition beanDefinition1 = beanDefinitionBuilder1.getBeanDefinition();

        BeanDefinitionBuilder beanDefinitionBuilder2 = BeanDefinitionBuilder.rootBeanDefinition(Car.class.getName());
        beanDefinitionBuilder2.addPropertyValue("name","宝马");
        AbstractBeanDefinition beanDefinition2 = beanDefinitionBuilder2.getBeanDefinition();

        ManagedList<String> stringList = new ManagedList<>();
        stringList.addAll(Arrays.asList("test1","test2","test3"));

        ManagedList<RuntimeBeanReference> carList = new ManagedList<>();
        carList.add(new RuntimeBeanReference("car1"));
        carList.add(new RuntimeBeanReference("car2"));

        ManagedSet<String> stringSet = new ManagedSet<>();
        stringSet.addAll(Arrays.asList("test1","test2","test3"));

        ManagedSet<RuntimeBeanReference> carSet = new ManagedSet<>();
        carSet.add(new RuntimeBeanReference("car1"));
        carSet.add(new RuntimeBeanReference("car2"));

        ManagedMap<String, String> stringMap = new ManagedMap<>();
        stringMap.put("测试1","test1");
        stringMap.put("测试2","test2");
        stringMap.put("测试3","test3");

        ManagedMap<String, RuntimeBeanReference> stringCarMap = new ManagedMap<>();
        stringCarMap.put("car1",new RuntimeBeanReference("car1"));
        stringCarMap.put("car2",new RuntimeBeanReference("car2"));

        BeanDefinitionBuilder beanDefinitionBuilder3 = BeanDefinitionBuilder.rootBeanDefinition(UserObj.class.getName());
        beanDefinitionBuilder3.addPropertyValue("name","张三");
        beanDefinitionBuilder3.addPropertyValue("salary",50000);
        beanDefinitionBuilder3.addPropertyValue("stringList",stringList);
        beanDefinitionBuilder3.addPropertyValue("carList",carList);
        beanDefinitionBuilder3.addPropertyValue("stringSet",stringSet);
        beanDefinitionBuilder3.addPropertyValue("carSet",carSet);
        beanDefinitionBuilder3.addPropertyValue("stringMap",stringMap);
        beanDefinitionBuilder3.addPropertyValue("stringCarMap",stringCarMap);
        AbstractBeanDefinition beanDefinition3 = beanDefinitionBuilder3.getBeanDefinition();

        DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
        factory.registerBeanDefinition("car1",beanDefinition1);
        factory.registerBeanDefinition("car2",beanDefinition2);
        factory.registerBeanDefinition("UserObj",beanDefinition3);

        System.out.println(factory.getBean("car1"));
        System.out.println(factory.getBean("car2"));
        System.out.println(factory.getBean("UserObj"));

    }

运行输出:

Car{name='奥迪'}
Car{name='宝马'}
UserObj{name='张三', salary=50000, car=null, stringList=[test1, test2, test3], carList=[Car{name='奥迪'}, Car{name='宝马'}], stringSet=[test1, test2, test3], carSet=[Car{name='奥迪'}, Car{name='宝马'}], stringMap={测试1=test1, 测试2=test2, 测试3=test3}, stringCarMap={car1=Car{name='奥迪'}, car2=Car{name='宝马'}}}

XML的方式

我们一开始学spring的时候使用的就是这种方式,已经很熟悉了,这里不做赘述

properties文件的方式

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

employee.(class)=MyClass // 等同于:<bean class="MyClass" />
employee.(abstract)=true // 等同于:<bean abstract="true" />
employee.group=Insurance // 为属性设置值,等同于:<property name="group" value="Insurance" />
employee.usesDialUp=false // 为employee这个bean中的usesDialUp属性设置值,等同于:<property name="usesDialUp" value="false" />
salesrep.(parent)=employee // 定义了一个id为salesrep的bean,指定父bean为employee,等同于:<bean id="salesrep" parent="employee" />
salesrep.(lazy-init)=true // 设置延迟初始化,等同于:<bean lazy-init="true" />
salesrep.manager(ref)=tony // 设置这个bean的manager属性值,是另外一个bean,名称为tony,等同于:<property name="manager" ref="tony" />
salesrep.department=Sales // 等同于:<property name="department" value="Sales" />
techie.(parent)=employee // 定义了一个id为techie的bean,指定父bean为employee,等同于:<bean id="techie" parent="employee" />
techie.(scope)=prototype // 设置bean的作用域,等同于<bean scope="prototype" />
techie.manager(ref)=jeff // 等同于:<property name="manager" ref="jeff" />
techie.department=Engineering // <property name="department" value="Engineering" />
techie.usesDialUp=true // <property name="usesDialUp" value="true" />
ceo.$0(ref)=secretary // 设置构造函数第1个参数值,等同于:<constructor-arg index="0" ref="secretary" />
ceo.$1=1000000 // 设置构造函数第2个参数值,等同于:<constructor-arg index="1" value="1000000" />

注解的方式

对于注解的方式注册bean的话,常见的就是@Component和@Bean了,这里也不做赘述了。

小结

不管是那一种方式注册bean,最终都是会解析成一个BeanDefinition对象。

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

Bean元信息的解析就是将各种方式定义的bean配置信息解析为BeanDefinition对象

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

  1. 解析xml方式定义的bean
  2. 解析properties文件定义的bean
  3. 解析注解方式定义的bean

XML方式解析:XmlBeanDefinitionReader

spring中提供了一个类 XmlBeanDefinitionReader ,将xml中定义的bean解析为BeanDefinition对 象。 

案例:

public class Car {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Car{" +
                "name='" + name + '\'' +
                '}';
    }
}
public class User {

    private String name;

    private Car car;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Car getCar() {
        return car;
    }

    public void setCar(Car car) {
        this.car = car;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", car=" + car +
                '}';
    }

}
<?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 id="car" class="com.example.Car">
        <property name="name" value="宝马"></property>
    </bean>

    <bean id="car1" class="com.example.Car">
        <property name="name" value="奥迪"></property>
    </bean>

    <bean id="car2" parent="car1"></bean>

    <bean id="user" class="com.example.User">
        <property name="name" value="张三"></property>
        <property name="car" ref="car2"></property>
    </bean>

</beans>
    @Test
    public void test1(){

        //创建一个spring容器
        DefaultListableBeanFactory factory = new DefaultListableBeanFactory();

        //定义一个xml方式的bean的读取器,需要传入一个bean的注册器
        XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(factory);

        //根据xml文件的位置解析定义的bean,并将其注册到我们上面指定的spring容器中
        String location="applicationContext.xml";
        xmlBeanDefinitionReader.loadBeanDefinitions(location);

        for (String beanName:factory.getBeanDefinitionNames()){
            System.out.println(beanName+"===>"+factory.getBean(beanName));
        }
    }

运行输出:

car===>Car{name='宝马'}
car1===>Car{name='奥迪'}
car2===>Car{name='奥迪'}
user===>User{name='张三', car=Car{name='奥迪'}}

properties文件定义bean的解析: PropertiesBeanDefinitionReader

spring中提供了一个叫PropertiesBeanDefinitionReader的类,将properties中定义的bean解析为一个BeanDefinition对象

案例:

car.(class)=com.example.Car
car.name=奥迪
car1.(class)=com.example.Car
car1.name=宝马
car2.(parent)=car1
user.(class)=com.example.User
user.name=张三
user.car(ref)=car
    @Test
    public void test2(){

        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();

        PropertiesBeanDefinitionReader propertiesBeanDefinitionReader = new PropertiesBeanDefinitionReader(beanFactory);

        String location="applicationContext.properties";
        propertiesBeanDefinitionReader.loadBeanDefinitions(location);

        for (String beanName:beanFactory.getBeanDefinitionNames()){
            System.out.println(beanName+"===>"+beanFactory.getBean(beanName));
        }
    }

运行输出:

user===>User{name='张三', car=Car{name='宝马'}}
car1===>Car{name='奥迪'}
car===>Car{name='宝马'}
car2===>Car{name='宝马'}

其实解析的方式也和xml差不多,只是换成了对应的类来解析bean而已。

注解方式:AnnotatedBeanDefinitionReader

@Primary
public class Car {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Car{" +
                "name='" + name + '\'' +
                '}';
    }
}
@Lazy
public class User {


    @Autowired
    private Car car;

    public Car getCar() {
        return car;
    }

    public void setCar(Car car) {
        this.car = car;
    }

    @Override
    public String toString() {
        return "User{" +
                "car=" + car +
                '}';
    }
}
    @Test
    public void test3(){

        DefaultListableBeanFactory factory = new DefaultListableBeanFactory();

        AnnotatedBeanDefinitionReader annotatedBeanDefinitionReader = new AnnotatedBeanDefinitionReader(factory);

        annotatedBeanDefinitionReader.register(Car.class,User.class);

        for (String beanName:factory.getBeanDefinitionNames()){
            System.out.println(beanName+"===>"+ factory.getBean(beanName));
        }
    }

运行输出:

car===>Car{name='null'}
user===>User{car=null}

注意:

  1. 我们所说的注解的解析方式,用到了AnnotatedBeanDefinitionReader类来解析
  2. 千万千万别理解错了,并不是说要在类上加上@Component注解,才能通过AnnotatedBeanDefinitionReader类来解析这个类。其实@Component注解就没啥用,相当于一个标识符,就是默认情况下看到@Component标注的注解以后,spring就认为我们要解析这个类为一个bean并放到spring容器中
  3. 可以看到案例里面,注解和xml或者properties方式的解析略有不同,xml或者properties方式是用到了一个叫loadBeanDefinitions()的方法,然后传入文件所在位置。而注解解析的方式是用到了register()方法,传入的参数是需要的类,且是一个可变参数。
  4. 根据输出,我们可以看到user里面的car为空,为什么啊?明明我们已经用@Autowired注入了啊,这个疑问后面再来解答

阶段3:Spring Bean注册阶段

bean注册阶段需要用到一个非常重要的接口:BeanDefinitionRegistry 

Bean注册接口:BeanDefinitionRegistry

该接口中定义了常用的操作bean的方法

先来看看这个接口的源码:

public interface BeanDefinitionRegistry extends AliasRegistry {

	/**
	 * 注册一个新的beanDefinition
	 */
	void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
			throws BeanDefinitionStoreException;

	/**
	 * 从容器中移除指定名称的bean
	 */
	void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;

	/**
	 * 返回该bean的定义信息
	 */
	BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;

	/**
	 * 返回容器中是否含有该bean
	 */
	boolean containsBeanDefinition(String beanName);

	/**
	 * 返回容器中bean的名称列表
	 */
	String[] getBeanDefinitionNames();

	/**
	 * 返回容器中bean的数量
	 */
	int getBeanDefinitionCount();

	/**
	 * 返回该bean是否被使用。(beanName可以时名称或者别名)
	 */
	boolean isBeanNameInUse(String beanName);

}

别名注册接口:AliasRegistry

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

public interface AliasRegistry {

	/**
	 * 为该bean创建一个别名
	 */
	void registerAlias(String name, String alias);

	/**
	 * 移除该别名
	 */
	void removeAlias(String alias);

	/**
	 * 返回该别名是否使用
	 */
	boolean isAlias(String name);

	/**
	 * 返回别名列表
	 */
	String[] getAliases(String name);

}

DefaultListableBeanFactory类

该类是BeanDefinitionRegistry的实现类

我们打开源码可以看到BeanDefinitionRegistry有很多实现类,那为什么特别提到了其中的DefaultListableBeanFactory实现类你,因为其它实现类的内部都是转发给DefaultListableBeanFactory进行处理的,所以真正的实现BeanDefinitionRegistry这个接口的类是DefaultListableBeanFactory

阶段4:BeanDefinition合并阶段

可能我们定义bean的时候有父子bean关系,此时子BeanDefinition中的信息是不完整的,比如设置属性的时候配置在父BeanDefinition中,此时子BeanDefinition中是没有这些信息的,或者子bean和父bean中都设置了属性,那我们此时的子beanDefinition肯定是不完整的,需要将子bean的 BeanDefinition和父bean的BeanDefinition进行合并,如果有冲突的属性,子bean的属性会覆盖父bean的,经过上面的操作最终就会得到一个 RootBeanDefinition ,合并之后得到的 RootBeanDefinition 包含bean定义的所有信息,包含了从父bean中继继承过来的所有信息,后续bean的所有创建工作就是依靠合并之后BeanDefinition来进行的。 合并BeanDefinition会使用下面这个方法:

org.springframework.beans.factory.support.AbstractBeanFactory#getMergedBeanDefin ition

bean定义可能存在多级父子关系,合并的时候进进行递归合并,最终得到一个包含完整信息的 RootBeanDefinition

案例

public class Course {

    private String courseName;

    private String description;

    public String getCourseName() {
        return courseName;
    }

    public void setCourseName(String courseName) {
        this.courseName = courseName;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    @Override
    public String toString() {
        return "Course{" +
                "courseName='" + courseName + '\'' +
                ", description='" + description + '\'' +
                '}';
    }
}
<?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 id="course" class="com.example.Course"></bean>

    <bean id="course1" parent="course">
        <property name="courseName" value="java"></property>
        <property name="description" value="java核心技术课程"></property>
    </bean>

    <bean id="course2" parent="course1">
        <property name="description" value="javaWeb课程"></property>
    </bean>

</beans>
public class mergeBeanDefinitionTest {
    @Test
    public void test(){

        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();

        XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

        String location="applicationContext.xml";
        xmlBeanDefinitionReader.loadBeanDefinitions(location);

        for (String beanName:beanFactory.getBeanDefinitionNames()){
            System.out.println("-------------------------");
            System.out.println(beanName);

            System.out.println("合并前");
            BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);
            System.out.println(beanDefinition);
            for (PropertyValue property:beanDefinition.getPropertyValues()){
                System.out.println(property.getName()+"====>"+property.getValue());
            }
            //调用该方法将父子beanDefinition合并,才能让子的beanDefinition完整
            BeanDefinition mergedBeanDefinition = beanFactory.getMergedBeanDefinition(beanName);

            System.out.println("合并后");
            System.out.println(mergedBeanDefinition);
            for (PropertyValue property:mergedBeanDefinition.getPropertyValues()){
                System.out.println(property.getName()+"====>"+property.getValue());
            }
            System.out.println("-------------------------");
        }
    }
}

 运行输出:

-------------------------
course
合并前
Generic bean: class [com.example.Course]; 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 [applicationContext.xml]
合并后
Root bean: class [com.example.Course]; scope=singleton; 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 [applicationContext.xml]
-------------------------
-------------------------
course1
合并前
Generic bean with parent 'course': class [null]; 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 [applicationContext.xml]
courseName====>TypedStringValue: value [java], target type [null]
description====>TypedStringValue: value [java核心技术课程], target type [null]

合并后
Root bean: class [com.example.Course]; scope=singleton; 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 [applicationContext.xml]
courseName====>TypedStringValue: value [java], target type [null]
description====>TypedStringValue: value [java核心技术课程], target type [null]

-------------------------
-------------------------
course2
合并前
Generic bean with parent 'course1': class [null]; 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 [applicationContext.xml]
description====>TypedStringValue: value [javaWeb课程], target type [null]

合并后
Root bean: class [com.example.Course]; scope=singleton; 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 [applicationContext.xml]
courseName====>TypedStringValue: value [java], target type [null]
description====>TypedStringValue: value [javaWeb课程], target type [null]

-------------------------

重点观察彩色字体部分, course1继承了course,但course本身就没有属性,绿色部分的属性本身就是course1自己的,所有合并前合并后都有这些属性并不奇怪。我们再看看cours2的黄色部分,course2是继承了course1的,course2本身有一个description属性,所以合并之前course2只有一个description属性并不奇怪,但是我们看看合并之后,course2有了courseName属性了,这就是从course1继承过来的属性,这说明了什么?说明就是通过我们调用了getMergeBeanDefinition()以后,子bean和父bean合并,从而让我们的子bean拥有完整的beanDefinition信息,验证了上面的说法!!!还有一点,如果我们在合并如果打印一下调用getMergeBeanDefinition方法返回的对象,就会发现该BeanDefinition对象的类型已经从GenericBeanDefinition变为RootBeanDefinition类型了,并且以后操作都是又这个完整的RootBeanDefinition来完成。

阶段5:Bean Class加载阶段

这个阶段就是将bean的class名称转换为Class类型的对象

BeanDefinition中有个Object类型的字段:beanClass

private volatile Object beanClass;

用来表示bean的class对象,通常这个字段的值有2种类型,一种是bean对应的Class类型的对象另一 种是bean对应的Class的完整类名,第一种情况不需要解析,第二种情况:即这个字段是bean的类名的时候,就需要通过类加载器将其转换为一个Class对象。 此时会对阶段4中合并产生的 RootBeanDefinition 中的 beanClass 进行解析,将bean的类名转换为 Class对象 ,然后赋值给 beanClass 字段。 

源码位置:

org.springframework.beans.factory.support.AbstractBeanFactory#resolveBeanClass

然后就开始进入下面的实例化这个对象的阶段了。我们下篇文章继续来看!!!文章来源地址https://www.toymoban.com/news/detail-435119.html

到了这里,关于Spring进阶(十六)之spring生命周期的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Spring整理-Spring Bean的生命周期

    Spring Bean的生命周期涉及多个阶段,从Bean的定义到其销毁。在这个过程中,Spring容器负责创建、初始化、使用和最终销毁Bean。了解这个生命周期有助于更好地管理Bean的行为和资源使用。 实例化(Instantiation): 容器首先创建Bean的实例。 填充属性(Populate Properties): 容器

    2024年01月21日
    浏览(53)
  • Spring Bean的生命周期 -- Spring入门(三)

    为了巩固所学的知识,作者尝试着开始发布一些学习笔记类的博客,方便日后回顾。当然,如果能帮到一些萌新进行新技术的学习那也是极好的。作者菜菜一枚,文章中如果有记录错误,欢迎读者朋友们批评指正。 (博客的参考源码以及可以在我主页的资源里找到,如果在学

    2024年02月15日
    浏览(36)
  • 【Spring】Spring之Bean生命周期源码解析

    什么是bean的生命周期 是指bean在spring中是如何生成,如何销毁的; spring创建对象的过程,就是IOC(控制反转)的过程; JFR Java Flight Record,java飞行记录,类似于飞机的黑匣子,是JVM内置的基于事件的JDK监控记录框架,主要用于问题定位和持续监控; 入口代码: Spring启动的时

    2024年02月15日
    浏览(46)
  • Spring bean 生命周期

    在互联网领域中,Spring框架扮演着重要的角色。作为一个开源的Java应用程序开发框架,Spring提供了一种灵活而强大的方式来构建可扩展的应用程序。Spring框架中的一个重要概念是Bean,它是Spring应用程序的基本构建块之一。了解Spring Bean的生命周期对于充分利用Spring框架的功能

    2024年02月11日
    浏览(47)
  • 【Spring】—— bean生命周期

    1、初始化容器 1)创建对象(分配内存) 2)执行构造方法 3)执行属性注入(set操作) 4)执行bean初始化方法 2、使用bean 1)执行业务操作 3、关闭/销毁容器 1)执行bean销毁方法

    2024年02月02日
    浏览(50)
  • Spring:Bean生命周期

    Bean 生命周期 是 bean 对象从创建到销毁的整个过程。 简单的 Bean 生命周期的过程: 1.实例化(调用构造方法对 bean 进行实例化) 2.依赖注入(调用 set 方法对 bean 进行赋值) 3.初始化(手动配置 xml 文件中 bean 标签的 init-method 属性值,来指定调用对应的初始化方法) 4.使用

    2024年02月13日
    浏览(42)
  • 浅析Spring生命周期

    Spring框架是一个非常流行的Java企业级应用程序框架,已经成为许多生产环境中的首选技术。它提供了一种便捷的方法来帮助开发人员构建可扩展和模块化的企业级应用程序。在Spring框架中,Bean生命周期是非常重要的一部分,它负责Bean的创建和销毁。 Spring框架中Bean的完整生

    2024年02月08日
    浏览(33)
  • 【Spring】Bean的作用域与生命周期详情:请简述Spring的执行流程并分析Bean的生命周期?

     我们都知道,Spring框架为开发人员提供了很多便捷,这使得开发人员能够更加专注于应用程序的核心业务逻辑,而不需要花费大量时间和精力在技术细节上。作为一个包含众多工具方法的IoC容器,存取JavaBean是其极为重要的一个环节。本文就对Spring中的Bean的作用域和生命周

    2024年02月12日
    浏览(48)
  • Spring Bean的生命周期

    Bean生命周期的整个执行过程描述如下: 1、根据配置情况调用Bean构造方法或工厂方法实例化 Bean。 2、利用依赖注入完成Bean中所有属性值的配置注入。 3、如果Bean 实现了BeanNameAware 接口,则 Spring调用Bean的setBeanName()方法传入当前Bean的id值。 4、如果Bean实现了BeanFactoryAware 接口

    2023年04月22日
    浏览(65)
  • Spring -- Bean的生命周期

    Spring容器在进行实例化时,会将xml配置的bean的信息封装成一个BeanDefinition对象,Spring根据BeanDefinition来创建Bean对象,里面有很多的属性用来描述Bean   BeanDefinition 中几个重要方法如下 beanClassName:bean 的类名 initMethodName:初始化方法名称 properryValues:bean 的属性值 scope:作用域

    2024年02月15日
    浏览(54)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包