Spring @Component Annotation – Spring @Component Annotation

最后修改: 2021年 2月 17日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

In this tutorial, we’ll take a comprehensive look at the Spring @Component annotation and related areas. We’ll see the different ways we can use it to integrate with some core Spring functionality and how to take advantage of its many benefits.

在本教程中,我们将全面了解Spring @Component注解和相关领域。我们将看到使用它与一些核心Spring功能集成的不同方式,以及如何利用它的许多优势。

2. Spring ApplicationContext

2.Spring ApplicationContext

Before we can understand the value of @Component, we first need to understand a little bit about the Spring ApplicationContext.

在我们理解@Component的价值之前,我们首先需要了解一下Spring ApplicationContext

Spring ApplicationContext is where Spring holds instances of objects that it has identified to be managed and distributed automatically. These are called beans.

Spring ApplicationContext是Spring保存对象实例的地方,它已经确定要自动管理和分发。这些被称为Bean。

Bean management and the opportunity for dependency injection are some of Spring’s main features.

Bean管理和依赖性注入的机会是Spring的一些主要特性。

Using the Inversion of Control principle, Spring collects bean instances from our application and uses them at the appropriate time. We can show bean dependencies to Spring without needing to handle the setup and instantiation of those objects.

使用控制反转原则Spring从我们的应用程序中收集Bean实例并在适当的时候使用它们。我们可以向Spring展示Bean的依赖关系,而不需要处理这些对象的设置和实例化。

The ability to use annotations like @Autowired to inject Spring-managed beans into our application is a driving force for creating powerful and scalable code in Spring.

使用像@Autowired这样的注解将Spring管理的Bean注入我们的应用程序的能力是在Spring中创建强大和可扩展代码的驱动力。

So, how do we tell Spring about the beans we want it to manage for us? We should take advantage of Spring’s automatic bean detection by using stereotype annotations on our classes.

那么,我们如何告诉Spring我们希望它为我们管理的bean呢?我们应该通过在我们的类上使用定型注解来利用Spring的自动Bean检测功能。

3. @Component

3.@Component

@Component is an annotation that allows Spring to automatically detect our custom beans.

@Component是一个注解,允许Spring自动检测我们的自定义Bean。

In other words, without having to write any explicit code, Spring will:

换句话说,不需要写任何明确的代码,Spring就会。

  • Scan our application for classes annotated with @Component
  • Instantiate them and inject any specified dependencies into them
  • Inject them wherever needed

However, most developers prefer to use the more specialized stereotype annotations to serve this function.

然而,大多数开发者更愿意使用更专业的定型注释来实现这一功能。

3.1. Spring Stereotype Annotations

3.1.Spring定型的注解

Spring has provided a few specialized stereotype annotations: @Controller, @Service and @Repository. They all provide the same function as @Component.

Spring提供了一些专门的定型注解。@Controller, @Service@Repository。它们都提供了与@Component相同的功能。

They all act the same because they are all composed annotations with @Component as a meta-annotation for each of them. They are like @Component aliases with specialized uses and meaning outside of Spring auto-detection or dependency injection.

它们的行为都是一样的,因为它们都是由@Component作为元注解组成的。它们就像@Component的别名,在Spring自动检测或依赖注入之外有专门的用途和意义。

If we really wanted to, we could theoretically choose to use @Component exclusively for our bean auto-detection needs. On the flip side, we could also compose our own specialized annotations that use @Component.

如果我们真的想这样做,理论上我们可以选择只使用@Component来满足我们的Bean自动检测需求。另一方面,我们也可以组成我们自己的专门注释,使用@Component

However, there are other areas of Spring that look specifically for Spring’s specialized annotations to provide additional automation benefits. So, we should probably just stick with using the established specializations most of the time.

然而,Spring的其他领域专门寻找Spring的专业注解以提供额外的自动化优势。因此,我们也许应该坚持在大多数情况下使用既定的专业化。

