How does spring recognize the param inside a constructor - java

I was trying to configure promethues in my code and I just had to create a bean like below. I was wondering how spring recognised CollectorRegistry. How did spring instantiate all the necessary variable for CollectorRegistry and setup all the necessary cofnfiguration?
#Component
public class TestProm{
public TestProm(CollectorRegistry registry){
// Some initialization code here
}
}
However, when I tried to define it in another way by defining a #Bean in my #Configuration class, it didn't seem to work properly as my own constructor for CollectorRegistry didn't have all the necessary properties.
#Configuration
public class PromConfiguration{
#Bean
public TestProm getTestProm() {
return new TestProm(new CollectorRegistry());
}
}
public class TestProm{
public TestProm(CollectorRegistry registry){
//Some code here
}
}
How do I recognise/replicate the initialization of CollectorRegistry done by spring when I do my custome implementation.

How did spring instantiate all the necessary variable for CollectorRegistry and setup all the necessary cofnfiguration?
In the first example you require a Bean of type CollectorRegistry and Spring will actually create such bean for you if you have spring-boot-starter-actuator and Prometheus dependencies on your classpath and you have autoconfiguration enabled :
if you use #EnableAutoConfiguration
if you are using Spring Boot and #SpringBootApplication annotation (#EnableAutoConfiguration is part of this annotation underneath) :
...
#EnableAutoConfiguration
#ConfigurationPropertiesScan
...
public #interface SpringBootApplication
In this case Spring will scan the classpath and load all configurations. The bean that you are interested in is part of PrometheusMetricsExportAutoConfiguration :
#Bean
#ConditionalOnMissingBean
public CollectorRegistry collectorRegistry() {
return new CollectorRegistry(true);
}
In the second example the instance of CollectorRegistry is not managed by Spring because you create it through new keyword. However it should work as CollectorRegistry has default constructor which initializes autoDescribe field to false. And the default Bean of this class which is created by Spring (in a way described above) has this field set to true. So the value of this field is the source of your differences.
Also if this instance is not managed by Spring - it prevents it to be injected into other components which require it. As the scope of CollectorRegistry is Singleton (shown above) other beans might require to share the instance to work properly (for example some beans might want to register/deregister collectors) but if you create CollectorRegistry like that with new keyword - you will not get the singleton instance but a new instance which cannot be shared across other beans.
How do I recognise/replicate the initialization of CollectorRegistry done by spring when I do my custom implementation?
If you want to use the default CollectorRegistry (assuming you want to use the bean that is created by default in the way described above) just inject bean of this type to your beans and it should be enough.

Related

If an instance is shown in both autowired and bean, which one Spring will use

Originally, there was a service instance to access the database and now we want to add a readonly instance. So I add the serviceReadonly in my configuration.
#Configuration
public class Config {
#Bean Service service() {...};
#Bean Service serviceReadonly() {...};
#Bean Proxy proxy() {return new Proxy(serviceReadonly())}; // replace the original Proxy(service())
}
But, the service is also autowired to Proxy
#Component
public class Proxy {
#Autowired
public Proxy(Service service) {this.service = service;}
}
I am confused which Service is injected in my API? service or serviceReadonly?
#Component
public class API {
#Autowired
public API(Proxy proxy) {this.proxy = proxy;}
}
The Proxy and API classes are in another shared library and avoiding change to the library is preferred. Also, the service is autowired to other components.
Short answer: #Bean Service service()
Explanation: Excerpt from the Spring documentation here
Autowiring by property name. Spring looks for a bean with the same
name as the property that needs to be autowired. For example, if a
bean definition is set to autowire by name, and it contains a master
property (that is, it has a setMaster(..) method), Spring looks for a
bean definition named master, and uses it to set the property.
I assume it will be #Bean Service service() because the Spring would find the bean with same name as the property i.e. Service as defined in official Spring guide.
You may also need to look into #Qualifier annotation. It is because if there is not exactly one bean of the constructor argument type in the container, a fatal error is raised, as mentioned in Spring documentation here. Have you checked if you receive this error of NoUniqueBeanDefinitionException? In that case you can use #Qualifer annotation to specify the bean you want.

How to specify a default bean for autowiring in Spring?

