Spring源码系列(二)BeanDefinition(一)

1.写在前面

如果想系统的学习Spring的源码,我们需要了解就是Spring的中BeanDefinition,简单的说这个就是Spring的Bean的描述信息。因为的Spring中Bean的创建都是根据这个BeanDefinition这个来创建,也可以叫这个为Spring的Bean的建模对象。

2.官网对BeanDefinition的解释

当我们打开对应的Spring的官网,具体在Bean Overview中有关于BeanDefinition的介绍,具体如下图:

在这里插入图片描述

大概的意思就是,Spring IOC容器管理一个或多个Bean。 这些bean是使用您提供给容器的配置元数据创建的。在容器本身内,这些Bean定义表示为BeanDefinition对象,其中包含以下元数据:

  • 包限定的类名:通常定义了Bean的实际实现类。
  • Bean行为配置元素,用于声明Bean在容器中的行为(作用域,生命周期回调等)。
  • 引用其他Bean进行其工作所需的Bean。 这些引用也称为协作者或依赖项。
  • 要在新创建的对象中设置的其他配置设置,例如,池的大小限制或在管理连接池的Bean中使用的连接数。

简而言之:BeanDefinition的就是对Bean的信息进行描述,然后Spring会根据这个来创建对应的Bean。这里感觉java的中的Class很像,那么这里为什么不用Class呢?

3.为什么不用Class作为Bean的描述信息?

Class也就是我们通常说的类对象,就是一个普通的建模的对象,那么为什么Spring不能用Class来建立Bean呢?因为Class无法完成对Bean的信息的抽象,Class对象中只能描述方法和属性等等。而Spring中的Bean中有作用域,注入的信息,是否是懒加载。很明显Class不适合。这就是Spring不用Class作为Bean的描述信息的原因。

java实例化一个对象的基本过程:我们都知道jvm运行时class文件,当我们写一个java文件的时候,然后通过java的编译的命令,将这个文件编译成class文件,然后在加载到jvm中运行。具体如下图:

在这里插入图片描述

上面我们大概介绍了Spring 中的BeanDefinition,但是这些东西都是比较空洞的。我们需要从源码的角度查看Spring的BeanDefinition。

4.从源码的角度看BeanDefinition

在idea中我们打开我们已经编译好的Spring的源码,然后搜索对应的BeanDefinition的类,打开发现是一个接口,我们今天会介绍其中一个实现类。打开的代码如下:

package org.springframework.beans.factory.config;

import org.springframework.beans.BeanMetadataElement;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.core.AttributeAccessor;
import org.springframework.core.ResolvableType;
import org.springframework.lang.Nullable;

public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {

  //单例
	String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;

  //原型
	String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;

	int ROLE_APPLICATION = 0;

	int ROLE_SUPPORT = 1;

	int ROLE_INFRASTRUCTURE = 2;

	void setParentName(@Nullable String parentName);

	@Nullable
	String getParentName();

  //设置Bean的类名
	void setBeanClassName(@Nullable String beanClassName);

  //获取Bean的类名
	@Nullable
	String getBeanClassName();

  //设置作用域
	void setScope(@Nullable String scope);

  //获取对应的作用域
	@Nullable
	String getScope();

  //设置为懒加载
	void setLazyInit(boolean lazyInit);

  //判断是否是懒加载
	boolean isLazyInit();

  //设置DependOn,对应的DependOn注解,或者是XML中的配置的
	void setDependsOn(@Nullable String... dependsOn);

  //获取DependOn设置的值
	@Nullable
	String[] getDependsOn();

  //自动装配的候选的对象
	void setAutowireCandidate(boolean autowireCandidate);

  //是否是自动装配的候选对象
	boolean isAutowireCandidate();

  //设置主要的注入的对象
	void setPrimary(boolean primary);

  //获取是否主要的注入对象
	boolean isPrimary();

  //设置工厂Bean的名称
	void setFactoryBeanName(@Nullable String factoryBeanName);

  //获取工厂Bean的名称
	@Nullable
	String getFactoryBeanName();

  //设置工厂方法的名称
	void setFactoryMethodName(@Nullable String factoryMethodName);

  //获取工厂方法的名称
	@Nullable
	String getFactoryMethodName();

  //获取构造器的参数的值
	ConstructorArgumentValues getConstructorArgumentValues();
	
  //是否构造器参数有值
	default boolean hasConstructorArgumentValues() {
		return !getConstructorArgumentValues().isEmpty();
	}

  //获取属性
	MutablePropertyValues getPropertyValues();

  //是否有属性
	default boolean hasPropertyValues() {
		return !getPropertyValues().isEmpty();
	}

  //设置对应的初始化方法
	void setInitMethodName(@Nullable String initMethodName);

  //获取对应的初始化方法
	@Nullable
	String getInitMethodName();

  //设置对应的销毁的方法
	void setDestroyMethodName(@Nullable String destroyMethodName);

  //获取对应的销毁的方法
	@Nullable
	String getDestroyMethodName();

	void setRole(int role);

	int getRole();

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

  //获取对应的描述信息
	@Nullable
	String getDescription();

	ResolvableType getResolvableType();

  //判断是否是单例
	boolean isSingleton();

  //判断是否是原型
	boolean isPrototype();

  //判断是否是抽象
	boolean isAbstract();

  //获取源的描述信息
	@Nullable
	String getResourceDescription();
  
  //返回原始的BeanDefinition
	@Nullable
	BeanDefinition getOriginatingBeanDefinition();
}

