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.

相關文章
相關標籤/搜索