Spring构造函数推断的原理是什么

发布时间:2023-04-07 16:57:00 作者:iii
来源:亿速云 阅读:75

这篇文章主要介绍了Spring构造函数推断的原理是什么的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Spring构造函数推断的原理是什么文章都会有所收获,下面我们一起来看看吧。

正文

Spring 提供了一组基本的功能,例如依赖注入(DI)和面向切面编程(AOP)。其中一个非常强大的功能是构造函数自动注入,也称为构造函数推断

自动注入

构造函数自动注入是指 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构造函数推断的原理是什么”这篇文章的内容就介绍到这里,感谢各位的阅读!相信大家对“Spring构造函数推断的原理是什么”知识都有一定的了解,大家如果还想学习更多知识,欢迎关注亿速云行业资讯频道。

推荐阅读:
  1. Spring Security认证的方法是什么
  2. Spring的IOC基本用法是什么

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

spring

上一篇:vue3与webpack5安装element-plus样式webpack编译报错问题怎么解决

下一篇:PHP结构型模式之代理模式怎么实现

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》