1. Overview
1.概述
Naming a Spring bean is quite helpful when we have multiple implementations of the same type. This is because it’ll be ambiguous to Spring to inject a bean if our beans don’t have unique names.
当我们有多个相同类型的实现时,命名Spring Bean是非常有用的。这是因为如果我们的Bean没有唯一的名字,那么Spring在注入Bean时就会产生歧义。
By having control over naming the beans, we can tell Spring which bean we want to inject into the targeted object.
通过对Bean命名的控制,我们可以告诉Spring我们想把哪个Bean注入到目标对象中。
In this article, we’ll discuss Spring bean naming strategies and also explore how we can give multiple names to a single type of bean.
在这篇文章中,我们将讨论Spring Bean的命名策略,同时探讨如何为单一类型的Bean赋予多个名字。
2. Default Bean Naming Strategy
2.默认的 Bean 命名策略
Spring provides multiple annotations for creating beans. We can use these annotations at different levels. For example, we can place some annotations on a bean class and others on a method that creates a bean.
Spring为创建Bean提供了多种注解。我们可以在不同层次上使用这些注解。例如,我们可以将一些注解放在Bean类上,另一些注解放在创建Bean的方法上。
First, let’s see the default naming strategy of Spring in action. How does Spring name our bean when we just specify the annotation without any value?
首先,让我们看看Spring的默认命名策略是如何运作的。当我们只指定注解而没有任何值时,Spring是如何命名我们的Bean的?
2.1. Class-Level Annotations
2.1.类级注解
Let’s start with the default naming strategy for an annotation used at the class level. To name a bean, Spring uses the class name and converts the first letter to lowercase.
让我们从在类级使用的注释的默认命名策略开始。要命名一个Bean,Spring使用类的名称,并将第一个字母转换成小写。
Let’s take a look at an example:
我们来看看一个例子。
@Service
public class LoggingService {
}
Here, Spring creates a bean for the class LoggingService and registers it using the name “loggingService“.
在这里,Spring为LoggingService类创建了一个Bean,并使用”loggingService“的名字注册了它。
This same default naming strategy is applicable for all class-level annotations that are used to create a Spring bean, such as @Component, @Service, and @Controller.
这种默认的命名策略同样适用于所有用于创建Spring Bean的类级注释,例如@Component,@Service,和@Controller。
2.2. Method-Level Annotation
2.2.方法层面的注释
Spring provides annotations like @Bean and @Qualifier to be used on methods for bean creation.
Spring提供了像@Bean和@Qualifier这样的注解,可用于创建Bean的方法。
Let’s see an example to understand the default naming strategy for the @Bean annotation:
让我们看一个例子来理解@Bean注解的默认命名策略。
@Configuration
public class AuditConfiguration {
@Bean
public AuditService audit() {
return new AuditService();
}
}
In this configuration class, Spring registers a bean of type AuditService under the name “audit” because when we use the @Bean annotation on a method, Spring uses the method name as a bean name.
在这个配置类中,Spring以”Audit“的名字注册了一个AuditService类型的Bean,因为当我们在一个方法上使用@Bean注解时,Spring将该方法名作为Bean名。
We can also use the @Qualifier annotation on the method, and we’ll see an example of it below.
我们还可以在方法上使用@Qualifier注解,下面我们将看到一个例子。
3. Custom Naming of Beans
3.Bean的自定义命名
When we need to create multiple beans of the same type in the same Spring context, we can give custom names to the beans and refer to them using those names.
当我们需要在同一个Spring上下文中创建多个相同类型的Bean时,我们可以给Bean自定义名称,并使用这些名称来引用它们。
So, let’s see how can we give a custom name to our Spring bean:
那么,让我们看看如何给我们的Spring Bean起一个自定义的名字。
@Component("myBean")
public class MyCustomComponent {
}
This time, Spring will create the bean of type MyCustomComponent with the name “myBean“.
这一次,Spring将创建类型为MyCustomComponent的Bean,名称为”myBean“。
As we’re explicitly giving the name to the bean, Spring will use this name, which can then be used to refer to or access the bean.
由于我们明确地给Bean起了名字,Spring会使用这个名字,然后可以用这个名字来引用或访问Bean。
Similar to @Component(“myBean”), we can specify the name using other annotations such as @Service(“myService”), @Controller(“myController”), and @Bean(“myCustomBean”), and then Spring will register that bean with the given name.
与@Component(“myBean”)类似,我们可以使用其他注解来指定名称,如@Service(“myService”)、@Controller(“myController”)和@Bean(“myCustomBean”),然后Spring将以给定名称注册该bean。
4. Naming Bean With @Bean and @Qualifier
4.用@Bean和@Qualifier命名Bean
4.1. @Bean With Value
4.1.@Bean有值
As we saw earlier, the @Bean annotation is applied at the method level, and by default, Spring uses the method name as a bean name.
正如我们前面所看到的,@Bean注解被应用于方法层面,默认情况下,Spring将方法名作为Bean名。
This default bean name can be overwritten — we can specify the value using the @Bean annotation:
这个默认的Bean名称可以被覆盖–我们可以使用 @Bean 注解来指定值。
@Configuration
public class MyConfiguration {
@Bean("beanComponent")
public MyCustomComponent myComponent() {
return new MyCustomComponent();
}
}
In this case, when we want to get a bean of type MyCustomComponent, we can refer to this bean by using the name “beanComponent“.
在这种情况下,当我们想获得一个MyCustomComponent类型的bean时,我们可以通过使用”beanComponent“这个名字来引用这个bean。
The Spring @Bean annotation is usually declared in configuration class methods. It may reference other @Bean methods in the same class by calling them directly.
Spring的@Bean注解通常在配置类方法中声明。它可以通过直接调用同一类中的其他@Bean方法来引用它们。
4.2. @Qualifier With Value
4.2.@Qualifier有值
We can also use the @Qualifier annotation to name the bean.
我们还可以使用@Qualifier注解来命名Bean。
First, let’s create an interface Animal that will be implemented by multiple classes:
首先,让我们创建一个接口Animal,它将被多个类所实现。
public interface Animal {
String name();
}
Now, let’s define an implementation class Cat and add the @Qualifier annotation to it with value “cat“:
现在,让我们定义一个实现类Cat,并为其添加@Qualifier注解,值为”cat“。
@Component
@Qualifier("cat")
public class Cat implements Animal {
@Override
public String name() {
return "Cat";
}
}
Let’s add another implementation of Animal and annotate it with @Qualifier and the value “dog“:
让我们添加另一个Animal的实现,并用@Qualifier和值”dog“来注释它:
@Component
@Qualifier("dog")
public class Dog implements Animal {
@Override
public String name() {
return "Dog";
}
}
Now, let’s write a class PetShow where we can inject the two different instances of Animal:
现在,让我们写一个PetShow类,在这里我们可以注入Animal的两个不同实例。
@Service
public class PetShow {
private final Animal dog;
private final Animal cat;
public PetShow (@Qualifier("dog")Animal dog, @Qualifier("cat")Animal cat) {
this.dog = dog;
this.cat = cat;
}
public Animal getDog() {
return dog;
}
public Animal getCat() {
return cat;
}
}
In the class PetShow, we’ve injected both the implementations of type Animal by using the @Qualifier annotation on the constructor parameters, with the qualified bean names in value attributes of each annotation. Whenever we use this qualified name, Spring will inject the bean with that qualified name into the targeted bean.
在PetShow类中,我们通过在构造函数参数上使用@Qualifier注解,注入了Animal类型的两个实现,每个注解的值属性中都有限定的bean名称。每当我们使用这个限定名称时,Spring将把具有该限定名称的Bean注入到目标Bean中。
5. Verifying Bean Names
5.核实Bean名称
So far, we’ve seen different examples to demonstrate giving names to Spring beans. Now the question is, how we can verify or test this?
到目前为止,我们已经看到了不同的例子来证明给Spring Bean起名。现在的问题是,我们如何验证或测试这一点?
Let’s look at a unit test to verify the behavior:
让我们看看一个单元测试来验证这个行为。
@ExtendWith(SpringExtension.class)
public class SpringBeanNamingUnitTest {
private AnnotationConfigApplicationContext context;
@BeforeEach
void setUp() {
context = new AnnotationConfigApplicationContext();
context.scan("com.baeldung.springbean.naming");
context.refresh();
}
@Test
void givenMultipleImplementationsOfAnimal_whenFieldIsInjectedWithQualifiedName_thenTheSpecificBeanShouldGetInjected() {
PetShow petShow = (PetShow) context.getBean("petShow");
assertThat(petShow.getCat().getClass()).isEqualTo(Cat.class);
assertThat(petShow.getDog().getClass()).isEqualTo(Dog.class);
}
In this JUnit test, we’re initializing the AnnotationConfigApplicationContext in the setUp method, which is used to get the bean.
在这个JUnit测试中,我们在setUp方法中初始化AnnotationConfigApplicationContext,该方法用于获取Bean。
Then we simply verify the class of our Spring beans using standard assertions.
然后,我们只需使用标准断言来验证我们的Spring Bean的类别。
6. Conclusion
6.结语
In this quick article, we’ve examined the default and custom Spring bean naming strategies.
在这篇快速文章中,我们已经研究了默认和自定义Spring Bean的命名策略。
We’ve also learned about how custom Spring bean naming is useful in use cases where we need to manage multiple beans of the same type.
我们还了解了自定义Spring Bean命名在我们需要管理多个相同类型的Bean的情况下是如何发挥作用的。
As usual, the complete code for this article is available over on GitHub.
像往常一样,本文的完整代码可以在GitHub上找到。