【问题标题】:How to instantiate separate bean member each time class is instantiate每次实例化类时如何实例化单独的bean成员
【发布时间】:2020-11-09 22:18:41
【问题描述】:
  private Last60MinutesArray last60MinutesOfBytes = new Last60MinutesArray();
  @Bean
  Last60MinutesArray last60MinutesOfBytes()
  {
    return last60MinutesOfBytes;
  }

  private Last60MinutesArray last60MinutesOfStartedTrackersCount = new Last60MinutesArray();
  @Bean
  Last60MinutesArray last60MinutesOfStartedTrackersCount()
  {
    return last60MinutesOfStartedTrackersCount;
  }

  @Bean
  InLast60MinutesChart bytesUploadedInLastMinutesChart()
  {
    return new InLast60MinutesChart("Bytes Uploaded"
        ,last60MinutesOfBytes);
  }

  @Bean
  InLast60MinutesChart uploadsStartedInLastMinutesChart()
  {
    return new InLast60MinutesChart("Uploads Started"
        ,last60MinutesOfStartedTrackersCount);
  }

我正在创建两个InLast60MinutesChart 类型的bean,它在构造函数中采用Last60MinutesArray。我宁愿不通过构造函数引入“Last60MinutesArray”,而是在InLast60MinutesChart 中实例化。但是,我仍然想要两个单独的“Last60MinutesArray”实例,并且我希望它们都是 Bean,因此我可以使用 spring 注释,例如 @Scheduled。 感谢您的任何想法:)

我希望它看起来像这样:

  @Bean
  InLast60MinutesChart bytesUploadedInLastMinutesChart()
  {
    return new InLast60MinutesChart("Bytes Uploaded");
  }

  @Bean
  InLast60MinutesChart uploadsStartedInLastMinutesChart()
  {
    return new InLast60MinutesChart("Uploads Started");
  }
public class InLast60MinutesChart
{
  @Autowired
  protected Last60MinutesArray last60MinutesArray;
}

我希望每个InLast60MinutesChart 都有自己独特的Last60MinutesArray,还可以说我想要50 个InLast60MinutesChart 实例,所以我真的不想为每个Last60MinutesArray 创建一个Bean。我必须为每个 InLast60MinutesChart 创建一个 Bean,但我不想在此之上创建那么多 Last60MinutesArray Bean 以及我想添加到 InLast60MinutesChart Bean 的任何其他 Bean。有点奇怪的场景,但我希望能解决我的问题。

