Pages

Monday, January 18, 2016

Auto-Wiring of Optional Beans with Spring using JSR-330

I've been using Spring for years and particularly like how little intrusive the framework is. For that reason I even still use the XML configuration option in order to have as little dependencies on the Spring framework as possible in my code. I also used to prefer explicit bean wiring over auto-wiring for the same reason, @Autowire is Spring annotation I tried to avoid; and also I have a tendency of being a control freak and didn't want some magic to determine my application setup. Not having a dependency on Spring is particularly important in my current project for various reasons. However, I'm over my control-freak attitude and with the arrival of JSR-330 I can get it all: Auto-wiring as well as JDK-only annotations/classes.

As one can see in the documentation of the Spring framework, Spring supports JSR-330 annotations for dependency injection. Auto-wiring of required dependencies is straight forward, @javax.inject.Inject can be used as a drop-in replacement for Springs own @Autowired annotation in that case. However, @Inject does not support the "required" attribute of @Autowired and there is no equivalent in Java 7. Java 8 supports an additional @Optional annotation, but there is nothing that simple in Java 7. However, JSR-330 defines a javax.inject.Provider<T> interface that can be used to achieve optional bean wiring: Instead of auto-wiring the actual bean, you can @Inject a provider to the bean and for example read it out after properties are set, in an init-method or at the time of access to the bean.

Here a short code snippet demonstrating the idea:

package com.example;

import javax.inject.Inject;
import javax.inject.Provider;

public class SomeBean {

    @Inject
    private Provider<ServiceBean> serviceBeanProvider;
    private ServiceBean serviceBean;

    private void lookupServiceBean() {
        if (serviceBean == null) {
            try {
                serviceBean = serviceBeanProvider.get();
            } catch (Exception e) {
                // not found
            }
        }
    }

[...]

}

Spring will wire in the Provider, which throws a NoSuchBeanException if the bean is not found. Again, to keep out all Spring dependencies I'll just catch all exceptions here.

No comments:

Post a Comment