Multiple instances of a bean Spring - java

I have a config file in spring which I want to define a constructor parameter for each instance of a particular #Component that I have in spring. How can I do that?
#Component
public class MyComponent {
public MyComponent(String config) {}
}
and in my application.yml I want to define something like this:
myconfig:
- config1
- config2
- config3
I would like to make spring create one instance per config entry in the application.yml. Is that possible?
Thanks

There's no way to do this automatically with Spring. You would have to define the beans individually probably by subclassing as #Mick suggested. Firstly, remove the #Component annotation from the base class:
public class MyComponent {
public MyComponent(String config) {}
}
Create however many extensions of this you require as #Components for each config: e.g.:
#Component
public class MyComponentConfig1 extends MyComponent {
public MyComponentConfig1(#Value("myconfig.config1") String config) {
super(config);
}
}
Where the values are injected into your constructor for you by Spring when registering the beans.

You want to create 3 beans with one annotation? Not possible as far as I know. Why not create 3 subclasses and pull in the configuration values with #Resource annotations?
And btw: you must provide a default constructor, because that is the one being called.

Related

Define a Spring RestController via Java configuration

Is it possible to Define a Spring RestController (#RestController annotated class) solely in the Java Configuration (the class with #Configuration annotated in the method marked with #Bean)?
I have an application managed by spring boot (the version doesn't matter for the sake of the question, even the last one available). This application exposes some endpoints with REST, so there are several rest controllers, which in turn call the services (as usual).
Now depending on configuration (property in application.yml) I would like to avoid starting some services and, say 2 classes annotated with #RestController annotation because they deal with the "feature X" that I want to exclude.
I would like to configure all my beans via Java configuration, and this is a requirement. So my initial approach was to define all the beans (controllers and services) in a separate configuration which is found by spring boot during the scanning) and put a #ConditionalOnProperty on the configuration so that it will appear in one place:
#Configuration
public class MyAppGeneralConfiguration {
// here I define all the beans that are not relevant for "feature X"
#Bean
public ServiceA serviceA() {}
...
}
#Configuration
#ConditionalOnProperty(name = "myapp.featureX.enabled", havingValue = "true")
public class MyAppFeatureXConfiguration {
// here I will define all the beans relevant for feature X:
#Bean
public ServiceForFeatureX1 serviceForFeatureX1() {}
#Bean
public ServiceForFeatureX2 serviceForFeatureX2() {}
}
With this approach My services do not have any spring annotations at all and I don't use #Autowired annotation as everything is injected via the constructors in #Configuration class:
// no #Service / #Component annotation
public class ServiceForFeatureX1 {}
Now my question is about the classes annotated with #RestContoller annotation. Say I have 2 Controllers like this:
#RestController
public class FeatureXRestController1 {
...
}
#RestController
public class FeatureXRestController2 {
...
}
Ideally I would like to define them in the Java Configuration as well, so that these two controllers won't even load when I disable the feature:
#ConditionalOnProperty(name = "myapp.featureX.enabled", havingValue = "true", matchIfMissing=true)
public class MyAppFeatureXConfiguration {
#Bean
#RestController // this doesn't work because the #RestController has target Type and can't be applied
// to methods
public FeatureXRestController1 featureXRestController1() {
}
So the question is basically is it possible to do that?
RestController is a Controller which is in turn a component hence its subject to component scanning. Hence if the feature X is disabled the rest controllers for feature X will still start loading and fail
because there won't be no "services" - beans excluded in the configuration, so spring boot won't be able to inject.
One way I thought about is to define a special annotation like #FeatureXRestController and make it #RestController and put #ConditionalOnProperty there but its still two places and its the best solution I could come up with:
#Target(ElementType.TYPE)
#Retention(RetentionPolicy.RUNTIME)
#Documented
#RestController
#ConditionalOnProperty(name = "myapp.featureX.enabled", havingValue = "true", matchIfMissing=true)
public #interface FeatureXRestController {
}
...
#FeatureXRestController
public class FeatureXRestController1 {...}
#FeatureXRestController
public class FeatureXRestController2 {...}
I've Found a relatively elegant workaround that might be helpful for the community:
I don't use a specialized meta annotation like I suggested in the question and annotate the controller of Feature X with the regular #RestController annotation:
#RestController
public class FeatureXController {
...
}
The Spring boot application class can be "instructed" to not load RestControllers during the component scanning exclusion filter. For the sake of example in the answer I'll use the built-in annotation filter, but in general custom filters can be created for more sophisticated (real) cases:
// Note the annotation - component scanning process won't recognize classes annotated with RestController, so from now on all the rest controllers in the application must be defined in `#Configuration` classes.
#ComponentScan(excludeFilters = #Filter(RestController.class))
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
Now, since I want the rest controller to be loaded only if Feature X is enabled, I create the corresponding method in the FeatureXConfiguration:
#Configuration
#ConditionalOnProperty(value = "mayapp.featureX.enabled", havingValue = "true", matchIfMissing = false)
public class FeatureXConfiguration {
#Bean
public FeatureXService featureXService () {
return new FeatureXService();
}
#Bean
public FeatureXRestController featureXRestController () {
return new FeatureXRestController(featureXService());
}
}
Although component scanning process doesn't load the rest controllers, the explicit bean definition "overrides" this behavior and the rest controller's bean definition is created during the startup. Then Spring MVC engine analyzes it and due to the presence of the #RestController annotation it exposes the corresponding end-point as it usually does.
You can use local classes in the java config. E.e.
#Configuration
public class MyAppFeatureXConfiguration {
#Bean
public FeatureXRestController1 featureXRestController1(AutowireCapableBeanFactory beanFactory) {
#RestController
class FeatureXRestController1Bean extends FeatureRestController1 {
}
FeatureXRestController1Bean featureBean = new FeatureXRestController1Bean();
// You don't need this line if you use constructor injection
autowireCapableBeanFactory.autowireBean(featureBean);
return featureBean;
}
}
Then you can omit the #RestController annotation on the "real" implementation, but use the other annotations like #RequestMapping as usual.
#RequestMapping(...)
public class FeatureXRestController1 {
#RequestMapping(value="/somePath/{someId}", method=RequestMethod.GET)
public String findSomething(#PathVariable String someId) {
...
}
}
Sine the FeatureXRestController1 doesn't have a #RestController annotation, it is not a #Component anymore and thus will not be picked up through component scan.
The MyAppFeatureXConfiguration returns a bean that is a #RestController. This FeatureXRestController1Bean extends the FeatureXRestController1 and thus has all the methods and request mappings of the superclass.
Since the FeatureXRestController1Bean is a local class it is not included in a component scan. This does the trick for me ;)
I like both the solutions presented above. However, I came up with another one which worked for me and is pretty clean.
So, I decided to create my beans only using #Configuration classes, and I gave up the #RestController annotations entirely. I put the #Configuration class for web controllers in a separate package, so that I can pass the class descriptor to the #ComponentScan or #ContextConfiguration annotations whenever I want to enable the creation of controller beans. The most important part is to add the #ResponseBody annotation to all controller classes, above the class name, to preserve the REST controller properties. Very clean.
The drawback is that the controller classes are not recognized by the #WebMvcTest annotation, and I need to create the beans for all my controllers every time I do a MockMvc test for one controller. As I have just four controllers though, I can live with it for now.

