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的实例化非常相似,下节介绍
欢迎关注,学习不迷路!