Let’s assume we have an example of each of these cases in our Spring Boot project:

让我们假设在我们的Spring Boot项目中,这些情况都有一个例子。

@Controller
public class ControllerExample {
}

@Service
public class ServiceExample {
}

@Repository
public class RepositoryExample {
}

@Component
public class ComponentExample {
}

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Component
public @interface CustomComponent {
}

@CustomComponent
public class CustomComponentExample {
}

We could write a test that proves that each one is auto-detected by Spring and added to the ApplicationContext:

我们可以写一个测试,证明每个人都被Spring自动检测到并添加到ApplicationContext

@SpringBootTest
@ExtendWith(SpringExtension.class)
public class ComponentUnitTest {

    @Autowired
    private ApplicationContext applicationContext;

    @Test
    public void givenInScopeComponents_whenSearchingInApplicationContext_thenFindThem() {
        assertNotNull(applicationContext.getBean(ControllerExample.class));
        assertNotNull(applicationContext.getBean(ServiceExample.class));
        assertNotNull(applicationContext.getBean(RepositoryExample.class));
        assertNotNull(applicationContext.getBean(ComponentExample.class));
        assertNotNull(applicationContext.getBean(CustomComponentExample.class));
    }
}

3.2. @ComponentScan

3.2.@ComponentScan

Before we rely completely on @Component, we must understand that it’s only a plain annotation. The annotation serves the purpose of differentiating beans from other objects, such as domain objects.

在我们完全依赖@Component之前,我们必须了解它只是一个普通的注释。这个注解的作用是将Bean与其他对象(如领域对象)区分开来。

However, Spring uses the @ComponentScan annotation to actually gather them all into its ApplicationContext.

然而,Spring使用@ComponentScan注解来实际收集它们到其ApplicationContext

If we’re writing a Spring Boot application, it is helpful to know that @SpringBootApplication is a composed annotation that includes @ComponentScan. As long as our @SpringBootApplication class is at the root of our project, it will scan every @Component we define by default.

如果我们正在编写一个Spring Boot应用程序,知道@SpringBootApplication是一个包括@ComponentScan的组成注解是很有帮助的。只要我们的@SpringBootApplication类在我们项目的根部,它就会默认扫描我们定义的每一个@Component

But in case our @SpringBootApplication class can’t be at the root of our project or we want to scan outside sources, we can configure @ComponentScan explicitly to look in whatever package we specify, as long as it exists on the classpath.

但是,如果我们的@SpringBootApplication类不能在我们项目的根部,或者我们想扫描外部资源,我们可以明确配置@ComponentScan来寻找我们指定的任何包,只要它存在于classpath。

Let’s define an out-of-scope @Component bean:

让我们定义一个范围外的@Component Bean。

package com.baeldung.component.scannedscope;

@Component
public class ScannedScopeExample {
}

Next, we can include it via explicit instructions to our @ComponentScan annotation:

接下来,我们可以通过对我们的@ComponentScan注解的明确指示来包括它。

package com.baeldung.component.inscope;

@SpringBootApplication
@ComponentScan({"com.baeldung.component.inscope", "com.baeldung.component.scannedscope"})
public class ComponentApplication {
    //public static void main(String[] args) {...}
}

Finally, we can test that it exists:

最后,我们可以测试它是否存在。

@Test
public void givenScannedScopeComponent_whenSearchingInApplicationContext_thenFindIt() {
    assertNotNull(applicationContext.getBean(ScannedScopeExample.class));
}

In reality, this is more likely to happen when we want to scan for an outside dependency that is included in our project.

在现实中,当我们想扫描一个包含在我们项目中的外部依赖关系时,这种情况更有可能发生。

3.3. @Component Limitations

3.3.@Component的限制

There are some scenarios where we want a certain object to become a Spring-managed bean when we can’t use @Component.

在某些情况下,当我们不能使用@Component时,我们希望某个对象成为Spring管理的bean。

