Spring @Primary注解

2023/05/11

1. 概述

在本文中,我们将介绍Spring的@Primary注解,它是在3.0版本中引入的。

简单地说,当有多个相同类型的bean时,我们可以使用@Primary给一个bean更高的优先级

2. 为什么需要@Primary?

在某些情况下,我们需要注册多个相同类型的bean

假设我们定义了两个Employee类型的bean:


@Configuration
@ComponentScan(basePackages = "cn.tuyucheng.taketoday.primary")
public class Config {

    @Bean
    public Employee johnEmployee() {
        return new Employee("John");
    }

    @Bean
    public Employee tonyEmployee() {
        return new Employee("Tony");
    }
}

@Data
@AllArgsConstructor
public class Employee {

    private final String name;
}

如果我们尝试获取Employee bean,Spring会抛出NoUniqueBeanDefinitionException

要访问具有相同类型的bean,我们通常使用@Qualifier(“beanName”)注解。

我们将它与@Autowired结合使用。在我们的例子中,我们在配置阶段选择了bean,所以@Qualifier不能在这里应用。

为了解决这个问题,Spring提供了@Primary注解。

3. 将@Primary与@Bean一起使用

让我们看一下配置类:


@Configuration
@ComponentScan(basePackages = "cn.tuyucheng.taketoday.primary")
public class Config {

    @Bean
    public Employee johnEmployee() {
        return new Employee("John");
    }

    @Bean
    @Primary
    public Employee tonyEmployee() {
        return new Employee("Tony");
    }
}

我们用@Primary标记tonyEmployee()方法。Spring将优先注入tonyEmployee bean,而不是johnEmployee

现在,让我们启动应用程序上下文并从中获取Employee bean:

public class PrimaryApplication {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
        Employee employee = context.getBean(Employee.class);
        System.out.println(employee);
    }
}

运行应用程序后,控制台的输出如下:

Employee{name='Tony'}

4. 将@Primary与@Component一起使用

我们可以直接在bean上使用@Primary。让我们看一下以下场景:

public interface Manager {
    String getManagerName();
}

我们有一个Manager接口和两个子类bean,DepartmentManager:


@Component
public class DepartmentManager implements Manager {

    @Override
    public String getManagerName() {
        return "Department manager";
    }
}

和GeneralManager bean:


@Primary
@Component
public class GeneralManager implements Manager {

    @Override
    public String getManagerName() {
        return "General manager";
    }
}

它们都重写了Manager接口的getManagerName()方法。另外,请注意我们用@Primary标记了GeneralManager bean。

这一次,@Primary仅在我们启用组件扫描时才有意义


@Configuration
@ComponentScan(basePackages = "cn.tuyucheng.taketoday.primary")
public class Config {

}

让我们创建一个Service类来注入Manager类型的bean:


@Service
public class ManagerService {

    @Autowired
    private Manager manager;

    public Manager getManager() {
        return manager;
    }
}

在这里,bean DepartmentManager和GeneralManager都符合自动装配的条件。

当我们用@Primary标记GeneralManager bean时,它将被选择用于依赖注入

public class PrimaryApplication {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
        ManagerService service = context.getBean(ManagerService.class);
        Manager manager = service.getManager();
        System.out.println(manager.getManagerName());
    }
}

运行以上程序,控制台的输出是“General manager”。

5. 总结

在本文中,我们了解了Spring的@Primary注解。通过代码示例,我们演示了@Primary的需求和用例。

与往常一样,本教程的完整源代码可在GitHub上获得。

Show Disqus Comments

Post Directory

扫码关注公众号:Taketoday
发送 290992
即可立即永久解锁本站全部文章