BeanDefinition
是定义Bean配置元信息的接口,Spring会加载指定的Java类变成BeanDefinition对象, 然后根据此来创建Bean,那么下面就来详细介绍一下
从类图中可以看出,BeanDefinition
继承了AttributeAccessor
和BeanMetadataElement
两个接口;
可以看到里面的方法很好理解,对属性的增删改查
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();
}
BeanDefinition
定义很多接口方法,对应Bean属性,通过这种方式定义,\、代表子类必须提供这些属性
AbstractBeanDefinition
对这个接口进行了实现,它提供了一个BeanDefinition
所需要具备的基本能力,它是最终全能BeanDefinition
实现类的基类,下面展示了部分属性,对应的我们在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的名字进行自动装配,即autowired属性的值为byname
public static final int AUTOWIRE_BY_NAME = AutowireCapableBeanFactory.AUTOWIRE_BY_NAME;
// 根据Bean的类型进行自动装配,调用setter函数装配属性,即autowired属性的值为byType
public static final int AUTOWIRE_BY_TYPE = AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE;
// 自动装配构造函数的形参,完成对应属性的自动装配,即autowired属性的值为byConstructor
public static final int AUTOWIRE_CONSTRUCTOR = AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR;
@Deprecated
public static final int AUTOWIRE_AUTODETECT = AutowireCapableBeanFactory.AUTOWIRE_AUTODETECT;
// 不进行依赖检查
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;
//若Bean未指定销毁方法,容器应该尝试推断Bean的销毁方法的名字
public static final String INFER_METHOD = "(inferred)";
// Bean的class对象或是类的全限定名
@Nullable
private volatile Object beanClass;
//bean的作用范围,对应bean属性scope是单例
@Nullable
private String scope = SCOPE_DEFAULT;
//是否是抽象,对应bean属性abstract 默认不为抽象类
private boolean abstractFlag = false;
//是否延迟加载,对应bean属性lazy-init
@Nullable
private Boolean lazyInit;
// 默认不进行自动装配
private int autowireMode = AUTOWIRE_NO;
// 默认不进行依赖检查
private int dependencyCheck = DEPENDENCY_CHECK_NONE;
//用来表示一个bean的实例化依靠另一个bean先实例化
//这里只会存放 标签的depends-on属性或是@DependsOn注解的值
@Nullable
private String[] dependsOn;
//autowire-candidate属性设置为false,这样容器在查找自动装配对象时,
//将不考虑该bean,即它不会被考虑作为其他bean自动装配的候选者,
//但是该bean本身还是可以使用自动装配来注入其他bean的
private boolean autowireCandidate = true;
//自动装配时出现多个bean候选者时,将作为首选者,对应bean属性primary
private boolean primary = false;
//用于记录Qualifier,对应子元素qualifier
private final Map<String, AutowireCandidateQualifier> qualifiers = new LinkedHashMap<>();
@Nullable
private Supplier<?> instanceSupplier;
//允许访问非公开的构造器和方法,程序设置
private boolean nonPublicAccessAllowed = true;
//是否以一种宽松的模式解析构造函数,默认为true
private boolean lenientConstructorResolution = true;
//对应bean属性factory-bean 工厂类名
@Nullable
private String factoryBeanName;
//对应bean属性factory-method 工厂方法名
@Nullable
private String factoryMethodName;
//记录构造函数注入属性,对应bean属性constructor-arg
@Nullable
private ConstructorArgumentValues constructorArgumentValues;
//普通属性集合
@Nullable
private MutablePropertyValues propertyValues;
//方法重写的持有者,记录lookup-method、replaced-method元素
private MethodOverrides methodOverrides = new MethodOverrides();
//初始化方法,对应bean属性init-method
@Nullable
private String initMethodName;
//销毁方法,对应bean属性destroy-method
@Nullable
private String destroyMethodName;
//是否执行init-method,程序设置
private boolean enforceInitMethod = true;
//是否执行destroy-method,程序设置
private boolean enforceDestroyMethod = true;
//是否是用户定义的而不是应用程序本身定义的,创建AOP时候为true,程序设置
private boolean synthetic = false;
//定义这个bean的应用,APPLICATION:用户,INFRASTRUCTURE:完全内部使用,与用户无关
private int role = BeanDefinition.ROLE_APPLICATION;
//bean的描述信息
@Nullable
private String description;
//bean的资源
@Nullable
private Resource resource;
继承自AbstractBeanDefinition
的全功能BeanDefinition实现类有 :
RootBeanDefinition
:Spring框架内部使用的,其他BeanDefinition都会转换为它GenericBeanDefinition
:编程定义使用的,官方推荐使用ChildBeanDefinition
:父子bean的时候使用,已逐步废弃ConfigurationClassBeanDefinition
:写在@Configuration
中的@Bean
,会被注册成该BeanDefinitionAnnotatedGenericBeanDefinition
:通过注解方式引入的Bean,最常见的是@Import
引入ScannedGenericBeanDefinition
:通过扫描方式引入的Bean,那就是@ComponentScan
RootBeanDefinition
仅作为运行时的BeanDefinition视图。GenericBeanDefinition
。GenericBeanDefinition
的优势在于,它允许动态定义父依赖项,而不是一个以”硬编码”定义BeanDefinition的角色。简单点说就是除了Spring框架,其它的编程都使用GenericBeanDefinition
,功能都一样,而且还有有优点GenericBeanDefinition
或是ConfigurationClassBeanDefinition
(用@Bean注解注释的类)存储用户自定义的Bean,在初始化Bean时,又会将其转换为RootBeanDefinition。上面的描述来自源码类注释,如下:
/**
* A root bean definition represents the merged bean definition that backs
* a specific bean in a Spring BeanFactory at runtime. It might have been created
* from multiple original bean definitions that inherit from each other,
* typically registered as {@link GenericBeanDefinition GenericBeanDefinitions}.
* A root bean definition is essentially the 'unified' bean definition view at runtime.
*
* Root bean definitions may also be used for registering individual bean definitions
* in the configuration phase. However, since Spring 2.5, the preferred way to register
* bean definitions programmatically is the {@link GenericBeanDefinition} class.
* GenericBeanDefinition has the advantage that it allows to dynamically define
* parent dependencies, not 'hard-coding' the role as a root bean definition.
*
* @author Rod Johnson
* @author Juergen Hoeller
* @see GenericBeanDefinition
* @see ChildBeanDefinition
*/
@SuppressWarnings("serial")
public class RootBeanDefinition extends AbstractBeanDefinition {
//....
}
当定义父子bean的时候,那么上面的RootBeanDefinition
可以作为一个普通的BeanDefinition
,也可以作为父bean,但是不能定义为子bean,那么这个时候就需要ChildBeanDefinition
,而且不可以单独存在,必须要依赖一个父BeanDetintiont
下面只展示该类中的部分代码,看到子类只是扩展了一个parentName
属性,存储父类
public class ChildBeanDefinition extends AbstractBeanDefinition {
@Nullable
private String parentName;
// 省略构造方法
}
Spring2.5之后废弃。
个人觉得废弃的原因有如下:
通用的BeanDefinition
,它的出现是为了替换掉ChildBeanDefinition
,简单点说,之前为了实现父子bean,需要使用RootBeanDefinition
和ChildBeanDefinition
,现在单独使用GenericBeanDefinition
就可以实现
public class GenericBeanDefinition extends AbstractBeanDefinition {
@Nullable
private String parentName;
// 省略构造方法...
}
从网上拷贝下来的,只通过GenericBeanDefinition
实现父子bean
package com.xjm.bean.definition;
import com.xjm.model.Child;
import com.xjm.model.Root;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class GenericBeanDefinitionDemo {
// 获取父bean
public static GenericBeanDefinition getRootBeanDefinition() {
GenericBeanDefinition rootBeanDefinition = new GenericBeanDefinition();
rootBeanDefinition.setBeanClass(Root.class);
MutablePropertyValues propertyValues = new MutablePropertyValues();
propertyValues.add("name", "root")
.add("description", "I am a rootBeanDefinition")
.add("isRoot", true);
rootBeanDefinition.setPropertyValues(propertyValues);
return rootBeanDefinition;
}
// 获取子bean
public static GenericBeanDefinition getChildBeanDefinition() {
GenericBeanDefinition childBeanDefinition = new GenericBeanDefinition();
childBeanDefinition.setBeanClass(Child.class);
MutablePropertyValues propertyValues = new MutablePropertyValues();
propertyValues.add("parentName", "root");
childBeanDefinition.setParentName("root");
childBeanDefinition.setPropertyValues(propertyValues);
return childBeanDefinition;
}
public static void main(String[] args) {
// 1. 构建一个空的容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
GenericBeanDefinition rootBeanDefinition = getRootBeanDefinition();
GenericBeanDefinition childBeanDefinition = getChildBeanDefinition();
applicationContext.registerBeanDefinition("root", rootBeanDefinition);
applicationContext.registerBeanDefinition("child", childBeanDefinition);
applicationContext.refresh();
Root root = applicationContext.getBean(Root.class);
Child child = applicationContext.getBean(Child.class);
System.out.println(root.toString());
System.out.println(child.toString());
}
}
@Configuration + @Bean
ConfigurationClassBeanDefinition
类型的BeanDefinition
非常多,大部分都是,原因:SpringBoot的自动化配置特点,会引入非常多的依赖,这些依赖注入自己的组件都是通过配置类的方式annotationMetadata
和factoryMethodMetadata
。扩展的属性有啥用?下面介绍factoryMethodMetadata
存储方法信息。用处:通过@Bean
定义的类,当获取时,就不是通过构造方法了,而是类似于工厂方法模式直接调用该方法,而且 如果@Bean
没有指定 Bean 的名字,默认会用方法的名字命名 Bean。那么factoryMethodMetadata
就存储方法的各种信息annotationMetadata
存储@Bean
注解属性。作用:@Bean
里面也有很多属性,创建的时候肯定需要用到// 静态内部类
private static class ConfigurationClassBeanDefinition extends RootBeanDefinition implements AnnotatedBeanDefinition {
// 存储@Bean注解的信息
private final AnnotationMetadata annotationMetadata;
// 存储@Bean方法的信息
private final MethodMetadata factoryMethodMetadata;
// 省略...
}
看到下图很多都是SpringBoot自动配置引入的Bean,基本都是ConfigurationClassBeanDefinition
它用来定义通过注解引入的Bean,最常见的肯定就是@Import
引入
下面截图解释:
AnnotatedGenericBeanDefinition
aspectConfig
就变成了ScannedGenericBeanDefinition
,为啥呢?因为它不是单独注册的,它是启动类上的@ComponentScan
注解扫描到的配置类,所以就会是该类型qqqq
,这个就是正常的AnnotatedGenericBeanDefinition
,为啥呢?首先我把它和启动类分成不同层级的包,启动类扫描不到,然后再启动类上引入该配置类@Import(TestConfig.class)
,就会是想要的结果通过名字可以看出是通过扫描的方式注入到Bean中,扫描需要是用到@ComponentScan
在扫描Bean的时候,会用到一个辅助类BeanDefinitionHolder
,顾名思义就是对BeanDefinition
的持有,通过包含其名称和别名
这个一般在解析@ComponentScan
的时候用到,会把扫描到的类封装成BeanDefinitionHolder
,把各种信息都存进去,就是一个辅助类很好理解
public class BeanDefinitionHolder implements BeanMetadataElement {
private final BeanDefinition beanDefinition;
// Bean名称
private final String beanName;
// 别名
@Nullable
private final String[] aliases;
}
有,通过包含其名称和别名
这个一般在解析@ComponentScan
的时候用到,会把扫描到的类封装成BeanDefinitionHolder
,把各种信息都存进去,就是一个辅助类很好理解
public class BeanDefinitionHolder implements BeanMetadataElement {
private final BeanDefinition beanDefinition;
// Bean名称
private final String beanName;
// 别名
@Nullable
private final String[] aliases;
}