SpringIOC源码解析(1)—— Bean与BeanDefinition

 2023-02-17
原文作者:小王曾是少年 原文地址:https://juejin.cn/post/7026299916381061156

全局视角看核心接口和类

解决了关键的问题:将对象之间的关系转而用配置来管理

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

Bean与BeanDefinition

Bean是Spring的一等公民:

  • Bean的本质就是java对象,只是这个对象的生命周期由容器来管理
  • 不需要为了创建Bean而在原来的java类上添加任何额外的限制
  • 对java对象的控制方式体现在配置上

BeanDefinition是Bean的定义

根据配置,生成用来描述Bean的BeanDefinition,常用属性如下:

jdk中使用java.lang.class来描述这个对象,spring使用BeanDefinition来描述bean

  • 作用范围 scope(@Scope

  • 懒加载 lazy-init(@Lazy):决定Bean实例是否延迟加载

  • 首选primary(@Primary):设置为true的bean会是优先的实现类

    • 一个接口对应多个实现bean的情况下,使用这个注解的接口会被优先实现
  • factory-bean 和 factory-method(@Configuration@Bean

无参构造方法创建bean的演示: 在项目中创建一个entity包,并创建一个User类

    package com.wjw.entity;
    
    public class User {
    
    }

此时在xml中定义相应的bean可以使用无参的构造方法来实现

    <bean id="user1" class="com.wjw.entity.User" scope="singleton" lazy-init="true" primary="true"/>

使用静态工厂创建bean演示: 再创建一个静态工厂类

    package com.wjw.entity.factory;
    
    import com.wjw.entity.User;
    
    public class StaticFactory {
    
       public static User getUser(){
          return new User();
       }
    }

此时在xml中定义相应的bean可以使用静态工厂方法来实现

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

使用实例工厂创建bean示例:

    package com.wjw.entity.factory;
    
    import com.wjw.entity.User;
    
    public class UserFactory {
    
       public User getUser(){
          return new User();
       }
    }

由于方法不是静态的,所以不能直接调用,只能先创建一个工厂的对象,然后通过对象再进行调用

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

测试:

    package com.wjw;
    
    import com.wjw.controller.WelcomeController;
    import com.wjw.entity.User;
    import com.wjw.service.WelcomeService;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.support.FileSystemXmlApplicationContext;
    
    @Configuration
    @ComponentScan("com.wjw")
    public class Entrance {
    
       public static void main(String[] args) {
          System.out.println("Hello World!");
          String xmlPath = "F:\\Java\\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");
          //得到静态工厂创建的对象:
          User user2a = (User) applicationContext.getBean("user2");
          User user2c = (User) applicationContext.getBean("user2");
          //得到实例工厂创建的对象:
          User user3a = (User) applicationContext.getBean("user3");
          User user3b = (User) applicationContext.getBean("user3");
    
    
          System.out.println("无参构造函数创建的对象:" + user1a);
          System.out.println("无参构造函数创建的对象:" + user1b);
          System.out.println("静态工厂创建的对象:" + user2a);
          System.out.println("静态工厂创建的对象:" + user2c);
          System.out.println("实例工厂创建的对象:" + user3a);
          System.out.println("实例工厂创建的对象:" + user3b);
       }
    }

202301012110413941.png

容器初始化主要做的事情(主要脉络)

202301012110420282.png

BeanDefinition源码

202301012110425223.png

202301012110430894.png 继承了两个接口,spring中充斥着大量接口,继承某个接口就意味着具有某一项功能。

  • AttributeAccessor定义了最基本的对任意对象元数据的修改或者获取方式,用在这里主要就是为了获取BeanDefinition的属性,并操作这些属性。
  • BeanMetadataElement主要定义了一个getSource方法,用于返回一个可配置的源对象,用在这里主要就是为了返回BeanDefinition对象本身。
  • AttributeAccessorSupportAttributeAccessor的实现类。
  • AbstractBeanDefinition是BeanDefinition实现类的基类,定义了一些初始化通用属性的构造函数,以及对应的getter和setter,还有一些操作的通用方法。基于AbstractBeanDefinition抽象类,spring实现了一些有特殊用途的BeanDefinition。
  • RootBeanDefinition可以单独作为BeanDefinition,也可以作为其他BeanDefinition的父类,但不能作为其他的子类。(通常用来在运行时接收多个BeanDefinition合并起来的信息,可以接收具有继承关系的多个BeanDefinition,承接他们合并在一起的除了parent属性以外的属性)。一般情况下,配置文件里的bean标签会被解析成为RootBeanDefinition,但spring2.5之后使用GenericBeanDefinition来代替了,但因为先前的根基,所以在合并BeanDefinition时还是会用RootBeanDefinition来接收。

202301012110435905.png ps:spring中的继承是通过设置parent属性来决定的,不是extends

  • ChildBeanDefinition 已经被取代了。
  • GenericBeanDefinition(bean文件配置属性定义类)除了具有BeanDefinition属性之外还有parent属性,方便程序运行时去设定parent BeanDefinition,不会报异常,是一种更好的方案。