Spring 中的BeanDefinition及其实现和BeanDefinitionReader

1 BeanDefinition

1.1 什么是BeanDefinition

什么是BeanDefinition?

在回答这个问题之前,先想一下我们通常是如何去定义一个Bean?

1、通过xml文件配置Bean,

2、通过配置类配置Bean,@Bean

3、通过注解自动扫描成Bean,@Component(@Service,@Controller等)

其实上面的三种我们通常定义Bean的方式,最终也都会被解析成BeanDefinition对象。再由BeanFactory根据BeanDefinition生成对应的Bean。

1.2 BeanDefinition设计理解

Spring 中的BeanDefinition及其实现和BeanDefinitionReader_第1张图片

 Spring 中的BeanDefinition及其实现和BeanDefinitionReader_第2张图片

     在Spring设计中,将Bean的属性抽离共性,从而定义了BeanDefinition接口,接口作为顶层设计,它抽象出了 Bean 的属性,将其统一管理起来。

    通过 BeanDefinition,可以将 Bean 的属性和配置信息抽象出来,并且将 BeanDefinition 存储在 Spring 容器中,以便在需要的时候创建和管理 Bean。

    BeanDefinition 中包含了许多属性,如 Bean 的名称、类型、作用域、构造函数参数、属性等等,这些属性可以通过 XML 配置、注解、Java 配置等方式进行配置,BeanDefinition 还可以设置生命周期回调方法,用于在 Bean 的生命周期中执行一些初始化或销毁操作。

    通过抽象出 BeanDefinition,Spring 将 Bean 的创建和管理逻辑与具体的实现解耦,使得用户可以更加灵活地配置 Bean,并且方便地进行单元测试、模拟等操作

2 BeanDefinition的父类及自身

2.1 AttributeAccessor接口

       BeanDefinition继承了AttributeAccessor接口,而AttributeAccessor接口主要定义了属性分访问方法,包括设置,获取,移除等等方法。

public interface AttributeAccessor {

    /**设置属性*/
    void setAttribute(String name, @Nullable Object value);

    /**获取属性*/
    Object getAttribute(String name);

    /**移除属性*/
    Object removeAttribute(String name);

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

    /**获取属性名称*/
    String[] attributeNames();
}

这个方法很简单,我们来看看他的实现类:AttributeAccessorSupport

2.1.1  AttributeAccessor接口实现类AttributeAccessorSupport

      AttributeAccessorSupport类是一个抽象类,实现了AttributeAccessor接口,里面定义了通用的方法来保存或者读取元数据的方法。

       AttributeAccessorSupport便实现了这个方法,AttributeAccessorSupport定义了一个map容器,元数据就被保存在这个map里面。

public abstract class AttributeAccessorSupport implements AttributeAccessor, Serializable {

	/** Map with String keys and Object values. */
	private final Map attributes = new LinkedHashMap<>();

	@Override
	public void setAttribute(String name, @Nullable Object value) {
		if (value != null) {
			this.attributes.put(name, value);
		}
		else {
			removeAttribute(name);
		}
	}

	@Override
	public Object getAttribute(String name) {
		return this.attributes.get(name);
	}
    
	@Override
	public Object removeAttribute(String name) {
		return this.attributes.remove(name);
	}

    
	@Override
	public boolean hasAttribute(String name) {
		return this.attributes.containsKey(name);
	}
    
	@Override
	public String[] attributeNames() {
		return StringUtils.toStringArray(this.attributes.keySet());
	}

	protected void copyAttributesFrom(AttributeAccessor source) {
		String[] attributeNames = source.attributeNames();
		for (String attributeName : attributeNames) {
			setAttribute(attributeName, source.getAttribute(attributeName));
		}
	}

	@Override
	public boolean equals(@Nullable Object other) {
		return (this == other || (other instanceof AttributeAccessorSupport &&
				this.attributes.equals(((AttributeAccessorSupport) other).attributes)));
	}

	@Override
	public int hashCode() {
		return this.attributes.hashCode();
	}
}

    实际上AttributeAccessorSupport维护着一个LinkedHashMap的属性集合,但是为什么不直接写在BeanDefinition接口中?Spring的AttributeAccessorSupport是一个实用类,用于方便地管理对象的属性(attributes),它实现了AttributeAccessor接口,这意味着它可以处理对象的任意属性,并提供一组便捷的方法来添加、获取、删除和检查属性。

2.2 BeanMetadataElement接口

BeanMetadataElement接口提供了一个方法来获取Bean的源对象,这个源对象就是源文件,我是我们编写的Class文件


public interface BeanMetadataElement {


	/*** 获取元数据的资源描述*/
	@Nullable
	default Object getSource() {
		return null;
	}
}

 2.3. BeanDefinition接口

Spring 的 BeanDefinition用于描述 Spring 容器中的 bean,包括 bean 的名称、类型、作用域、构造函数参数、属性等。

接口设计

Spring 的 BeanDefinition 是一个接口,它定义了一系列方法用于设置和获取 bean 的属性。这种设计模式使得 Spring 可以通过实现 BeanDefinition 接口来支持不同类型的 bean 定义。

属性配置

BeanDefinition 中包含了许多属性,如 bean 的名称、类型、作用域、构造函数参数、属性等。Spring 提供了多种方式来配置这些属性,包括 XML 配置、注解、Java 配置等。

延迟初始化

Spring 支持延迟初始化,即只有在需要使用 bean 的时候才会初始化它。为了实现延迟初始化,BeanDefinition 中可以设置一个 lazy-init 属性。当这个属性设置为 true 时,Spring 将会在第一次使用 bean 的时候才创建它。

作用域

BeanDefinition 中包含一个 scope 属性,用于设置 bean 的作用域。Spring 支持多种作用域,包括 singleton、prototype、request、session、application 等。不同的作用域对应着不同的生命周期,Spring 会根据不同的作用域来管理 bean 的生命周期。

生命周期回调

BeanDefinition 中可以设置生命周期回调方法,这些方法会在 bean 的生命周期中被调用。Spring 提供了多种生命周期回调方法,包括 InitializingBean 和 DisposableBean 接口、@PostConstruct 和 @PreDestroy 注解等。