What's the difference between #Bean and #Component? [duplicate]

I understand that #Component annotation was introduced in spring 2.5 in order to get rid of xml bean definition by using classpath scanning.
#Bean was introduced in spring 3.0 and can be used with #Configuration in order to fully get rid of xml file and use java config instead.
Would it have been possible to re-use the #Component annotation instead of introducing #Bean annotation? My understanding is that the final goal is to create beans in both cases.
#Component
Preferable for component scanning and automatic wiring.
When should you use #Bean?
Sometimes automatic configuration is not an option. When? Let's imagine that you want to wire components from 3rd-party libraries (you don't have the source code so you can't annotate its classes with #Component), so automatic configuration is not possible.
The #Bean annotation returns an object that spring should register as bean in application context. The body of the method bears the logic responsible for creating the instance.
#Component and #Bean do two quite different things, and shouldn't be confused.
#Component (and #Service and #Repository) are used to auto-detect and auto-configure beans using classpath scanning. There's an implicit one-to-one mapping between the annotated class and the bean (i.e. one bean per class). Control of wiring is quite limited with this approach, since it's purely declarative.
#Bean is used to explicitly declare a single bean, rather than letting Spring do it automatically as above. It decouples the declaration of the bean from the class definition, and lets you create and configure beans exactly how you choose.
To answer your question...
would it have been possible to re-use the #Component annotation instead of introducing #Bean annotation?
Sure, probably; but they chose not to, since the two are quite different. Spring's already confusing enough without muddying the waters further.
#Component auto detects and configures the beans using classpath scanning whereas #Bean explicitly declares a single bean, rather than letting Spring do it automatically.
#Component does not decouple the declaration of the bean from the class definition where as #Bean decouples the declaration of the bean from the class definition.
#Component is a class level annotation whereas #Bean is a method level annotation and name of the method serves as the bean name.
#Component need not to be used with the #Configuration annotation where as #Bean annotation has to be used within the class which is annotated with #Configuration.
We cannot create a bean of a class using #Component, if the class is outside spring container whereas we can create a bean of a class using #Bean even if the class is present outside the spring container.
#Component has different specializations like #Controller, #Repository and #Service whereas #Bean has no specializations.
Let's consider I want specific implementation depending on some dynamic state.
#Bean is perfect for that case.
#Bean
#Scope("prototype")
public SomeService someService() {
switch (state) {
case 1:
return new Impl1();
case 2:
return new Impl2();
case 3:
return new Impl3();
default:
return new Impl();
}
}
However there is no way to do that with #Component.
Both approaches aim to register target type in Spring container.
The difference is that #Bean is applicable to methods, whereas #Component is applicable to types.
Therefore when you use #Bean annotation you control instance creation logic in method's body (see example above). With #Component annotation you cannot.
I see a lot of answers and almost everywhere it's mentioned #Component is for autowiring where component is scanned, and #Bean is exactly declaring that bean to be used differently. Let me show how it's different.
#Bean
First it's a method level annotation.
Second you generally use it to configure beans in Java code (if you are not using xml configuration) and then call it from a class using the
ApplicationContext.getBean method. Example:
#Configuration
class MyConfiguration{
#Bean
public User getUser() {
return new User();
}
}
class User{
}
// Getting Bean
User user = applicationContext.getBean("getUser");
#Component
It is the general way to annotate a bean and not a specialized bean.
It is a class level annotation and is used to avoid all that configuration stuff through java or xml configuration.
We get something like this.
#Component
class User {
}
// to get Bean
#Autowired
User user;
That's it. It was just introduced to avoid all the configuration steps to instantiate and use that bean.
You can use #Bean to make an existing third-party class available to your Spring framework application context.
#Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setPrefix("/WEB-INF/view/");
viewResolver.setSuffix(".jsp");
return viewResolver;
}
By using the #Bean annotation, you can wrap a third-party class (it may not have #Component and it may not use Spring), as a Spring bean. And then once it is wrapped using #Bean, it is as a singleton object and available in your Spring framework application context. You can now easily share/reuse this bean in your app using dependency injection and #Autowired.
So think of the #Bean annotation is a wrapper/adapter for third-party classes. You want to make the third-party classes available to your Spring framework application context.
By using #Bean in the code above, I'm explicitly declare a single bean because inside of the method, I'm explicitly creating the object using the new keyword. I'm also manually calling setter methods of the given class. So I can change the value of the prefix field. So this manual work is referred to as explicit creation. If I use the #Component for the same class, the bean registered in the Spring container will have default value for the prefix field.
On the other hand, when we annotate a class with #Component, no need for us to manually use the new keyword. It is handled automatically by Spring.
When you use the #Component tag, it's the same as having a POJO (Plain Old Java Object) with a vanilla bean declaration method (annotated with #Bean). For example, the following method 1 and 2 will give the same result.
Method 1
#Component
public class SomeClass {
private int number;
public SomeClass(Integer theNumber){
this.number = theNumber.intValue();
}
public int getNumber(){
return this.number;
}
}
with a bean for 'theNumber':
#Bean
Integer theNumber(){
return new Integer(3456);
}
Method 2
//Note: no #Component tag
public class SomeClass {
private int number;
public SomeClass(Integer theNumber){
this.number = theNumber.intValue();
}
public int getNumber(){
return this.number;
}
}
with the beans for both:
#Bean
Integer theNumber(){
return new Integer(3456);
}
#Bean
SomeClass someClass(Integer theNumber){
return new SomeClass(theNumber);
}
Method 2 allows you to keep bean declarations together, it's a bit more flexible etc. You may even want to add another non-vanilla SomeClass bean like the following:
#Bean
SomeClass strawberryClass(){
return new SomeClass(new Integer(1));
}
You have two ways to generate beans.
One is to create a class with an annotation #Component.
The other is to create a method and annotate it with #Bean. For those classes containing method with #Bean should be annotated with #Configuration
Once you run your spring project, the class with a #ComponentScan annotation would scan every class with #Component on it, and restore the instance of this class to the Ioc Container. Another thing the #ComponentScan would do is running the methods with #Bean on it and restore the return object to the Ioc Container as a bean.
So when you need to decide which kind of beans you want to create depending upon current states, you need to use #Bean. You can write the logic and return the object you want.
Another thing worth to mention is the name of the method with #Bean is the default name of bean.
Difference between Bean and Component:
#component and its specializations(#Controller, #service, #repository) allow for auto-detection
using classpath scanning. If we see component class like #Controller, #service, #repository will be scan automatically by the spring framework using the component scan.
#Bean on the other hand can only be used to explicitly declare a single bean in a configuration class.
#Bean used to explicitly declare a single bean, rather than letting spring do it automatically. Its make septate declaration of bean from the class definition.
In short #Controller, #service, #repository are for auto-detection and #Bean to create seprate bean from class
- #Controller
public class LoginController
{ --code-- }
- #Configuration
public class AppConfig {
#Bean
public SessionFactory sessionFactory()
{--code-- }
Spring supports multiple types annotations such as #Component, #Service, #Repository. All theses can be found under the org.springframework.stereotype package.
#Bean can be found under the org.springframework.context.annotation package.
When classes in our application are annotated with any of the above mentioned annotation then during project startup spring scan(using #ComponentScan) each class and inject the instance of the classes to the IOC container. Another thing the #ComponentScan would do is running the methods with #Bean on it and restore the return object to the Ioc Container as a bean.
#Component
If we mark a class with #Component or one of the other Stereotype annotations these classes will be auto-detected using classpath scanning. As long as these classes are in under our base package or Spring is aware of another package to scan, a new bean will be created for each of these classes.
package com.beanvscomponent.controller;
import org.springframework.stereotype.Controller;
#Controller
public class HomeController {
public String home(){
return "Hello, World!";
}
}
There's an implicit one-to-one mapping between the annotated class and the bean (i.e. one bean per class). Control of wiring is quite limited with this approach since it's purely declarative. It is also important to note that the stereotype annotations are class level annotations.
#Bean
#Bean is used to explicitly declare a single bean, rather than letting Spring do it automatically like we did with #Controller. It decouples the declaration of the bean from the class definition and lets you create and configure beans exactly how you choose. With #Bean you aren't placing this annotation at the class level. If you tried to do that you would get an invalid type error. The #Bean documentation defines it as:
Indicates that a method produces a bean to be managed by the Spring container.
Typically, #Bean methods are declared within #Configuration classes.We have a user class that we needed to instantiate and then create a bean using that instance. This is where I said earlier that we have a little more control over how the bean is defined.
package com.beanvscomponent;
public class User {
private String first;
private String last;
public User(String first, String last) {
this.first = first;
this.last = last;
}
}
As i mentioned earlier #Bean methods should be declared within #Configuration classes.
package com.beanvscomponent;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
#Configuration
public class ApplicationConfig {
#Bean
public User superUser() {
return new User("Partho","Bappy");
}
}
The name of the method is actually going to be the name of our bean. If we pull up the /beans endpoint in the actuator we can see the bean defined.
{
"beans": "superUser",
"aliases": [],
"scope": "singleton",
"type": "com.beanvscomponent.User",
"resource": "class path resource
[com/beanvscomponent/ApplicationConfig.class]",
"dependencies": []
}
#Component vs #Bean
I hope that cleared up some things on when to use #Component and when to use #Bean. It can be a little confusing but as you start to write more applications it will become pretty natural.
#Bean was created to avoid coupling Spring and your business rules in compile time. It means you can reuse your business rules in other frameworks like PlayFramework or JEE.
Moreover, you have total control on how create beans, where it is not enough the default Spring instantation.
I wrote a post talking about it.
https://coderstower.com/2019/04/23/factory-methods-decoupling-ioc-container-abstraction/
1. About #Component
#Component functs similarily to #Configuration.
They both indicate that the annotated class has one or more beans need to be registered to Spring-IOC-Container.
The class annotated by #Component, we call it Component of Spring. It is a concept that contains several beans.
Component class needs to be auto-scanned by Spring for registering those beans of the component class.
2. About #Bean
#Bean is used to annotate the method of component-class(as mentioned above). It indicate the instance retured by the annotated method needs to be registered to Spring-IOC-Container.
3. Conclusion
The difference between them two is relatively obivious, they are used in different circumstances.
The general usage is:
// #Configuration is implemented by #Component
#Configuration
public ComponentClass {
#Bean
public FirstBean FirstBeanMethod() {
return new FirstBean();
}
#Bean
public SecondBean SecondBeanMethod() {
return new SecondBean();
}
}
Additional Points from above answers
Let’s say we got a module which is shared in multiple apps and it contains a few services. Not all are needed for each app.
If use #Component on those service classes and the component scan in the application,
we might end up detecting more beans than necessary
In this case, you either had to adjust the filtering of the component scan or provide the configuration that even the unused beans can run. Otherwise, the application context won’t start.
In this case, it is better to work with #Bean annotation and only instantiate those beans,
which are required individually in each app
So, essentially, use #Bean for adding third-party classes to the context. And #Component if it is just inside your single application.
#Bean can be scoped and #component cannot
such as
#Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)

Create Spring Components dynamically [duplicate]

I understand that #Component annotation was introduced in spring 2.5 in order to get rid of xml bean definition by using classpath scanning.
#Bean was introduced in spring 3.0 and can be used with #Configuration in order to fully get rid of xml file and use java config instead.
Would it have been possible to re-use the #Component annotation instead of introducing #Bean annotation? My understanding is that the final goal is to create beans in both cases.
#Component
Preferable for component scanning and automatic wiring.
When should you use #Bean?
Sometimes automatic configuration is not an option. When? Let's imagine that you want to wire components from 3rd-party libraries (you don't have the source code so you can't annotate its classes with #Component), so automatic configuration is not possible.
The #Bean annotation returns an object that spring should register as bean in application context. The body of the method bears the logic responsible for creating the instance.
#Component and #Bean do two quite different things, and shouldn't be confused.
#Component (and #Service and #Repository) are used to auto-detect and auto-configure beans using classpath scanning. There's an implicit one-to-one mapping between the annotated class and the bean (i.e. one bean per class). Control of wiring is quite limited with this approach, since it's purely declarative.
#Bean is used to explicitly declare a single bean, rather than letting Spring do it automatically as above. It decouples the declaration of the bean from the class definition, and lets you create and configure beans exactly how you choose.
To answer your question...
would it have been possible to re-use the #Component annotation instead of introducing #Bean annotation?
Sure, probably; but they chose not to, since the two are quite different. Spring's already confusing enough without muddying the waters further.
#Component auto detects and configures the beans using classpath scanning whereas #Bean explicitly declares a single bean, rather than letting Spring do it automatically.
#Component does not decouple the declaration of the bean from the class definition where as #Bean decouples the declaration of the bean from the class definition.
#Component is a class level annotation whereas #Bean is a method level annotation and name of the method serves as the bean name.
#Component need not to be used with the #Configuration annotation where as #Bean annotation has to be used within the class which is annotated with #Configuration.
We cannot create a bean of a class using #Component, if the class is outside spring container whereas we can create a bean of a class using #Bean even if the class is present outside the spring container.
#Component has different specializations like #Controller, #Repository and #Service whereas #Bean has no specializations.
Let's consider I want specific implementation depending on some dynamic state.
#Bean is perfect for that case.
#Bean
#Scope("prototype")
public SomeService someService() {
switch (state) {
case 1:
return new Impl1();
case 2:
return new Impl2();
case 3:
return new Impl3();
default:
return new Impl();
}
}
However there is no way to do that with #Component.
Both approaches aim to register target type in Spring container.
The difference is that #Bean is applicable to methods, whereas #Component is applicable to types.
Therefore when you use #Bean annotation you control instance creation logic in method's body (see example above). With #Component annotation you cannot.
I see a lot of answers and almost everywhere it's mentioned #Component is for autowiring where component is scanned, and #Bean is exactly declaring that bean to be used differently. Let me show how it's different.
#Bean
First it's a method level annotation.
Second you generally use it to configure beans in Java code (if you are not using xml configuration) and then call it from a class using the
ApplicationContext.getBean method. Example:
#Configuration
class MyConfiguration{
#Bean
public User getUser() {
return new User();
}
}
class User{
}
// Getting Bean
User user = applicationContext.getBean("getUser");
#Component
It is the general way to annotate a bean and not a specialized bean.
It is a class level annotation and is used to avoid all that configuration stuff through java or xml configuration.
We get something like this.
#Component
class User {
}
// to get Bean
#Autowired
User user;
That's it. It was just introduced to avoid all the configuration steps to instantiate and use that bean.
You can use #Bean to make an existing third-party class available to your Spring framework application context.
#Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setPrefix("/WEB-INF/view/");
viewResolver.setSuffix(".jsp");
return viewResolver;
}
By using the #Bean annotation, you can wrap a third-party class (it may not have #Component and it may not use Spring), as a Spring bean. And then once it is wrapped using #Bean, it is as a singleton object and available in your Spring framework application context. You can now easily share/reuse this bean in your app using dependency injection and #Autowired.
So think of the #Bean annotation is a wrapper/adapter for third-party classes. You want to make the third-party classes available to your Spring framework application context.
By using #Bean in the code above, I'm explicitly declare a single bean because inside of the method, I'm explicitly creating the object using the new keyword. I'm also manually calling setter methods of the given class. So I can change the value of the prefix field. So this manual work is referred to as explicit creation. If I use the #Component for the same class, the bean registered in the Spring container will have default value for the prefix field.
On the other hand, when we annotate a class with #Component, no need for us to manually use the new keyword. It is handled automatically by Spring.
When you use the #Component tag, it's the same as having a POJO (Plain Old Java Object) with a vanilla bean declaration method (annotated with #Bean). For example, the following method 1 and 2 will give the same result.
Method 1
#Component
public class SomeClass {
private int number;
public SomeClass(Integer theNumber){
this.number = theNumber.intValue();
}
public int getNumber(){
return this.number;
}
}
with a bean for 'theNumber':
#Bean
Integer theNumber(){
return new Integer(3456);
}
Method 2
//Note: no #Component tag
public class SomeClass {
private int number;
public SomeClass(Integer theNumber){
this.number = theNumber.intValue();
}
public int getNumber(){
return this.number;
}
}
with the beans for both:
#Bean
Integer theNumber(){
return new Integer(3456);
}
#Bean
SomeClass someClass(Integer theNumber){
return new SomeClass(theNumber);
}
Method 2 allows you to keep bean declarations together, it's a bit more flexible etc. You may even want to add another non-vanilla SomeClass bean like the following:
#Bean
SomeClass strawberryClass(){
return new SomeClass(new Integer(1));
}
You have two ways to generate beans.
One is to create a class with an annotation #Component.
The other is to create a method and annotate it with #Bean. For those classes containing method with #Bean should be annotated with #Configuration
Once you run your spring project, the class with a #ComponentScan annotation would scan every class with #Component on it, and restore the instance of this class to the Ioc Container. Another thing the #ComponentScan would do is running the methods with #Bean on it and restore the return object to the Ioc Container as a bean.
So when you need to decide which kind of beans you want to create depending upon current states, you need to use #Bean. You can write the logic and return the object you want.
Another thing worth to mention is the name of the method with #Bean is the default name of bean.
Difference between Bean and Component:
#component and its specializations(#Controller, #service, #repository) allow for auto-detection
using classpath scanning. If we see component class like #Controller, #service, #repository will be scan automatically by the spring framework using the component scan.
#Bean on the other hand can only be used to explicitly declare a single bean in a configuration class.
#Bean used to explicitly declare a single bean, rather than letting spring do it automatically. Its make septate declaration of bean from the class definition.
In short #Controller, #service, #repository are for auto-detection and #Bean to create seprate bean from class
- #Controller
public class LoginController
{ --code-- }
- #Configuration
public class AppConfig {
#Bean
public SessionFactory sessionFactory()
{--code-- }
Spring supports multiple types annotations such as #Component, #Service, #Repository. All theses can be found under the org.springframework.stereotype package.
#Bean can be found under the org.springframework.context.annotation package.
When classes in our application are annotated with any of the above mentioned annotation then during project startup spring scan(using #ComponentScan) each class and inject the instance of the classes to the IOC container. Another thing the #ComponentScan would do is running the methods with #Bean on it and restore the return object to the Ioc Container as a bean.
#Component
If we mark a class with #Component or one of the other Stereotype annotations these classes will be auto-detected using classpath scanning. As long as these classes are in under our base package or Spring is aware of another package to scan, a new bean will be created for each of these classes.
package com.beanvscomponent.controller;
import org.springframework.stereotype.Controller;
#Controller
public class HomeController {
public String home(){
return "Hello, World!";
}
}
There's an implicit one-to-one mapping between the annotated class and the bean (i.e. one bean per class). Control of wiring is quite limited with this approach since it's purely declarative. It is also important to note that the stereotype annotations are class level annotations.
#Bean
#Bean is used to explicitly declare a single bean, rather than letting Spring do it automatically like we did with #Controller. It decouples the declaration of the bean from the class definition and lets you create and configure beans exactly how you choose. With #Bean you aren't placing this annotation at the class level. If you tried to do that you would get an invalid type error. The #Bean documentation defines it as:
Indicates that a method produces a bean to be managed by the Spring container.
Typically, #Bean methods are declared within #Configuration classes.We have a user class that we needed to instantiate and then create a bean using that instance. This is where I said earlier that we have a little more control over how the bean is defined.
package com.beanvscomponent;
public class User {
private String first;
private String last;
public User(String first, String last) {
this.first = first;
this.last = last;
}
}
As i mentioned earlier #Bean methods should be declared within #Configuration classes.
package com.beanvscomponent;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
#Configuration
public class ApplicationConfig {
#Bean
public User superUser() {
return new User("Partho","Bappy");
}
}
The name of the method is actually going to be the name of our bean. If we pull up the /beans endpoint in the actuator we can see the bean defined.
{
"beans": "superUser",
"aliases": [],
"scope": "singleton",
"type": "com.beanvscomponent.User",
"resource": "class path resource
[com/beanvscomponent/ApplicationConfig.class]",
"dependencies": []
}
#Component vs #Bean
I hope that cleared up some things on when to use #Component and when to use #Bean. It can be a little confusing but as you start to write more applications it will become pretty natural.
#Bean was created to avoid coupling Spring and your business rules in compile time. It means you can reuse your business rules in other frameworks like PlayFramework or JEE.
Moreover, you have total control on how create beans, where it is not enough the default Spring instantation.
I wrote a post talking about it.
https://coderstower.com/2019/04/23/factory-methods-decoupling-ioc-container-abstraction/
1. About #Component
#Component functs similarily to #Configuration.
They both indicate that the annotated class has one or more beans need to be registered to Spring-IOC-Container.
The class annotated by #Component, we call it Component of Spring. It is a concept that contains several beans.
Component class needs to be auto-scanned by Spring for registering those beans of the component class.
2. About #Bean
#Bean is used to annotate the method of component-class(as mentioned above). It indicate the instance retured by the annotated method needs to be registered to Spring-IOC-Container.
3. Conclusion
The difference between them two is relatively obivious, they are used in different circumstances.
The general usage is:
// #Configuration is implemented by #Component
#Configuration
public ComponentClass {
#Bean
public FirstBean FirstBeanMethod() {
return new FirstBean();
}
#Bean
public SecondBean SecondBeanMethod() {
return new SecondBean();
}
}
Additional Points from above answers
Let’s say we got a module which is shared in multiple apps and it contains a few services. Not all are needed for each app.
If use #Component on those service classes and the component scan in the application,
we might end up detecting more beans than necessary
In this case, you either had to adjust the filtering of the component scan or provide the configuration that even the unused beans can run. Otherwise, the application context won’t start.
In this case, it is better to work with #Bean annotation and only instantiate those beans,
which are required individually in each app
So, essentially, use #Bean for adding third-party classes to the context. And #Component if it is just inside your single application.
#Bean can be scoped and #component cannot
such as
#Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)

Better way to register beans in Spring

I am new in Spring. I understand process of Dependency Injection and Inversion Of Control as well. But in few days ago I found one source code which compel me thinking about it.
If I am not wrong, Beans can be registered by Stereotype annotations - #Component, #Service, etc.
In code which I found will be defined class with some logic, but without annotation. Next that same class will be initialized in some #Configuration class as been like that:
#Bean
public Foo fooBean() {
return new Foo();
}
Can you tell me what is different between these options and when they use? Thanks in advice.
The greatest benefit of #Configuration and #Bean is that allows you to create spring beans that are not decorated with #Component or any of its children (#Service, #Repository and those). This is really helpful when you want/need to define spring beans that are defined in an external library that has no direct interaction with Spring (maybe written by you or somebody else).
E.g.
You have a jar created by an external provider that contains this class:
public class EmailSender {
private String config1;
private String config2;
//and on...
public void sendEmail(String from, String to, String title, String body, File[] attachments) {
/* implementation */
}
}
Since the class is in an external jar, you cannot modify it. Still, Spring allows you to create spring beans based on this class (remember, the bean is the object, not the class).
In your project, you'll have something like this:
import thepackage.from.externaljar.EmailSender;
#Configuration
public class EmailSenderConfiguration {
#Bean
public EmailSender emailSender() {
EmailSender emailSender = new EmailSender();
emailSender.setConfig1(...);
emailSender.setConfig2(...);
//and on...
return emailSender;
}
}
And then you can inject the bean as needed:
#Service
public class MyService {
#Autowired
private EmailSender emailSender;
}
#Configuration is used to define your configuration of your application. In the end #Bean, #Service, #Component will all register a bean, but using #Configuration with all beans (services, components) defined in a single place makes your app more organized and easier to troubleshoot.

How can I test only one bean using existing application's spring configuration class?

In my code, I don't want to load all the beans defined in the XXApplicationConfig class.
XXApplicationConfig is a #Configuration annotated file which has bunch of spring beans defined.
So, I want to load only AppBean from XXApplicationConfig class while testing to reduce loading test time and also differentiate what I am testing. I also want to load the class using XXApplicationConfig class to make sure the bean configuration defined is correct as well.
This is my Test class ( modified ) to test AppBean class.
Could you let me know if this is the right approach and suggest how to make it better? Currently, this approach seems to be working. But, not sure if it is correct way of approaching it.
#ContextConfiguration(loader=AnnotationConfigContextLoader.class)
#RunWith(SpringJUnit4ClassRunner.class)
public class ApplicationTest {
#Configuration
#PropertySources(value = {#PropertySource("classpath:test.properties")})
static class MyTestConfiguration {
#Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceHolderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
#Bean
public XXApplicationConfig xxAppConfig() {
return new XXApplicationConfig();
}
#Bean
public CustomTestService customTestService() {
return new CustomTestService();
}
#Bean
public AppBean appBean() throws Exception {
return XXApplicationConfig().appBean();
}
}
#Autowired
private AppBean appBean;
#Test
public void testAppBean() {
test appBean.doSomething();
}
}
If you want to test just one object, just create one object of that class, using the constructor of that class. Spring beans are designed to be POJOs. The Spring context is just a convenient way of creating and connecting objects. Nothing stops you creating and connecting them yourself.
If you can instantiated the class you want to test and manually inject all the dependencies it required via constructor and/or setter getters, then you don't need to use Spring in your test.
However, if your bean:
uses private fields annotated with #Autowired or #Value without corresponding getters/setters.
depends on many other beans.
the behavior you want to test depends on Spring AOP/Proxies (you use #Transactional or #Cacheable for example).
Then you will need Spring to wired the bean. I personally prefer to define a a minimal #Configuration class for these cases.
Then again, if your bean meets the conditions on the list you should consider refactoring the bean to minimize its dependencies and facilitate testing.

Categories