Let’s define an object annotated with @Component in a package outside of our project:

让我们在我们项目之外的包中定义一个用@Component注释的对象。

package com.baeldung.component.outsidescope;

@Component
public class OutsideScopeExample {
}

Here is a test that proves that the ApplicationContext does not include the outside component:

这里有一个测试,证明ApplicationContext不包括外部组件。

@Test
public void givenOutsideScopeComponent_whenSearchingInApplicationContext_thenFail() {
    assertThrows(NoSuchBeanDefinitionException.class, () -> applicationContext.getBean(OutsideScopeExample.class));
}

Also, we may not have access to the source code because it comes from a third-party source, and we’re unable to add the @Component annotation. Or perhaps we want to conditionally use one bean implementation over another depending on the environment we’re running in. Auto-detection is sufficient most of the time, but when it’s not, we can use @Bean.

另外,我们可能无法访问源代码,因为它来自第三方来源,我们无法添加@Component注解。或者我们想根据我们运行的环境,有条件地使用一个bean的实现而不是另一个。自动检测在大多数情况下是足够的,但当它不足够时,我们可以使用@Bean

4. @Component vs @Bean

4.@Component@Bean对比

@Bean is also an annotation that Spring uses to gather beans at runtime, but it’s not used at the class level. Instead, we annotate methods with @Bean so that Spring can store the method’s result as a Spring bean.

@Bean也是Spring用来在运行时收集Bean的注解,但它不是在类的层次上使用。相反,我们用@Bean来注解方法,这样Spring就可以将方法的结果存储为一个Spring Bean。

We’ll first create a POJO that has no annotations:

我们首先创建一个没有注解的POJO。

public class BeanExample {
}

Inside of our class annotated with @Configuration, we can create a bean generating method:

在我们用@Configuration注解的类中,我们可以创建一个bean生成方法。

@Bean
public BeanExample beanExample() {
    return new BeanExample();
}

BeanExample might represent a local class, or it might be an external class. It doesn’t matter because we simply need to return an instance of it.

BeanExample可能代表一个本地类,也可能是一个外部类。这并不重要,因为我们只需要返回它的一个实例。

We can then write a test that verifies Spring did pick up the bean:

然后,我们可以写一个测试来验证Spring是否捡到了Bean。

@Test
public void givenBeanComponent_whenSearchingInApplicationContext_thenFindIt() {
    assertNotNull(applicationContext.getBean(BeanExample.class));
}

There are some important implications we should note because of the differences between @Component and @Bean.

由于@Component@Bean之间的差异,有一些重要的影响我们应该注意。

  • @Component is a class-level annotation, but @Bean is at the method level, so @Component is only an option when a class’s source code is editable. @Bean can always be used, but it’s more verbose.
  • @Component is compatible with Spring’s auto-detection, but @Bean requires manual class instantiation.
  • Using @Bean decouples the instantiation of the bean from its class definition. This is why we can use it to make even third-party classes into Spring beans. It also means we can introduce logic to decide which of several possible instance options for a bean to use.

5. Conclusion

5.总结

We’ve just explored the Spring @Component annotation as well as other relevant topics. First, we discussed the various Spring stereotype annotations, which are just specialized versions of @Component.

我们刚刚探讨了Spring的@Component注解以及其他相关话题。首先,我们讨论了各种Spring定型注解,它们只是@Component的专门版本。

Then we learned that @Component doesn’t do anything unless it can be found by @ComponentScan.

然后我们了解到,@Component不会做任何事情,除非它能被@ComponentScan找到。

Finally, since it’s not possible to use @Component on classes that we don’t have the source code for, we learned how to use the @Bean annotation instead.

最后,由于不可能在我们没有源代码的类上使用@Component,我们学会了如何使用@Bean注解来代替。

All of these code examples and more can be found over on GitHub.

所有这些代码示例以及更多的代码都可以在GitHub上找到over