【问题标题】:Someone can explain to me for a use case of springboot injection有人可以向我解释一下spring boot注入的用例
【发布时间】:2020-03-21 21:52:07
【问题描述】:

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

    @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() 每次都返回相同的数据源。它是怎么发生的?如果我确实需要另一个数据源,我需要即时创建它吗?

【问题讨论】:

  • Spring 默认使用@Bean 创建一个实例,通常情况下,这是正确的做法。假设你的 DataSource 是一个真正的数据源,你为什么需要 2 个 bean?
  • 第二个问题只是出于好奇。例如:我需要一个具有不同超时的数据源。我真正想知道的是为什么this.mysqlDataSource()没有用spring创建一个新的Datasource?

标签: spring-boot dependency-injection coding-style


【解决方案1】:

this.mysqlDataSource() 方法返回 bean,因为 Spring 为配置类创建了代理。可以查看详情here

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

你可以使用注解@Scope("prototype")来做到这一点。

【讨论】:

  • 感谢您的回复。但我的问题是 this.mysqlDataSource() 不是注射,而是 spring 对待它。
  • 方法this.mysqlDataSource()返回bean。该方法通过 CGLIB 代理,因此返回缓存版本的 bean(不创建新版本)。你可以看看this detailed answer
  • 谢谢。该链接很有用。其他回复直接有更多细节。
【解决方案2】:

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

“常规 Spring 组件中的 @Bean 方法的处理方式与 Spring @Configuration 类中的对应方法不同。不同之处在于 @Component 类未使用 CGLIB 增强以拦截调用方法和字段。CGLIB 代理是在 @Configuration 类中调用 @Bean 方法中的方法或字段创建协作对象的 bean 元数据引用的方法;这些方法不是用普通 Java 语义调用的,而是通过容器为了提供 Spring bean 的常规生命周期管理和代理,即使通过编程调用 @Bean 方法引用其他 bean。相反,在普通 @Component 类中调用 @Bean 方法中的方法或字段具有标准Java 语义,没有特殊的CGLIB 处理或其他应用约束。”

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

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

【讨论】:

    猜你喜欢
    • 2014-04-20
    • 2011-04-24
    • 1970-01-01
    • 2019-10-14
    • 2019-11-28
    • 2015-01-31
    • 2012-04-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多