上面的有些东西没回加上注释,是有些我自己也不清楚。希望大佬可以教教我。我们对上面的BeanDefinition进行一一解释,同时配上对应的应用。

4.1作用域,懒加载,BeanClassName

我们通过实现Spring中实现对应BeanFactoryPostProcessor接口拿出对应的BeanDefinition信息。然后主要查看对应的作用域和懒加载以及BeanClassName的属性值。具体的代码如下:

package com.ys.beanDefinition.scopeOrLazyOrBeanClassName;

import org.springframework.stereotype.Component;

@Component
public class A {
}

package com.ys.beanDefinition.scopeOrLazyOrBeanClassName;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan("com.ys.beanDefinition.scopeOrLazyOrBeanClassName")
public class AppConfig {
}

package com.ys.beanDefinition.scopeOrLazyOrBeanClassName;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.stereotype.Component;

@Component
public class ABeanFactoryPostProcessor implements BeanFactoryPostProcessor {
	@Override
	public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
		BeanDefinition beanDefinition = beanFactory.getBeanDefinition("a");
		System.out.println("scope:" + beanDefinition.getScope());
		System.out.println("lazy:" + beanDefinition.isLazyInit());
		System.out.println("beanClassName:" + beanDefinition.getBeanClassName());
	}
}

package com.ys.beanDefinition.scopeOrLazyOrBeanClassName;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Main {
	public static void main(String[] args) {
		ApplicationContext anno = new AnnotationConfigApplicationContext(AppConfig.class);
	}
}

运行结果如下:

在这里插入图片描述

可以看到我们Bean的默认的作用域是单例的模式,同时不是懒加载,同时BeanClassName的值就是Class的全类名,同时我们的使用对应的注解修改对应的值,具体如下图:

在这里插入图片描述

4.2DependsOn

DependsOn就表示:如果A DependsOn B,那么A创建好之前B已经创建好了。具体的代码如下:

package com.ys.beanDefinition.dependsOn;

import org.springframework.context.annotation.DependsOn;
import org.springframework.stereotype.Component;

@Component
@DependsOn("b")
public class A {

	public A() {
		System.out.println("A.A");
	}
}

package com.ys.beanDefinition.dependsOn;

import org.springframework.stereotype.Component;

@Component
public class B {

	public B() {
		System.out.println("B.B");
	}
}

package com.ys.beanDefinition.dependsOn;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan("com.ys.beanDefinition.dependsOn")
public class AppConfig {
}

package com.ys.beanDefinition.dependsOn;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.stereotype.Component;

import java.util.Arrays;

@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
	@Override
	public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
		BeanDefinition aBeanDefinition = beanFactory.getBeanDefinition("a");
		BeanDefinition bBeanDefinition = beanFactory.getBeanDefinition("b");
		System.out.println("a.DependsOn:" + Arrays.toString(aBeanDefinition.getDependsOn()));
		System.out.println("b.DependsOn:" + Arrays.toString(bBeanDefinition.getDependsOn()));
	}
}

package com.ys.beanDefinition.dependsOn;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Main {
	public static void main(String[] args) {
		ApplicationContext anno = new AnnotationConfigApplicationContext(AppConfig.class);
	}
}

运行的结果如下:

在这里插入图片描述

可以看到在A对象创建之前,先创建的是B对象,同时打印的依赖信息也是依赖B,如果没有依赖就是null。

4.3自动装配的候选对象和Primary。

还记得我们上篇博客中说道,如果是ByType的装配的模式,如果找到两个满足条件的类,会直接报错,因为Spring不知道装配那个,因为每一个对象都是自动装配的候选对象,如果我们将其中设置一个不是候选对象,就可以完成自动装配。或者将其中一个对象设置成主要装配的对象,也可以完成自动装配。具体的代码如下:

<?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"
		default-autowire="byType">

	<bean id="a" class="com.ys.beanDefinition.autowireCandidateOrPrimary.A"/>

	<bean id="i1" class="com.ys.beanDefinition.autowireCandidateOrPrimary.I1"/>

	<bean primary="true" autowire-candidate="false" id="i2" class="com.ys.beanDefinition.autowireCandidateOrPrimary.I2"/>

	<bean id="myBeanFactoryBeanPostProcessor" class="com.ys.beanDefinition.autowireCandidateOrPrimary.MyBeanFactoryBeanPostProcessor"/>
