有人可以向我解释一个 spring boot 注入的用例

Someone can explain to me for a use case of springboot injection

我从一位同事的代码中读到这些行:

    @Bean(name = "mysql")
    @ConfigurationProperties(prefix = "spring.mysql")
    @Primary
    public DataSource mysqlDataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean
    public ClassA classA () {
        return new ClassA (this.mysqlDataSource());
    }

    @Bean
    public ClassB classB () {
        return new ClassB (this.mysqlDataSource());
    }

我认为这将为 Bean classA 和 classB 创建 2 个数据源。为了注入数据源,我们需要类似的东西:

    @Bean
    public ClassA classA (DataSource ds) {
        return new ClassA (ds);
    }

但是Spring 只创建一个数据源,this.mysqlDataSource() returns 每次都创建相同的数据源。它是怎么发生的?如果我确实需要另一个数据源,我需要即时创建它吗?

方法 this.mysqlDataSource() returns bean 因为 Spring 为配置 class 创建代理。可以查看详情

默认情况下 Spring 容器使用 scope "singleton" 创建 bean。 所以你在容器中有一个 DataSource 实例,这个实例将被注入到 ClassA 和 ClassB 对象。如果你想要不同的实例,你应该将范围更改为 "prototype".

您可以使用注释 @Scope("prototype") 来完成。

Spring 表示 @Component@Configuration 具有不同的含义。 如果您使用 @Configuration 而不是 @Component,将使用 CGLIB 代理。

"The @Bean methods in a regular Spring component are processed differently than their counterparts inside a Spring @Configuration class. The difference is that @Component classes are not enhanced with CGLIB to intercept the invocation of methods and fields. CGLIB proxying is the means by which invoking methods or fields within @Bean methods in @Configuration classes creates bean metadata references to collaborating objects; such methods are not invoked with normal Java semantics but rather go through the container in order to provide the usual lifecycle management and proxying of Spring beans even when referring to other beans via programmatic calls to @Bean methods. In contrast, invoking a method or field in an @Bean method within a plain @Component class has standard Java semantics, with no special CGLIB processing or other constraints applying."

https://docs.spring.io/spring/docs/5.0.4.RELEASE/spring-framework-reference/core.html#spring-core

或者,您可以将 @ConfigurationProperties 保留在 class 级别并从 DataSource 中删除 @Bean,这样 mysqlDataSource() 将被视为常规方法..