相关推荐recommended
【Spring面试全家桶】@Primary注解你真的会用吗
作者:mmseoamin日期:2024-01-18

文章目录

  • @Primary注解的作用
  • @Primary注解的使用
    • 1. 常见使用
      • 1.1 在单个配置类中标记@Primary
      • 1.2 在单个@Service、@Controller等注解的类中标记@Primary
      • 2. 高级用法
        • 2.1 使用@Qualifier与@Primary组合
        • 2.2 使用@ConditionalOnMissingBean与@Primary组合
        • 3. 总结
        • @Primary注解的优先级
        • @Primary注解的局限性
        • @Qualifier和@Primary注解的区别
        • @Primary注解的底层工作原理
        • @Primary注解实战问题与解决方案
          • 问题一:多个同类型的Bean,如何确定哪个Bean被@Primary注解?
          • 问题二:如何在不影响原有@Primary注解的前提下,指定使用其他Bean?
          • 问题三:如何在测试代码中使用不同的Bean?

            @Primary注解是Spring Framework中的一个注解,用于标记具有多个实例的Bean的主要实例。以下是关于@Primary注解的知识点:

            1. @Primary注解的作用:@Primary注解用于标记具有相同类型的多个实例中的主要实例。当一个Bean需要注入这种类型的Bean时,Spring会注入使用@Primary注解标记的主要实例。
            2. @Primary注解的使用:在一个有多个实例的Bean中使用@Primary注解来标记主要实例。可以通过在Bean的类定义或构造函数参数中添加@Primary注解来使用它。
            3. @Primary注解的优先级:当一个类中有多个具有相同类型的Bean时,可以使用@Primary注解设置主要实例。主要实例优先于其他实例被注入。如果没有使用@Primary注解,则最后一个装配的Bean会被注入。
            4. @Primary注解的局限性:@Primary注解只适用于Bean的类型,不能用于Bean的名称。因此,如果有多个同一类型的Bean,但它们需要以不同的名称被注入,则无法使用@Primary来确定主要实例。
            5. @Qualifier和@Primary注解的区别:@Primary注解用于标记具有相同类型的多个实例中的主要实例。而@Qualifier注解用于标记具有特定名称的Bean,以便在多个具有相同类型的Bean中选择特定的实例。

              总之,@Primary注解是Spring Framework中的一个重要注解,用于标记具有多个实例的Bean的主要实例。它可以帮助解决多个同一类型的Bean被注入时的问题。

            @Primary注解的作用

            @Primary是一个Spring Framework的注解,用于标记一个bean(组件)是首选的bean(组件)。当多个相同类型的bean被定义时,被标记为@Primary的bean会被优先选择。该注解可以用于以下场景中:

            1. 当有多个同类型的bean时,注入第一个:例如,一个Spring应用程序中可能有多个名为“datasource”的DataSource实例,但应用程序可能需要使用其中一个特定的实例作为首选DataSource。可以通过在此标有@Primary注解的bean上使用@Autowired注解来指示Spring将此bean注入到所有需要Datasource依赖项的组件中。

            2. 当使用@Configuration注释的配置类时,作为默认bean:在使用@Configuration配置类时,可以将@Primary注解用于其中一个bean,以指示Spring在主配置类中定义的bean和其他@Configuration配置类中定义的bean之间选择该bean。

            示例:

            public interface PaymentService {
                void pay();
            }
            @Service
            @Primary
            public class AliPaymentServiceImpl implements PaymentService {
                @Override
                public void pay() {
                    System.out.println("使用阿里支付");
                }
            }
            @Service
            public class WxPaymentServiceImpl implements PaymentService {
                @Override
                public void pay() {
                    System.out.println("使用微信支付");
                }
            }
            @Autowired
            private PaymentService paymentService;
            

            在这个例子中,我们定义了两个PaymentService的实现类,AliPaymentServiceImpl上应用了@Primary注解,表示它是优先选择的实现类。在使用@Autowired注入PaymentService的时候,Spring 会自动选择AliPaymentServiceImpl这个类。如果没有使用@Primary,会抛出NoUniqueBeanDefinitionException。

            总之,@Primary注解是一个非常有用的注解,它可以让开发人员在多个同类型的bean中选择一个首选bean,避免了在使用注入时出现歧义的问题。

            @Primary注解的使用

            @Primary注解是Spring框架中的一个重要注解之一,用来标识一个bean是首选的(primary),在使用自动装配(auto-wiring)时,如果存在多个类型(type)相同的bean,Spring会优先选择标记为@Primary的bean进行注入。下面详细介绍@Primary注解的常见使用与高级用法。

            1. 常见使用

            @Primary注解常见使用场景如下:

            1.1 在单个配置类中标记@Primary

            在Spring配置类中,通过@Bean注解定义多个相同类型的bean时,可以使用@Primary注解标记一个首选的bean,例如:

            @Configuration
            public class AppConfig {
                @Bean
                public DataSource dataSource() {
                    // ...
                }
                @Primary // 标记为首选bean
                @Bean("mySqlDataSource")
                public DataSource mySqlDataSource() {
                    // ...
                }
                @Bean("oracleDataSource")
                public DataSource oracleDataSource() {
                    // ...
                }
            }
            

            在上述配置中,如果需要注入DataSource,由于存在两个DataSource类型的bean,Spring会优先选择@Primary注解标记的mySqlDataSource。

            1.2 在单个@Service、@Controller等注解的类中标记@Primary

            在@Service、@Controller等注解的类中,如果存在多个相同类型的bean,也可以使用@Primary注解标记一个首选的bean,例如:

            @Service
            @Primary // 标记为首选bean
            public class SomeServiceA implements SomeService {
                // ...
            }
            @Service
            public class SomeServiceB implements SomeService {
                // ...
            }
            

            在上述配置中,如果需要注入SomeService,由于存在两个SomeService类型的bean,Spring会优先选择标记为@Primary的SomeServiceA。

            2. 高级用法

            除了常见使用场景,@Primary注解还有一些高级用法,如下:

            2.1 使用@Qualifier与@Primary组合

            @Qualifier注解是Spring提供的注解之一,用于指定一个特定的bean,例如:

            @Component
            public class SomeComponent {
                @Autowired
                @Qualifier("mySqlDataSource")
                private DataSource dataSource;
                // ...
            }
            

            在上述代码中,@Qualifier(“mySqlDataSource”)指定了需要注入的bean名称为mySqlDataSource的DataSource。然而,如果存在多个类型为DataSource的bean,这种方式可能会出现歧义,因此可以与@Primary注解组合使用,例如:

            @Configuration
            public class AppConfig {
                @Bean
                @Primary // 标记为首选bean
                @Qualifier("mySqlDataSource")
                public DataSource mySqlDataSource() {
                    // ...
                }
                @Bean
                @Qualifier("oracleDataSource")
                public DataSource oracleDataSource() {
                    // ...
                }
            }
            

            在上述配置中,指定@Qualifier(“mySqlDataSource”)时,由于存在两个DataSource类型的bean,但是标记为@Primary的mySqlDataSource会被优先选择。

            2.2 使用@ConditionalOnMissingBean与@Primary组合

            @ConditionalOnMissingBean注解是Spring提供的注解之一,用于判断当前上下文中是否存在指定类型(type)的bean,如果不存在,则创建一个新的bean。与@Primary注解结合使用时,可以在不存在指定类型的bean时创建标记为@Primary的bean,例如:

            @Configuration
            public class AppConfig {
                @Bean
                @Primary // 标记为首选bean
                @ConditionalOnMissingBean // 如果不存在 DataSource 类型的bean,则创建一个新的
                public DataSource dataSource() {
                    // ...
                }
            }
            

            在上述配置中,如果当前上下文中不存在DataSource类型的bean,会创建标记为@Primary的dataSource,否则,已存在的bean会被优先选择。

            3. 总结

            @Primary注解是Spring框架中的一个重要注解,用来标识一个bean是首选的,在使用自动装配时,如果存在多个类型相同的bean,Spring会优先选择标记为@Primary的bean进行注入。除了常见使用场景外,@Primary注解还有一些高级用法,如与@Qualifier和@ConditionalOnMissingBean注解组合使用。在实际开发中,开发者可根据实际需求,选择合适的使用方式。

            @Primary注解的优先级

            @Primary注解是Spring框架提供的一个用于解决依赖注入歧义的注解。在一个类(或者一个接口)有多个实现类的情况下,@Primary注解可以指定其中一种实现类作为Spring容器中被注入的主要实现类。在使用@Autowired或者@Qualifier注入Bean时,如果没有指定具体的名称,那么Spring容器将会优先选择使用带有@Primary注解的Bean。

            @Primary注解的优先级如下:

            1. @Primary注解具有最高优先级。如果一个类同时标注了@Primary注解和@Qualifier注解,那么@Primary注解会覆盖@Qualifier注解。

            2. @Primary注解作用于Bean的定义层(即在@Configuration或者@Component注解的类中定义的Bean),而不是作用于Bean的使用层。这意味着在使用@Autowired或者@Qualifier注解进行注入时,如果有多个同类型的Bean都标注了@Primary注解,那么Spring容器将会使用最先加载的那个@Primary注解的Bean进行注入。

            3. 如果在使用@Autowired或者@Qualifier注解时,没有特别指定Bean的名称或者类型,那么Spring容器会使用带有@Primary注解的Bean进行注入。

            总的来说,@Primary注解可以非常方便地解决多个同类型Bean的注入问题,并且具有最高优先级,使用起来非常简单。但是需要注意的是,在使用@Primary注解时,一定要确保它标注的是正确的主要Bean,否则可能会引发一些意料之外的问题。

            @Primary注解的局限性

            @Primary注解是Spring框架中的一个非常常用的注解,主要用于在多个相同类型的bean中指定默认的实现。然而,@Primary注解也存在一些局限性,具体如下:

            1. 只能指定一个默认实现:@Primary注解只能用来指定一个默认实现,如果有多个实现,只能有一个默认实现。如果需要指定多个默认实现,则需要使用其他的方式,比如使用@Qualifier注解。

            2. 不可以与@Autowired注解同时使用:当我们使用@Primary注解指定默认实现时,如果需要在代码中注入bean实例,不可以使用@Autowired注解,因为这会导致Spring无法确定应该注入哪个bean实例。此时,我们需要使用@Qualifier注解来指定具体的bean实例。

            3. 无法应对特殊情况:虽然@Primary注解可以用来指定默认实现,但是在一些特殊情况下可能会失效,比如当我们在使用Spring的Profile功能时,如果针对不同的Profile配置了不同的bean实现,那么@Primary注解指定的默认实现可能会失效,此时我们需要使用其他方式来指定默认实现。

            因此,虽然@Primary注解非常方便,但是在一些特殊情况下可能无法满足需求,需要使用其他方式来指定bean实现。

            @Qualifier和@Primary注解的区别

            在Spring框架中,@Qualifier和@Primary注解都是用来解决依赖注入中多个同类型Bean的问题,它们的功能略有不同。

            @Qualifier注解是通过指定Bean的名称来指定注入哪个Bean,它可以和@Autowired或@Inject一起使用。如果存在多个同类型的Bean时,通过添加@Qualifier注解来指定需要注入的Bean,如下面的例子所示:

            @Component
            public class ClassA {
                ...
            }
            @Component
            public class ClassB {
                ...
            }
            @Component
            public class ClassC {
                
                @Autowired
                @Qualifier("ClassA")
                private ClassA classA;
                
                @Autowired
                @Qualifier("ClassB")
                private ClassB classB;
                
                ...
            }
            

            在上面的例子中,通过@Qualifier注解指定了需要注入的ClassA和ClassB。

            @Primary注解是用来标记一个Bean为首选的Bean,当存在多个同类型的Bean时,会自动选择被@Primary标记的Bean注入,如下面的例子所示:

            @Component
            @Primary
            public class ClassA {
                ...
            }
            @Component
            public class ClassB {
                ...
            }
            @Component
            public class ClassC {
                
                @Autowired
                private ClassA classA;
                
                @Autowired
                private ClassB classB;
                
                ...
            }
            

            在上面的例子中,ClassA被标记为@Primary,当注入ClassC中的classA时,会自动选择被标记为@Primary的ClassA注入。如果没有被标记为@Primary的Bean,则会报错。

            总之,@Qualifier注解是用来指定具体的Bean名称来注入的;@Primary注解是用来标记一个首选的Bean,当存在多个同类型的Bean时,在没有指定具体注入哪个Bean时,会首先注入被标记为@Primary的Bean。

            @Primary注解的底层工作原理

            @Primary注解是Spring Framework中的一个注解,用于标记一个Bean作为默认Bean,在出现多个同类型的Bean时,优先使用被@Primary注解标记的Bean。

            @Primary注解的底层工作原理可以分为以下几个步骤:

            1.在BeanDefinition中注册Bean时,如果该Bean被@Primary注解标记,则会在BeanDefinition中添加一个primary属性,表示该Bean是默认Bean。

            2.当Spring容器需要获取某个类型的Bean时,会先判断是否有该类型的@Primary注解标记的Bean,如果有,则直接使用该Bean。

            3.如果没有@Primary注解标记的Bean,则会选择一个BeanDefinition中primary属性为true的Bean作为默认Bean。

            4.如果BeanDefinition中没有primary属性为true的Bean,则会选择一个名称最小的Bean作为默认Bean。

            总之,@Primary注解是通过标记BeanDefinition中的primary属性来实现的,而选择默认Bean则是通过选择具有primary属性的Bean或名称最小的Bean来实现的。在多个同类型的Bean中使用@Primary注解可以让我们更方便地控制默认Bean的选择,方便我们实现业务逻辑。

            @Primary注解实战问题与解决方案

            @Primary注解是Spring Framework提供的一种用于注入Bean的方式,它的作用是当有多个相同类型的Bean时,优先使用被@Primary注解的Bean。在实际开发中,经常会遇到使用@Primary注解的问题,下面介绍一些实战问题与解决方案。

            问题一:多个同类型的Bean,如何确定哪个Bean被@Primary注解?

            解决方案:在Spring容器启动时,会扫描所有被@Bean注解的方法,并将返回的对象作为Bean放入容器中。如果有多个同类型的Bean,需要在其中一个添加@Primary注解,表示优先使用该Bean。当需要使用该类型的Bean时,Spring Framework会自动选择@Primary注解的Bean。如果想要查看哪个Bean被@Primary注解,可以使用以下方法:

            @Autowired
            public void setBeans(List beans) {
                for (TypeOfBean bean : beans) {
                    if (bean.getClass().isAnnotationPresent(Primary.class)) {
                        System.out.println(bean.getClass().getName() + " is @Primary");
                    }
                }
            }
            

            该方法会自动查找所有类型为TypeOfBean的Bean,打印出被@Primary注解的Bean。

            问题二:如何在不影响原有@Primary注解的前提下,指定使用其他Bean?

            解决方案:在某些情况下,我们需要使用非@Primary注解的Bean,而不是默认的@Primary注解的Bean。可以使用@Qualifier注解指定使用哪个Bean。@Qualifier注解需要与@Autowired注解一起使用,如下所示:

            @Autowired
            @Qualifier("beanName")
            private TypeOfBean bean;
            

            其中,beanName为要使用Bean的名称。

            问题三:如何在测试代码中使用不同的Bean?

            解决方案:在测试代码中,与业务代码不同的是,我们可以使用不同的配置文件或者配置类进行测试,以达到使用不同的Bean的目的。可以通过在测试类中添加@ActiveProfiles注解,并指定使用的配置文件或配置类来实现。如下所示:

            @SpringBootTest
            @ActiveProfiles("test")
            public class TestClass {
                ...
            }
            

            在这个例子中,我们可以在test配置文件中设置优先使用哪个Bean,或者在TestConfig配置类中设置优先使用哪个Bean。

            以上是使用@Primary注解的一些实战问题与解决方案,希望能对您有所帮助。