DEV Community

loading...

@Bean and @Component. What is the different? Which one should use be used?

Tin Trinh
Fullstack Software Engineer, love automation, coding, writing.
・2 min read

The most benefit of using a framework like Spring is auto-configuration. By only introducing the library or the module to the classpath, Spring could automatically scan it and create the necessary object and @Autowrired it.

@Component is an annotation that annotates a class. It tells Spring to use this class to create a bean if there is somewhere else depend on this class. The creation of the class is totally controlled by Spring. And only one bean created per class.

@Component
class UserService {
    public void updateUser(User user) {
    
    }
}

@Controller
class UserController {
    private final UserService userService;

    @Autowired
    public UserController(UserService userService) {
        this.userService = userService;
    }
}

In this example, Spring will recognize the appearance of the UserSerivce class because it was marked with @Component annotation. So when it tries to initiate the UserController object, it knows that it needs a UserService to put to UserController constructor. And the creation of the UserService will be controlled totally by Spring. It is a pretty declarative way to define dependency.

With @Component our life is so good. So why do we even need something like @Bean annotation? When should we use it? First, @Bean is an annotation that used for annotating the function (not a class) that will return an object of a class that will be registered as a bean object by Spring.

You could use it in case you are using a third-party library when you don’t have access to the source code of the library. So you can’t just put @Component annotation of the class that you to create a bean.
You can combine with the @Configuration annotated the class that contains the method return the beans or otherwise Spring won’t catch and register it as a bean for your dependency resolution.
Let’s consider this example.

class UserService {
    private final PasswordEncoder encoder;

    @Autowired
    public UserService(PasswordEncoder encoder) {    
            this.encoder = encoder;
    }

    public String createUser(UserCreateReq req) {
        UserEntity user = UserEntity.builder()
                            .setPassword(this.encoder.encode(req.getPassword()))
                            
                            .build();
        repo.save(user);
    }
} 

@Configuration
class PasswordEncoderConfiguration {
    @Bean
    public PasswordEncoder bCryptPasswordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

In this example, I couldn’t change the code base of the bcrypt library so to create the encoder object. I have to use a @Configuration class to create the bean that I need in a method inside that @Configuration class. In this way, we could create as many as you want bean objects. And you have to explicitly configure those bean by yourself when the conflict happens. One way to resolve that conflict is by using the @Qualifier annotation in the constructor of the dependent class.

That's all. Happy coding.

Discussion (0)