21. Spring扩展点之推断构造方法

简介

spring自己本身有推断构造方法的逻辑,但同时也提供了扩展,SmartInstantiationAwareBeanPostProcessor#determineCandidateConstructors,实现该方法就可以自己定制获取哪个构造器的逻辑,该扩展点spring有一个默认的实现AutowiredAnnotationBeanPostProcessor#determineCandidateConstructors

本文主要分析的就是该默认的推断构造方法实现类

public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, final String beanName)
			throws BeanCreationException {
			
    // lookup逻辑上节已经介绍过了,这里省略掉

    // 并发安全检查过滤掉
    Constructor<?>[] candidateConstructors = this.candidateConstructorsCache.get(beanClass);
    if (candidateConstructors == null) {
        synchronized (this.candidateConstructorsCache) {
          
            candidateConstructors = this.candidateConstructorsCache.get(beanClass);
            if (candidateConstructors == null) {
                Constructor<?>[] rawCandidates;
                // 拿到所有的构造方法
                rawCandidates = beanClass.getDeclaredConstructors();
                
                // 记录的是所有加了@Autowrite注解的构造方法
                List<Constructor<?>> candidates = new ArrayList<>(rawCandidates.length);

                // 记录加了@Autowrite注解required为true的构造方法,只能赋值一个
                Constructor<?> requiredConstructor = null;
                // 记录无参构造
                Constructor<?> defaultConstructor = null;
               
                int nonSyntheticConstructors = 0;

                // 遍历每个构造方法
                for (Constructor<?> candidate : rawCandidates) {
                    // isSynthetic后面文章分析
                    if (!candidate.isSynthetic()) {
                        nonSyntheticConstructors++;
                    }

                    // 如果当前构造器加了@Autowired注解,那么ann就有值
                    MergedAnnotation<?> ann = findAutowiredAnnotation(candidate);

                    // 当前构造方法上加了@Autowired
                    if (ann != null) {
                        // 只能有一个Autowired的required为true,多了就报错
                        if (requiredConstructor != null) {
                            throw new BeanCreationException(beanName,
                                    "Invalid autowire-marked constructor: " + candidate +
                                    ". Found constructor with 'required' Autowired annotation already: " +
                                    requiredConstructor);
                        }
                        // 获取required值
                        boolean required = determineRequiredStatus(ann);
                        if (required) {
                            // 如果说required为true,那么就不允许出现有其它的@Autowired,为false也不行
                            if (!candidates.isEmpty()) {
                                throw new BeanCreationException(beanName,
                                        "Invalid autowire-marked constructors: " + candidates +
                                        ". Found constructor with 'required' Autowired annotation: " +
                                        candidate);
                            }
                            // 记录唯一一个required为true的构造方法
                            requiredConstructor = candidate;
                        }
                        
                        // 记录@Autowired标记的构造器
                        candidates.add(candidate);

                    } else if (candidate.getParameterCount() == 0) {
                        // 记录无参的构造方法,如果加了@Autowired,就不需要记录
                        defaultConstructor = candidate;
                    }

                    // 有参数,但是没有添加@Autowired的构造器没有做判断
                }


                if (!candidates.isEmpty()) { // 存在@Autowired
                    if (requiredConstructor == null) { // 没有required为true的构造方法
                        if (defaultConstructor != null) {
                            // 没有required为true的情况下 无参构造与required为false一样的
                            candidates.add(defaultConstructor);
                        }
                        
                    }
                    candidateConstructors = candidates.toArray(new Constructor<?>[0]);
                }
                // 没有添加了@Autowired注解的构造方法,并且类中只有一个构造方法,并且是有参的
                else if (rawCandidates.length == 1 && rawCandidates[0].getParameterCount() > 0) {
                    candidateConstructors = new Constructor<?>[] {rawCandidates[0]};
                }
                else {
                    // 没有加@Autowired,构造器又不止一个,那么返回空,后面由spring经过算法去推断使用哪一个
                    candidateConstructors = new Constructor<?>[0];
                }
                // 缓存起来
                this.candidateConstructorsCache.put(beanClass, candidateConstructors);
            }
        }
    }
    return (candidateConstructors.length > 0 ? candidateConstructors : null);
}

上面就是默认提供的一个推断构造器扩展实现,大致总结下

1. 如果有一个构造器添加了@Autowired并且required值为true,那么就不能再出现@Autowired修饰的构造器
2. 如果没有required值为true的,那么添加了@Autowired与无参的构造器都返回,由spring根据算法去选择
3. 只有一个构造器,并且不是无参的,那么就直接返回这个构造器
4. 如果都没有加@Autowired,构造器又不止一个,那么返回空,由spring根据算法去选择哪个

测试

测试1 两个Autowired,一个为required = true

@Component
public class OrderBean {

	@Autowired(required = false)
	public OrderBean() {

	}

	@Autowired
	public OrderBean(String orderName) {

	}
}

报错
Error creating bean with name 'orderBean': Invalid autowire-marked constructors: [public com.shura.beans.OrderBean()]. Found constructor with 'required' Autowired annotation: public com.shura.beans.OrderBean(java.lang.String)

测试2 加了Autowired,那么会使用该构造器

@Component
public class OrderBean {

	public OrderBean() {

	}

	@Autowired
	public OrderBean(UserBean userBean) {
		System.out.println("OrderBean 1");
	}
}

执行输出
OrderBean 1

自定义

自定义一个推断构造器扩展,规则是优先使用有一个参数的构造器

@Component
public class DefaultConstructors implements SmartInstantiationAwareBeanPostProcessor {
	@Override
	public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, String beanName) throws BeansException {
		Constructor<?>[] declaredConstructors = beanClass.getDeclaredConstructors();
		for (Constructor<?> declaredConstructor : declaredConstructors) {
			if (declaredConstructor.getParameterCount() == 1) {
			    // 有一个参数的构造器直接返回
				return new Constructor<?>[]{declaredConstructor};
			}
		}
		return null;
	}
}

@Component
public class OrderBean {

	public OrderBean() {
        System.out.println("OrderBean 0");
	}

	public OrderBean(UserBean userBean) {
		System.out.println("OrderBean 1");
	}
}


@ComponentScan({"com.shura"})
public class AppConfig {
}

启动类

public static void main(String[] args) {
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
    System.out.println(context.getBean("orderBean"));
}

执行输出

OrderBean 1
com.shura.beans.OrderBean@5cc7c2a6

总结

以上就是推断构造函数扩展点的讲解,下一节讲解扩展点没有推断出来构造器,那么spring又该怎么给我们选择构造器呢,其实跟@Bean的实例化非常相似,下节介绍


欢迎关注,学习不迷路!

你可能感兴趣的:(spring,framework,spring,java)