Partner – Microsoft – NPI (cat= Spring)
announcement - icon

Azure Spring Apps is a fully managed service from Microsoft (built in collaboration with VMware), focused on building and deploying Spring Boot applications on Azure Cloud without worrying about Kubernetes.

And, the Enterprise plan comes with some interesting features, such as commercial Spring runtime support, a 99.95% SLA and some deep discounts (up to 47%) when you are ready for production.

>> Learn more and deploy your first Spring Boot app to Azure.

You can also ask questions and leave feedback on the Azure Spring Apps GitHub page.

1. Introduction

In this short tutorial, we’ll show how to dynamically autowire a bean in Spring.

We’ll start by presenting a real-world use case where dynamic autowiring might be helpful. In addition to this, we’ll show how to solve it in Spring in two different ways.

2. Dynamic Autowiring Use Cases

Dynamic autowiring is helpful in places where we need to dynamically change the Spring’s bean execution logic. It’s practical especially in places where what code to execute is chosen based on some runtime variables.

To demonstrate a real-world use case, let’s create an application that controls servers in different regions of the world. For this reason, we’ve created an interface with two simple methods:

public interface RegionService {
    boolean isServerActive(int serverId);

    String getISOCountryCode();
}

and two implementations:

@Service("GBregionService")
public class GBRegionService implements RegionService {
    @Override
    public boolean isServerActive(int serverId) {
        return false;
    }

    @Override
    public String getISOCountryCode() {
        return "GB";
    }
}
@Service("USregionService")
public class USRegionService implements RegionService {
    @Override
    public boolean isServerActive(int serverId) {
        return true;
    }

    @Override
    public String getISOCountryCode() {
        return "US";
    }
}

Let’s say we have a website where a user has an option to check whether the server is active in the selected region. Consequently, we’d like to have a service class that dynamically changes the RegionService interface implementation given the input of the user. Undoubtedly, this is the use case where dynamic bean autowiring comes into play.

3. Using BeanFactory

BeanFactory is a root interface for accessing a Spring bean container. In particular, it contains useful methods to obtain specific beans. Since BeanFactory is also a Spring bean, we can autowire and use it directly in our class:

@Service
public class BeanFactoryDynamicAutowireService {
    private static final String SERVICE_NAME_SUFFIX = "regionService";
    private final BeanFactory beanFactory;

    @Autowired
    public BeanFactoryDynamicAutowireService(BeanFactory beanFactory) {
        this.beanFactory = beanFactory;
    }

    public boolean isServerActive(String isoCountryCode, int serverId) {
        RegionService service = beanFactory.getBean(getRegionServiceBeanName(isoCountryCode), 
          RegionService.class);

        return service.isServerActive(serverId);
    }

    private String getRegionServiceBeanName(String isoCountryCode) {
        return isoCountryCode + SERVICE_NAME_SUFFIX;
    }
}

We’ve used an overloaded version of the getBean() method to get the bean with the given name and desired type.

And while this works, we’d really rather rely on something more idiomatic; that is, something that uses dependency injection.

4. Using Interfaces

To solve this with dependency injection, we’ll rely on one of Spring’s lesser-known features.

Besides standard single-field autowiring, Spring gives us an ability to collect all beans that are implementations of the specific interface into a Map:

@Service
public class CustomMapFromListDynamicAutowireService {
    private final Map<String, RegionService> servicesByCountryCode;

    @Autowired
    public CustomMapFromListDynamicAutowireService(List<RegionService> regionServices) {
        servicesByCountryCode = regionServices.stream()
                .collect(Collectors.toMap(RegionService::getISOCountryCode, Function.identity()));
    }

    public boolean isServerActive(String isoCountryCode, int serverId) {
        RegionService service = servicesByCountryCode.get(isoCountryCode);

        return service.isServerActive(serverId);
    }
}

We’ve created a map in a constructor that holds implementations by their country code. Furthermore, we can use it later in a method to get a particular implementation to check whether a given server is active in a specific region.

5. Conclusion

In this quick tutorial, we’ve seen how to dynamically autowire a bean in Spring using two different approaches.

As always, the code shown in this article is available on GitHub.

Course – LS (cat=Spring)

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

>> THE COURSE
res – REST with Spring (eBook) (everywhere)
Comments are open for 30 days after publishing a post. For any issues past this date, use the Contact form on the site.