我正试图从这个视频中了解@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是如何改变这种行为的?
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.propertiesspring.profiles.active=英文
完整源代码:
如果您考虑这个源代码
@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通过查看@Bean
方法名称来分配它们(,然后使用@Qualifier("polish")
自动连接
好的,所以您的示例没有用最新的代码更新。但是我假设您想要创建相同bean类型的多个实例,并将它们用于不同的语言。这很容易实现,而且不需要@Profile
和@Primary
。
您只需要为bean实例分配限定符(或者使用spring默认分配的限定符(。并通过这个限定符注入bean。
@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;
. . .
}
更新
当您希望有一个bean实例作为优先级选项时,当存在多个候选注入时,通常会将bean标记为@Primary
。具有良好榜样的官方文件。
@Profile
只是缩小了bean搜索范围,但如果在同一个配置文件中有多个相同类型的bean,则仍然可以使用@Primary
(如果按类型自动布线,则按限定符自动布线仍然可以正常工作(。
开发人员这样做通常是为了避免您最初使用的NoUniqueBeanDefinitionException
。