How to Dynamically Inject and Select Spring Beans

Are you looking for a flexible way to choose between multiple service implementations in your Spring Boot application? In this tutorial, we’ll show you how to use Map injection to dynamically select and invoke Spring beans based on user input. This approach is perfect for scenarios where you have multiple strategies or services, such as sending messages via email or SMS.

What You’ll Learn

  • How to define a common interface for your services

  • How to implement multiple beans with custom names

  • How to inject all beans as a Map in your controller

  • How to select and use a service dynamically based on a request parameter

1. Define a Common Interface

First, create an interface that all your message services will implement:

MessageService.java

				
					public interface MessageService {
    void sendMessage(String message);
}
				
			

2. Implement Multiple Services with Custom Bean Names

Use the @Service("beanName") annotation to give each service a unique name. This name will be used as the key in the injected Map.

EmailService.java

				
					import org.springframework.stereotype.Service;

@Service("emailService")
public class EmailService implements MessageService {
    @Override
    public void sendMessage(String message) {
        System.out.println("Email sent: " + message);
    }
}
				
			

SMSService.java

				
					import org.springframework.stereotype.Service;

@Service("smsService")
public class SMSService implements MessageService {
    @Override
    public void sendMessage(String message) {
        System.out.println("SMS sent: " + message);
    }
}
				
			

3. Inject All Beans as a Map in Your Controller

Spring Boot allows you to inject all beans of a certain type as a Map<String, BeanType>. The key is the bean name, and the value is the bean instance.

MessageController.java

				
					import org.springframework.web.bind.annotation.*;
import java.util.Map;

@RestController
@RequestMapping("/api/message")
public class MessageController {

    private final Map<String, MessageService> messageServiceMap;

    public MessageController(Map<String, MessageService> messageServiceMap) {
        this.messageServiceMap = messageServiceMap;
    }

    @GetMapping("/send")
    public String sendMessage(@RequestParam String type, @RequestParam String msg) {
        MessageService service = messageServiceMap.get(type);
        if (service != null) {
            service.sendMessage(msg);
            return "Message sent via: " + type;
        } else {
            return "Service not found for type: " + type;
        }
    }
}
				
			

4. Example API Calls

Try these API calls to see dynamic bean selection in action:

Send Email:

				
					GET /api/message/send?type=emailService&msg=Hello

Output:
      Email sent: Hello
				
			

Send SMS:

				
					GET /api/message/send?type=smsService&msg=Hello

Output:
      SMS sent: Hello
				
			

Why Use Map Injection in Spring?

 

  • Flexibility: Add new message services (e.g., Push Notification) without changing controller logic.

  • Maintainability: Decouple service selection from your controller logic.

  • Scalability: Easily support many strategies or implementations.

Conclusion

Map injection in Spring Boot is a powerful technique for building flexible and maintainable applications. By injecting all beans of a certain type as a Map, you can easily select the right implementation at runtime based on user input or other criteria. Try this pattern in your next project to simplify your code and support more features with less effort!


Ready to level up your Spring Boot skills? Try this pattern in your next project and share your experience in the comments below!

Share the Post: