Понимание первичной аннотации в профиле - PullRequest
0 голосов
/ 29 марта 2020

Я пытаюсь понять поведение @Primary в @Profile из этого видео

Внедрение зависимости с помощью профиля. Активный профиль в файле application.properties имеет значение english, и при его запуске выдается ошибка

expected single matching bean but found 2: helloWorldServiceEnglish,helloWorldServiceSpanish

Добавление аннотации @Primary в helloConfig. java устраняет ошибку:

    @Bean
    @Profile("english")
    @Primary
    public HelloWorldService helloWorldServiceEnglish(HelloWorldFactory factory) {
        return factory.createHelloWorldService("en");
    }

Когда я использую Autowiring с использованием Profile, и существует только один профиль с именем english, почему он ищет другие компоненты, которые не имеют аннотации @Profile? И как добавление @Primary меняет это поведение?

Сканирует ли Spring сначала для Autowire по типу и полностью игнорирует @Profile, из-за чего выдает ошибку expected single matching bean but found 2.

helloConfig . java

package com.spring.config;

import com.spring.services.HelloWorldFactory;
import com.spring.services.HelloWorldService;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.context.annotation.Profile;

@Configuration
public class HelloConfig {

    @Bean
    public HelloWorldFactory helloWorldFactory() {
        return new HelloWorldFactory();
    }

    @Bean
    @Profile("english")
    @Primary
    public HelloWorldService helloWorldServiceEnglish(HelloWorldFactory factory) {
        return factory.createHelloWorldService("en");
    }

    @Bean
    @Qualifier("spanish")
    public HelloWorldService helloWorldServiceSpanish(HelloWorldFactory factory) {
        return factory.createHelloWorldService("es");
    }

    @Bean
    @Profile("french")
    public HelloWorldService helloWorldServiceFrench(HelloWorldFactory factory) {
        return factory.createHelloWorldService("fr");
    }

    @Bean
    @Profile("german")
    public HelloWorldService helloWorldServiceGerman(HelloWorldFactory factory) {
        return factory.createHelloWorldService("de");
    }

    @Bean
    @Profile("polish")
    public HelloWorldService helloWorldServicePolish(HelloWorldFactory factory) {
        return factory.createHelloWorldService("pl");
    }

    @Bean
    @Profile("russian")
    public HelloWorldService helloWorldServiceRussian(HelloWorldFactory factory) {
        return factory.createHelloWorldService("ru");
    }
}

DependencyInjectionApplication. java

package com.spring.componentScan;

import com.spring.controllers.GreetingController;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.ComponentScan;

@SpringBootApplication
@ComponentScan("com.spring")
public class DependencyInjectionApplication {
    public static void main(String[] args) {
        ApplicationContext ctx = SpringApplication.run(DependencyInjectionApplication.class, args);
        GreetingController controller = (GreetingController) ctx.getBean("greetingController");
        controller.sayHello();
    }
}

GreetingController. java

package com.spring.controllers;

import com.spring.services.HelloWorldService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;

@Controller
public class GreetingController {
    private HelloWorldService helloWorldService;
    private HelloWorldService helloWorldServiceSpanish;

    @Autowired
    public void setHelloWorldService(HelloWorldService helloWorldService) {
        this.helloWorldService = helloWorldService;
    }

    @Autowired
    @Qualifier("spanish")
    public void setHelloWorldServiceFrench(HelloWorldService helloWorldServiceSpanish) {
        this.helloWorldServiceSpanish = helloWorldServiceSpanish;
    }

    public String sayHello() {
        String greeting = helloWorldService.getGreeting();
        System.out.println(helloWorldServiceSpanish.getGreeting());
        System.out.println(greeting);
        return greeting;
    }
}

Application.properties spring.profiles.active = engli sh

Полный исходный код:

Ответы [ 2 ]

0 голосов
/ 29 марта 2020

Хорошо, значит, ваш пример не обновлен последним кодом. Но я предполагаю, что вы хотите создать несколько экземпляров одного и того же типа бина и использовать их для разных языков. Это легко сделать, и вам не нужно иметь @Profile и @Primary для этого.

Вам нужно просто назначить спецификатор для экземпляра компонента (или использовать тот, который Spring назначает по умолчанию) , И бин-инъекция с помощью этого квалификатора.

@Bean
public HelloWorldService helloWorldServiceFrench(HelloWorldFactory factory) {
    return factory.createHelloWorldService("fr");
}

@Bean
public HelloWorldService helloWorldServiceGerman(HelloWorldFactory factory) {
    return factory.createHelloWorldService("de");
}

@Bean
public HelloWorldService helloWorldServicePolish(HelloWorldFactory factory) {
    return factory.createHelloWorldService("pl");
}

@Bean
public HelloWorldService helloWorldServiceRussian(HelloWorldFactory factory) {
    return factory.createHelloWorldService("ru");
}

Контроллер:

@Controller
public class GreetingController {
    @Qualifier("helloWorldServiceGerman")
    @Autowired
    private HelloWorldService helloWorldServiceGerman;
    @Qualifier("helloWorldServiceFrench")
    @Autowired
    private HelloWorldService helloWorldServiceFrench;
    @Qualifier("helloWorldServicePolish")
    @Autowired
    private HelloWorldService helloWorldServicePolish;
    @Qualifier("helloWorldServiceRussian")
    @Autowired
    private HelloWorldService helloWorldServiceRussian;
    . . .
}

Обновление

Обычно бин помечается как @Primary, если вы хотите его иметь. экземпляр компонента в качестве приоритетной опции, когда имеется несколько кандидатов на внедрение. Официально выполните c с хорошим примером .

@Profile только сужает поиск bean-компонентов, но, тем не менее, если у вас несколько бинов одного типа в одном профиле - @Primary для rescue (если вы автоматически проводите по типу, хотя autowire по квалификатору все еще работает нормально).

Разработчики обычно делают это, чтобы избежать NoUniqueBeanDefinitionException, который вы имели изначально.

0 голосов
/ 29 марта 2020

Если вы считаете этот исходный код

@Bean(name = "french")
public HelloWorldService helloWorldServiceFrench(HelloWorldFactory factory) {
    return factory.createHelloWorldService("fr");
}

@Bean
public HelloWorldService helloWorldServiceGerman(HelloWorldFactory factory) {
    return factory.createHelloWorldService("de");
}

@Bean
public HelloWorldService helloWorldServicePolish(HelloWorldFactory factory) {
    return factory.createHelloWorldService("pl");
}

@Bean
public HelloWorldService helloWorldServiceRussian(HelloWorldFactory factory) {
    return factory.createHelloWorldService("ru");
}

здесь нет аннотации @Profile, и именно поэтому Spring создает несколько бинов одного типа, если вы хотите, чтобы они распознавались по-разному, попробуйте дать им высокую квалификацию явное имя с помощью @Bean(name="polish") (или Spring в любом случае назначьте их, посмотрев на @Bean имя метода), а затем автоматически подключите, используя @Qualifier("polish")

...