在代码的设计中,可以看到 BeanDefinition 接口提供了一系列操作 Bean 元数据的set、get方法,这些操作为 Bean 的描述定义了一套模板,具体的实现则交由子类。

Spring 中的BeanDefinition及其实现和BeanDefinitionReader_第3张图片

 

public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {

	// 单例、原型标识符
	String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;
	String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;

    // 标识 Bean 的类别,分别对应 用户定义的 Bean、来源于配置文件的 Bean、Spring 内部的 Bean
	int ROLE_APPLICATION = 0;
	int ROLE_SUPPORT = 1;
	int ROLE_INFRASTRUCTURE = 2;

    // 设置、返回 Bean 的父类名称
	void setParentName(@Nullable String parentName);
	String getParentName();

    // 设置、返回 Bean 的 className
	void setBeanClassName(@Nullable String beanClassName);
	String getBeanClassName();

    // 设置、返回 Bean 的作用域
	void setScope(@Nullable String scope);
	String getScope();

    // 设置、返回 Bean 是否懒加载
	void setLazyInit(boolean lazyInit);
	boolean isLazyInit();
	
	// 设置、返回当前 Bean 所依赖的其它 Bean 名称。
	void setDependsOn(@Nullable String... dependsOn);
	String[] getDependsOn();
	
	// 设置、返回 Bean 是否可以自动注入。只对 @Autowired 注解有效
	void setAutowireCandidate(boolean autowireCandidate);
	boolean isAutowireCandidate();
	
	// 设置、返回当前 Bean 是否为主要候选 Bean 。
	// 当同一个接口有多个实现类时,通过该属性来配置某个 Bean 为主候选 Bean。
	void setPrimary(boolean primary);
	boolean isPrimary();

    // 设置、返回创建该 Bean 的工厂类。
	void setFactoryBeanName(@Nullable String factoryBeanName);
	String getFactoryBeanName();
	
	// 设置、返回创建该 Bean 的工厂方法
	void setFactoryMethodName(@Nullable String factoryMethodName);
	String getFactoryMethodName();
	
	// 返回该 Bean 构造方法参数值、所有属性
	ConstructorArgumentValues getConstructorArgumentValues();
	MutablePropertyValues getPropertyValues();

    // 返回该 Bean 是否是单例、是否是非单例、是否是抽象的
	boolean isSingleton();
	boolean isPrototype();
	boolean isAbstract();

    // 返回 Bean 的类别。类别对应上面的三个属性值。
	int getRole();
    ...
}

2.3.1  组装一个简单Bean

package com.cect.BeanDefinition;

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 + '\'' + '}';
    }
}
package com.cect.BeanDefinition;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;

public class MainClass {
    public static void main(String args[]){
        BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.rootBeanDefinition(User.class.getName());
        AbstractBeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();
        System.out.println(beanDefinition);
    }
}

运行结果:

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

2.3.2  组装一个有属性的Bean

User.class 同组装一个简单Bean

package com.cect.BeanDefinition;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;

