Code-Life
Code-Life copied to clipboard
IOC容器简易实现的知识点
简易IOC容器实现: https://github.com/Draymonders/IoC-Implement
四种定义Bean的注解
- Controller
- Service
- Repository
- Component
IOC容器需要使用者给出具体的扫描的位置,才能获取相对应的bean
在此我们使用 包名 作为扫描的位置,如何根据包名定位到具体的class路径呢?
- 使用绝对路径是不优雅的,因为每个用户的绝对路径不同,且最终打成jar包或者war包,少有人知道package的实际路径。
实现方式:
- 获取当前的类加载器。
- 根据类加载器去获取对应包名的URI信息
- 根据URI提取出来绝对路径
- 对绝对路径下的所有的文件夹扫描,收集Class信息 (具体的packageName,className)
- 通过反射机制去获取到Class
我们最终期待系统中有一个bean容器,那么如何构造线程安全的bean容器呢?
用到了单例模式
有三种实现
- 饿汉式
- 懒汉式
- 反射无法注入的 枚举方法(EnumSingleton)
实现容器
- 保存Class对象及示例的载体 (这里用ConcurrentHashMap来存)
- 容器的加载 (加载容器 && 加载beans)
- 容器的操作方式
- 增加,删除bean
- 根据Class获取对应实例
- 获取所有的Class和实例
- 通过注解来获取被注解标注的Class
AController a = new AController();
- 通过超类获取对应的子类Class (类似这种
AService a = new AServiceImpl()
) - 获取容器载体保存Class的数量
简易依赖注入(暂无循环依赖情况, 暂时也不考虑多impl的情况), 只注入到Field
上
- 扫描
basePackage
下的所有的bean,并且加载到bean容器中 - 对所有的bean扫描其所有的
field
,找出包含Autowired
的字段 - 提取
Autowired
注解的类,然后根据类去bean容器中寻找对应的bean - 对相关的
bean
的filed
进行反射注入。
多impl的情况
- 比如
AService
有AServiceImpl1
,AServiceImpl2
两个实现类 - 如果不指定,IoC容器不知道注入哪个依赖,因而抛出异常,如果指定了
@Qualifier
, 则会去取@Qualifier
对应的值去关联对应的AService
实现类
BeanFactory 和 FactoryBean的区别
-
BeanFactory
是Spring
里最基础的容器,定义了多种getBean
方法 -
FactoryBean
则是Bean
的工厂实现,用于获取对应的bean, 定义了getObject
方法
简单BeanFactory实现
todo: 阅读 DefaultListableBeanFactory
源码
ApplicationContext
Spring高级容器
- 传统使用有
FileSystemXmlApplicationContext
,ClassPathXmlApplicationContext
,XmlWebApplicationContext
- 当今使用有
AnnotationConfigServletWebServerApplicationContext
,AnnotationConfigServletReactiveApplicationContext
Spring处理流程
Bean -> Spring托管的对象
|
|
Resource -> 配置,文件, xml,数据库的一个抽象
|
|
ResourceLoader / ResourcePatternResolver -> 根据路径或者其他信息,定位到Resource
|
|
BeanDefinitonReader -> 获取BeanDefinition容器, 也即BeanFactory, ApplicationContext的实现类
|
|
BeanDefinition -> 获取bean的配置信息,以用于生成bean,可以注册到容器中。Map<name, BeanDefintion>
|
|
BeanFactory -> 基础容器
|
|
ApplicationContext -> 高级容器
循环依赖
- 如何发现循环依赖? A:加入一个正在构造的bean的记录,每个bean开始构造时加入到记录中,构造完成就移走,如果有依赖,先看依赖的bean是否在构造中,如果是,就构成了循环,抛出异常