前言
前面已经实现了IOC容器(最简单版本),接下分析DI
一、DI是什么?
Dependency injection 依赖注入
-
它使用的地方:
构造参数 和 属性
-
依赖注入的本质:
赋值(给属性值或者构造参数赋值)
-
参数值和属性值可能是什么值
直接值(基本数据类型,数组,集合,map, String等直接给的值)和bean依赖
- bean工厂在进行依赖注入时就是给入值.
- 如何告诉bean工厂该给什么样的构造参数值,及如何定义构造参数依赖。如何定义属性依赖
思考如何定义构造参数依赖:
public class DIConstructorBean { private String name; private DIConstructorParamBean paramBean; public DIConstructorBean(String name, DIConstructorParamBean paramBean) { this.name = name; this.paramBean = paramBean; } }
解决方案是:
DIConstructorParamBean paramBean = new DIConstructorParamBean ();
DIConstructorBean test = new DIConstructorBean ("name1",paramBean));
因此我们可以这样定义构造参数依赖,
例如:第一个参数是 “name1”,第二参数是paramBean
DI参数依赖设计:
多个参数用list存储。
2.参数有顺序入如何体现顺序?
按参数的顺序放入list
3.参数可以是一个直接值,也可以是一个Bean依赖,怎么表示
只能用Object.原因,类型太多。
List<Object>constructorArgumentValues
4.如果用Object,怎么区分是直接值和Bean依赖
为Bean定义一种数据类型(BeanReference),Bean工厂在构造Bean实例时,遍历参数是否是BeanReference.若是,则替换为bean实例
5.直接值,如数组,集合 中元素有Bean依赖,怎么处理
还是用BeanReference 表示,遍历替换
6。BeanReference怎么设计
beanReference就使用来说明bean依赖的,依赖那个bean的
public BeanReference{
String beanName;
String getBeanName();
public BeanReference(String beanName) {
this.beanName=beanName;
}
}
DI实现,构造参数依赖注入:
在beanDefinition中加入获得构造参数的得接口 List<Object> getConstructorArgumentValues();
BeanFactory中实现构造参数依赖注入第一步
将Bean定义中的构造参数引用,转为真实的值。在defaultFactoryBen中增加一个方法。
getConstructorArgumentValues(BeanDefinitin db) :return object[]
BeanFactory中实现构造参数依赖注入第二步
问题:
1.有参数了,如何判定哪构造方法,哪个工厂方法
2.方法是可以重载的
3.形参定义时可能时接口或者父类,实参则是具体子类的实现
反射提供的获取的构造方法,方法的api。
根据参数类进行精准匹配查找,如未找到,则将所有的构造方法,遍历,通过参数数量过滤,再对比形参的类型和实参类型。
优化,当我们判断出构造方法或者工厂方法后,对于原型bean(单例相反的就是原型),下次获取bean可以缓存起来。
实现逻辑
在BeanDefinition中增加缓存的方法。给beanFactory使用
public Constructor<?> getConstructor();
public void setConstructor(Constructor<?> constructor);
public Method getFactoryMethod();
public void setFactoryMethod(Method factoryMethod);
3.第三步在DefaultDeanFactory增加查找构造方法的方法
4.修改DefaultDeanFactory中用构造方式创建实例的代码
5.修改静态工厂方法和工厂方法的方式依赖