</beans>
package com.ys.beanDefinition.autowireCandidateOrPrimary;

public class A {
	private I i;

	public void setI(I i) {
		this.i = i;
	}

	public I getI() {
		return i;
	}
}

package com.ys.beanDefinition.autowireCandidateOrPrimary;

public interface I {
}

package com.ys.beanDefinition.autowireCandidateOrPrimary;

public class I1 implements I {
}

package com.ys.beanDefinition.autowireCandidateOrPrimary;

public class I2 implements I {
}

package com.ys.beanDefinition.autowireCandidateOrPrimary;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;

public class MyBeanFactoryBeanPostProcessor implements BeanFactoryPostProcessor {
	@Override
	public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
		BeanDefinition i1 = beanFactory.getBeanDefinition("i1");
		BeanDefinition i2 = beanFactory.getBeanDefinition("i2");
		System.out.println("i1:autowire-candidate:" + i1.isAutowireCandidate());
		System.out.println("i1:primary:" + i1.isPrimary());
		System.out.println("i2:autowire-candidate:" + i2.isAutowireCandidate());
		System.out.println("i2:primary:" + i2.isPrimary());

	}
}

package com.ys.beanDefinition.autowireCandidateOrPrimary;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Main {

	public static void main(String[] args) {
		ApplicationContext applicationContext = new ClassPathXmlApplicationContext("SpringXml.xml");
		System.out.println(applicationContext.getBean(A.class).getI());
	}
}

运行的结果如下:

在这里插入图片描述

从上面的运行结果我们可以看到autowire-candidate的优先级要大于primary的优先级,因为我们在I2上同时加上了这个属性,我们将autowire-candidate的值设置成false,将primary的值设置成true,这个时候注入的是I1,所以autowire-candidate的优先级是大于primary的优先级。

4.4FactoryBean与FactoryMethod

根据对应的工厂bean和对应共产方法创建出对应的bean,具体的代码如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	   xsi:schemaLocation="http://www.springframework.org/schema/beans
	   http://www.springframework.org/schema/beans/spring-beans.xsd">

	<bean id="serviceLocator" class="com.ys.beanDefinition.factoryBeanOrFactoryMethod.DefaultServiceLocator"/>


	<bean id="clientService"
		  factory-bean="serviceLocator"
		  factory-method="createClientServiceInstance"/>

	<bean id="myBeanFactoryBeanPostProcessor" class="com.ys.beanDefinition.factoryBeanOrFactoryMethod.MyBeanFactoryBeanPostProcessor"/>

</beans>
package com.ys.beanDefinition.factoryBeanOrFactoryMethod;

public interface ClientService {
}

package com.ys.beanDefinition.factoryBeanOrFactoryMethod;

public class ClientServiceImpl implements ClientService{
}

package com.ys.beanDefinition.factoryBeanOrFactoryMethod;

public class DefaultServiceLocator {

    private static ClientService clientService = new ClientServiceImpl();

    public ClientService createClientServiceInstance() {
        return clientService;
    }
}
package com.ys.beanDefinition.factoryBeanOrFactoryMethod;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;

public class MyBeanFactoryBeanPostProcessor implements BeanFactoryPostProcessor {
	@Override
	public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
		BeanDefinition clientService = beanFactory.getBeanDefinition("clientService");
		BeanDefinition defaultServiceLocator = beanFactory.getBeanDefinition("serviceLocator");
		System.out.println("clientService:factoryBeanName:" + clientService.getFactoryBeanName());
		System.out.println("clientService:factoryMethodName:" + clientService.getFactoryMethodName());
		System.out.println("defaultServiceLocator:factoryBeanName:" + defaultServiceLocator.getFactoryBeanName());
		System.out.println("defaultServiceLocator:factoryMethodName:" + defaultServiceLocator.getFactoryMethodName());
	}
}

package com.ys.beanDefinition.factoryBeanOrFactoryMethod;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Main {

	public static void main(String[] args) {
		ApplicationContext xml = new ClassPathXmlApplicationContext("SpringFactoryBean.xml");
		System.out.println(xml.getBean(ClientService.class));
	}
}

运行结果如下:

在这里插入图片描述

可以看到如果我们使用工厂bean和工厂方法创建出来的对象,这两个的值就不为null,如果不是就为null,这儿存的factoryBeanName的值是容器中的bean的ID的值。

4.5InitMethodName与DestroyMethodName

我们先看下官网中介绍的实现的方式有几种。具体如下图:

在这里插入图片描述

