其实底层是个接口

BeanDefinition表示Bean定义,BeanDefinition中存在很多属性用来描述一个Bean的特点。比如:
在Spring中,我们经常会通过以下几种方式来定义Bean:
这些,我们可以称之声明式定义Bean。
如果底层用的xml,spring也会解析成一个beanDefinition对象

bean注解解析也会生成beanDefinition

这里加了Bean注解直接调用这个方法对吗?

不太对,
首先会生成BeanDefinition对象,然后放到BeanDefinitionMap里面,再从map里面取出非懒加载的单例bean再拿出来,才会调用这个方法。
(Spring提供定义bean的方式)
我们还可以编程式定义Bean,那就是直接通过BeanDefinition,比如:
也就是说这个编程式定义Bean可以替代@Bean注解的一种写法。
(但是平常不会这么干,spring底层是这么干的)
- AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
-
- // 生成一个BeanDefinition对象,并设置beanClass为User.class,并注册到ApplicationContext中
- AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
- beanDefinition.setBeanClass(User.class);
- // 还能指定作用域
- beanDefinition.setScope("prototype");
- // 指定beanName
- context.registerBeanDefinition("user", beanDefinition);
-
- System.out.println(context.getBean("user"));
我们还可以通过BeanDefinition设置一个Bean的其他属性
- beanDefinition.setScope("prototype"); // 设置作用域
- beanDefinition.setInitMethodName("init"); // 设置初始化方法
- beanDefinition.setLazyInit(true); // 设置懒加载
和申明式事务、编程式事务类似,通过
被注解的BeanDefinitionReader(BeanDefinition的一个读取器 spring提供的一个工具类)
可以直接把某个类转换为BeanDefinition,并且会解析该类上的注解,比如
- // 先构造一个spring的容器
- AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
- // 读到哪里去 肯定读到容器 所以要传参一个context
- AnnotatedBeanDefinitionReader annotatedBeanDefinitionReader = new AnnotatedBeanDefinitionReader(context);
- // 利用了BeanDefinition的一个读取器去注册了一个User
- // 将User.class解析为BeanDefinition 也就是最终这个User就会成为BeanDefinition,放在spring容器里
- annotatedBeanDefinitionReader.register(User.class);
-
- System.out.println(context.getBean("user"));
register底层源码:这里只传了一个类User.class

构造了一个BeanDefinition,类就是传进来的类

然后还会去判断当前类上有没有@Lazy注解之类的,然后设置到刚才的BeanDefinition中


注意:它能解析的注解是:@Conditional,@Scope、@Lazy、@Primary、@DependsOn、@Role、@Description
User也没加注解

运行正常,说明我们的User是一个bean,报错就说明不是bean

比如AnnotationConfigApplicationContext底层就调用到了这个
被注解的BeanDefinitionReader(BeanDefinition的一个读取器 spring提供的一个工具类)

这个register底层其实就是调用的这个BeanDefinition的一个读取器


他就是BeanDefinition的一个读取器 ,传给他一个类,他就能解析类上面的注解,然后变成一个BeanDefinition,然后放到spring的容器中,然后就成为了一个bean。
可以解析xml文件的,解析
- AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
-
- XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(context);
- int i = xmlBeanDefinitionReader.loadBeanDefinitions("spring.xml");
-
- System.out.println(context.getBean("user"));

这里就不会报错,能拿到bean,底层解析xml

ClassPathBeanDefinitionScanner是扫描器,但是它的作用和BeanDefinitionReader类似,它可以进行扫描,扫描某个包路径,对扫描到的类进行解析,比如,扫描到的类上如果存在@Component注解,那么就会把这个类解析为一个BeanDefinition,比如:
- AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
- context.refresh();
-
- ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context);
- // 定义扫描路径 扫描得到的都是BeanDefinition 然后放到spring容器
- scanner.scan("com.zhouyu");
-
- System.out.println(context.getBean("userService"));
在UserService上加了@Component注解


答:不行 因为这里构造了空的spring容器,没有传配置文件进去,而且没刷新
加个代码context.refresh();(强制要求,不过就算加了也没丝毫作用)

这里定义了扫描器,然后把容器传进扫描器里。然后去路径下扫描,发现有@Component注解,然后就生成BeanDefinition,接着会加入到spring容器里,这样就能拿到UserService的bean了
我们的spring容器 也就是这个context,既可以注册某一个类成为bean
也可以自己触发去扫描



底层先调用空的构造方法
再把传进来的类进行注册


通过AnnotatedBeanDefinitionReader进行注册 注册成为一个BeanDefinition
再去刷新

也可以这么操作实现一样的效果