Where to put @Bean in Spring Boot?

JavaSpringSpring Boot

Java Problem Overview


I am wondering what the best place would be for a Spring Boot app to register additional beans. I have a Main class that is annotated with @SpringBootApplication and beans defined in that class are picked up. But when i put those beans in another class it seems that the are not being registered.

When reading the documentation i got the idea that the @SpringBootApplication would implicitly search for classes that have @Bean annotations in them.

So my options are now:

  1. Put all @Bean annotated bean in my main class

     @SpringBootApplication
     public class MyApplication {
    
         @Bean
         public Filter AuthenticationFilter() {
             return new AuthenticationFilter();
         }
    
         public static void main(String[] args) {
             SpringApplication.run(MyApplication.class, args);
         }
     }
    
  2. Create a configuration class and annotate that with @Configuration

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

Is there a better way of doing this?

Java Solutions


Solution 1 - Java

It is pretty much a matter of preference, but it is generally considered best practice to put exposed beans in configuration classes, which are logically grouped.

For example, you might have several configuration classes with a number of beans contained within each: An authentication configuration class with beans for AuthenticationProvider or UserDetailsService; a Thymeleaf configuration class containing beans for various Thymeleaf dialects, etc.

Solution 2 - Java

Actually, it is your choice there is no spring standard present to tell which one is best but while defining a class OOP design principles says A class should be loosely coupled and highly cohesive, should follow Single Responsibility Principle (SRP), Here

Coupling --> Degree of knowledge a class has about another class

Cohesion --> Degree which tells how well focused your class is

SRP --> A class should have only one responsibility, there should be only one reason to change a class.

So according to cohesion and SRP principle class should be well focused and have only one responsibility.

Here in your case you have only 2 beans but in future, these beans might increase. So should follow your second point and create another class for your bean declaration.

And In my choice should even create more configuration classes, So one configuration class should have a similar type of beans.

Solution 3 - Java

Yes, including your beans inside the @Configuration class is usually the preferred way for Spring.

This is also one of the ways Spring recommends injecting inter-dependencies between beans is shown in the following sample copied from the Spring's reference guide here:

Additionally, the default scope of @Beans is SINGLETON, if you specify a different scope such as PROTOTYPE the call will be passed to the original method. Have a look at this section in the Spring Reference Guide

Solution 4 - Java

It depends on where the main class is located which has generally @SpringBootApplication annotations. You can annotate this main class with @ComponentScan(basePackageClasses = HelloWorld.class). Here HelloWorld has bean definitions annotated with @Beans and the class is annotated with @Configurations.

Spring container will scan all the sub-packages of the class specified in @ComponentScan arguments. You can also give wild card entries instead of class name.

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();
	}

}

Solution 5 - Java

It depends on where the main class is located which has generally @SpringBootApplication annotations. You can annotate this main class with @ComponentScan(basePackageClasses = HelloWorld.class). Here HelloWorld has had definitions annotated with @Beans and the class is annotated with @Configurations. Spring container will scan all the sub-packages of the class specified in @ComponentScan arguments. You can also give wild card entries for basePackageClasses argument instead of class name as specified above. E.g.

@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();
    }      
}

Another approach:

Generally in big projects, we will have multiple spring config classes containing bean definitions. We can avoid worrying about that all the bean class should be in sub-package of main class. What we can do is that we can have a single master spring config class(but make sure this master spring config class is under sub-package of main class so that @SpringBootApplication annotations automatically detects the master config) and import all the other bean classes.

I have 2 bean classes (TweetBeansConfig, TweetSystemHealthBeansConfig) in the package com.ronak.tweet (This package is not sub-package where main class exists). I have one master spring config class (TweetMasterSpringConfig) and this class resides in package which is sub-package where my main class resides.

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);
	  }

}

Solution 6 - Java

It depends on personal choices and there is no good or bad way to do it. As it is preferred or showed way in documentation of Spring Boot references.

As annotating main class with @SpringBootApplication makes it convenient to Bootstrap spring app. But it does only looks for subpackages so nesting configuration inside subfolder would not detect the @Bean automatically that is the only thing to remember other than it's all about personal preferences.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMarcoView Question on Stackoverflow
Solution 1 - JavaDaniel CottoneView Answer on Stackoverflow
Solution 2 - JavaNaresh JoshiView Answer on Stackoverflow
Solution 3 - JavaTomasz KubiakView Answer on Stackoverflow
Solution 4 - JavaRonak JainView Answer on Stackoverflow
Solution 5 - JavaRonak JainView Answer on Stackoverflow
Solution 6 - JavaMoshiourView Answer on Stackoverflow