发现总共的方式有三种,同时执行的顺序是先注解的,然后是实现接口的,最后是XML的文件中,由于笔者的测试,这两个属性,只有在配置XML文件的时候才不会null,其他的时候都为null,其实也能理解,因为这三种方式,都可以存在,同时还有执行的顺序,如果都用这个两个属性存的话,就会将前面的给覆盖掉,具体的代码如下:

package com.ys.beanDefinition.initOrDestroy;

public class A implements InitializingBean, DisposableBean {

	public A() {
		System.out.println("A.A");
	}

	public void init() {
		System.out.println("A.init");
	}

	public void destroy() {
		System.out.println("A.destroy");
	}
}
package com.ys.beanDefinition.initOrDestroy;

public class B {

	public B() {
		System.out.println("B.B");
	}
}
<?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="a" class="com.ys.beanDefinition.initOrDestroy.A" init-method="init" destroy-method="destroy"/>

	<bean id="b" class="com.ys.beanDefinition.initOrDestroy.B"/>

	<bean id="myBeanFactoryBeanPostProcessor" class="com.ys.beanDefinition.initOrDestroy.MyBeanFactoryBeanPostProcessor"/>

</beans>
package com.ys.beanDefinition.initOrDestroy;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;

public class MyBeanFactoryBeanPostProcessor implements BeanFactoryPostProcessor {
	@Override
	public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
		BeanDefinition a = beanFactory.getBeanDefinition("a");
		BeanDefinition b = beanFactory.getBeanDefinition("b");
		System.out.println("a:InitMethodName:" + a.getInitMethodName());
		System.out.println("a:DestroyMethodName:" + a.getDestroyMethodName());
		System.out.println("b:InitMethodName:" + b.getInitMethodName());
		System.out.println("b:DestroyMethodName:" + b.getDestroyMethodName());
	}
}

package com.ys.beanDefinition.initOrDestroy;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Main {

	public static void main(String[] args) {
		ApplicationContext anno = new ClassPathXmlApplicationContext("SpringInit.xml");
	}
}

运行的结果如下:

在这里插入图片描述

可以看到我们其中存了对应方法名。

5.BeanDefinition的父接口AttributeAccessor

我们可以看到BeanDefinition继承了AttributeAccessor接口,那么这个接口中主要是干嘛的。具体的代码如下:

package org.springframework.core;

import org.springframework.lang.Nullable;

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();

}

可以看到上面只是定义了一些方法的增删查改,我们看不懂,这个时候我们需要找到对应的实现类。具体的类图如下:

在这里插入图片描述

可以看到AttributeAccessor接口的实现类是AttributeAccessorSupport类,打开对应的代码中发现主要通过一个LinkedHashMap的Map用来存对应的键值队,键是String类型,值是Object。这个是用来干嘛的呢?因为BeanDefinition不可能对Bean的信息所有的信息都抽象,就算能,后期也有可能回扩展,所以这儿用了一个Map来存没有对Bean信息的描述的值。我们可以打印看看这个值,具体的代码如下:

package com.ys.beanDefinition.Attribute;

import org.springframework.stereotype.Component;

@Component
public class A {

}

package com.ys.beanDefinition.Attribute;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan("com.ys.beanDefinition.Attribute")
public class AppConfig {
}

package com.ys.beanDefinition.Attribute;

import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.GenericApplicationContext;

public class Main {
	public static void main(String[] args) {
		GenericApplicationContext genericApplicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
		BeanDefinition a = genericApplicationContext.getBeanDefinition("a");
		System.out.println();
	}
}

运行的结果如下:

在这里插入图片描述

至于这个属性是什么意思后面会讲。

6.BeanDefinition的父接口BeanMetadataElement

我们打开对应的代码如下:

package org.springframework.beans;

import org.springframework.lang.Nullable;

public interface BeanMetadataElement {

	@Nullable
	default Object getSource() {
		return null;
	}

}

我们可以写一个测试类看下打印出来的是什么东西,具体的代码如下:

package com.ys.beanDefinition.source;

import org.springframework.stereotype.Component;

@Component
public class A {
}

package com.ys.beanDefinition.source;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan("com.ys.beanDefinition.source")
public class AppConfig {
}

package com.ys.beanDefinition.source;

import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.GenericApplicationContext;

public class Main {
	public static void main(String[] args) {
		GenericApplicationContext genericApplicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
		BeanDefinition a = genericApplicationContext.getBeanDefinition("a");
		System.out.println("source:" + a.getSource());
	}
}

运行的结果如下:

在这里插入图片描述

可以看到存的是这个类的绝对路径的class文件。可能是为了后面反射创建对象用。

7.写在最后

本篇博客主要简单的介绍了一下BeanDefinition这个接口,以及他的父接口,下篇博客会讲下它对应的实现类。因为BeanDefinition对Spring来说太重要了,Spring创建Bean都是是根据这个来的。搞懂了这个,可以说Spring已经搞懂的大半了。

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值