Spring的BeanDefinition使用和理解

BeanDefinition 顾名思义就是 Bean的定义, 那么他应该包含Bean的元信息. 因此就是这个意思. 对的他就是这么个意思.java

Spring中对于BeanFactory生成的Bean所有由这个去定义的.spring

咱们看看Spring提供了什么的BeanDefinition工具

基本就是上图所示的几种. 大部分都是由 abs组成的. 另外一个是内部类. 咱们不考虑 ,ui

那么咱们就学学如何使用吧.this

GenericBeanDefinition

它是个通用的.spa

public class SringApp {

    @Data
    static class Bean {
        String name;
        int age;
    }

    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();

        GenericBeanDefinition definition = new GenericBeanDefinition();
        definition.setBeanClass(Bean.class);
        definition.getPropertyValues().add("name", "xiaoli");
        definition.getPropertyValues().add("age", 1);
        // 注册.
        context.registerBeanDefinition("bean1", definition);

        context.refresh();
        Bean bean = (Bean) context.getBean("bean1");
        System.out.println(bean);
    }
}
复制代码

其实还能够继承的code

public static void main(String[] args) {
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();

    GenericBeanDefinition definition = new GenericBeanDefinition();
    definition.setBeanClass(Bean.class);
    definition.getPropertyValues().add("name", "xiaoli");
    definition.getPropertyValues().add("age", 1);
    context.registerBeanDefinition("bean1", definition);

    GenericBeanDefinition definition2 = new GenericBeanDefinition();
    definition2.setParentName("bean1");
    // bean2 的属性继承了 bean1
    context.registerBeanDefinition("bean2", definition2);

    context.refresh();

    Bean bean1 = (Bean) context.getBean("bean1");
    Bean bean2 = (Bean) context.getBean("bean2");
    // 虽然是这样,可是返回的false. 由于只是继承了属性.
    System.out.println(bean1==bean2);
}
复制代码

那么它什么时候加载的. 显然是在 context.refresh(); 的时候. 在fresh中的这个方法中. 初始化non-lazy.cdn

// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);

// 而后进入在
// Instantiate all remaining (non-lazy-init) singletons.
beanFactory.preInstantiateSingletons();

// 主要流程就是去注册Bean. 到 , 详细代码能够看看. 其实很简单的. 
复制代码

RootBeanDefinitionChildBeanDefinition

​ 这俩成双成对的. 你说不是吗. root节点不能有父类 , 其中儿子节点, 必须有父类 . 用法上和上面那个没啥区别.xml

public static void main(String[] args) {
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();

    // root
    RootBeanDefinition definition = new RootBeanDefinition();
    definition.setBeanClass(Bean.class);
    definition.getPropertyValues().add("name", "xiaoli");
    definition.getPropertyValues().add("age", 1);
    context.registerBeanDefinition("bean1", definition);

    // child
    ChildBeanDefinition definition2 = new ChildBeanDefinition("bean1");
    context.registerBeanDefinition("bean2", definition2);

    // 刷新
    context.refresh();

    Bean bean1 = (Bean) context.getBean("bean1");
    Bean bean2 = (Bean) context.getBean("bean2");
    System.out.println(bean1==bean2);
}
复制代码

BeanDefinitionBuilder 工具

​ 很显然就是一个Builder的工具类.对象

BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(Bean.class);
// lazy 的意思是. 你须要(调用get("beanname")方法)的时候才要实例化.
builder.setLazyInit(true);
// builder.getBeanDefinition() 实际上是一个 GenericBeanDefinition
context.registerBeanDefinition("bean3", builder.getBeanDefinition());
复制代码

BeanDefinitionHolder

​ 很显然是一个持有者

// 三个参数: 
// beanDefinition , bean_name, bean_alias(别名的意思就是小名,能够经过小名获取)
BeanDefinitionHolder holder = new BeanDefinitionHolder(definition, "bean1", new String[]{"bean2"});
context.registerBeanDefinition(holder.getBeanName(), holder.getBeanDefinition());
for (String alias : Objects.requireNonNull(holder.getAliases())) {
    context.registerAlias(holder.getBeanName(), alias);
}
复制代码

BeanDefinitionParser

​ 这个接口就是一个对象. 是spring的xml配置中 解析xml须要使用到的. parser. 其实这个返回值没卵用. 有兴趣能够看看源码 , 分析一下为啥这个返回值没啥用. 因此返回null也行. 只要注册到context中就好了.

public interface BeanDefinitionParser {
	@Nullable
    // Element , 其实就是XML的一组标签
    // ParserContext 其实就是Spring的上下文,由于xmlcontext基础了这个.
	BeanDefinition parse(Element element, ParserContext parserContext);
}
复制代码

BeanDefinitionReader

​ 这个名字 , 很显然是从什么地方读的BeanDefinition 的.

其实主要就是俩. XmlBeanDefinitionReader 他实现了 BeanDefinition 接口.

可是 AnnotatedBeanDefinitionReader 并无.

其主要实现就是. 一下三个方法. 其实也简单. 由于须要BeanDefinitionRegistry ,而后拿到Resource去注册就好了.

BeanDefinitionRegistry getRegistry();

int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException;

int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException;
复制代码

咱们先看最熟悉的 AnnotatedBeanDefinitionReader

AnnotatedBeanDefinitionReader reader = new AnnotatedBeanDefinitionReader(context);
// SringApp类做为配置类. context做为register.
reader.registerBean(SringApp.class);
复制代码

xml那个 也是 , 拿着source去作就好了.

XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(context);
reader.loadBeanDefinitions("user.xml");
// 刷新 . 获取就好了. 
context.refresh();
// 内部实现比较麻烦. 因此自行去了解. 
User bean = context.getBean(User.class);
System.out.println(bean);
复制代码

ClassPathBeanDefinitionScanner

​ 这是一个根据类路径进行一个加载器

// 咱们调用scan方法 , 实际上是调用的ClassPathBeanDefinitionScanner去加载的. 
public void scan(String... basePackages) {
    Assert.notEmpty(basePackages, "At least one base package must be specified");
    this.scanner.scan(basePackages);
}
复制代码

他会扫描. 全部组件 . 默认过滤器是一下实现.

Candidate classes are detected through configurable type filters. The default filters include classes that are annotated with Spring's @Component, @Repository, @Service, or @Controller stereotype.
复制代码

BeanDefinitionRegistry

​ 比较核心. 毕竟是注册BeanDefinition用的.

核心接口方法

void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException;
复制代码

通常咱们常见的SpringApplication 默认就是一个实现好的register.

相关文章
相关标签/搜索