Spring Top

Get started with Spring 5 and Spring Boot 2, through the reference Learn Spring course:

>> LEARN SPRING

1. Overview

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

2. Spring ApplicationContext

Before we can understand the value of @Component, we must first understand a little bit about the Spring ApplicationContext. This is where Spring holds instances of objects that it has identified to be managed and distributed automatically. These are called beans. Bean management and the opportunity for dependency injection are some of Spring's main features.

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.

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.

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

3. @Component

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

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

  • 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

Spring has provided a few specialized stereotype annotations: @Controller, @Service, and @Repository. They all provide the same function as @Component. The reason they all act the same is that 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.

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. 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.

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

@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:

@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

Before we rely completely on @Component, we must understand that in and of itself, it's only a plain annotation. The annotation serves the purpose of differentiating beans from other objects, such as domain objects. However, Spring uses the @ComponentScan annotation to actually gather them all into its 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.

However, in the case that our @SpringBootApplication class cannot 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.

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

package com.baeldung.component.scannedscope;

@Component
public class ScannedScopeExample {
}

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

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

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

For example, let's define an object annotated with @Component in a package outside of our project:

package com.baeldung.component.outsidescope;

@Component
public class OutsideScopeExample {
}

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

@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 3rd 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.

4. @Component vs. @Bean

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

To see an example of how it works, let's first create a POJO that has no annotations:

public class BeanExample {
}

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

@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.

We can then write a test that verifies Spring did pick up the 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 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 3rd 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

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. Then we learned that @Component doesn't do anything unless it can be found by @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.

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

Spring bottom

Get started with Spring 5 and Spring Boot 2, through the Learn Spring course:

>> THE COURSE
Generic footer banner
Comments are closed on this article!