我正在尝试从此video了解@Profile中@Primary的行为
使用配置文件进行依赖注入。文件application.properties中的活动配置文件为english
,运行该配置文件会显示错误
expected single matching bean but found 2: helloWorldServiceEnglish,helloWorldServiceSpanish
在helloConfig.java中添加@Primary批注解决了该错误:
@Bean
@Profile("english")
@Primary
public HelloWorldService helloWorldServiceEnglish(HelloWorldFactory factory) {
return factory.createHelloWorldService("en");
}
当我使用Profile自动装配时,只有一个名为english
的Profile,那么为什么要搜索没有@Profile注释的其他bean?以及如何添加@Primary来改变这种行为?是否可以在不使用@primary的情况下运行此示例?
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=english
如果您考虑此源代码
@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的原因,如果您希望它们被不同地识别,请尝试使用@Bean(name="polish")
为它们指定完全合格的显式名称(或者Spring总是通过查看[ C0]方法名称),然后使用@Bean
好的,因此您的示例未使用最新代码进行更新。但是我假设您想创建相同bean类型的多个实例,并将它们用于不同的语言。这很容易实现,因此您不需要@Qualifier("polish")
和@Profile
。
[您需要为bean实例分配限定符(或使用spring默认分配的限定符)。然后通过该限定符注入bean。
@Primary
控制器:
@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");
}
通常,当有多个注入候选对象时,想要将一个bean实例作为优先选项时,通常将bean标记为@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
。
[Official doc with good example只是缩小了bean的搜索范围,但是仍然可以在同一个配置文件中使用多个相同类型的bean-拯救@Profile
(如果通过类型自动装配,但通过限定符自动装配仍然可以正常工作)。
开发人员通常这样做是为了避免最初使用的@Primary
。