Spring源码之手写DI
我们来回顾一下前面手写IOC的内容。
一、DI介绍
DI(Dependency injection)依赖注入。对象之间的依赖由容器在运行期决定,即容器动态的将某个依赖注入到对象之中。说直白点就是给Bean对象的成员变量赋值。
在这里我们就需要明白几个问题。
1. 哪些地方会有依赖
- 构造参数依赖
- 属性依赖
2. 依赖注入的本质是什么?
依赖注入的本质是 赋值
。赋值有两种情况
- 给有参构造方法赋值
- 给属性赋值
3. 参数值、属性值有哪些?
具体赋值有两种情况:直接值和Bean依赖。比如
public clsss Girl{public Girl(String name, int age, Clouth clouth){private String name;private Integer age;private Clothes clothes;}
}
4. 直接赋值有哪些?
- 基本数据类型:String、int 等
- 数组,集合
- map
二、构造注入
我们先来看看构造参数注入的情况应该要如何解决。
1.构造注入分析
我们应该如何定义构造参数的依赖?也就是我们需要通过构造方法来创建实例,然后对应的构造方法我们需要传入对应的参数。如果不是通过IoC来处理,我们可以直接通过如下的代码实现。
public static void main(String[] args) {Clouth clouth = new Dress();Girl girl = new Girl("小龙女", 18, clouth);}
我们通过直接赋值的方式就可以了。但是在IOC中我们需要通过反射的方式来进行通用处理。在使用反射操作的时候就需要能获取到对应的构造参数的依赖了,这时我们得分析怎么来存储我们的构造参数的依赖了。构造参数的依赖有两个特点:
- 顺序
- 数量
- 类型
上面例子中构造函数的参数
- 小丽, String类型
- 20, int 类型
- clouth, 自定义的Clouth类型,是一个依赖Bean
参数可以有多个,我们可以通过List集合来存储,这样构造参数的顺序就可以通过控制往List集合中add元素的顺来保证。但是需要注意的是,依赖Bean如何表示呢?
基本类型的值直接添加到集合中就可以了,但是依赖Bean的实例对象可能还没有创建,那么这时我们可以抽象出一个类,用来描述依赖Bean的信息。
2. BeanReference
注意:
BeanReference其实就是用来描述依赖Bean信息的
/*** 用于依赖注入中描述bean依赖*/
public class BeanReference {private String beanName;private Class<?> type;public BeanReference(Class<?> type) {this.type = type;}public String getBeanName() {return beanName;}public void setBeanName(String beanName) {this.beanName = beanName;}public Class<?> getType() {return type;}public void setType(Class<?> type) {this.type = type;}
}
可以根据name来依赖,也可以按照Type来依赖。另外还有一点需要考虑,就是如何来区分是直接值还是依赖Bean呢?有了上面的设计其实就很容易判断了。
if ( obj instanceOf BeanReference)
但是下面这种直接值是数组或者集合等,同时容器中的元素是依赖Bean的情况:
import java.io.Serializable;
import java.util.List;public class Girl implements Serializable {private String name;private Integer age;private List<Clothes> clothesList;public Girl(String name, Integer age, List<Clothes> clothesList) {this.name = name;this.age = age;this.clothesList = clothesList;}
}
这种情况下元素值仍然可以用BeanReference来处理。Bean工厂在处理时需要遍历替换。
3. BeanDefinition实现
接下来我们看看如何具体的来实现DI基于构造函数参数依赖的相关操作。首先是BeanDefinition定义的相关处理。需要在 BeanDefinition
中增加构造参数的获取的方法。
然后我们需要在默认的实现GenericBeanDefinition中增加对应的方法来处理。
BeanDefinition接口
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.List;import org.apache.commons.lang3.StringUtils;/*** bean定义接口*/
public interface BeanDefinition {String SCOPE_SINGLETON = "singleton";String SCOPE_PROTOTYPE = "prototype";/*** 类*/Class<?> getBeanClass();/*** Scope*/String getScope();/*** 是否单例*/boolean isSingleton();/*** 是否原型*/boolean isPrototype();/*** 工厂bean名*/String getFactoryBeanName();/*** 工厂方法名*/String getFactoryMethodName();/*** 初始化方法*/String getInitMethodName();/*** 销毁方法*/String getDestroyMethodName();boolean isPrimary();/*** 校验bean定义的合法性*/default boolean validate() {// 没定义class,工厂bean或工厂方法没指定,则认为不合法。if (this.getBeanClass() == null) {if (StringUtils.isBlank(getFactoryBeanName()) || StringUtils.isBlank(getFactoryMethodName())) {return false;}}// 定义了类,又定义工厂bean,不合法if (this.getBeanClass() != null && StringUtils.isNotBlank(getFactoryBeanName())) {return false;}return true;}/*** 获得构造参数定义*/List<?> getConstructorArgumentValues();/*** 属性依赖*/List<PropertyValue> getPropertyValues();/*** 下面的四个方法是供beanFactory中使用的*/public Constructor<?> getConstructor();public void setConstructor(Constructor<?> constructor);public Method getFactoryMethod();public void setFactoryMethod(Method factoryMethod);}
BeanDefinition的通用实现GernericBeanDefinition
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.List;import org.apache.commons.lang3.StringUtils;public class GenericBeanDefinition implements BeanDefinition {private Class<?> beanClass;private String scope = BeanDefinition.SCOPE_SINGLETON;private String factoryBeanName;private String factoryMethodName;private String initMethodName;private String destroyMethodName;private boolean primary;private Constructor<?> constructor;private Method factoryMethod;private List<?> constructorArgumentValues;private List<PropertyValue> propertyValues;public void setBeanClass(Class<?> beanClass) {this.beanClass = beanClass;}public void setScope(String scope) {if (StringUtils.isNotBlank(scope)) {this.scope = scope;}}public void setFactoryBeanName(String factoryBeanName) {this.factoryBeanName = factoryBeanName;}public void setFactoryMethodName(String factoryMethodName) {this.factoryMethodName = factoryMethodName;}public void setInitMethodName(String initMethodName) {this.initMethodName = initMethodName;}public void setDestroyMethodName(String destroyMethodName) {this.destroyMethodName = destroyMethodName;}@Overridepublic Class<?> getBeanClass() {return this.beanClass;}@Overridepublic String getScope() {return this.scope;}@Overridepublic boolean isSingleton() {return BeanDefinition.SCOPE_SINGLETON.equals(this.scope);}@Overridepublic boolean isPrototype() {return BeanDefinition.SCOPE_PROTOTYPE.equals(this.scope);}@Overridepublic String getFactoryBeanName() {return this.factoryBeanName;}@Overridepublic String getFactoryMethodName() {return this.factoryMethodName;}@Overridepublic String getInitMethodName() {return this.initMethodName;}@Overridepublic String getDestroyMethodName() {return this.destroyMethodName;}public void setPrimary(boolean primary) {this.primary = primary;}@Overridepublic boolean isPrimary() {return this.primary;}public List<?> getConstructorArgumentValues() {return constructorArgumentValues;}public void setConstructorArgumentValues(List<?> constructorArgumentValues) {this.constructorArgumentValues = constructorArgumentValues;}public List<PropertyValue> getPropertyValues() {return propertyValues;}public void setPropertyValues(List<PropertyValue> propertyValues) {this.propertyValues = propertyValues;}public Constructor<?> getConstructor() {return constructor;}public void setConstructor(Constructor<?> constructor) {this.constructor = constructor;}public Method getFactoryMethod() {return factoryMethod;}public void setFactoryMethod(Method factoryMethod) {this.factoryMethod = factoryMethod;}@Overridepublic String toString() {return "GenericBeanDefinition [beanClass=" + beanClass + ", scope=" + scope + ", factoryBeanName="+ factoryBeanName + ", factoryMethodName=" + factoryMethodName + ", initMethodName=" + initMethodName+ ", destroyMethodName=" + destroyMethodName + "]";}@Overridepublic int hashCode() {final int prime = 31;int result = 1;result = prime * result + ((beanClass == null) ? 0 : beanClass.hashCode());result = prime * result + ((destroyMethodName == null) ? 0 : destroyMethodName.hashCode());result = prime * result + ((factoryBeanName == null) ? 0 : factoryBeanName.hashCode());result = prime * result + ((factoryMethodName == null) ? 0 : factoryMethodName.hashCode());result = prime * result + ((initMethodName == null) ? 0 : initMethodName.hashCode());result = prime * result + ((scope == null) ? 0 : scope.hashCode());return result;}@Overridepublic boolean equals(Object obj) {if (this == obj)return true;if (obj == null)return false;if (getClass() != obj.getClass())return false;GenericBeanDefinition other = (GenericBeanDefinition) obj;if (beanClass == null) {if (other.beanClass != null)return false;} else if (!beanClass.equals(other.beanClass))return false;if (destroyMethodName == null) {if (other.destroyMethodName != null)return false;} else if (!destroyMethodName.equals(other.destroyMethodName))return false;if (factoryBeanName == null) {if (other.factoryBeanName != null)return false;} else if (!factoryBeanName.equals(other.factoryBeanName))return false;if (factoryMethodName == null) {if (other.factoryMethodName != null)return false;} else if (!factoryMethodName.equals(other.factoryMethodName))return false;if (initMethodName == null) {if (other.initMethodName != null)return false;} else if (!initMethodName.equals(other.initMethodName))return false;if (scope == null) {if (other.scope != null)return false;} else if (!scope.equals(other.scope))return false;return true;}}
定义后我们来测试一下对应的应用,定义个TestOneBean,依赖了TestTwoBean
public class TestOneBean {private String name;private TestTwoBean testTwoBean;public TestOneBean(String name, TestTwoBean testTwoBean) {super();this.name = name;this.testTwoBean = testTwoBean;System.out.println("调用了含有TestTwoBean参数的构造方法");}public TestOneBean(String name, TestThreeBean testThreeBean) {super();this.name = name;this.testThreeBean = testThreeBean;System.out.println("调用了含有TestThreeBean参数的构造方法");}public ABean(TestTwoBean testTwoBean) {super();this.testTwoBean = testTwoBean;}public void doSomthing() {System.out.println(String.format("TestOneBean.doSomthing(): %s TestOneBean.name= %s", this.name, this.testTwoBean.getName()));}public void init() {System.out.println("TestOneBean.init() 执行了");}public void destroy() {System.out.println("TestOneBean.destroy() 执行了");}
}
然后在实例化时我们需要做相关的绑定
GenericBeanDefinition bd = new GenericBeanDefinition();
bd.setBeanClass(TestOneBean.class);
// 定义的构造参数的依赖
List<Object> args = new ArrayList<>();
args.add("testOneBean");
// 依赖Bean 通过BeanReference来处理
args.add(new BeanReference("testTwoBean"));
bd.setConstructorArgumentValues(args);
bf.registerBeanDefinition("testOneBean", bd);
构造参数传递后,接下来需要在 BeanFactory
中来实现构造参数的注入了
4.BeanFactory实现
前面我们在BeanFactory中实现Bean对象的创建有几种方式
- 构造方法创建
- 工厂静态方法
- 工厂成员方法
import java.util.Map;public interface BeanFactory {Object getBean(String name) throws Exception;<T> T getBean(Class<T> type)throws Exception;<T> Map<String,T> getBeansOfType(Class<T> type)throws Exception;Class<?> getType(String name) throws Exception;
}
BeanFactory的默认实现DefaultBeanFactory
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;import java.io.Closeable;
import java.io.IOException;
import java.lang.reflect.*;
import java.util.*;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;/*** 1.构造参数依赖注入的: 参数真实值获取实现,构造方法方式的构造方法的判定实现* 2.缓存原型bean的构造方法、工厂方法,增加了 静态工厂方法、工厂bean工厂方法的参数依赖实现* 3.构造循环依赖检测* 4.属性依赖实现*/
@Slf4j
public class DefaultBeanFactory implements BeanFactory, BeanDefinitionRegistry, Closeable {protected Map<String, BeanDefinition> beanDefintionMap = new ConcurrentHashMap<>(256);private final Map<String, Object> singletonBeanMap = new ConcurrentHashMap<>(256);private final Map<Class<?>, Set<String>> typeMap = new ConcurrentHashMap<>(256);private final ThreadLocal<Set<String>> buildingBeansRecorder = new ThreadLocal<>();/*** Spring 中属性依赖的情况: 如果循环依赖中不存在单例,则不可以,否则可以*/private final ThreadLocal<Map<String, Object>> earlyExposeBuildingBeans = new ThreadLocal<>();@Overridepublic void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)throws BeanDefinitionRegistException {Objects.requireNonNull(beanName, "注册bean需要指定beanName");Objects.requireNonNull(beanDefinition, "注册bean需要指定beanDefinition");// 校验给入的bean是否合法if (!beanDefinition.validate()) {throw new BeanDefinitionRegistException("名字为[" + beanName + "] 的bean定义不合法:" + beanDefinition);}if (this.containsBeanDefinition(beanName)) {throw new BeanDefinitionRegistException("名字为[" + beanName + "] 的bean定义已存在:" + this.getBeanDefinition(beanName));}this.beanDefintionMap.put(beanName, beanDefinition);}public void registerTypeMap() throws Exception {for (String name : this.beanDefintionMap.keySet()) {Class<?> type = this.getType(name);//映射本类this.registerTypeMap(name, type);//父类this.registerSuperClassTypeMap(name, type);//接口this.registerInterfaceTypeMap(name, type);}}private void registerInterfaceTypeMap(String name, Class<?> type) {Class<?>[] interfaces = type.getInterfaces();for (Class<?> interfaceClasses : interfaces) {this.registerTypeMap(name, interfaceClasses);//递归找父接口this.registerInterfaceTypeMap(name, interfaceClasses);}}private void registerSuperClassTypeMap(String name, Class<?> type) {Class<?> superClass = type.getSuperclass();if (superClass != null && !superClass.equals(Object.class)) {this.registerTypeMap(name, superClass);//递归找父类this.registerSuperClassTypeMap(name, superClass);//找父类实现的接口注册this.registerInterfaceTypeMap(name, superClass);}}private void registerTypeMap(String name, Class<?> type) {Set<String> names2type = this.typeMap.computeIfAbsent(type, k -> new HashSet<>());names2type.add(name);}@Overridepublic Class<?> getType(String name) throws Exception {BeanDefinition beanDefinition = this.getBeanDefinition(name);Class<?> type = beanDefinition.getBeanClass();if (type != null) {if (StringUtils.isBlank(beanDefinition.getFactoryMethodName())) {// 构造方法来构造对象的,Type就是beanClass,不需做什么。} else {// 静态工厂方法方式的,反射获得Method,再获取Method的返回值类型type = type.getDeclaredMethod(beanDefinition.getFactoryMethodName(), null).getReturnType();}} else {// 获得工厂Bean的Classtype = this.getType(beanDefinition.getFactoryBeanName());// 获取工厂方法的返回值类型type = type.getDeclaredMethod(beanDefinition.getFactoryMethodName(), null).getReturnType();}return type;}@Overridepublic BeanDefinition getBeanDefinition(String beanName) {return this.beanDefintionMap.get(beanName);}@Overridepublic boolean containsBeanDefinition(String beanName) {return this.beanDefintionMap.containsKey(beanName);}@Overridepublic Object getBean(String name) throws Exception {return this.doGetBean(name);}@Overridepublic <T> T getBean(Class<T> type) throws Exception {/** 逻辑:* 1. 获取其对应的所有的BeanDefinition* 2. 如果只有一个,直接获取bean实例返回,否则* 3. 遍历找出Primary的* 4. 如果primary没有,或大于1个,抛出异常* 5. 返回Primary的实例*/Set<String> names = this.typeMap.get(type);if (names != null) {if (names.size() == 1) {return (T) this.getBean(names.iterator().next());} else {//找PrimaryBeanDefinition beanDefinition = null;String primaryName = null;StringBuilder nameStrings = new StringBuilder();for (String name : names) {beanDefinition = this.getBeanDefinition(name);if (beanDefinition != null && beanDefinition.isPrimary()) {if (primaryName != null) {String mess = type + " 类型的Bean存储多个Primary[" + primaryName + "," + name + "]";log.error(mess);throw new Exception(mess);} else {primaryName = name;}}nameStrings.append(" ").append(name);}if (primaryName != null) {return (T) this.getBean(primaryName);} else {String mess = type + " 类型的Bean存在多个[" + nameStrings + "] 但无法确定Primary";log.error(mess);throw new Exception(mess);}}}return null;}@Overridepublic <T> Map<String, T> getBeansOfType(Class<T> type) throws Exception {Set<String> names = this.typeMap.get(type);if (names != null) {Map<String, T> map = new HashMap<>();for (String name : names) {map.put(name, (T) this.getBean(name));}return map;}return null;}protected Object doGetBean(String beanName) throws Exception {Objects.requireNonNull(beanName, "beanName不能为空");Object instance = singletonBeanMap.get(beanName);if (instance != null) {return instance;}instance = this.getFromEarlyExposeBuildingBeans(beanName);if (instance != null) { //这是属性依赖时的循环引用,返回提前暴露的实例return instance;}BeanDefinition beanDefinition = this.getBeanDefinition(beanName);Objects.requireNonNull(beanDefinition, "beanDefinition不能为空");// 检测构造参数循环依赖Set<String> buildingBeans = this.buildingBeansRecorder.get();if (buildingBeans == null) {buildingBeans = new HashSet<>();this.buildingBeansRecorder.set(buildingBeans);}if (buildingBeans.contains(beanName)) {throw new Exception(beanName + " 循环依赖!" + buildingBeans);}// 记录正在创建的BeanbuildingBeans.add(beanName);if (beanDefinition.isSingleton()) { //如果是单例synchronized (this.singletonBeanMap) { //加锁instance = this.singletonBeanMap.get(beanName);if (instance == null) {//第二次检查instance = doCreateInstance(beanName, beanDefinition);this.singletonBeanMap.put(beanName, instance);}}} else {instance = doCreateInstance(beanName, beanDefinition);}// 创建好实例后,移除创建中记录buildingBeans.remove(beanName);return instance;}private Object getFromEarlyExposeBuildingBeans(String beanName) {Map<String, Object> earlyExposeBuildingBeansMap = earlyExposeBuildingBeans.get();return earlyExposeBuildingBeansMap == null ? null : earlyExposeBuildingBeansMap.get(beanName);}private Object doCreateInstance(String beanName, BeanDefinition beanDefinition) throws Exception {Class<?> type = beanDefinition.getBeanClass();Object instance;if (type != null) {if (StringUtils.isBlank(beanDefinition.getFactoryMethodName())) {// 构造方法来构造对象instance = this.createInstanceByConstructor(beanDefinition);} else {// 静态工厂方法instance = this.createInstanceByStaticFactoryMethod(beanDefinition);}} else {// 工厂bean方式来构造对象instance = this.createInstanceByFactoryBean(beanDefinition);}this.doEarlyExposeBuildingBeans(beanName, instance);// 给入属性依赖this.setPropertyDIValues(beanDefinition, instance);this.removeEarlyExposeBuildingBeans(beanName, instance);// 执行初始化方法this.doInit(beanDefinition, instance);return instance;}private void removeEarlyExposeBuildingBeans(String beanName, Object instance) {earlyExposeBuildingBeans.get().remove(beanName);}private void doEarlyExposeBuildingBeans(String beanName, Object instance) {Map<String, Object> earlyExposeBuildingBeansMap = earlyExposeBuildingBeans.get();if (earlyExposeBuildingBeansMap == null) {earlyExposeBuildingBeansMap = new HashMap<>();earlyExposeBuildingBeans.set(earlyExposeBuildingBeansMap);}earlyExposeBuildingBeansMap.put(beanName, instance);}// 给入属性依赖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);p.set(instance, this.getOneArgumentRealValue(pv.getValue()));}}/*** 构造方法来构造对象** @param beanDefinition bean定义* @return bean实例对象* @throws Exception 异常*/private Object createInstanceByConstructor(BeanDefinition beanDefinition)throws Exception {/*构造参数依赖注入,这里需要做些什么?1 得到真正的参数值,因为List<?> constructorArgumentValues = beanDefinition.getConstructorArgumentValues();constructorArgumentValues 中可能有 BeanReference*/Object[] args = this.getConstructorArgumentValues(beanDefinition);// 2 判定应该调用哪个构造方法来创建实例return this.determineConstructor(beanDefinition, args).newInstance(args);}private Object[] getConstructorArgumentValues(BeanDefinition bd) throws Exception {List<?> constructorArgumentValues = bd.getConstructorArgumentValues();if (CollectionUtils.isEmpty(constructorArgumentValues)) {return null;}Object[] values = new Object[constructorArgumentValues.size()];int i = 0;for (Object originalValue : constructorArgumentValues) {values[i++] = getOneArgumentRealValue(originalValue); //获取真正参数值的逻辑应该是怎样的?}return values;}private Object getOneArgumentRealValue(Object originalValue) throws Exception {//获取真正参数值,主要是处理BeanReference,得到真正的Bean实例Object realValue = null;if (originalValue != null) {if (originalValue instanceof BeanReference) {BeanReference beanReference = (BeanReference) originalValue;if (StringUtils.isNotBlank(beanReference.getBeanName())) {realValue = this.getBean(beanReference.getBeanName());} else if (beanReference.getType() != null) {realValue = this.getBean(beanReference.getType());}} else if (originalValue instanceof Object[]) {// 处理数组中的bean引用Object[] originalValueNew = (Object[]) originalValue;for (int i = 0; i < originalValueNew.length; i++) {Object attr = originalValueNew[i];Class<?> attrClass = attr.getClass();String simpleName = attrClass.getSimpleName();BeanReference beanReference = new BeanReference(attrClass);beanReference.setBeanName(getBeanName(simpleName));originalValueNew[i] = beanReference;}realValue = originalValueNew;} else if (originalValue instanceof Collection) {// 处理集合中的bean引用Type genericSuperclass = originalValue.getClass().getGenericSuperclass();Class<? extends Type> genericClass = genericSuperclass.getClass();BeanReference beanReference = new BeanReference(genericClass);String simpleName = genericClass.getSimpleName();String beanName = getBeanName(simpleName);beanReference.setBeanName(beanName);Collection<BeanReference> originalValueNew = new ArrayList<>();originalValueNew.add(beanReference);realValue = originalValueNew;} else if (originalValue instanceof Properties) {// 处理properties中的bean引用Properties originValueNew = new Properties();originValueNew.put(new BeanReference(null), new BeanReference(null));realValue = originValueNew;} else if (originalValue instanceof Map) {// 处理Map中的bean引用Map<BeanReference, BeanReference> originValueNew = new HashMap<>();originValueNew.put(new BeanReference(null), new BeanReference(null));realValue = originValueNew;} else {realValue = originalValue;}}return realValue;}private String getBeanName(String simpleName) {if (simpleName == null) {throw new IllegalArgumentException("simpleName不能为空");}String firstChar = simpleName.charAt(0) + "";return firstChar.toLowerCase() + simpleName.substring(1);}private Constructor<?> determineConstructor(BeanDefinition bd, Object[] args) throws Exception {/*判定构造方法的逻辑应是怎样的?1 先根据参数的类型进行精确匹配查找,如未找到,则进行第2步查找;2获得所有的构造方法,遍历,通过参数数量过滤,再比对形参类型与实参类型。* */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);}}private Method determineFactoryMethod(BeanDefinition bd, Object[] args, Class<?> type) throws Exception {/*判定工厂方法的逻辑同构造方法的判定逻辑1 先根据实参的类型进行精确匹配查找,如未找到,则进行第2步查找;2 获得所有方法,遍历,通过方法名、参数数量过滤,再比对形参类型与实参类型。* */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;}// 1 先根据实参的类型进行精确匹配查找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) {// 没有精确参数类型匹配的,则遍历匹配所有的方法// 2 获得所有方法,遍历,通过方法名、参数数量过滤,再比对形参类型与实参类型。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);}}// 静态工厂方法private Object createInstanceByStaticFactoryMethod(BeanDefinition bd) throws Exception {Object[] realArgs = this.getConstructorArgumentValues(bd);Class<?> type = bd.getBeanClass();Method m = this.determineFactoryMethod(bd, realArgs, type);return m.invoke(type, realArgs);}// 工厂bean方式来构造对象private Object createInstanceByFactoryBean(BeanDefinition bd) throws Exception {Object[] realArgs = this.getConstructorArgumentValues(bd);Method m = this.determineFactoryMethod(bd, realArgs, this.getType(bd.getFactoryBeanName()));Object factoryBean = this.doGetBean(bd.getFactoryBeanName());return m.invoke(factoryBean, realArgs);}/*** 执行初始化方法** @param beanDefinition bean定义* @param instance 实例对象* @throws Exception 异常*/private void doInit(BeanDefinition beanDefinition, Object instance) throws Exception {// 执行初始化方法if (StringUtils.isNotBlank(beanDefinition.getInitMethodName())) {Method m = instance.getClass().getMethod(beanDefinition.getInitMethodName(), null);m.invoke(instance, null);}}@Overridepublic void close() throws IOException {// 执行单例实例的销毁方法for (Entry<String, BeanDefinition> e : this.beanDefintionMap.entrySet()) {String beanName = e.getKey();BeanDefinition bd = e.getValue();if (bd.isSingleton() && StringUtils.isNotBlank(bd.getDestroyMethodName())) {Object instance = this.singletonBeanMap.get(beanName);try {Method m = instance.getClass().getMethod(bd.getDestroyMethodName(), null);m.invoke(instance, null);} catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException| InvocationTargetException e1) {log.error("执行bean[" + beanName + "] " + bd + " 的 销毁方法异常!", e1);}}}}
}
我们通过构造方法创建其实是通过无参构造方法来处理的,这时我们需要改变这块的逻辑,通过有参构造方法来实现。
// 构造方法来构造对象
private Object createInstanceByConstructor(BeanDefinition bd)throws InstantiationException, IllegalAccessException {try {return bd.getBeanClass().newInstance();} catch (SecurityException e1) {log.error("创建bean的实例异常,beanDefinition:" + bd, e1);throw e1;}
}
我们就需要对上面的方法做出改变。
// 构造方法来构造对象
private Object createInstanceByConstructor(BeanDefinition bd)throws InstantiationException, IllegalAccessException {// 1. 得到真正的参数值List<?> constructorArgumentValues = bd.getConstructorArgumentValues(); // 2.根据对应的构造参数依赖获取到对应的 Constructor Constructor constructor = 得到对应的构造方法// 3.用实际参数值调用构造方法创建对应的对象return constructor.newInstance(Object ... 实参值);
}
通过上面的分析我们需要获取对应的构造器。这块我们需要通过反射来获取了。下面是具体的实现逻辑
根据上面的分析,实现逻辑可分为两步
- 先根据参数的类型进行精确匹配查找,如果没有找到,继续执行第二步操作
- 获得所有的构造方法,遍历构造方法,通过参数数量过滤,再比对形参与实参的类型
因为这里有个情况,实参是Boy,构造方法的形参是Person,第一种精确匹配就没有办法关联了。
具体的实现代码如下:
private Constructor<?> determineConstructor(BeanDefinition bd, Object[] args) throws Exception {/*判定构造方法的逻辑应是怎样的?1 先根据参数的类型进行精确匹配查找,如未找到,则进行第2步查找;2获得所有的构造方法,遍历,通过参数数量过滤,再比对形参类型与实参类型。* */Constructor<?> ct = null;//没有参数,则用无参构造方法if (args == null) {return bd.getBeanClass().getConstructor(null);}// 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) {return ct;} else {throw new Exception("不存在对应的构造方法!" + bd);}
}
上面我们考虑的是BeanFactory通过构造器来获取对象的逻辑,那如果我们是通过静态工厂方法或者成员工厂方法的方式来处理的,那么构造参数依赖的处理是否和前面的是一样的呢?其实是差不多的,我们需要根据对应的构造参数来推断对应的工厂方法
// 静态工厂方法
private Object createInstanceByStaticFactoryMethod(BeanDefinition bd) throws Exception {Object[] realArgs = this.getConstructorArgumentValues(bd);Class<?> type = bd.getBeanClass();Method m = this.determineFactoryMethod(bd, realArgs, type);return m.invoke(type, realArgs);
}// 工厂bean方式来构造对象
private Object createInstanceByFactoryBean(BeanDefinition bd) throws Exception {Object[] realArgs = this.getConstructorArgumentValues(bd);Method m = this.determineFactoryMethod(bd, realArgs, this.getType(bd.getFactoryBeanName()));Object factoryBean = this.doGetBean(bd.getFactoryBeanName());return m.invoke(factoryBean, realArgs);
}
5.缓存功能
对于上面的处理过程相信大家应该清楚了,我们通过推断也得到了对应的构造方法或者对应的工厂方法,那么我们可以不可以在下次需要再次获取的时候省略掉推导的过程呢?显然我们可以在BeanDefinition中增加缓存方法可以实现这个需求。
6. 循环依赖问题
上图是循环依赖的三种情况,虽然方式有点不一样,但是循环依赖的本质是一样的,就你的完整创建要依赖于我,我的完整创建也依赖于你。相互依赖从而没法完整创建造成失败。
我们通过构造参数依赖是完全可能出现上面的情况的,那么这种情况我们能解决吗?构造依赖的情况我们是解决不了的。
public class Test01 {public static void main(String[] args) {new TestService1();}
}class TestService1{private TestService2 testService2 = new TestService2();
}class TestService2{private TestService1 testService1 = new TestService1();
}
既然解决不了,那么我们在程序中如果出现了,应该要怎么来解决呢?
其实我们可以在创建一个Bean的时候记录下这个Bean,当这个Bean创建完成后我们再移除这个Bean,然后我们在getBean的时候判断记录中是否有该Bean,如果有就判断为循环依赖,并抛出异常。数据结构我们可以通过Set集合来处理。
到此构造注入的实现就告一段落了。
三、属性注入
上面搞定了构造注入的方式。接下来我们再看看属性注入的方式有什么需要注意的地方。
1. 属性依赖分析
属性依赖就是某个属性依赖某个值。
public class Girl {private String name;private int age;private List<Clothes> ClothesList;// ....
}
那么在获取实例对象后如何根据相关的配置来给对应的属性来赋值呢?这时我们可以定义一个实体类 PropertyValue
来记录相关的属性和值。
2.BeanDefinition实现
这时我们就需要在BeanDefinition中关联相关属性信息了。
3.BeanFactory实现
然后我们在BeanFactory的默认实现DefaultBeanFactory中实现属性值的依赖注入。
// 创建好实例对象
// 给属性依赖赋值
this.setPropertyDIValues(bd,instance);
// 执行初始化相关方法
this.doInit(bd,instance);
具体的实现代码如下:
// 给入属性依赖
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());//暴力访问 privatep.setAccessible(true);p.set(instance, this.getOneArgumentRealValue(pv.getValue()));}
}
4.循环依赖问题
在构造参数依赖中我们发现没有办法解决,在属性依赖中同样会存在循环依赖的问题,这时我们能解决吗?
其实这种循环依赖的情况,不在IOC场景下非常好解决。如下
Boy b = new Boy();
Girl g = new Girl();
b.setGirl(g);
g.setBoy(b);
但是在IOC好像不是太好解决:
针对这种情况我们需要通过 提前暴露
来解决这个问题,具体看代码!!!
private void doEarlyExposeBuildingBeans(String beanName, Object instance) {Map<String,Object> earlyExposeBuildingBeansMap = earlyExposeBuildingBeans.get();if(earlyExposeBuildingBeansMap == null) {earlyExposeBuildingBeansMap = new HashMap<>();earlyExposeBuildingBeans.set(earlyExposeBuildingBeansMap);}earlyExposeBuildingBeansMap.put(beanName,instance);
}
最后现阶段已经实现的类图结构