了解配置文件中的主要注释



我正试图从这个视频中了解@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

最新更新