@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 ProjectDependencies and Technologies Used: - Spring Context 4.3.4.RELEASE: Spring Context.
- JDK 1.8
- Maven 3.3.9
|