I have read that #Qualifier can be used in Injection phase whereas #Primary is used in Configuration phase. Am still unclear when to use which.
Also I have below doubts
can #Primary and #Qualifier be used together? if yes does #Qualifier take precedence?
can #Primary be used with #Autowired?
How is the Injection phase different from Configuration phase, this in respect to Spring beans
#Primary indicates that a bean should be given preference when multiple candidates
are qualified to autowire a single-valued dependency.
#Qualifier indicates specific bean should be autowired when there are multiple candidates.
For example, we have two beans both implement the same interface.
public interface BeanInterface {
String getName();
}
public class Bean1 implements BeanInterface {
#Override
public String getName() {
return "bean 1";
}
}
public class Bean2 implements BeanInterface {
#Override
public String getName() {
return "bean2";
}
}
Here is our service.
#Service
public class BeanService {
#Autowired
private BeanInterface bean;
}
And our configuration.
#Configuration
public class Config {
#Bean("bean1")
public BeanInterface bean1() {
return new Bean1();
}
#Bean("bean2")
public BeanInterface bean2() {
return new Bean2();
}
}
When Spring starts, it will find there are two beans("bean1" and "bean2") both can be autowired to BeanService since they implement the same interface BeanInterface. It reports an error in my Idea.
Could not autowire. There is more than one bean of 'BeanInterface' type.
Beans: bean1 (Config.java)
bean2 (Config.java)
And without a hint, Spring does not know which one to use.
So in our case, when we add #Primary to Config.bean1().
#Bean("bean1")
#Primary
public BeanInterface bean1() {
return new Bean1();
}
It tells Spring, "when you find more than one beans that both can be autowired, please use the primary one as your first choose." So, Spring will pick bean1 to autowire to BeanService.
Here is another way to autowire bean1 to BeanService by using #Qualifier in BeanService.class.
#Service
public class BeanService {
#Autowired
#Qualifier("bean1")
private BeanInterface bean;
}
#Qualifier will tell Spring, "no matter how many beans you've found, just use the one I tell you."
So you can find both #Qualifier and #Primary are telling Spring to use the specific bean when multiple candidates are qualified to autowire. But #Qualifier is more specific and has high priority. So when both #Qualifier and #Primary are found, #Primary will be ignored.
Here is the test.
#Configuration
public class Config {
#Bean("bean1")
#Primary
public BeanInterface bean1() {
return new Bean1();
}
#Bean("bean2")
public BeanInterface bean2() {
return new Bean2();
}
}
#Service
public class BeanService {
#Autowired
#Qualifier("bean2")
private BeanInterface bean;
#PostConstruct
public void test() {
String name = bean.getName();
System.out.println(name);
}
}
The output is "bean2".
Also, need to remember that #Qualifier as bigger priority then #Primary, that's means that it's waste to define both of the annotations.
#Primary means default implementation, while #Qualifier is the specific implementation.
You can review my blog I wrote regarding this annotations -
http://shaikezam.com/#/spring_qualifier
Yes, #Qualifier takes precedence.
Yes we can user #Primary and #Autowired together.
#Configuration Class related to Application Context which can be use to configure application level configuration.
To access beans with the same type we usually use #Qualifier(“beanName”) annotation. We apply it at the injection point along with #Autowired. In our case, we select the beans at the configuration phase so #Qualifier can't be applied here.
To resolve this issue Spring offers the #Primary annotation along with #Bean annotation.
Source
Related
I want declare multiple object using same class but different properties in Spring boot annotation
application.properties
test1.name=Ken
test2.name=Anthony
the code example
#Component
public class People {
private String name;
public String getName() {
return this.name;
}
}
#SpringBootApplication
public class Application {
#AutoWired
public People man1;
#AutoWired
public People man2;
System.out.println(man1.getName());
System.out.println(man2.getName());
}
I try to add #ConfigurationProperties(prefix="test1") before declare man1
but it returned
The annotation #ConfigurationProperties is disallowed for this location
#ConfigurationProperties is only allow to be placed on the #Bean method in the #Configuration class or at the class level. For the former case , it will map the properties from the application.properties to the bean instance , which means you have to :
#SpringBootApplication
public class Application {
#Bean
#ConfigurationProperties(prefix="test1")
public People man1() {
return new People();
}
#Bean
#ConfigurationProperties(prefix="test2")
public People man2() {
return new People();
}
}
And since both man1 and man2 are the same type , you have to further use #Qualifier to tell Spring which instance you actually want to inject by specifying its bean name. The bean name can be configured by #Bean("someBeanName"). If #Bean is used without configuring the bean name, the method name will be used as the bean name. (i.e. man1 and man2)
#Autowired
#Qualifier("man1")
public People man1;
#Autowired
#Qualifier("man2")
public People man2;
It might be a very simple question for you.But I read lots of documents and I am totally confused.We can use #Component instead of #Bean or #Bean instead of #Component(as well as #Repository #Service #Controller) ?
Cheers
Component
#Component also for #Service and #Repository are used to auto-detect and auto-configure beans 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
Bean and Component are mapped as one to one i.e one bean per Class.
These annotations (#Component, #Service, #Repository) are Class level annotations.
Example:
Lets Say we have a UserService Class which contains all methods for User Operation.
#Service
public class UserService {
#Autowired
private UserRepository userRepository;
#Override
public User findByUsername( String username ) throws UsernameNotFoundException {
User u = userRepository.findByUsername( username );
return u;
}
public List<User> findAll() throws AccessDeniedException {
List<User> result = userRepository.findAll();
return result;
}
}
Spring will create a Bean for UserService and we can use this at multiple location/classes.
#Bean
#Bean is used to declare a single bean, rather than letting Spring do it automatically as in case of Component.
It decouples the declaration of the bean from the class definition, and lets you create and configure beans exactly how you choose.
#Bean are used at method level and can be configured as required
eg:
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Bean
public SpringTemplateEngine springTemplateEngine()
{
SpringTemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.addTemplateResolver(htmlTemplateResolver());
return templateEngine;
}
#Bean
public SpringResourceTemplateResolver htmlTemplateResolver()
{
SpringResourceTemplateResolver emailTemplateResolver = new SpringResourceTemplateResolver();
emailTemplateResolver.setPrefix("classpath:/static/template/");
emailTemplateResolver.setSuffix(".html");
emailTemplateResolver.setTemplateMode("HTML");
emailTemplateResolver.setCharacterEncoding(StandardCharsets.UTF_8.name());
return emailTemplateResolver;
}
...
Read more about Stereotype Annotations here.
#Bean is used to define a method as a producer, which tells Spring to use that method to retrieve an object of the method return type and inject that object as a dependency whenever it's required.
#Component is used to define a class as a Spring component, which tells Spring to create an object (if it's Singleton) from and take care of it's lifecycle and dependencies and inject that object whenever it's required.
#Service and #Repository are basically just like #Component and AFAIK they are just for better grouping of your components.
#Service for Defining your service classes where you have your business logic, and #Repository for Defining your repository classes where you interact with an underlying system like database.
#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.
I'm a Spring rookie and trying to benefit from the advantages of the easy 'profile' handling of Spring. I already worked through this tutorial: https://spring.io/blog/2011/02/14/spring-3-1-m1-introducing-profile and now I'd like to adapt that concept to an easy example.
I've got two profiles: dev and prod. I imagine a #Configuration class for each profile where I can instantiate different beans (implementing a common interface respectively) depending on the set profile.
My currently used classes look like this:
StatusController.java
#RestController
#RequestMapping("/status")
public class StatusController {
private final EnvironmentAwareBean environmentBean;
#Autowired
public StatusController(EnvironmentAwareBean environmentBean) {
this.environmentBean = environmentBean;
}
#RequestMapping(method = RequestMethod.GET)
Status getStatus() {
Status status = new Status();
status.setExtra("environmentBean=" + environmentBean.getString());
return status;
}
}
EnvironmentAwareBean.java
public interface EnvironmentAwareBean {
String getString();
}
EnvironmentAwareBean.java
#Service
public class DevBean implements EnvironmentAwareBean {
#Override
public String getString() {
return "development";
}
}
EnvironmentAwareBean.java
#Service
public class ProdBean implements EnvironmentAwareBean {
#Override
public String getString() {
return "production";
}
}
DevConfig.java
#Configuration
#Profile("dev")
public class DevConfig {
#Bean
public EnvironmentAwareBean getDevBean() {
return new DevBean();
}
}
ProdConfig.java
#Configuration
#Profile("prod")
public class ProdConfig {
#Bean
public EnvironmentAwareBean getProdBean() {
return new ProdBean();
}
}
Running the example throws this exception during startup (SPRING_PROFILES_DEFAULT is set to dev):
(...) UnsatisfiedDependencyException: (...) nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [EnvironmentAwareBean] is defined: expected single matching bean but found 3: prodBean,devBean,getDevBean
Is my approach far from a recommended configuration? In my opinion it would make more sense to annotate each Configuration with the #Profile annotation instead of doing it for each and every bean and possibly forgetting some variants when new classes are added later on.
Your implementations of EnvironmentAwareBean are all annotated with #Service.
This means they will all be picked up by component scanning and hence you get more than one matching bean. Do they need to be annotated with #Service?
Annotating each #Configuration with the #Profile annotation is fine. Another way as an educational exercise would be to not use #Profile and instead annotate the #Bean or Config classes with your own implementation of #Conditional.
So this is basically what I am trying to achieve: Inject User with constructor into UserClass. But it is throwing "No default constructor found" error. As I suspect if I add #Autowired to class User constructor it expects injection there so I'm not really sure where the problem is.
The question might be too basic so you can redirect me to older such questions. There is very little information on annotation based DI.
#Component
public class UserClass {
public User user;
#Autowired
public UserClass(User user) {
this.user = user;
}
}
#Configuration
public class DIconfig {
#Bean
public User getUser() {
return new User('John');
}
}
#Component
public class User {
public String name;
//#Autowired
public User(String name) {
this.name = name;
}
}
Thank you for your time.
You define two beans of the class User, one with #Component, and one with #Bean. The bean configuration with #Bean is fine so far, however the bean definition with #Component is indeed lacking the default constructor. Every bean which is defined with #Component must either have a default constructor or a constructor where all dependencies are autowired. Neither is the case with your bean. So either add a default constructor or remove the #Component and only create beans of that class with an #Bean method.
I've created a Spring #Configuration annotated class and I want to autowire a ResourceLoader to it so that I can use it in one of the #Bean methods to lookup a file given by a String. When I am running the app and initialising the context I get a NPE accessing the autowired field, and in debug mode it is shown as being null/not set. Am I wrong expecting the resourceLoader to be present? Am I wrong asserting the autowiring of the Configuration bean happens before its methods get called? The xml configuration loading this bean is tagged with <context:annotation-config/>
#Configuration
public class ClientConfig {
#Autowired
private ResourceLoader resourceLoader;
public #Bean
String configHome() {
return System.getProperty("CONFIG_HOME");
}
public #Bean
PropertiesFactoryBean appProperties() {
String location = "file:" + configHome() + "/conf/webservice.properties";
PropertiesFactoryBean factoryBean = new PropertiesFactoryBean();
factoryBean.setLocation(resourceLoader.getResource(location));
return factoryBean;
}
}
I'm not sure whether this is a bug or is the expected behavior. Sometimes it worked for me, sometimes didn't. Anyway, there is another way of achieving what you want:
public #Bean PropertiesFactoryBean appProperties(ResourceLoader resourceLoader) {
// resourceLoader is injected correctly
...
}