In Spring framework, the @Primary annotation is used to give higher preference to a bean, when there are multiple beans of same type.
The @Primary annotation may be used on any class directly or indirectly annotated with @Component or on methods annotated with @Bean.
The following examples demonstrate the use of the @Primary annotation.
Consider the following User interface.
User.java
package com.boraji.tutorial.spring;
public interface User {
public void doSomething();
}
Create two beans named as AdminUser and GuestUser, which implement the User interface.
AdminUser.java
package com.boraji.tutorial.spring;
/**
* @author imssbora
*/
public class AdminUser implements User {
@Override
public void doSomething() {
System.out.println("Inside doSomething() method of AdminUser");
}
}
GuestUser.java
package com.boraji.tutorial.spring;
/**
* @author imssbora
*/
public class GuestUser implements User {
@Override
public void doSomething() {
System.out.println("Inside doSomething() method of GuestUser");
}
}
Declare the AdminUser and GuestUser beans in java based configuration class.
AppConfig.java
package com.boraji.tutorial.spring.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import com.boraji.tutorial.spring.AdminUser;
import com.boraji.tutorial.spring.GuestUser;
import com.boraji.tutorial.spring.User;
@Configuration
public class AppConfig {
@Bean
@Primary
public User getAdminUser() {
return new AdminUser();
}
@Bean
public User getGuestUser() {
return new GuestUser();
}
}
Now create main class and run application.
MainApp.java
package com.boraji.tutorial.spring;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import com.boraji.tutorial.spring.config.AppConfig;
/**
* @author imssbora
*/
public class MainApp {
public static void main(String[] args) {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(AppConfig.class);
User user=context.getBean(User.class);
user.doSomething();
context.close();
}
}
Output
Inside doSomething() method of AdminUser
It is clear from the above output that the getAdminUser() method, annotated with @Primary, is autowired.
=============================================================
Create Component with @Primary
We have an interface and we will create two classes implementing that interface.
Animal.java
package com.concretepage;
public interface Animal {
void displayName();
}
Lion.java
package com.concretepage;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;
@Component
@Primary
public class Lion implements Animal {
@Override
public void displayName() {
System.out.println("--- Lion ---");
}
}
Tiger.java
package com.concretepage;
import org.springframework.stereotype.Component;
@Component
public class Tiger implements Animal {
@Override
public void displayName() {
System.out.println("-- Tiger ---");
}
}
Dependency Injection
Find the class for dependency injection with @Autowired annotation.
AnimalService.java
package com.concretepage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class AnimalService {
private Animal animal;
public Animal getAnimal() {
return animal;
}
@Autowired
public void setAnimal(Animal animal) {
this.animal = animal;
}
}
Configuration and Main Method
AppConfig.java
package com.concretepage;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan(basePackages="com.concretepage")
public class AppConfig {
}
SpringDemo.java
package com.concretepage;
import java.sql.SQLException;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class SpringDemo {
public static void main(String[] args) throws SQLException {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(AppConfig.class);
ctx.refresh();
Animal animal = ctx.getBean(Animal.class);
animal.displayName();
ctx.registerShutdownHook();
}
}
Output
Case 1. As we have used @Primary annotation on Lion bean. This will be selected for dependency injection. Find the output.
--- Lion ---
Case 2. If we do not provide @Primary annotation on any bean, we will get error.
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.concretepage.Animal] is defined: expected single matching bean but found 2: lion,tiger
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1054) Case 3. If we provide @Primary annotation on both the bean, we will get error.
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.concretepage.Animal] is defined: more than one 'primary' bean found among candidates: [lion, tiger]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.determinePrimaryCandida
No comments:
Post a Comment