在Spring Boot中放置@Bean的位置?

时间:2015-03-19 13:34:24

标签: java spring spring-boot

我想知道Spring Boot应用程序注册其他bean的最佳位置是什么。我有一个使用@SpringBootApplication注释的Main类,并且该类中定义的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();
        }
    }
    
  3. 有更好的方法吗?

6 个答案:

答案 0 :(得分:13)

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

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

答案 1 :(得分:8)

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

follow Single Responsibility Principle (SRP) - >一个班级对另一个班级的知识程度

Coupling - >能说明你的课程重点是什么的学位

Cohesion - >一个班级应该只有一个责任,只有一个理由来改变一个班级。

因此,根据凝聚力和SRP原则,课程应该集中精力并且只有一个责任。

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

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

答案 2 :(得分:5)

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

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

此外,@ Beans的默认范围是SINGLETON,如果指定其他范围(例如PROTOTYPE),则调用将传递给原始方法。 请查看Spring Reference Guide

中的此部分

答案 3 :(得分:1)

这取决于个人选择,并没有好的或坏的方法。 因为它在弹簧引导参考文档中是首选或显示的方式。

使用@SpringBootApplication注释主类可以方便地引导spring应用程序。但它只查找子包,因此在子文件夹中嵌套配置不会自动检测@Bean,这是唯一需要记住的事情,而不仅仅是个人偏好。

答案 4 :(得分:0)

这取决于通常具有@SpringBootApplication批注的主类所在的位置。您可以使用@ComponentScan(basePackageClasses = HelloWorld.class)注释这个主类。这里的HelloWorld具有用@Beans注释的bean定义,而类则用@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();
    }

}

答案 5 :(得分:0)

这取决于通常具有@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);
    }

}

Bean类:

@Configuration
public class HelloWorld {

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

另一种方法:

通常在大型项目中,我们将有多个包含Bean定义的spring config类。我们可以避免担心所有的Bean类都应该放在主类的子包中。我们可以做的就是拥有一个单一的主spring config类(但请确保该主spring config类位于main类的子包下,以便@SpringBootApplication批注会自动检测该主config)并导入所有其他bean类。

我在包TweetBeansConfig中有2个bean类(TweetSystemHealthBeansConfigcom.ronak.tweet)(该包不是存在主类的子包)。我有一个主spring config类(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);
      }

}