文章目录
手写spring ioc(三)
前言
前面已经完成了ioc基本功能,也解决了循环依赖,现在ioc剩下的最大一块就是推断构造器,这一块比较难写,涉及到spring扩展点BeanPostProcessor, 这个扩展点可以说是艺术般的存在,不仅解耦,而且可扩展性极强,代码也清晰明了,笔者先声明一点,推断构造器笔者是模仿spring framework写的,模仿的有7,8成,几乎一模一样了,没办法,技术菜就得从模仿开始。
其实本篇挺难写的,感觉比我写源码还难,在此我先给出ioc3的源码,可以直接照着源码学习,不看本篇亦可。
ioc3源码
推断构造器
本篇不会像之前两篇给出完整代码,因为改动较大,只写关键地方
最好参照笔者另一篇博客剑指spring源码4的推断构造器,结合起来理解效果更佳
createBeanInstance
private Object createBeanInstance(String beanName,BeanDefinition bd) throws Exception {
//省略factoryMethod
//推断构造器
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(bd.getBeanClass(), beanName);
//自动装配
if (ctors != null || bd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
bd.hasConstructorArgumentValues()) {
return new ConstructorResolver(this).autowireConstructor(beanName, bd, ctors);
}
//使用默认构造器
return bd.getBeanClass().newInstance();
}
determineConstructorsFromBeanPostProcessors
private Constructor<?>[] determineConstructorsFromBeanPostProcessors(Class<?> beanClass, String beanName) {
if (beanClass != null && hasInstantiationAwareBeanPostProcessors) {
for (BeanPostProcessor bp : beanPostProcessors) {
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
Constructor<?>[] ctors = ibp.determineCandidateConstructors(beanClass, beanName);
if (ctors != null) {
return ctors;
}
}
}
}
return null;
}
determineCandidateConstructors
@Override
public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, String beanName) {
//所有的构造器
Constructor<?>[] rawCandidates = beanClass.getDeclaredConstructors();
//@Autowired(false)的构造器
List<Constructor<?>> candidates = new ArrayList<>(rawCandidates.length);
//@Autowired(true)的构造器
Constructor<?> requiredConstructor = null;
//默认无参构造器
Constructor<?> defaultConstructor = null;
//最终返回的构造器
Constructor<?>[] candidateConstructors = null;
for (Constructor<?> candidate : rawCandidates) {
Autowired auto = candidate.getAnnotation(Autowired.class);
if(auto!=null){
//取出Autowired的属性值required
boolean required = auto.required();
//如果是true
if (required) {
//@Autowired(true)的构造器只能有一个 ,如果多个直接报错
if (requiredConstructor != null) {
throw new RuntimeException("find more than one required(true) constructor when determine "+beanName+" constructor");
}
//给requiredConstructor赋值
requiredConstructor = candidate;
}
//添加到false构造器集合
candidates.add(candidate);
}//给默认构造器赋值
else if (candidate.getParameterCount() == 0) {
defaultConstructor = candidate;
}
}
// true的构造器
if(requiredConstructor!=null){
candidateConstructors = new Constructor<?>[] {requiredConstructor};
}
//false的构造器
else if (!candidates.isEmpty()) {
//只有Autowried(false)会出现candidates不空,而requiredConstructor为空的现象
if (requiredConstructor == null) {
//添加默认的
if (defaultConstructor != null) {
candidates.add(defaultConstructor);
}
}
candidateConstructors = candidates.toArray(new Constructor<?>[0]);
}
//只有一个构造器(有参),直接返回这个就行了
else if (rawCandidates.length == 1 && rawCandidates[0].getParameterCount() > 0) {
candidateConstructors = new Constructor<?>[] {rawCandidates[0]};
}
else {
candidateConstructors = new Constructor<?>[0];
}
return (candidateConstructors.length > 0 ? candidateConstructors : null);
}
autowireConstructor
public Object autowireConstructor(String beanName, BeanDefinition bd, Constructor<?>[] ctors) throws IllegalAccessException, InstantiationException, InvocationTargetException {
//最终使用的构造器
Constructor<?> constructorToUse = null;
//最终使用的构造器的参数
Object[] argsToUse = null;
Constructor<?>[] candidates = ctors;
if(null==candidates){
candidates = bd.getBeanClass().getDeclaredConstructors();
}
//只有一个构造器
if (candidates.length == 1 && !bd.hasConstructorArgumentValues()) {
Constructor<?> uniqueCandidate = candidates[0];
//并且是默认构造
if (uniqueCandidate.getParameterCount() == 0) {
return bd.getBeanClass().newInstance();
}
}
//是否需要自动装配,如果有构造器或者装配模式是构造器装配都要进行自动装配
//即springbean 会自动装配给参数
//如果只有constructorArgumentValues,但是没有ctors,也不是构造器装配模式,autowiring=false
//他只会找和constructorArgumentValues参数一摸一样的构造器
boolean autowiring = (ctors != null ||
bd.getResolvedAutowireMode() == BeanFactory.AUTOWIRE_CONSTRUCTOR);
//最小参数个数
int minNrOfArgs = bd.getConstructorArgumentValues()==null?0:bd.getConstructorArgumentValues().size();
//最小类型差异权重,此值越大差异越大,初始化为最大差异
int minTypeDiffWeight = Integer.MAX_VALUE;
//模棱两可的构造器集合,用于存储spring都不确定的构造器集合
Set<Constructor<?>> ambiguousConstructors = null;
//遍历构造器
for (Constructor<?> candidate : candidates) {
//构造器参数类型数组
Class<?>[] paramTypes = candidate.getParameterTypes();
//已经有最终构造器&&已经有最终构造器参数&&最终构造器参数长度>当前构造器参数长度(直接跳出循环,使用constructorToUse)
if (constructorToUse != null && argsToUse != null && argsToUse.length > paramTypes.length) {
break;
}
//当前构造器参数长度<构造器参数的最小个数,这种情况当前构造器肯定不合格,直接抛弃当前构造器
if (paramTypes.length < minNrOfArgs) {
continue;
}
Object[] arguments = null;
try {
arguments = createArgumentArray(candidate,bd,autowiring);
} catch (Exception e) {
//若构造器参数不是@Value的&&不在spring容器就抛异常,并且跳过此构造器
//转换异常也会抛异常
e.printStackTrace();
continue;
}
int typeDiffWeight = ClassUtils.getAssignabilityWeight(paramTypes,arguments);
if (typeDiffWeight < minTypeDiffWeight) {
//记录当前构造器及参数
constructorToUse = candidate;
argsToUse = arguments;
//更新最小差异权重
minTypeDiffWeight = typeDiffWeight;
//重置ambiguousConstructors为null
ambiguousConstructors = null;
}
//如果已经有了最终的构造器可供使用&&当前构造器计算出来的权重==最小差异权重
else if (constructorToUse != null && typeDiffWeight == minTypeDiffWeight) {
//这下spring就为难了,他把这两个构造器加到模糊集合了
if (ambiguousConstructors == null) {
ambiguousConstructors = new LinkedHashSet<>();
ambiguousConstructors.add(constructorToUse);
}
ambiguousConstructors.add(candidate);
}
}
if (constructorToUse == null) {
throw new RuntimeException(beanName+
" Could not resolve matching constructor ");
}else if (ambiguousConstructors != null && !bd.isLenientConstructorResolution()) {
throw new RuntimeException("Ambiguous constructor matches found in bean '" + beanName + "' "+ ambiguousConstructors);
}
Objects.requireNonNull(argsToUse, beanName+ " Unresolved constructor arguments");
return constructorToUse.newInstance(argsToUse);
}
createArgumentArray
//argsToUse: 涉及@Value,@Autowired,springBean,constructorArgumentValues,autowiring
private Object[] createArgumentArray(Constructor<?> candidate, BeanDefinition bd, boolean autowiring)throws Exception{
//autowiring=true 自动装配,会解析@Value,@Autowired,springBean
//autowiring=false,手动装配,不会解析@Value,@Autowired,springBean,只要解析constructorArgumentValues
if(autowiring){
//如果是自动注入并且还有constructorArgumentValues,以constructorArgumentValues优先
Parameter[] params = candidate.getParameters();
Object[] arguments = new Object[params.length];
List<?> constructorArgumentValues = bd.getConstructorArgumentValues();
//引入spring-core的asm技术,因为params[i].getName() 获得的参数名字是arg0 arg1
LocalVariableTableParameterNameDiscoverer localVariableTableParameterNameDiscoverer = new LocalVariableTableParameterNameDiscoverer();
String[] parameterNames = localVariableTableParameterNameDiscoverer.getParameterNames(candidate);
for (int i=0;i<params.length;i++){
if(params[i].isAnnotationPresent(Value.class)){
//拿到@Value的值
String value = params[i].getAnnotation(Value.class).value();
//基本类型转包装类型
Class<?>paramType = params[i].getType();
if(ClassUtils.primitiveTypeToWrapperMap.containsKey(paramType)){
paramType = ClassUtils.primitiveTypeToWrapperMap.get(paramType);
}
//如果constructorArgumentValues有此参数&&并且类型一致,优先使用constructorArgumentValues
if(null!=constructorArgumentValues&&
constructorArgumentValues.size()>i&&
null!=constructorArgumentValues.get(i)&&
paramType.isAssignableFrom(constructorArgumentValues.get(i).getClass())){
arguments[i] = constructorArgumentValues.get(i);
}else{
//使用@Value的值(getBaseValue防止 object to int/float/... error)
arguments[i] = ValueUtils.getBaseValue(params[i].getType(),value);
}
}else{
if(null!=constructorArgumentValues&&
constructorArgumentValues.size()>i&&
null!=constructorArgumentValues.get(i)&&
params[i].getType().isAssignableFrom(constructorArgumentValues.get(i).getClass())){
arguments[i] = constructorArgumentValues.get(i);
}else{
arguments[i] = beanFactory.getBean(parameterNames[i]);
}
}
}
return arguments;
}
//autowiring为false的话constructorArgumentValues必定不为null
else{
return bd.getConstructorArgumentValues().toArray(new Object[0]);
}
}
本篇博客不仅难于源代码,连测试用例笔者也是想了又想,生怕漏了情况没有测试到,在上传的文件中就有一个比较好的测试用例,另外如果有疏漏的地方欢迎大家指出,我会优化