I am coding both a library and service consuming this library. I want to have a UsernameProvider service, which takes care of extracting the username of the logged in user. I consume the service in the library itself:
class AuditService {
#Autowired
UsernameProvider usernameProvider;
void logChange() {
String username = usernameProvider.getUsername();
...
}
}
I want to have a default implementation of the UsernameProvider interface that extracts the username from the subject claim of a JWT. However, in the service that depends on the library I want to use Basic authentication, therefore I'd create a BasicAuthUsernameProvider that overrides getUsername().
I naturally get an error when there are multiple autowire candidates of the same type (DefaultUsernameProvider in the library, and BasicAuthUsernameProvider in the service), so I'd have to mark the bean in the service as #Primary. But I don't want to have the library clients specify a primary bean, but instead mark a default.
Adding #Order(value = Ordered.LOWEST_PRECEDENCE) on the DefaultUsernameProvider didn't work.
Adding #ConditionalOnMissingBean in a Configuration class in the library didn't work either.
EDIT: Turns out, adding #Component on the UsernameProvider implementation classes renders #ConditionalOnMissingBean useless, as Spring Boot tries to autowire every class annotated as a Component, therefore throwing the "Multiple beans of type found" exception.
You can annotate the method that instantiates your bean with #ConditionalOnMissingBean. This would mean that the method will be used to instantiate your bean only if no other UserProvider is declared as a bean.
In the example below you must not annotate the class DefaultUserProvider as Component, Service or any other bean annotation.
#Configuration
public class UserConfiguration {
#Bean
#ConditionalOnMissingBean
public UserProvider provideUser() {
return new DefaultUserProvider();
}
}
You've not posted the code for DefaultUsernameProvider but I guess its annotated as a #Component so it is a candidate for auto wiring, and the same with the BasicAuthUsernameProvider. If you want to control which of these is used, rather than marking them both as components, add a #Configuration class, and create your UsernameProvider bean there:
#Configuration
public class ProviderConfig {
#Bean
public UsernameProvider() {
return new BasicAuthUsernameProvider();
}
}
This bean will then be auto wired wherever its needed

Spring Custom Converter - To Bean or Not to Bean

I am implementing Custom Converter in Spring so my beans can convert from java.util.Date to java.time.LocalDateTime. I have implemented Converter already (by implementing Spring Converter interface)
Here is bean definition in #Configuration class
#Bean
ConversionService conversionService(){
DefaultConversionService service = new DefaultConversionService();
service.addConverter(new DateToLocalDateTimeConverter());
return service;
}
My question is : shall I pass my custom converter as Java Object or Spring Bean to service.addConverter?
In general what are the guidelines (criterias) whether to bean or not to bean in such scenarios?
Making an object a Spring Bean makes sense as you want that this object may benefit from Spring features (injections, transaction, aop, etc...).
In your case, it seems not required.
As conversionService is a Spring bean singleton that will be instantiated once, creating during its instantiation a plain java instance of DateToLocalDateTimeConverter seems fine : new DateToLocalDateTimeConverter().
Now, if later you want to inject the DateToLocalDateTimeConverter instance in other Spring beans, it would make sense to transform it to a Spring Bean.
For information Spring provides already this utility task in the Jsr310Converters class (included in the spring-data-commons dependency) :
import static java.time.LocalDateTime.*;
public abstract class Jsr310Converters {
...
public static enum DateToLocalDateTimeConverter implements Converter<Date, LocalDateTime> {
INSTANCE;
#Override
public LocalDateTime convert(Date source) {
return source == null ? null : ofInstant(source.toInstant(), ZoneId.systemDefault());
}
}
...
}
You could directly use it.
If you intend to inject this as a dependency of some kind into your application, and/or you intend to reuse it in multiple places, then it makes sense to register it as a bean. If you're not, then newing an instance up is acceptable.
Dependency injection and inversion of control are just that - how you inject dependencies into your app, and an acknowledgment that you no longer control how that's instantiated. Should you desire either of these, beans are suitable; if you don't, then new it up.
In you simple case, it does not seem to be necessary to add DateToLocalDateTimeConverter as a spring bean.
Reasons to add DateToLocalDateTimeConverter as a spring bean:
If it would make the implementation of conversionService() more readable (not the case in the question example)
You need the DateToLocalDateTimeConverter in other beans
The implementation of DateToLocalDateTimeConverter itself would need to have Spring beans injected, i.e. using #Autowired

How do I add a bean to Spring context in my library without breaking consumers who have their own instance of that bean?

I have a library which produces beans into a Spring context for use by clients. The beans I produce are configured by Spring. I need to add a new bean to my context in order to satisfy a dependency of a new bean I'm publishing. However, I believe some of my clients already have an instance of this bean and are autowiring it by type. So I have something like this:
// Code in my Library
#Component
public class PublicUtilityClass {
// This is all new code in my library
private NewDependency newDependency;
public void newCapability() {
newDependency.doNewThing();
}
#AutoWired
public void setNewDependency(NewDependency newDependency) {
this.newDependency = newDependency;
}
// Other library code omitted.
}
How can I use Spring to instantiate NewDependency and inject it into PublicUtilityClass without impacting customers who already have a NewDependency bean in their context?
You should look at #Qualifier annotation. Qualifier allows you to have multiple instance of your bean

Spring: #Component versus #Bean

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)

Categories

Resources