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