You’ve learned by now that Spring provides different ways to create container-managed beans. One of them is by using the @Bean annotation and another is applying the @Component annotation. Both of them provide special objects that can be initialized at startup and automatically wired across different parts of an application. However, it might sometimes be unclear how to use them together and which of them to choose in certain cases.

In this topic, you will learn about the key differences between the @Bean and @Component annotations and how to use them together.

Using @Bean and @Component together

In practice, beans created manually by annotating a method with @Bean can be injected into components using the @Autowired annotation and it’s quite a canonical way of using them. In this case, @Bean is used to create different application- or component-wide configs and autowire them when needed.

To see how it works, let’s take a look at an application that generates random passwords. You’ve already seen it in previous topics. We are going to discuss three key parts of this application:

  • a configuration bean that is used to define a set of characters for creating passwords;
  • a component that requires this configuration bean and performs some calculations;
  • a component that is used to interact with the IO system.

Here is PasswordConfig that produces the bean containing the information about the alphabet we’d like to use:

@Configuration
public class PasswordConfig {
    private static final String ALPHA = "abcdefghijklmnopqrstuvwxyz";
    private static final String NUMERIC = "0123456789";
    private static final String SPECIAL_CHARS = "!@#$%^&*_=+-/";

    @Bean
    public PasswordAlphabet allCharacters() {
        return new PasswordAlphabet(ALPHA + NUMERIC + SPECIAL_CHARS);
    }

    static class PasswordAlphabet {
        private final String characters;

        public PasswordAlphabet(String characters) {
            this.characters = characters;
        }

        public String getCharacters() {
            return characters;
        }
    }
}

Below is a new version of the PasswordGenerator component that applies this config to the password generation process.

@Component
public class PasswordGenerator {
    private static final Random random = new Random();
    private final PasswordAlphabet alphabet;

    public PasswordGenerator(@Autowired PasswordAlphabet alphabet) {
        this.alphabet = alphabet;
    }

    public String generate(int length) {
        String allCharacters = alphabet.getCharacters(); // get the characters from the bean
        StringBuilder result = new StringBuilder();
        for (int i = 0; i < length; i++) {
            int index = random.nextInt(allCharacters.length());
            result.append(allCharacters.charAt(index));
        }
        return result.toString();
    }
}

And, last but not least, here is the component that is responsible for interacting with IO:

@Component
public class Runner implements CommandLineRunner {
    private final PasswordGenerator generator;

    public Runner(PasswordGenerator generator) {
        this.generator = generator;
    }

    @Override
    public void run(String... args) {
        System.out.println("A short password: " + generator.generate(5));
        System.out.println("A long password: " + generator.generate(10));
    }
}

If you run this application again, you will most likely get passwords containing digits and special characters.

A short password: e&7sd
A long password: up_&g4xtj7

Besides, it is possible to declare several alphabet config beans and, depending on our intentions, inject them using the @Qualifier annotation. It will allow you to make this application much more customizable for different use cases.

Usually, components depend on other components or objects produced by @Bean-annotated methods. However, technically, you can also autowire a component into the parameters of a method.

@Component vs @Bean

So far, we have used both @Bean and @Component annotations to create beans that can be injected into each other. Now let’s look at the differences between these annotations.

  • The @Bean annotation is a method-level annotation and @Component is a class level annotation.
  • The @Component annotation doesn’t need to be used with the @Configuration annotation whereas the @Bean annotation has to be used within the class which is annotated with @Configuration.
  • If you want to create a bean for a class from an external library, you cannot just add the @Component annotation because you cannot edit the class. However, you can declare a method annotated with @Bean and return an object of this class from this method.
  • There are several specializations of the @Component annotation, whereas @Bean doesn’t have them.

In most cases, you can use both approaches but Spring developers typically prefer @Component whenever possible. The @Bean annotation is mostly used for producing beans of unmodifiable classes or creating some configs.

Specializations of components

As we mentioned before, there are several specializations of components depending on their role in Spring applications:

  • @Component indicates a generic Spring-managed component;
  • @Service indicates a business logic component but doesn’t provide any additional functions;
  • @Controller / @RestController indicates a component that can work in a web environment;
  • @Repository indicates a component that interacts with an external data storage (e.g. a database).

In the following topics, you will learn more about different types of Spring components and the way they are typically used in applications. For now, you can just remember: if your component doesn’t need to communicate with a database or return an HTTP result, you can use just the @Service annotation whenever using the @Component annotation is possible. Overall, as long as you write simple programs, there should be no difference.

Conclusion

Now you’ve learned about the differences between the @Bean and @Component annotations and when to use them for developing Spring applications. We discussed an example with two components and one @Bean-annotated method and saw how these two concepts are used together to make your application more customizable. We also introduced several component specializations, and you are going to further explore and gradually start using them in future topics.

Leave a Reply

Your email address will not be published.