简介
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);// 当前构造方法上加了@Autowiredif (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()) { // 存在@Autowiredif (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() {}@Autowiredpublic 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() {}@Autowiredpublic OrderBean(UserBean userBean) {System.out.println("OrderBean 1");}
}执行输出
OrderBean 1
自定义
自定义一个推断构造器扩展,规则是优先使用有一个参数的构造器
@Component
public class DefaultConstructors implements SmartInstantiationAwareBeanPostProcessor {@Overridepublic 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的实例化非常相似,下节介绍
欢迎关注,学习不迷路!