文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

一文详解Spring构造函数推断

2023-05-14 20:29

关注

正文

Spring 提供了一组基本的功能,例如依赖注入(DI)和面向切面编程(AOP)。其中一个非常强大的功能是构造函数自动注入,也称为构造函数推断。在本文中,我们将深入探讨Spring构造函数推断的底层原理,并解释Spring是如何实现它的。

自动注入

构造函数自动注入是指 Spring 自动解析 bean 的构造函数参数,并将它们传递给相应的构造函数。这样,我们就不必显式地在XML或Java配置文件中指定每个 bean 的构造函数参数。这是一个非常方便的功能,特别是在有许多 bean 需要注入的情况下。

底层原理

Spring 使用 Java 反射机制来执行构造函数推断。当 Spring 需要实例化一个 bean 时,它将首先使用 Java 反射机制检查该 bean 的构造函数。

然后,它将检查每个构造函数的参数类型,并尝试在 Spring 应用程序上下文中查找与参数类型匹配的 bean。

如果找到匹配的 bean,则 Spring 将使用该 bean 实例化构造函数参数。如果找不到匹配的 bean,则 Spring 将继续检查下一个构造函数。

如果没有任何构造函数可以匹配,则 Spring 将抛出一个异常。但是,可以使用 @Autowired(required=false) 注解来取消必需的依赖关系,这意味着如果找不到与构造函数参数类型匹配的bean,则 Spring 将不会抛出异常。

以下是一个简单的例子,说明如何在 Spring 中使用构造函数推断:

public class MyBean {
    private final MyDependency myDependency;
    public MyBean(MyDependency myDependency) {
        this.myDependency = myDependency;
    }
    public void doSomething() {
        myDependency.doSomething();
    }
}

在这个例子中,MyBean依赖于MyDependency。Spring 将使用构造函数推断自动注入 MyDependency,而不需要在XML或Java配置文件中显式指定。

@Configuration
public class AppConfig {
    @Bean
    public MyDependency myDependency() {
        return new MyDependency();
    }
    @Bean
    public MyBean myBean() {
        return new MyBean(myDependency());
    }
}

在这个例子中,AppConfig 类使用 @Configuration 注解指定一个 Spring 应用程序上下文,并定义两个bean:MyDependency 和 MyBean。在 MyBean 的构造函数中,我们将 MyDependency 作为参数传递,Spring 将使用构造函数推断自动注入 MyDependency。

构造函数推断的限制

构造函数推断有一些限制,例如:

源码解析

Spring 使用 BeanWrapperImpl 类来执行构造函数推断。BeanWrapperImpl 类是 Spring 的核心类之一,它提供了一种方便的方式来对 Java 对象进行包装和访问。以下是 Spring 中用于执行构造函数推断的 BeanWrapperImpl 类的源代码:

public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWrapper {
    // ...
    @Override
    public Object createInstance() throws BeansException {
        // 获取Bean的构造函数
        Constructor<?> constructorToUse = this.constructorResolver.autowireConstructor;
        if (constructorToUse == null) {
            throw new BeansException("No default constructor found");
        }
        try {
            // 使用构造函数创建Bean实例,并返回
            return constructorToUse.newInstance(getConstructorArgumentValues(constructorToUse), getBeanClassLoader());
        }
        catch (Throwable ex) {
            throw new BeanCreationException("Could not instantiate bean", ex);
        }
    }
    // ...
    private Constructor<?> autowireConstructor;
    // ...
    public BeanWrapperImpl(Class<?> clazz) {
        super();
        this.objectType = clazz;
        this.propertyEditorRegistry = new SimpleTypeConverter();
        this.constructorResolver = new ConstructorResolver(this.objectType, this);
    }
    // ...
    private class ConstructorResolver {
        // ...
        public ConstructorResolver(Class<?> clazz, BeanWrapperImpl bw) {
            // 查找可以使用的构造函数并将其缓存
            Constructor<?>[] candidates = clazz.getDeclaredConstructors();
            Constructor<?> autowireCandidate = null;
            int numAutowireCandidates = 0;
            for (Constructor<?> candidate : candidates) {
                if (candidate.isAnnotationPresent(Autowired.class)) {
                    autowireCandidate = candidate;
                    numAutowireCandidates++;
                }
            }
            if (numAutowireCandidates == 1) {
                this.autowireConstructor = autowireCandidate;
            }
            else if (numAutowireCandidates > 1) {
                throw new BeansException("Multiple autowire constructors found");
            }
        }
        // ...
    }
    // ...
}

在BeanWrapperImpl 类中,构造函数推断是在 createInstance() 方法中执行的。该方法首先获取与Bean匹配的构造函数(由constructorResolver.autowireConstructor决定),然后使用该构造函数创建 Bean 实例。

ConstructorResolver 内部类中,构造函数推断是通过查找带有 @Autowired 注解的构造函数来实现的。如果找到了一个带有 Autowired注解 的构造函数,则它将被缓存到 autowireConstructor 字段中,并在 createInstance() 方法中使用。

结论

构造函数自动注入是 Spring 的一个非常强大的功能,它可以大大简化 bean 的配置和管理。我们深入探讨了 Spring 构造函数推断的底层原理,并解释了 Spring 是如何实现它的,还提供了一个简单的例子和源代码解析,以帮助大家更好地了解构造函数推断的工作方式。

以上就是一文详解Spring构造函数推断的详细内容,更多关于Spring 构造函数推断的资料请关注编程网其它相关文章!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     801人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     348人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     311人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     432人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     220人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