public class MainClass {
    public static void main(String args[]){
        BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.rootBeanDefinition(User.class.getName());
        //给该bean的name属性设置值
        beanDefinitionBuilder.addPropertyValue("name","liq");
        AbstractBeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();
        System.out.println(beanDefinition);
        //创建一个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.cect.BeanDefinition.User]; scope=; abstract=false; lazyInit=null; autowireMode=0;dependencyCheck=0;autowireCandidate=true;primary=false; factoryBeanName=null;factoryMethodName=null;initMethodName=null;destroyMethodName=null

User{name='liq'}

2.3.3 组装一个有依赖关系的Bean

package com.cect.BeanDefinition;

public class User {

    private String name;
    private Car car;
    //setter and getter
}


package com.cect.BeanDefinition;

public class Car {
    private String name;
    //setter and getter
}
package com.cect.BeanDefinition;

import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;

public class MainClass {
    public static void main(String args[]){
        //创建Car对象,并为其赋值
        BeanDefinitionBuilder beanDefinitionBuilder2 = BeanDefinitionBuilder.rootBeanDefinition(Car.class.getName());
        beanDefinitionBuilder2.addPropertyValue("name","SKODA");
        AbstractBeanDefinition CarBeanDefinition = beanDefinitionBuilder2.getBeanDefinition();

        //创建User对象,并为其赋值
        BeanDefinitionBuilder beanDefinitionBuilder1 = BeanDefinitionBuilder.rootBeanDefinition(User.class.getName());
        beanDefinitionBuilder1.addPropertyValue("name","Liq");
        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='SKODA'}

User{name='Liq', car=Car{name='SKODA'}}

2.3.4  组装一个有父子关系的Bean

package com.cect.BeanDefinition;

public class User {

    private String name;

    private String  age;
//setter and getter
}
package com.cect.BeanDefinition;

import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;

public class MainClass {
    public static void main(String args[]){
        //创建一个bean
        BeanDefinitionBuilder beanDefinitionBuilder1 = BeanDefinitionBuilder.rootBeanDefinition(User.class.getName());
        beanDefinitionBuilder1.addPropertyValue("name","Liq");
        AbstractBeanDefinition UserBeanDefinition = beanDefinitionBuilder1.getBeanDefinition();

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

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

        User user = (User) beanFactory.getBean("user");
        BeanDefinition userBD = beanFactory.getBeanDefinition("user");
        System.out.println("userBD="+userBD);
        System.out.println("user="+user);
        User userSon = (User) beanFactory.getBean("userSon");
        BeanDefinition userSonBD = beanFactory.getBeanDefinition("userSon");
        System.out.println("userSonBD="+userSonBD);
        System.out.println("userSon="+userSon);
    }
}

运行结果:

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

user=User{name='Liq', age=null}

userSonBD=Child bean with parent 'user': class [null]; scope=; abstract=false; lazyInit=null; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null

userSon=User{name='Liq', age=28}

2.3.5  通过api设置(Map、Set、List)属性

package com.cect.BeanDefinition;

public class User {

    private String name;
//setter and getter
}
package com.cect.BeanDefinition;

import java.util.List;
import java.util.Map;
import java.util.Set;

public class UserObj {

    private String name;
    private Integer salary;
    private User user;
    private List stringList;
    private List userList;
    private Set stringSet;
    private Set userSet;
    private Map stringMap;
    private Map stringUserMap;
//setter and getter
}
package com.cect.BeanDefinition;

import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.support.*;
import java.util.Arrays;

public class MainClass {
    public static void main(String args[]){
        BeanDefinitionBuilder liqBDB = BeanDefinitionBuilder.rootBeanDefinition(User.class.getName());
        liqBDB.addPropertyValue("name","Liq");
        AbstractBeanDefinition liqBD = liqBDB.getBeanDefinition();

        BeanDefinitionBuilder ScyBDB = BeanDefinitionBuilder.rootBeanDefinition(User.class.getName());
        ScyBDB.addPropertyValue("name","Scy");
        AbstractBeanDefinition ScyBD = ScyBDB.getBeanDefinition();

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

        ManagedList userList = new ManagedList<>();
        userList.add(new RuntimeBeanReference("LiqBean"));
        userList.add(new RuntimeBeanReference("ScyBean"));

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

        ManagedSet userSet = new ManagedSet<>();
        userSet.add(new RuntimeBeanReference("LiqBean"));
        userSet.add(new RuntimeBeanReference("ScyBean"));

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

        ManagedMap stringUserMap = new ManagedMap<>();
        stringUserMap.put("user1",new RuntimeBeanReference("LiqBean"));
        stringUserMap.put("user2",new RuntimeBeanReference("ScyBean"));

        BeanDefinitionBuilder beanDefinitionBuilder3 = BeanDefinitionBuilder.rootBeanDefinition(UserObj.class.getName());
        beanDefinitionBuilder3.addPropertyValue("name","jwl");
        beanDefinitionBuilder3.addPropertyValue("salary",50000);
        beanDefinitionBuilder3.addPropertyValue("user",new RuntimeBeanReference("LiqBean"));
        beanDefinitionBuilder3.addPropertyValue("stringList",stringList);
        beanDefinitionBuilder3.addPropertyValue("userList",userList);
        beanDefinitionBuilder3.addPropertyValue("stringSet",stringSet);
        beanDefinitionBuilder3.addPropertyValue("userSet",userSet);
        beanDefinitionBuilder3.addPropertyValue("stringMap",stringMap);
        beanDefinitionBuilder3.addPropertyValue("stringUserMap",stringUserMap);
        AbstractBeanDefinition beanDefinition3 = beanDefinitionBuilder3.getBeanDefinition();

        DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
        factory.registerBeanDefinition("LiqBean",liqBD);
        factory.registerBeanDefinition("ScyBean",ScyBD);
        factory.registerBeanDefinition("UserObj",beanDefinition3);

        System.out.println(factory.getBean("LiqBean"));
        System.out.println(factory.getBean("ScyBean"));
        System.out.println(factory.getBean("UserObj"));
    }
}

运行结果:

User{name='Liq}

User{name='Scy}

UserObj{name='jwl', salary=50000, user=User{name='Liq}, stringList=[test1, test2, test3], userList=[User{name='Liq}, User{name='Scy}], stringSet=[test1, test2, test3], userSet=[User{name='Liq}, User{name='Scy}], stringMap={测试1=test1, 测试2=test2, 测试3=test3}, stringUserMap={user1=User{name='Liq}, user2=User{name='Scy}}}

3  BeanDefinition各子类说明

3.1  AnnotatedBeanDefinition

AnnotatedBeanDefinition :该接口扩展了 BeanDefinition 的功能,其用来操作注解元数据。 通过注解方式得到的 Bean(@Component、@Bean),其 BeanDefinition 类型都是该接口的实现类。

public interface AnnotatedBeanDefinition extends BeanDefinition {

	// 获得当前 Bean 的注解元数据
	AnnotationMetadata getMetadata();

	// 获得当前 Bean 的工厂方法上的元数据
	MethodMetadata getFactoryMethodMetadata();
}

该接口可以返回两个元数据的类:

AnnotationMetadata:主要对 Bean 的注解信息进行操作,如:获取当前 Bean 标注的所有注解、判断是否包含指定注解。

MethodMetadata:方法的元数据类。提供获取方法名称、此方法所属类的全类名、是否是抽象方法、判断是否是静态方法、判断是否是final方法等。

3.2   AbstractBeanDefinition抽象类

AbstractBeanDefinition 是 BeanDefinition 的子抽象类,也是其他 BeanDefinition 类型的基类,其实现了接口中定义的一系列操作方法,并定义了一系列的常量属性,这些常量会直接影响到 Spring 实例化 Bean 时的策略。

public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccessor
		implements BeanDefinition, Cloneable {

    // 默认的 SCOPE,默认是单例
	public static final String SCOPE_DEFAULT = "";
	// 不进行自动装配
	public static final int AUTOWIRE_NO = AutowireCapableBeanFactory.AUTOWIRE_NO;
    // 根据 Bean 的名字进行自动装配,byName
	public static final int AUTOWIRE_BY_NAME = AutowireCapableBeanFactory.AUTOWIRE_BY_NAME;
	// 根据 Bean 的类型进行自动装配,byType
	public static final int AUTOWIRE_BY_TYPE = AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE;
	// 根据构造器进行自动装配
	public static final int AUTOWIRE_CONSTRUCTOR = AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR;
	// 首先尝试按构造器自动装配。如果失败,再尝试使用 byType 进行自动装配。(Spring 3.0 之后已废除)
	public static final int AUTOWIRE_AUTODETECT = AutowireCapableBeanFactory.AUTOWIRE_AUTODETECT;
    // 通过依赖检查来查看 Bean 的每个属性是否都设置完成
    // 以下常量分别对应:不检查、对依赖对象检查、对基本类型,字符串和集合进行检查、对全部属性进行检查
	public static final int DEPENDENCY_CHECK_NONE = 0;
	public static final int DEPENDENCY_CHECK_OBJECTS = 1;
	public static final int DEPENDENCY_CHECK_SIMPLE = 2;
	public static final int DEPENDENCY_CHECK_ALL = 3;
	// 关闭应用上下文时需调用的方法名称
	public static final String INFER_METHOD = "(inferred)";
    // 存放 Bean 的 Class 对象
	private volatile Object beanClass;
	// Bean 的作用范围
	private String scope = SCOPE_DEFAULT;
    // 非抽象
	private boolean abstractFlag = false;
	// 非延迟加载
	private boolean lazyInit = false;
    // 默认不自动装配
	private int autowireMode = AUTOWIRE_NO;
    // 默认不依赖检查
	private int dependencyCheck = DEPENDENCY_CHECK_NONE;
	// 依赖的 Bean 列表
	private String[] dependsOn;
    // 可以作为自动装配的候选者,意味着可以自动装配到其他 Bean 的某个属性中
	private boolean autowireCandidate = true;
	// 创建当前 Bean 实例工厂类名称
	private String factoryBeanName;
    // 创建当前 Bean 实例工厂类中方法名称
	private String factoryMethodName;
	// 存储构造方法的参数
	private ConstructorArgumentValues constructorArgumentValues;
    // 存储 Bean 属性名称以及对应的值
	private MutablePropertyValues propertyValues;
    // 存储被覆盖的方法信息
	private MethodOverrides methodOverrides;
	// init、destroy 方法名称
	private String initMethodName;
	private String destroyMethodName;
    // 是否执行 init 和 destroy 方法
	private boolean enforceInitMethod = true;
	private boolean enforceDestroyMethod = true;
    // Bean 是否是用户定义的而不是应用程序本身定义的
	private boolean synthetic = false;
    // Bean 的身份类别,默认是用户定义的 Bean
	private int role = BeanDefinition.ROLE_APPLICATION;
	// Bean 的描述信息
	private String description;
	// Bean 定义的资源
	private Resource resource;
}

以上是 AbstractBeanDefinition 中定义的一些常量和属性,该类中还有一部分是操作这些属性的 set 和 get 方法,这些方法都由子类来操作,且应用程序中真正使用的也是这些子类 BeanDefinition。

AbstractBeanDefinition的直接实现类:RootBeanDefinition、GenericBeanDefinition、ChildBeanDefinition。

3.3  AbstractBeanDefinition的实现类

3.3.1 RootBeanDefinition

RootBeanDefinition:该类继承自 AbstractBeanDefinition,用于描述一个完整的 Bean 定义,包括 Bean 的类型、构造函数参数、属性、依赖关系、作用域等。它是一个独立的 Bean 定义,不依赖于任何其他的 Bean 定义。它可以作为一个独立的 Bean 实例存在,也可以作为其他 Bean 的父 Bean 使用。

public class RootBeanDefinition extends AbstractBeanDefinition {

    // BeanDefinitionHolder 存储 Bean 的名称、别名、BeanDefinition
	private BeanDefinitionHolder decoratedDefinition;

	// AnnotatedElement 是java反射包的接口,通过它可以查看 Bean 的注解信息
	private AnnotatedElement qualifiedElement;

    // 允许缓存
	boolean allowCaching = true;
    
    // 工厂方法是否唯一
	boolean isFactoryMethodUnique = false;

	// 封装了 java.lang.reflect.Type,提供了泛型相关的操作
	volatile ResolvableType targetType;

	// 缓存 Class,表示 RootBeanDefinition 存储哪个类的信息
	volatile Class resolvedTargetType;

	// 缓存工厂方法的返回类型
	volatile ResolvableType factoryMethodReturnType;

	// 这是以下四个构造方法字段的通用锁
	final Object constructorArgumentLock = new Object();
	// 用于缓存已解析的构造方法或工厂方法
	Executable resolvedConstructorOrFactoryMethod;
	// 将构造方法参数标记为已解析
	boolean constructorArgumentsResolved = false;
	// 用于缓存完全解析的构造方法参数
	Object[] resolvedConstructorArguments;
	// 缓存待解析的构造方法参数
	Object[] preparedConstructorArguments;

	// 这是以下两个后处理字段的通用锁
	final Object postProcessingLock = new Object();
	// 表明是否被 MergedBeanDefinitionPostProcessor 处理过
	boolean postProcessed = false;
	// 在生成代理的时候会使用,表明是否已经生成代理
	volatile Boolean beforeInstantiationResolved;

	// 实际缓存的类型是 Constructor、Field、Method 类型
	private Set externallyManagedConfigMembers;

	// InitializingBean中 的 init 回调函数名 afterPropertiesSet 会在这里记录,以便进行生命周期回调
	private Set externallyManagedInitMethods;

	// DisposableBean 的 destroy 回调函数名 destroy 会在这里记录,以便进生命周期回调
	private Set externallyManagedDestroyMethods;
}

RootBeanDefinition是 Spring BeanFactory 运行时统一的 BeanDefinition 视图。

在 Spring 源码中,我们也可以看到,Spring 在通过 BeanDefinition 创建 bean 的实例时,通常都会将 BeanDefinition 转化为 RootBeanDefinition 后,再进行 bean 实例的创建。比如我们非常熟悉的final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);这句代码,就是去合并parent的属性进来,这样体现了继承的强大,属性也才完整。

举例如下

package com.cect.BeanDefinition;

public class FooService {
    public String id;
    public String name;
//setters and getters
}
package com.cect.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.ChildBeanDefinition;
import org.springframework.beans.factory.support.RootBeanDefinition;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class MainClass {
    public static void main(String args[]){
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        RootBeanDefinition rbd=new RootBeanDefinition();
        rbd.setBeanClass(FooService.class);
        rbd.setScope(BeanDefinition.SCOPE_SINGLETON);
        rbd.getPropertyValues().add("id", "123");
        rbd.getPropertyValues().add("name", "zhangsan");
        context.registerBeanDefinition("rootFooService", rbd);

        ChildBeanDefinition cbd = new ChildBeanDefinition("rootFooService");
        cbd.setBeanClass(FooService.class);
        cbd.getPropertyValues().add("id", "456");
        context.registerBeanDefinition("childFooService", cbd);
        context.refresh();

        FooService childFooService = (FooService)context.getBean("childFooService");
        System.out.println(childFooService.toString());
    }
}

代码运行结果

Spring 中的BeanDefinition及其实现和BeanDefinitionReader_第4张图片

如果此时进入源码跟踪会发现

Spring 中的BeanDefinition及其实现和BeanDefinitionReader_第5张图片

Spring 中的BeanDefinition及其实现和BeanDefinitionReader_第6张图片

Spring 中的BeanDefinition及其实现和BeanDefinitionReader_第7张图片

Spring 中的BeanDefinition及其实现和BeanDefinitionReader_第8张图片

3.3.1.1 ConfigurationClassBeanDefinition

ConfigurationClassBeanDefinition:该类继承自 RootBeanDefinition ,并实现了 AnnotatedBeanDefinition 接口。这个BeanDefinition用来描述加了@Bean 注解的Bean

该类继承自 RootBeanDefinition ,并实现了 AnnotatedBeanDefinition 接口。这个 BeanDefinition 用来描述在标注在 @Configuration 注解的类中,通过 @Bean 注解实例化的 Bean。

注意ConfigurationClassBeanDefinition是一个内部类,外部不可以访问。

Spring 中的BeanDefinition及其实现和BeanDefinitionReader_第9张图片

 其功能特点如下:

1、如果 @Bean 注解没有指定 Bean 的名字,默认会用方法的名字命名 Bean。

2、标注 @Configuration 注解的类会成为一个工厂类,而标注 @Bean 注解的方法会成为工厂方法,通过工厂方法实例化 Bean,而不是直接通过构造方法初始化。

3、标注 @Bean 注解的类会使用构造方法自动装配

示例:

package com.cect.BeanDefinition;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Indexed;

@Indexed
@Configuration
public class MyConfig {

    @Bean(value="fs",initMethod="fooInitMethod")
    public FooService getFooService(){
        return new FooService("182","Liqq");
    }
}
package com.cect.BeanDefinition;

public class FooService {
    public String id;
    public String name;

    private void fooInitMethod() {
        System.out.println("this is initMethod");
    }
    public FooService(String id, String name) {
        this.id = id;
        this.name = name;
    }
//setters and getters
}
package com.cect.BeanDefinition;
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.annotation.MergedAnnotation;
import org.springframework.core.type.AnnotationMetadata;
@SpringBootApplication
public class MainClass {
    public static void main(String args[]){
        ConfigurableApplicationContext context=  SpringApplication.run(MainClass.class,args);
        FooService rootFooService = (FooService)context.getBean("fs");
        AnnotatedBeanDefinition fsbd = (AnnotatedBeanDefinition)context.getBeanFactory().getBeanDefinition("fs");
        fsbd.getMetadata();
        fsbd.getFactoryMethodMetadata();
        System.out.println("1  fsbd.getFactoryMethodName()="+fsbd.getFactoryMethodName());
        System.out.println("2   fsbd.getFactoryBeanName()="+fsbd.getFactoryBeanName());
        System.out.println("3   fsbd.getFactoryMethodMetadata().getDeclaringClassName()="+fsbd.getFactoryMethodMetadata().getDeclaringClassName());
        System.out.println("4   fsbd.getFactoryMethodMetadata().getMethodName()="+fsbd.getFactoryMethodMetadata().getMethodName());
        System.out.println("5   fsbd.getFactoryMethodMetadata().getReturnTypeName()="+fsbd.getFactoryMethodMetadata().getReturnTypeName());
        MergedAnnotation beanAnnotation = fsbd.getFactoryMethodMetadata().getAnnotations().get(org.springframework.context.annotation.Bean.class);
        System.out.println("6   "+beanAnnotation.getValue("initMethod").get( ));
        String[] valu= (String[]) beanAnnotation.getValue("value").get();
        System.out.println("7   "+valu[0]);
        AnnotationMetadata metadata = fsbd.getMetadata();
        System.out.println("8   fsbd.getMetadata().getAnnotationTypes().toArray()="+ fsbd.getMetadata().getAnnotationTypes());
        System.out.println("9   fsbd.getMetadata().getClassName()=;"+ fsbd.getMetadata().getClassName());
    }
}

fsbd.getMetadata()的值

Spring 中的BeanDefinition及其实现和BeanDefinitionReader_第10张图片

fsbd.getFactoryMethodMetadata()

Spring 中的BeanDefinition及其实现和BeanDefinitionReader_第11张图片

Spring 中的BeanDefinition及其实现和BeanDefinitionReader_第12张图片

3.3.2 ChildBeanDefinition

ChildBeanDefinition:不可以单独存在,必须依赖一个父 BeanDetintion,构造 ChildBeanDefinition 时,通过构造方法传入父 BeanDetintion 的名称或通过 setParentName 设置父名称。

3.3.3 GenericBeanDefinition

GenericBeanDefinition可以描述一个独立的 Bean 定义,也可以作为其他 Bean 的父 Bean 使用。它包含了 RootBeanDefinition 的所有属性和方法,并增加了一些额外的属性和方法,例如自动装配模式、是否允许循环依赖等。它提供了更多的扩展性和灵活性,可以适应更多的场景。

public class GenericBeanDefinition extends AbstractBeanDefinition {

	private String parentName;

    public GenericBeanDefinition() {
		super();
	}

	/**
	 * Create a new GenericBeanDefinition as deep copy of the given bean definition.	 */
	public GenericBeanDefinition(BeanDefinition original) {
		super(original);
	}
}

示例

package com.cect.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.ChildBeanDefinition;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.beans.factory.support.RootBeanDefinition;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class MainClass {
    public static void main(String args[]){
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        GenericBeanDefinition rbd=new GenericBeanDefinition ();
        rbd.setBeanClass(FooService.class);
        rbd.setScope(BeanDefinition.SCOPE_SINGLETON);
        rbd.getPropertyValues().add("id", "123");
        rbd.getPropertyValues().add("name", "zhangsan");
        context.registerBeanDefinition("rootFooService", rbd);

        ChildBeanDefinition cbd = new ChildBeanDefinition("rootFooService");
        cbd.setBeanClass(FooService.class);
        cbd.getPropertyValues().add("id", "456");
        context.registerBeanDefinition("childFooService", cbd);
        context.refresh();

        FooService rootFooService = (FooService)context.getBean("rootFooService");
        System.out.println(rootFooService.toString());
        FooService childFooService = (FooService)context.getBean("childFooService");
        System.out.println(childFooService.toString());
    }
}

Spring 中的BeanDefinition及其实现和BeanDefinitionReader_第13张图片

 3.3.3.1 GenericBeanDefinition各子类
3.3.3.1.1 AnnotatedGenericBeanDefinition

AnnotatedGenericBeanDefinition:该类继承自 GenericBeanDefinition ,并实现了 AnnotatedBeanDefinition 接口。这个 BeanDefinition 用来描述标注 @Configuration 注解的 Bean以及@Configuration 注解类中@Bean注解的方法。

public class AnnotatedGenericBeanDefinition extends GenericBeanDefinition implements AnnotatedBeanDefinition {

	private final AnnotationMetadata metadata;

	@Nullable
	private MethodMetadata factoryMethodMetadata;


	/**
	 * Create a new AnnotatedGenericBeanDefinition for the given bean class.	 */
	public AnnotatedGenericBeanDefinition(Class beanClass) {
		setBeanClass(beanClass);
		this.metadata = AnnotationMetadata.introspect(beanClass);
	}
}

示例

package com.cect.BeanDefinition;

import org.springframework.beans.factory.annotation.AnnotatedGenericBeanDefinition;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

@SpringBootApplication
public class MainClass {
    public static void main(String args[]){
        ConfigurableApplicationContext context=  SpringApplication.run(MainClass.class,args);
       AnnotatedGenericBeanDefinition mcbd = (AnnotatedGenericBeanDefinition)context.getBeanFactory().getBeanDefinition("mainClass");
    }
}

Spring 中的BeanDefinition及其实现和BeanDefinitionReader_第14张图片

 3.3.3.1.2 ScannedGenericBeanDefinition

ScannedGenericBeanDefinition:该类继承自 GenericBeanDefinition ,并实现了 AnnotatedBeanDefinition 接口。这个 BeanDefinition 用来描述标注 @Component 注解的 Bean, @Import,其派生注解如 @Service、@Controller 也同理。

示例:

@Component
@Service
@Controller
public class EooService {
    public String eid;
    public String ename;
//setters and geters
}
package com.cect.BeanDefinition;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ScannedGenericBeanDefinition;
import org.springframework.core.type.AnnotationMetadata;

import java.lang.annotation.Annotation;

@SpringBootApplication
public class MainClass {
    public static void main(String args[]){
        ConfigurableApplicationContext context=  SpringApplication.run(MainClass.class,args);
        ScannedGenericBeanDefinition esbd = (ScannedGenericBeanDefinition)context.getBeanFactory().getBeanDefinition("eooService");

        AnnotationMetadata metadata = esbd.getMetadata();
        System.out.println(metadata.getAnnotationTypes());
    }
}

Spring 中的BeanDefinition及其实现和BeanDefinitionReader_第15张图片

Spring 中的BeanDefinition及其实现和BeanDefinitionReader_第16张图片

Spring 中的BeanDefinition及其实现和BeanDefinitionReader_第17张图片

Spring 中的BeanDefinition及其实现和BeanDefinitionReader_第18张图片

4 BeanDefinition合并

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

合并BeanDefinition会使用下面这个方法:org.springframework.beans.factory.support.AbstractBeanFactory#getMergedBeanDefinition

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

示例:

package com.cect.BeanDefinition;

public class User {

    private String name;
    private String desc;
//setter and getter
}

ac.xml

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="wc" class="com.cect.BeanDefinition.User">
        <property name="name" value="wc">property>
        <property name="desc" value="good wc">property>
    bean>
    <bean id="liq" class="com.cect.BeanDefinition.User">
        <property name="name" value="wc">property>
        <property name="desc" value="good wc and liq">property>
    bean>
beans>

package com.cect.BeanDefinition;

import org.springframework.beans.PropertyValue;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.*;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;


public class MainClass {
    public static void main(String args[]){
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
        xmlBeanDefinitionReader.loadBeanDefinitions("ac.xml");

        for (String beanName:beanFactory.getBeanDefinitionNames()){
            System.out.println("-------------------------");
            System.out.println(beanName+"BeanDefinition  合并前");
            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(beanName+"BeanDefinition  合并后");
            System.out.println(mergedBeanDefinition);
            for (PropertyValue property:mergedBeanDefinition.getPropertyValues()){
                System.out.println(property.getName()+"====>"+property.getValue());
            }
        }
    }
}

运行结果

Spring 中的BeanDefinition及其实现和BeanDefinitionReader_第19张图片

5 BeanDefinitionReader

 Spring 中的BeanDefinition及其实现和BeanDefinitionReader_第20张图片

 

BeanDefinitionReader 的作用是读取 Spring 配置文件中的内容,将其转换为 IoC 容器内部的数据结构:BeanDefinition。

BeanDefinitionRegistry 接口一次只能注册一个 BeanDefinition,而且只能自己构造 BeanDefinition 类来注册。BeanDefinitionReader 解决了这些问题,它一般可以使用一个 BeanDefinitionRegistry 构造,然后通过 loadBeanDefinitions()等方法,把 Resources 转化为多个 BeanDefinition 并注册到 BeanDefinitionRegistry。

public interface BeanDefinitionReader {
    //返回Bean工厂以向其注册Bean定义。
    BeanDefinitionRegistry getRegistry();

    /**返回资源加载器以用于资源位置。可以检查ResourcePatternResolver接口并进行相应的转换,以针对给定的资源模式加载多个资源。一个null返回值表明,绝对资源加载不适用于这个bean定义阅读器。

    这主要用于从bean定义资源中导入其他资源,例如,通过XML bean定义中的“ import”标记。但是,建议相对于定义资源应用此类导入;只有明确的完整资源位置才会触发绝对资源加载。
    **/
    @Nullable
    ResourceLoader getResourceLoader();

    //返回用于Bean类的类加载器。
    @Nullable
    ClassLoader getBeanClassLoader();

    //返回BeanNameGenerator用于匿名Bean(未指定显式Bean名称)。
    BeanNameGenerator getBeanNameGenerator();

    //从指定的资源加载bean定义。
    int loadBeanDefinitions(Resource var1) throws BeanDefinitionStoreException;

    int loadBeanDefinitions(Resource... var1) throws BeanDefinitionStoreException;

    //从指定的资源位置加载bean定义。
    //该位置也可以是位置模式,前提是此bean定义读取器的ResourceLoader是ResourcePatternResolver。
    int loadBeanDefinitions(String var1) throws BeanDefinitionStoreException;

    int loadBeanDefinitions(String... var1) throws BeanDefinitionStoreException;
}

关于 BeanDefinitionReader 的结构图如下:

AbstractBeanDefinitionReader:实现了 EnvironmentCapable,提供了获取/设置环境的方法。定义了一些通用方法,使用策略模式,将一些具体方法放到子类实现。

XmlBeanDefinitionReader:读取 XML 文件定义的 BeanDefinition

PropertiesBeanDefinitionReader:可以从属性文件,Resource,Property 对象等读取 BeanDefinition

GroovyBeanDefinitionReader:可以读取 Groovy 语言定义的 Bean。

5.1 AbstractBeanDefinitionReader

该类是实现了 BeanDefinitionReader 和 EnvironmentCapable 接口的抽象类,提供常见属性:工作的 bean 工厂、资源加载器、用于加载 bean 类的类加载器、环境等。具体定义如下:

private final BeanDefinitionRegistry registry;

@Nullable

private ResourceLoader resourceLoader;

@Nullable

private ClassLoader beanClassLoader;

private Environment environment;

private BeanNameGenerator beanNameGenerator;

关于该类最核心的方法是 loadBeanDefinitions()方法,所以接下来我们主要就是分析该方法。

public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException {

    Assert.notNull(locations, "Location array must not be null");

    int count = 0;

    String[] var3 = locations;

    int var4 = locations.length;

    for(int var5 = 0; var5 < var4; ++var5) {

        String location = var3[var5];

        count += this.loadBeanDefinitions(location);

    }

    return count;

}

当传入的参数为资源位置数组时,进入上述方法,如果为字符串数组,则挨个遍历调用 loadBeanDefinitions(location)方法。其定义如下:

public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException {

    return this.loadBeanDefinitions(location, (Set)null);

}

public int loadBeanDefinitions(String location, @Nullable Set actualResources) throws BeanDefinitionStoreException {

    //获取资源加载器,该ResourceLoader是ResourcePatternResolver

    ResourceLoader resourceLoader = this.getResourceLoader();

    if (resourceLoader == null) {

        throw new BeanDefinitionStoreException("Cannot load bean definitions from location [" + location + "]: no ResourceLoader available");

    } else {

        int count;

        if (resourceLoader instanceof ResourcePatternResolver) {

            try {

                //根据资源路径调用resourceLoader的getResources方法,,此方法可以加载多个资源

                Resource[] resources = ((ResourcePatternResolver)resourceLoader).getResources(location);

                //根据资源来加载bean定义

                count = this.loadBeanDefinitions(resources);

                if (actualResources != null) {

                    Collections.addAll(actualResources, resources);

                }

                if (this.logger.isTraceEnabled()) {

                    this.logger.trace("Loaded " + count + " bean definitions from location pattern [" + location + "]");

                }

                return count;

            } catch (IOException var6) {

                throw new BeanDefinitionStoreException("Could not resolve bean definition resource pattern [" + location + "]", var6);

            }

        } else {

            //此方法只能加载一个资源

            Resource resource = resourceLoader.getResource(location);

            count = this.loadBeanDefinitions((Resource)resource);

            if (actualResources != null) {

                actualResources.add(resource);

            }

            if (this.logger.isTraceEnabled()) {

                this.logger.trace("Loaded " + count + " bean definitions from location [" + location + "]");

            }

            return count;

        }

    }

}

根据资源加载器的不同,来处理资源路径,从而返回多个或一个资源,然后再将资源作为参数传递给 loadBeanDefinitions(resources)方法。在该类中存在一个 loadBeanDefinitions(Resource... resources)方法,该方法用于处理多个资源,归根结底,最后还是调用 loadBeanDefinitions((Resource)resource)方法,该方法的具体实现在 XmlBeanDefinitionReader 中。

5.2 XmlBeanDefinitionReader

该类作为 AbstractBeanDefinitionReader 的扩展类,继承了 AbstractBeanDefinitionReader 所有的方法,同时也扩展了很多新的方法,主要用于读取 XML 文件中定义的 bean。

XmlBeanDefinitionReader ,将xml中定义的bean解析为BeanDefinition对 象

具体使用如下:

public void getBeanDefinition(){

    ClassPathResource resource = new ClassPathResource("application_context.xml");

    DefaultListableBeanFactory factory = new DefaultListableBeanFactory();

    XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);

    reader.loadBeanDefinitions(resource);

}

这段代码是 Spring 中编程式使用 IOC 容器,通过这四段简单的代码,我们可以初步判断 IOC 容器的使用过程。

获取资源

获取 BeanFactory

根据新建的 BeanFactory 创建一个BeanDefinitionReader对象,该Reader 对象为资源的解析器

装载资源 整个过程就分为三个步骤:资源定位、装载、注册,如下:

资源定位。我们一般用外部资源来定义 Bean 对象,所以在初始化 IoC 容器的第一步就是需要定位这个外部资源。

装载。装载就是 BeanDefinition 的载入,BeanDefinitionReader 读取、解析 Resource 资源,也就是将用户定义的 Bean 表示成 IoC 容器 的内部数据结构:BeanDefinition。在 IoC 容器内部维护着一个 BeanDefinition Map 的数据结构,在配置文件中每一个都对应着一个 BeanDefinition 对象。

注册。向 IoC 容器注册在上一步解析好的 BeanDefinition,这个过程是通过 BeanDefinitionRegistry 接口来实现的。本质上是将解析得到的 BeanDefinition 注入到一个 HashMap 容器中,IoC 容器就是通过这个HashMap 来维护这些 BeanDefinition 的。注意:此过程并没有完成依赖注入,依赖注册是发生在应用第一次调用 getBean()向容器索要 Bean 时。当然我们可以通过设置预处理,即对某个 Bean 设置 lazyInit 属性,那么这个 Bean 的

接着上述的 loadBeanDefinitions(),我们看一下在 XmlBeanDefinitionReader 类中的具体实现。

public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
    return this.loadBeanDefinitions(new EncodedResource(resource));
}

public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
    Assert.notNull(encodedResource, "EncodedResource must not be null");
    if (this.logger.isTraceEnabled()) {
        this.logger.trace("Loading XML bean definitions from " + encodedResource);
    }

    //获取已经被加载的资源集合中的资源集合,如果为null,则开辟空间
    Set currentResources = (Set)this.resourcesCurrentlyBeingLoaded.get();
    if (currentResources == null) {
        currentResources = new HashSet(4);
        this.resourcesCurrentlyBeingLoaded.set(currentResources);
    }

    //判断currentResources中是否包含encodedResource,如果有则抛出异常,没有则加入
    if (!((Set)currentResources).add(encodedResource)) {
        throw new BeanDefinitionStoreException("Detected cyclic loading of " + encodedResource + " - check your import definitions!");
    } else {
        int var5;
        try {
            //获取Resource对应的字节流
            InputStream inputStream = encodedResource.getResource().getInputStream();

            try {
                //使用字节流创建新的输入源
                InputSource inputSource = new InputSource(inputStream);
                if (encodedResource.getEncoding() != null) {
                    //设置编码
                    inputSource.setEncoding(encodedResource.getEncoding());
                }

                //该方法就是创建BeanDefinition的关键
                var5 = this.doLoadBeanDefinitions(inputSource, encodedResource.getResource());
            } finally {
                inputStream.close();
            }
        } catch (IOException var15) {
            throw new BeanDefinitionStoreException("IOException parsing XML document from " + encodedResource.getResource(), var15);
        } finally {
            ((Set)currentResources).remove(encodedResource);
            if (((Set)currentResources).isEmpty()) {
                this.resourcesCurrentlyBeingLoaded.remove();
            }

        }
        return var5;
    }
}

loadBeanDefinitions(resource) 是加载资源的真正实现,从指定的 XML 文件加载 Bean Definition,这里会对 Resource 封装成 EncodedResource,主要是为了对 Resource 进行编码,保证内容读取的正确性。封装成 EncodedResource 后,调用 loadBeanDefinitions(encodedResource)。

首先通过 resourcesCurrentlyBeingLoaded.get() 来获取已经加载过的资源,然后将 encodedResource 加入其中,如果 resourcesCurrentlyBeingLoaded 中已经存在该资源,则抛出 BeanDefinitionStoreException 异常。完成后从 encodedResource 获取封装的 Resource 资源并从 Resource 中获取相应的 InputStream ,最后将 InputStream 封装为 InputSource 调用 doLoadBeanDefinitions()。方法 doLoadBeanDefinitions() 为从 xml 文件中加载 Bean Definition 的真正逻辑。

示例:

package com.cect.BeanDefinition;

public class User {

    private String name;

    private String  age;
//setter and getter
}
ac.xml




    
        
    

package com.cect.BeanDefinition;

import org.springframework.beans.factory.support.*;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;


public class MainClass {
    public static void main(String args[]){
//创建一个spring容器
        DefaultListableBeanFactory factory = new DefaultListableBeanFactory();

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

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

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

运行输出:

user===>User{name='wc}

5.3 PropertiesBeanDefinitionReader

示例:

package com.cect.BeanDefinition;

public class Car {
    private String name;

    public String getName() {
        return name;
    }
//setter and getter
}
package com.cect.BeanDefinition;

public class User {

    private String name;
    private Car car;
//setter and getter

}
ac.properties
car.(class)=com.cect.BeanDefinition.Car
car.name=长城
car1.(class)=com.cect.BeanDefinition.Car
car1.name=海马

user.(class)=com.cect.BeanDefinition.User
user.name=张三
user.car(ref)=car
package com.cect.BeanDefinition;

import org.springframework.beans.factory.support.*;


public class MainClass {
    public static void main(String args[]){
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();

        PropertiesBeanDefinitionReader propertiesBeanDefinitionReader = new PropertiesBeanDefinitionReader(beanFactory);

        String location="ac.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='长城'}

5.4. AnnotatedBeanDefinitionReader

在AnnotationConfigApplicationContext的构造函数里,会创建两个很重要的对象,AnnotatedBeanDefinitionReader顾名思义就是基于注解的BeanDefinition读取器,ClassPathBeanDefinitionScanner是基于ClassPath路径下的BeanDefinition扫描器。

示例:

package com.cect.BeanDefinition;

public class EooService {
    public String eid;
    public String ename;
}
package com.cect.BeanDefinition;

public class FooService {
    public String id;
    public String name;
    public FooService() {

    }
}
package com.cect.BeanDefinition;

import org.springframework.context.annotation.AnnotatedBeanDefinitionReader;
import org.springframework.context.support.StaticApplicationContext;

public class MainClass {
    public static void main(String args[]){
        StaticApplicationContext context=new  StaticApplicationContext();
        AnnotatedBeanDefinitionReader annoreader=new AnnotatedBeanDefinitionReader(context);
        annoreader.register(EooService.class);
        annoreader.register(FooService.class);
        context.refresh();
        for (String s : context.getBeanDefinitionNames()) {
            System.out.println(s);
        }
    }
}

Spring 中的BeanDefinition及其实现和BeanDefinitionReader_第21张图片

 5.5 ClassPathBeanDefinitionScanner

ClassPathBeanDefinitionScanner是一个BefanDefinition扫描器,它检测classpath上的bean候选者,使用注册器(BeanFactory或ApplicationContext)注册相应的BeanDefiniton。通过可配置的类型过滤器检测候选类。 默认的类型过滤器含有使用Spring的@Component,@Repository,@Service或@Controller注解的类。

示例:

package com.cect.BeanDefinition;

import org.springframework.stereotype.Service;

@Service
public class EooService {
    public String eid;
    public String ename;
//setters and getters
}
package com.cect.BeanDefinition;

import org.springframework.stereotype.Controller;

@Controller
public class FooService {
    public String id;
    public String name;


    public FooService() {
    }
//setters and getters
}
package com.cect.BeanDefinition;

import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
import org.springframework.context.support.StaticApplicationContext;

public class MainClass {
    public static void main(String args[]){

        StaticApplicationContext scontext=new  StaticApplicationContext();

        ClassPathBeanDefinitionScanner cpreader=new ClassPathBeanDefinitionScanner(scontext);
        cpreader.scan("com.cect.BeanDefinition");

        scontext.refresh();
        for (String s : scontext.getBeanDefinitionNames()) {
            System.out.println(s);
        }

    }
}

Spring 中的BeanDefinition及其实现和BeanDefinitionReader_第22张图片

 

你可能感兴趣的:(spring,java,后端)