【问题讨论】:

    标签: java spring


    【解决方案1】:

    您的标题实际上与您的问题描述不匹配,但如果您想要标题中所说的内容,那么您需要具有“原型”范围的 bean。 默认情况下,Spring bean 是单例。它们被创建一次并在每次自动装配时注入。但是,如果您希望每次自动装配 bean 时都有一个新实例,那么您需要指定“原型”类型的“范围”

    @Bean("bytesChart")
    @Scope("prototype")
    public InLast60MinutesChart bytesUploadedInLastMinutesChart(@Qualifier("bytesCount") Last60MinutesArray last60MinutesOfBytes) {
        return new InLast60MinutesChart("Bytes Uploaded", last60MinutesOfBytes);
    }
    

    现在,每次自动装配时都会创建一个“InLast60MinutesChart”的新实例。 还有其他作用域,大部分都没有用:P

    https://www.baeldung.com/spring-bean-scopes

    【讨论】:

    • 我认为这可能会从外观上做到这一点,但当我测试它时,我意识到这会创建假/原型对象。我正在寻找与此类似的东西,但要创建 Last60MinutesArray 的真实实例
    • 我不知道您所说的“假/原型”对象是什么意思……这是 Java,而不是 JavaScript。注释指示容器在每次自动装配时创建一个新的 bean 实例。要对此进行测试,您可以在创建 bean 的函数中放置一个断点并自己查看。
    • 好吧,你是对的,我使用调试器的第一次测试显示了奇怪的结果。我创建了一个新项目并进行了一些实验,是的 @Scope("prototype") 是我正在寻找的,谢谢 :)
    • 根据问题描述,原型范围不是你想要的。 Prototype每次被请求时都会创建一个新的 bean(通过例如 applicationContext.getBean(Last60MinutesArray.class)。如果您请求的 bean 也执行计划任务,那么这可能不会像预期的那样运行。
    【解决方案2】:

    如果您想在应用程序上下文中提供多个相同类型的@Bean 定义,您可以将您的Last60MinutesArray 实例定义为@Beans,然后为它们提供一个特定的bean 名称作为限定符,如下所示:

    @Configuration
    public class MyConfiguration {
    
        @Bean("bytesCount")
        public Last60MinutesArray last60MinutesOfBytes() {
             return new Last60MinutesArray();
        }
    
        @Bean("trackersCount")
        public Last60MinutesArray trackersCount () {
            return new Last60MinutesArray();
        }
    }
    

    这使您的 Last60MinutesArrays 成为成熟的 Spring bean,它们是应用程序生命周期的一部分(除其他外,能够根据需要使用 @Scheduled 方法)。

    之后,您可以使用@Qualifier 将相关的@Bean 传递给正确的InLast60MinutesChart,如下所示:

      // in the same class or another marked as @Configuration
    
        @Bean("bytesChart")
        public InLast60MinutesChart bytesUploadedInLastMinutesChart(@Qualifier("bytesCount") Last60MinutesArray last60MinutesOfBytes) {
            return new InLast60MinutesChart("Bytes Uploaded", last60MinutesOfBytes);
        }
    
        @Bean("uploadsChart")
        public InLast60MinutesChart uploadsStartedInLastMinutesChart(@Qualifier("trackersCount") Last60MinutesArray last60MinutesOfStartedTrackersCount ) {
            return new InLast60MinutesChart("Uploads Started", last60MinutesOfStartedTrackersCount);
        }
    

    请注意,您的InLast60MinutesChart bean很可能也应该是合格的,因为使用@Autowired 注入它们中的任何一个(或Last60MinutesArrays 中的任何一个)将产生一个NoUniqueBeanDefinitionException注入,因为匹配类型的 bean 不止一个。在这种情况下,自动装配还需要@Qualifier,例如如下:

    @Service
    public class MyService {
    
        @Autowired
        @Qualifier("uploadsChart")
        private InLast60MinutesChart uploadsChart;
    
    }
    

    或者,如果您不关心特定实例,则可以注入给定类型的所有 bean,如下所示:

    @Service
    public class MyService {
    
       @Autowired
       private List<InLast60MinutesChart> charts;
    
    }
    

    然后您可以对其进行迭代。

    请注意,如果您将其中一个标记为 @Primary,则不必限定 bean 名称,但从您的代码来看,这可能不是您想要做的。

    它也可能会帮助您浏览reference documentation,它会更详细地介绍。


    假设我在配置中创建了 50 个 InLast60MinutesChart Bean。有没有办法让我不必创建 50 个 Last60MinutesArray 的 Bean/我可能希望包含在 InLast60MinutesChart 中的任何其他 bean。还要记住,我希望它们每个都是一个单独的实例。

    您需要创建的 bean 数量是一个重要的细节,这使得维护工作对于上述幼稚的方法来说并非微不足道。在这种情况下,您很可能希望基本上按照我上面所说的方式进行操作,但要以编程方式:

    1. 以编程方式创建nLast60MinutesArray bean,每个bean 都有一个单独的名称(您要使用哪种模式进行命名取决于您)。
    2. 以编程方式创建nInLast60MinutesChart bean,其构造函数采用Last60MinutesArray

    重要的部分是您必须跟踪将哪个Last60MinutesArrays 传递给哪个InLast60MinutesChart,本质上是模拟上述声明式bean 创建。

    不要重复已经存在的信息,而是查看this 答案,以使用 BeanDefinitionRegistryPostProcessor.postProcessBeanDefinitionRegistry() 在应用程序上下文中以编程方式注册bean。

    【讨论】:

    • 假设我在配置中创建了 50 个 InLast60MinutesChart 的 Bean。有没有一种方法可以让我不必创建 50 个 Last60MinutesArray 的 Bean / 我可能希望包含在 InLast60MinutesChart 中的任何其他 bean。还要记住,我希望它们每个都是一个单独的实例。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-18
    • 1970-01-01
    • 2013-06-08
    • 1970-01-01
    • 2018-09-05
    • 1970-01-01
    相关资源
    最近更新 更多