spring 注解@primary解析

本文通过具体的示例介绍了Spring框架中@Primary注解的作用及其使用方法。当存在多个相同类型的Bean时,该注解可以帮助Spring确定优先使用的Bean。

文章引自:http://jackyrong.iteye.com/blog/2208000

spring中少见的注解@primary注解,例子

@Component  
public class MetalSinger implements Singer{  

    @Override  
    public String sing(String lyrics) {  
        return "I am singing with DIO voice: "+lyrics;  
    }  
}  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
public class OperaSinger implements Singer {  
    @Override  
    public String sing(String lyrics) {  
        return "I am singing in Bocelli voice: "+lyrics;  
    }  
}  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

这两个类都实现了singer接口

public interface Singer {  
    String sing(String lyrics);  
}  
  • 1
  • 2
  • 3

那么来个注入的:

@Component  
public class SingerService {  
    private static final Logger logger = LoggerFactory.getLogger(SingerService.class);  

    @Autowired  
    private Singer singer;  

    public String sing(){  
        return singer.sing("song lyrics");  
    }  
}  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

那么最后输出应该是:I am singing with DIO voice: song lyrics.

原因是只有MetalSinger使用了注解@component,那么autowird会只寻找这个标记的
进行注入:
如果也在OperaSinger 中使用了注解,则spring会报异常,不知道到底应该用
哪个:
org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [main.service.Singer] is defined: expected single matching bean but found 2: metalSinger,operaSinger
而如果要让spring知道必须注入的是OperaSinger ,则可以用@primary注解告诉
spring:

@Primary  
@Component  
public class OperaSinger implements Singer{  

    @Override  
    public String sing(String lyrics) {  
        return "I am singing in Bocelli voice: "+lyrics;  
    }  
}  
<think>根据用户的问题,用户关注的是在Spring框架中使用@Autowired注入接口时,如果该接口有多个实现类,其中有一个实现类被标记为@Primary,那么注入的是哪个实现类,以及调用方法时是调用父类(接口)方法还是子类(实现类)方法。 关键点: 1. @Autowired注入的是接口类型,但实际注入的是该接口的一个具体实现类的实例。 2. @Primary注解用于指定当存在多个相同类型的bean时,优先选择被标记为@Primary的bean。 3. 接口本身不能被实例化,所以注入的一定是某个实现类的实例。因此,当调用方法时,实际上调用的是该实现类(子类)中重写的方法。 因此,回答应该明确:注入的是被@Primary标记的实现类(子类)的实例,因此调用方法时调用的是子类的方法。 另外,注意用户提到“调用父类还是子类方法”,这里需要澄清:接口是父类型,实现类是子类型。但方法调用是动态绑定到实际实例的类(子类)的方法。 同时,用户提到“该接口有被@Primary标记且实现了该接口并带有@Component注解子类存在”,这里注意@Primary是标记在实现类上,而不是接口上。 因此,总结回答: - 当使用@Autowired注入接口时,Spring会查找该接口的所有实现类中符合条件的bean。 - 如果有一个实现类被标记为@Primary,则优先注入该实现类的实例。 - 由于注入的是具体实现类的实例,因此调用接口方法时,实际执行的是该实现类中重写的方法(即子类方法)。 另外,注意用户问题中有一个小错误:@Primary是标记在实现类上,而不是接口上。所以用户描述“该接口有被@Primary标记”应理解为“该接口的某个实现类被@Primary标记”。 最后,按照要求生成相关问题。 </think> 在 Spring 框架中使用 `@Autowired` 注入接口对象时,**实际注入的是被 `@Primary` 标记的子类实现**,因此调用的是**子类重写后的方法**。以下是详细分析: ### 关键规则解析 1. **`@Autowired` 的注入逻辑** Spring 通过类型匹配自动注入 bean。当注入接口类型时,Spring 会查找该接口的所有实现类中符合条件的 bean。 2. **`@Primary` 的作用** 若存在多个实现类,`@Primary` 标记的类会被优先选择。例如: ```java public interface MyService { void execute(); } @Component public class DefaultServiceImpl implements MyService { @Override public void execute() { System.out.println("默认实现"); } } @Component @Primary // 优先注入此实现 public class PrimaryServiceImpl implements MyService { @Override public void execute() { System.out.println("@Primary 实现"); } } ``` 3. **方法调用行为** 注入的实例是 `@Primary` 标记的子类对象(如 `PrimaryServiceImpl`)。调用接口方法时,**实际执行的是子类重写的方法**(动态绑定)。例如: ```java @Autowired private MyService myService; // 实际注入 PrimaryServiceImpl myService.execute(); // 输出:"@Primary 实现" ``` ### 验证实验 ```java // 测试类 @SpringBootTest public class InjectionTest { @Autowired private MyService myService; @Test public void testInjection() { myService.execute(); // 实际调用 PrimaryServiceImpl.execute() System.out.println(myService.getClass().getName()); // 输出: com.example.PrimaryServiceImpl } } ``` ### 特殊情况处理 - **无 `@Primary` 时**:若存在多个实现类且无 `@Primary`,Spring 会抛出 `NoUniqueBeanDefinitionException`。 - **显式指定名称**:可通过 `@Qualifier("beanName")` 覆盖 `@Primary` 的优先级。 ### 总结 | 场景 | 注入对象 | 方法调用来源 | |-------------------------------|---------------|------------------| | 有 `@Primary` 子类实现 | 子类实例 | 子类重写方法 | | 无 `@Primary`(多实现类) | 报错 | - | | 唯一实现类(无 `@Primary`) | 子类实例 | 子类重写方法 | > **核心原则**:Spring 注入的是具体子类对象,方法调用始终遵循 Java 的多态特性,执行实际子类的重写方法[^1]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值