spring-DI 依赖注入
鄙人刚开始写博客,定有很多不足的地方,尽量以多种方式进行讲解,如果有那种方式更容易你理解或者有任何意见可以给我留言或者私信,欢迎大家评论。
由于DI比较简单,所以这里采取以设计者的角度,从需求分析到设计分享自己的一点看法。
一、需求分析
依赖注入的本质:赋值,给构造参数赋值,给属性赋值
背景:在ioc容器负责生成bean的实例,bean不仅有方法还有属性,我们需要将bean的是属性进行初始化,在这样的背景下,我们将面对第一个问题
问题1:我们需要在什么时候或者在哪里对bean的属性进行初始化?
分析:我们平时写代码时如何创建bean,例如 GirlFriend,存在以下俩种情况:
1GirlFriend gf=new GirlFriend();
2GirlFriend gf=new GirlFriend(“小红”,18);
3GirlFriend gf=GirlFriendFactory.getGirlFriend(“小红”,18);
4 class boy{
GirlFriend gf=new GirlFriend();
}
答:根据举例分析得出分为俩种,1:有参构造参数/工厂方法;2:属性依赖。
解决了第一个问题,我们将面临第二个问题,问题2:构造参数的入参有哪几种情况?·
答:基本类型、String、集合、依赖另一个ioc容器中的bean 等
面对以上的情况,我们将如何设计,详情请看设计
二DI设计
1构造参数依赖
如果我们什么设计,首先要考虑的是先把信息存贮起来,以便后续的使用,那么第一个问题则是:
问题1:参数可以是一个也可以是多个,用什么来存贮呢?
答:答案很明显,是用list,一定要保证存贮多个并且有序,其中有序很重要,因为存在构造函数的重载。
问题2:参数可以是直接只,也可以是bean依赖,如何表示?
答:object
如果用object表示,那我们如何区分是bean依赖?
答:无法判断
问题3:尽然无法判断,我们有没有其他解决方案,不是用object还能使用其他的吗?
答:只需要区分是否为bean依赖即可,使用object是没有问题的。
问题4:如何进行bean依赖的区分
答:基于面向接口的编程的思想,定义个专门标识bean依赖的接口BeanReference,这样就可以解决。
问题5:如果某个参数是数组或者集合等,他们元素中有的是bean依赖,该如何处理
答:元素值还是用BeanReference,同样bean工厂在使用时需要遍历替换
问题6:BeanReference如何定义
public interface BeanReference{ //依赖的bean的名称 private String beanName; //获取依赖bean的名称 String getBeanName(); }
问题7:ioc容器如何获取构造函数
答:在BeanDefinition中添加个方法,即List getConstructorArgumentValues(),通过此方法来获取构造函数
问题8:有参数,如何判断是个构造方法或者工厂方法
分析:存在以下情况
1方法可以重载的
2形参定义时可能是接口或者父类,实参则是具体的子实现
3反射提供的获取的构造方法、方法的API如下:
答:
1先根据参数的类型进行精确匹配查找,如果未找到,则进行第2步
2获取所有的构造方法,扁你了,通过参数数量过滤,再比较形参类型与实参类型。
问题9:对于原型bean在第二次时否可以省略判断,即对于原型bean,我们可以缓存下这个构造方法或者工厂方法?
答:可以,提升性能,我们需要在BeanDefinition接口中添加4个方法。
/* 下面的四个方法是供beanFactory中使用的 */ public Constructor<?> getConstructor(); public void setConstructor(Constructor<?> constructor); public Method getFactoryMethod(); public void setFactoryMethod(Method factoryMethod);
问题10:循环依赖如何处理?(注意:面试题来喽)
分析:循环依赖会导致什么问题? 答:会导致死循环,所以我们时是不允许循环依赖的,尤其是构造函数的循环依赖
答:将正在构造的bean进行缓存,构造完成后移除,当遇到bean的依赖时,首先查看依赖的bean是否在构造中,如果在,则抛出异常。
2属性依赖
问题1:属性依赖时什么?、
答:某个属性依赖某个值
问题2:该如何描述一个属性依赖?
答:属性名,只,定义一个类来表示这个俩值
问题3:会有多个属性依赖,怎么存放
答:list
问题4:属性只的情况和构造参数值时一样的吗?
答:是
2 3 /** 4 * 属性值依赖定义 5 * 6 */ 7 public class PropertyValue { 8 9 private String name; 10 11 private Object value; 12 13 public PropertyValue(String name, Object value) { 14 super(); 15 this.name = name; 16 this.value = value; 17 } 18 19 public String getName() { 20 return name; 21 } 22 23 public void setName(String name) { 24 this.name = name; 25 } 26 27 public Object getValue() { 28 return value; 29 } 30 31 public void setValue(Object value) { 32 this.value = value; 33 } 34 35 }
注意:BeanDefinition中添加List<PropertyValue > getPropertyValues(); 以便BeanFactory可以获取属性依赖的信息
最后总结下循环依赖:
1构造实例对象时(即构造参数循环依赖),会陷入死循环,不允许构造对象时循环依赖的
2属性可以循环依赖, 因为bean已经构建完毕。