BeanDefinition 顾名思义就是 Bean的定义, 那么他应该包含Bean的元信息. 所以就是这个意思. 对的他就是这么个意思.
Spring中对于BeanFactory生成的Bean全部由这个去定义的.
我们看看Spring提供了什么的BeanDefinition
基本就是上图所示的几种. 大部分都是由 abs组成的. 另一个是内部类. 我们不考虑 ,
那么我们就学学如何使用吧.
GenericBeanDefinition 它是个通用的.
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);
}
}
复制代码
其实还可以继承的
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.
// Instantiate all remaining (non-lazy-init) singletons. finishBeanFactoryInitialization(beanFactory); // 然后进入在 // Instantiate all remaining (non-lazy-init) singletons. beanFactory.preInstantiateSingletons(); // 主要流程就是去注册Bean. 到 , 详细代码可以看看. 其实很简单的. 复制代码
RootBeanDefinition 和 ChildBeanDefinition 这俩成双成对的. 你说不是吗. root节点不能有父类 , 其中儿子节点, 必须有父类 . 用法上和上面那个没啥区别.
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. 复制代码