源码也看了好几遍了,但是就是记不住,所以又来缕缕。
IOC现在是一个框架都具备了,虽然在自己也实现了一个简单的 框架,也具备IOC的功能,但是还是太简单了。下面来看看Spring的IOC到到底是个什么情况。
初始化容器一般用两种方式,从xml文件读取,从配置类解析。分别对应于以下代码。
ApplicationContext applicationContext = new FileSystemXmlApplicationContext(xmlPath);
//Entrance.class 你的配置类,被@Configuration标记
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(Entrance.class);
通过
String[] names = applicationContext.getBeanDefinitionNames();
for (String name : names) {
System.out.println(name);
}
可以输出容器初始化了哪些Bean.
可以看到容器的初始化,除了我们自己的打上了注解的类,还有一些Spring自己的类。
Spring框架虽然负责,总体来说IOC可以概括为3个步骤。
1.解析配置
2.定位和注册兑现对象
3.注入对象
预备知识
在JAVA中,通过类.classs对象,或者对象.getClass()获取 该对象的描述,简而言之
class对象就是描述这个对象“我是谁的问题”。
在Spring中,Bean的概念对应于Java的对象,但是因为Spring需要做更多额外的事情,Spring通过BeanDefinition来描述Bean。对应于JAVA用CLASS来描述对象。回答我是谁的问题。
BeanDefinition的属性我们经常用到,只是不知道我们其实在使用而已。
他的常用属性:
- 懒加载 作用范围(单例,多例)
- 别名
- 优先级(当多个类型共同竞争的时候的参考优先使用这个)
- 工厂方法
- 工厂类
等等
不管是xml配置还是注解类配置,最终都会被框架解析成 一个个的BeanDefiniton注册在容器中。
最后 容器才根据BeanDefinition的指示来初始化Bean.
BeanDefiniton家族
BeanDefiniton也是有parent属性的,最后的Definition会综合各个层级统一生成定义。
Java里面是通过集成声明父子关系,而Spring是通过属性设置的。
BeanFactory
Spring的设计完全遵循了单一职责,每个接口提供一个能力。所以看源码的时候 ,各种分支特别多。
BeanFactory是简单容器,提供了一些容器常用的功能。主要面向Spring自己使用或者是基础设施。
我们正真用到的是ApplicationContext.
下图就是BeanFactory申明的方法。
ApplicationContext
public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,
MessageSource, ApplicationEventPublisher, ResourcePatternResolver
EnvironmentCapable:获取配置环境信息
ListableBeanFactory:可以列表的形式管理容器类的BeanDeFinition
HierarchicalBeanFactory 容器可以设置父容器
MessageSource:国际化接口
** ApplicationEventPublisher**事件发布
ResourcePatternResolver资源解析器
注解配置的加载和解析注册
以调式的方式启动。
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(Entrance.class);
因为Spring默认使用的就是DefaultListableBeanFactory,容器 的初始化必然要注册BeanDefinition,所以提前在registerBeanDefinition打上断点。
最开始出现的BeanDefinition并不是 我们熟悉的类,因为 初始化之前还要注册一些系统自带的BeanDefinition。
栈1:启动类调用
栈2:注册BeanDefinition的读取类,组件扫描器。
此时也顺便初始化了DefaultListAbleBeanFactory.
可以得出结论 ,注解类启动方式最开始启动的时候,会注册BeanDefinitionrReader,和一个 默认的容器 。
然后继续RESUME,直到出现用户的类。
后面我直接文字说明了。
读取到配置类,执行注册配置类的逻辑。具体是解析配置类的注解相关信息,然后利用动态代理生成一个 BeanDefinitin注册到容器。
继续调式,看看普通的业务Bean是怎么注册的。
到refresh方法,可以看到 普通的业务类是在Refresh的时候才注册的。
更进一步,发现是在容器的后置处理器时候进行普通Bean的注册。
但是在处理容器的后置处理器时,要优先判断是否有Bedefinition的后置处理器 ,如果有,要限制行。
最后才将BeanDefnition注册到容器中。
我在后面发现一个疑问,为什么每次解析普通类的时候,都要