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. 到 , 詳細代碼能夠看看. 其實很簡單的.
複製代碼
RootBeanDefinition
和 ChildBeanDefinition
這倆成雙成對的. 你說不是嗎. 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.