Spring - @Configuration selection by using ImportSelector

[Updated: Dec 26, 2016, Created: Dec 26, 2016]

@Import annotation can be used for importing bean definitions from other @Configuration classes.

@Import annotation can also be configured with an ImportSelector implementation to select @Configuration classes programmatically, based on some selection criteria.

Let's understand that with an example.


Implementing ImportSelector

In this example we are selecting @Configuration classes, based on a System property value.

public class MyImportSelector implements ImportSelector {

      @Override
      public String[] selectImports (AnnotationMetadata importingClassMetadata) {
          String prop = System.getProperty("myProp");
          if ("someValue".equals(prop)) {
              return new String[]{MyConfig1.class.getName()};
          } else {
              return new String[]{MyConfig2.class.getName()};
          }
      }
}
@Configuration
public class MyConfig1 {
    @Bean
    AppBean appBean () {
        return new AppBean("from config 1");
    }
}
@Configuration
public class MyConfig2 {
    @Bean
    AppBean appBean () {
        return new AppBean("from config 2");
    }
}
public class AppBean {
    private String message;

    public AppBean (String message) {
        this.message = message;
    }

    public String getMessage () {
        return message;
    }
}

Main Configuration

@Configuration
@Import(MyImportSelector.class)
public class MainConfig {

    @Bean
    ClientBean clientBean () {
        return new ClientBean();
    }

}
public class ClientBean {
    @Autowired
    private AppBean appBean;

    public void doSomething () {
        System.out.println(appBean.getMessage());
    }
}

The main method

public class ImportSelectorExample {

   public static void main (String[] args) {
        System.setProperty("myProp", "someValue");

       ApplicationContext context =
                 new AnnotationConfigApplicationContext(
                           MainConfig.class);
       ClientBean bean = context.getBean(ClientBean.class);
       bean.doSomething();
   }
}

Output

from config 1



Using Annotation based ImportSelector

Let's modify above example to see how to use a user defined annotation along with ImportSelector.

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Import(MyImportSelector.class)
public @interface EnableSomeModule {
      String value () default "";
}
import org.springframework.context.annotation.*;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.type.AnnotationMetadata;

public class MyImportSelector implements ImportSelector {

    @Override
    public String[] selectImports (AnnotationMetadata importingClassMetadata) {
        AnnotationAttributes attributes = AnnotationAttributes.fromMap(
                  importingClassMetadata.getAnnotationAttributes(
                                         EnableSomeModule.class.getName(), false));

        String value = attributes.getString("value");
        if ("someValue".equals(value)) {
            return new String[]{MyConfig1.class.getName()};
        } else {
            return new String[]{MyConfig2.class.getName()};
        }
    }
}

In our main configuration class we will use our new annotation instead of directly using @Import:

@Configuration
@EnableSomeModule("someValue")
public static class MainConfig {
    @Bean
    ClientBean clientBean () {
        return new ClientBean();
    }
}

Other classes remains the same. Here's the main method:

public class ImportSelectorWithAnnotationExample {
  public static void main (String[] args) {
      ApplicationContext context =
                new AnnotationConfigApplicationContext(
                          MainConfig.class);
      ClientBean bean = context.getBean(ClientBean.class);
      bean.doSomething();
  }

Output

from config 1



ImportSelector use cases

ImportSelector can be used for dynamic configuration selection rather than static @Profile based selection.

Spring framework itself uses ImportSelector at many places to ease the configuration burden on the client side, for example @EnableAsync, @EnableScheduling etc.




Example Project


Dependencies and Technologies Used :
  • Spring Context 4.3.4.RELEASE: Spring Context.
  • JDK 1.8
  • Maven 3.3.9

Spring Import Selector Examples Select All Download
  • spring-import-selector
    • src
      • main
        • java
          • com
            • logicbig
              • example