2.0手写spring-DI
依赖注入
依赖注入的分析
构造参数依赖定义分析
BeanReference说明
在BeanDefinition中增加获得构造参数的接口
从BeanDefinition中获得真实的值
从方法中添加了新的方法用于,从BeanDefinition中获得真实的值
确定构造方法或者工厂方法
对于原型Bean工厂需要每一次判断工厂方法,所以可以缓存在BeanDefinition中用于后续使用中
从BeanDefinition的参数选择当前的构造方法和工厂方法
private Constructor<?> determineConstructor(BeanDefinition bd, Object[] args) throws Exception {
Constructor<?> ct = null;
if (args == null) {
return bd.getBeanClass().getConstructor(null);
}
// 对于原型bean,从第二次开始获取bean实例时,可直接获得第一次缓存的构造方法。
ct = bd.getConstructor();
if (ct != null) {
return ct;
}
// 1.根据参数类型获取精确匹配的构造方法
Class<?>[] paramTypes = new Class[args.length];
int j = 0;
for (Object p : args) {
paramTypes[j++] = p.getClass();
}
try {
ct = bd.getBeanClass().getConstructor(paramTypes);
} catch (Exception e) {
// 这个异常不需要处理
}
if (ct == null) {
// 2. 没有精确参数类型匹配的,则遍历匹配所有的构造方法
// 判断逻辑:先判断参数数量,再依次比对形参类型与实参类型
outer: for (Constructor<?> ct0 : bd.getBeanClass().getConstructors()) {
Class<?>[] paramterTypes = ct0.getParameterTypes();
if (paramterTypes.length == args.length) {
for (int i = 0; i < paramterTypes.length; i++) {
if (!paramterTypes[i].isAssignableFrom(args[i].getClass())) {
continue outer;
}
}
ct = ct0;
break outer;
}
}
}
if (ct != null) {
// 对于原型bean,可以缓存找到的构造方法,方便下次构造实例对象。在BeanDefinfition中获取设置所用构造方法的方法。
// 同时在上面增加从beanDefinition中获取的逻辑。
if (bd.isPrototype()) {
bd.setConstructor(ct);
}
return ct;
} else {
throw new Exception("不存在对应的构造方法!" + bd);
}
}
从BeanDefinition的参数选择当前的工厂方法
private Method determineFactoryMethod(BeanDefinition bd, Object[] args, Class<?> type) throws Exception {
if (type == null) {
type = bd.getBeanClass();
}
String methodName = bd.getFactoryMethodName();
if (args == null) {
return type.getMethod(methodName, null);
}
Method m = null;
// 对于原型bean,从第二次开始获取bean实例时,可直接获得第一次缓存的构造方法。
m = bd.getFactoryMethod();
if (m != null) {
return m;
}
// 根据参数类型获取精确匹配的方法
Class[] paramTypes = new Class[args.length];
int j = 0;
for (Object p : args) {
paramTypes[j++] = p.getClass();
}
try {
m = type.getMethod(methodName, paramTypes);
} catch (Exception e) {
// 这个异常不需要处理
}
if (m == null) {
// 没有精确参数类型匹配的,则遍历匹配所有的方法
// 判断逻辑:先判断参数数量,再依次比对形参类型与实参类型
outer: for (Method m0 : type.getMethods()) {
if (!m0.getName().equals(methodName)) {
continue;
}
Class<?>[] paramterTypes = m.getParameterTypes();
if (paramterTypes.length == args.length) {
for (int i = 0; i < paramterTypes.length; i++) {
if (!paramterTypes[i].isAssignableFrom(args[i].getClass())) {
continue outer;
}
}
m = m0;
break outer;
}
}
}
if (m != null) {
// 对于原型bean,可以缓存找到的方法,方便下次构造实例对象。在BeanDefinfition中获取设置所用方法的方法。
// 同时在上面增加从beanDefinition中获取的逻辑。
if (bd.isPrototype()) {
bd.setFactoryMethod(m);
}
return m;
} else {
throw new Exception("不存在对应的构造方法!" + bd);
}
}
循环依赖的处理
属性依赖的分析
BeanDefinition中的属性依赖
在DefaultDeanFactory 中增加setProperty的方法
private void setPropertyDIValues(BeanDefinition bd, Object instance) throws Exception {
if (CollectionUtils.isEmpty(bd.getPropertyValues())) {
return;
}
for (PropertyValue pv : bd.getPropertyValues()) {
if (StringUtils.isBlank(pv.getName())) {
continue;
}
Class<?> clazz = instance.getClass();
Field p = clazz.getDeclaredField(pv.getName());
p.setAccessible(true);
Object rv = pv.getValue();
Object v = null;
if (rv == null) {
v = null;
} else if (rv instanceof BeanReference) {
v = this.doGetBean(((BeanReference) rv).getBeanName());
} else if (rv instanceof Object[]) {
// TODO 处理集合中的bean引用
} else if (rv instanceof Collection) {
// TODO 处理集合中的bean引用
} else if (rv instanceof Properties) {
// TODO 处理properties中的bean引用
} else if (rv instanceof Map) {
// TODO 处理Map中的bean引用
} else {
v = rv;
}
p.set(instance, v);
}
}