【问题标题】:Where to put @Bean in Spring Boot?在 Spring Boot 中将 @Bean 放在哪里?
【发布时间】:2015-05-22 15:38:25
【问题描述】:

我想知道 Spring Boot 应用程序注册附加 bean 的最佳位置是什么。我有一个用 @SpringBootApplication 注释的 Main 类,并且该类中定义的 bean 被拾取。但是当我把这些 bean 放在另一个类中时,它们似乎没有被注册。

阅读文档时,我想到@SpringBootApplication 会隐式搜索其中包含@Bean 注释的类。

所以我现在的选择是:

  1. 把所有@Bean注解的bean放到我的主类中

    @SpringBootApplication
    public class MyApplication {
    
        @Bean
        public Filter AuthenticationFilter() {
            return new AuthenticationFilter();
        }
    
        public static void main(String[] args) {
            SpringApplication.run(MyApplication.class, args);
        }
    }
    
  2. 创建一个配置类并用@Configuration注释它

    @Configuration
    public class MyConfiguration {
        @Bean
        public Filter AuthenticationFilter() {
            return new AuthenticationFilter();
        }
    }
    

有更好的方法吗?

【问题讨论】:

  • API docs of @Bean。通常你会将这些方法放在一个用@Configuration 注释的类中。为什么你认为这不是一个好主意?文档还谈到了“精简”模式。
  • 2.是的方法。 @SpringBootApplication 是一个方便的注解,包含了@Configuration,所以如果你没有很多bean,你可以把它们都放在那里。如果您有许多 bean,和/或它们以某种方式在逻辑上分组,您可以添加额外的 @Configuration 类。但是没有“更好”的方法可以做到这一点。

标签: java spring spring-boot


【解决方案1】:

这取决于主类所在的位置,通常有@SpringBootApplication 注释。你可以用@ComponentScan(basePackageClasses = HelloWorld.class)注释这个主类。这里HelloWorld 的定义用@Beans 注释,类用@Configurations 注释。 Spring容器将扫描@ComponentScan参数中指定的类的所有子包。您还可以为basePackageClasses 参数提供通配符条目,而不是上面指定的类名。例如

@SpringBootApplication
@ComponentScan(basePackageClasses = HelloWorld.class)
public class DemoApplication extends SpringBootServletInitializer {

    public static void main(String[] args) {
          SpringApplication.run(DemoApplication.class);
    }

}

豆类:

@Configuration
public class HelloWorld {

    @Bean
    public TweetUserSevice tweetUserSevice() {
        return new TweetUserSeviceImpl();
    }      
}

另一种方法:

一般在大型项目中,我们会有多个包含 bean 定义的 spring 配置类。我们可以避免担心所有的bean类都应该在主类的子包中。我们可以做的是我们可以有一个主spring config类(但要确保这个主spring config类在主类的子包下,以便@SpringBootApplication注解自动检测主配置)并导入所有其他bean类。

我在包com.ronak.tweet中有2个bean类(TweetBeansConfigTweetSystemHealthBeansConfig)(这个包不是主类存在的子包)。我有一个主 spring 配置类 (TweetMasterSpringConfig),这个类位于我的主类所在的子包中。

package com.ronak.tweet.beans;
@Configuration
@Order(value=1)
@Import({
    TweetBeansConfig.class,
    TweetSystemHealthBeansConfig.class
})
public class TweetMasterSpringConfig {

    public TweetMasterSpringConfig() {
        System.out.println("Initilaizing master spring config");
    }

}

package com.ronak.beans;
@Configuration
public class TweetBeansConfig {

    @Bean
    {
    //
    }

}

package com.ronak.beans;
@Configuration
public class TweetSystemHealthBeansConfig {

    @Bean
    {
    //
    }

}


Main class

package com.ronak.tweet;

@SpringBootApplication
public class DemoApplication extends SpringBootServletInitializer {

      /**This is for registing REST layer for Jersey which implements jaxb. It will register all the classes which is in the pacakage com.ronak.tweet.rest. You can add comma separated package names too.
      @Bean
      ResourceConfig resourceConfig() {
          return new ResourceConfig().packages("com.ronak.tweet.rest");
      }

     public static void main(String[] args) {
          SpringApplication.run(DemoApplication.class);
      }

}

【讨论】:

    【解决方案2】:

    这取决于个人选择,没有好坏之分。 因为它在 Spring Boot 参考文档中是首选或显示方式。

    使用@SpringBootApplication 注释主类使得Bootstrap spring 应用程序变得很方便。但它只查找子包,因此子文件夹中的嵌套配置不会自动检测到@Bean,这是唯一要记住的事情,除了个人喜好。

    【讨论】:

      【解决方案3】:

      这取决于主类所在的位置,通常有@SpringBootApplication 注释。你可以用@ComponentScan(basePackageClasses = HelloWorld.class)注释这个主类。这里HelloWorld 的bean 定义用@Beans 注释,类用@Configurations 注释。

      Spring容器会扫描@ComponentScan参数中指定的类的所有子包。您还可以提供通配符条目而不是类名。

      Ex: 
      
      @SpringBootApplication
      @ComponentScan(basePackageClasses = HelloWorld.class)
      public class DemoApplication extends SpringBootServletInitializer {
      
           public static void main(String[] args) {
                SpringApplication.run(DemoApplication.class);
            }
      
      }
      
      **Bean Class:**
      
      @Configuration
      public class HelloWorld {
      
          @Bean
          public TweetUserSevice tweetUserSevice() {
              return new TweetUserSeviceImpl();
          }
      
      }
      

      【讨论】:

        【解决方案4】:

        是的,在 @Configuration 类中包含你的 bean 通常是 Spring 的首选方式。

        这也是 Spring 建议在 bean 之间注入相互依赖关系的方法之一,以下示例显示了从 Spring 的参考指南 here 复制而来的示例:

        另外,@Beans 的默认范围是 SINGLETON,如果您指定不同的范围,例如 PROTOTYPE,调用将被传递给原始方法。 在Spring Reference Guide中查看此部分

        【讨论】:

          【解决方案5】:

          实际上,您可以选择没有弹簧标准来判断哪个是最好的,但是在定义类时 OOP 设计原则说 A 类应该是loosely coupledhighly cohesive,应该是follow Single Responsibility Principle (SRP),这里

          Coupling --> 一个班级对另一个班级的了解程度

          Cohesion --> 程度表明你的班级的专注程度

          SRP --> 一个类应该只有一个职责,改变一个类应该只有一个原因。

          所以根据内聚力和SRP原则,类应该是重点突出的,只有一个职责。

          在您的情况下,您只有 2 个 bean,但将来这些 bean 可能会增加。所以应该遵循你的第二点,为你的 bean 声明创建另一个类。

          而且在我的选择中甚至应该创建更多的配置类,所以一个配置类应该有类似类型的 bean。

          【讨论】:

            【解决方案6】:

            这几乎是一个偏好问题,但通常认为最好的做法是将暴露的 bean 放在配置类中,这些配置类按逻辑分组。

            例如,您可能有多个配置类,每个配置类中都包含多个 bean: 一个身份验证配置类,其中包含 AuthenticationProvider 或 UserDetailsS​​ervice 的一个 Thymeleaf 配置类,包含各种 Thymeleaf 方言等的 bean。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2017-10-31
              • 2015-01-26
              • 1970-01-01
              • 2017-05-23
              • 2019-01-17
              • 1970-01-01
              相关资源
              最近更新 更多