Spring源码解析之 Bean与BeanDefinition详解

Spring解决的核心问题
Spring解决的核心问题: 把对象之间的关系用配置来管理

  • 依赖注入: 依赖关系在Spring的IOC容器中管理
  • 通过把对象包装在Bean中, 以达到管理对象和进行额外操作的目的


Bean与BeanDefinition
Bean 是Spring的一等公民

  • Bean 的本质就是Java对象, 这个对象的生命周期由Spring容器来进行管理
  • 不需要为了创建Spring的Bean 而在Java类上做额外的限制, 体现了Spring的低侵入.
  • 对于Java对象的控制体现在配置上(配置文件或注解)

 

在Spring中, 是根据配置, 生成用来描述Bean的BeanDefinition. 类似于Java中描述类的Class.
BeanDefinition的几个重要属性:

  1. Bean 的作用范围 @Scope: singleton prototype session globalsession request
  2. 懒加载lazy-init(@Lazy) : 决定Bean实例是否延迟加载
  3. 首选primary(@Primary) : 如果一个接口有多个实现类, 那么设置为true的bean,会被选择优先的实现类
  4. factory-bean(工厂bean的名称) 和factory-method(工厂 方法的名称) (@Configuration和@Bean)

 

创建一个User类
package com.imooc.entity;

public class User {
}

静态工厂类
package com.imooc.entity.factory;

import com.imooc.entity.User;

public class StaticFactory {
    public static User getUser() {
        return new User();
    }
}

实例工厂类

package com.imooc.entity.factory;

import com.imooc.entity.User;

public class UserFactory {
    public User getUser() {
        return new User();
    }
}
<?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="welcomeService" class="com.imooc.service.impl.WelcomeServiceImpl"/>
    <!--1. 使用类的无参构造函数创建-->
    <bean id = "user1" class="com.imooc.entity.User" scope="singleton" lazy-init="true" primary="true"/>

    <!--2.使用静态工厂进行创建-->
    <!-- class的值不是写User对象的全路径 而是写静态工厂的全路径 -->
    <!-- factory-method的值写要调用的方法 -->
    <bean id="user2" class="com.imooc.entity.factory.StaticFactory" factory-method="getUser" scope="singleton" />

    <!--3.使用实例工厂进行创建-->
    <!--需要先创建factoryBean对象,再通过factoryBean对象进行调用-->
    <bean id="userFactory" class="com.imooc.entity.factory.UserFactory" />
    <bean id="user3" factory-bean="userFactory" factory-method="getUser" scope="singleton"/>


</beans>

配置文件的解读

  1. bean的id为user1的, 配置了Scope为单例, 延迟加载, 并且是首选的bean
  2. id为user2的bean , 定义了一个factory-method 即工厂方法. 之所以能够定义一个工厂方法, 是因为StaticFactory类中, 有public static User getUser()静态方法, 可以从该方法中, 通过类名静态的获取Bean的实例.
  3. id为userFactory的bean, 定义了UserFactory这个类, 该类的方法为public User getUser(), 由于不是静态的, 因此不能定义工厂方法
  4. id为user3的, 定义了一个factory-bean, 即工厂bean, 这个bean取自id为userFactory的bean , factory-method工厂方法为UserFactory这个类的getUser方法

 

代码运行测试

    public static void main(String[] args) {
        System.out.println("hello world");
        String xmlPath = "D:\\coding\\spring-framework-5.2.0.RELEASE\\springdemo\\src\\main\\resources\\spring\\spring-config.xml";
        ApplicationContext applicationContext = new FileSystemXmlApplicationContext(xmlPath);
        WelcomeService welcomeService = (WelcomeService)applicationContext.getBean("welcomeService");
        welcomeService.sayHello("试水Spring框架");

        User user1a = (User) applicationContext.getBean("user1");
        User user1b = (User) applicationContext.getBean("user1");

        System.out.println("无参构造函数创建的对象:"+user1a);
        System.out.println("无参构造函数创建的对象:"+user1b);

        User user2a = (User) applicationContext.getBean("user2");
        User user2b = (User) applicationContext.getBean("user2");
        System.out.println("静态工厂创建的对象:"+user2a);
        System.out.println("静态工厂创建的对象:"+user2b);

        User user3a = (User) applicationContext.getBean("user3");
        User user3b = (User) applicationContext.getBean("user3");
        System.out.println("实例工厂创建的对象:"+user3a);
        System.out.println("实例工厂创建的对象:"+user3b);

    }

 

Spring容器主要流程

  • 读取配置(xml或者注解)到内存中 (解析配置)
  • 在内存中, 这些配置会被转化为Resource对象
  • Resource对象被解析为BeanDefinition实例
  • 把BeanDefinition实例注册到容器中 (通过配置定位对象, 把定位到的对象, 注册到容器中)

与BeanDefinition相关的类

BeanDefinition的主要类关系图如下

 

 

 

 

BeanDefinition 是在spring-beans模块中的

 

spring-beans模块存放的是Bean和简单容器相关的接口和类.
BeanDefinition 继承了AttributeAccessor, BeanMetadataElement 这两个接口 .
在Spring中, 某个类继承或实现了某个接口, 也就代表了这个类或者接口有哪些功能.

 

AttributeAccessor

AttributeAccessor : 该接口的描述如下, 该接口定义了对任意数据元数据的修改或获取方式.

* Interface defining a generic contract for attaching and accessing metadata
 * to/from arbitrary objects.

 

BeanMetadataElement
BeanMetadataElement 接口, 主要是提供了getSource() 方法. 该方法是用于传输一个可配置的元对象, 主要是返回BeanDefinition 这个对象本身.

Return the configuration source Object for this metadata element (may be null).

 


AbstractBeanDefinition
AbstractBeanDefinition 抽象类, 实现了BeanDefinition 接口, 里面的方法用于给通用的属性赋值.
其一些方法如下.

 

 

 

AbstractBeanDefinition 抽象类基础上, 衍生出了如下的一些子类.

 

 

RootBeanDefinition

RootBeanDefinition 类中有如下的方法. 该方法说明了RootBeanDefinition 类不能作为其他BeanDefinition类的子类 , 但可以作为父类.

    @Override
    public void setParentName(@Nullable String parentName) {
        if (parentName != null) {
            throw new IllegalArgumentException("Root bean cannot be changed into a child bean with parent reference");
        }
    }

 

 

在DefaultListableBeanFactory 类中有private String[] doGetBeanNamesForType(ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit) 方法, 使用到了RootBeanDefinition.
可以看到是调用了getMergedLocalBeanDefinition 方法用于合并bean 的.

 

 

ChildBeanDefinition
ChildBeanDefinition是一个子类, 不能单独存在, 必须要依赖于一个父的BeanDefinition. ChildBeanDefinition目前已经完全被GenericBeanDefinition 取代.

GenericBeanDefinition
GenericBeanDefinition 是通用的BeanDefinition实现. 是一个Bean文件属性定义类,
GenericBeanDefinition 类有如下的setParentName方法, 该方法可以设置parentName, 不会像RootBeanDefinition去抛异常.

@Override
    public void setParentName(@Nullable String parentName) {
        this.parentName = parentName;
    }

 

posted @ 2021-05-30 15:27  year12  阅读(389)  评论(0编辑  收藏  举报