目錄
Spring的@Import注解
作用
- 將沒有使用@Component注解的普通class加入到Spring容器, 由Spring管理
- 導入一個Configuration類(比如你想組合多個Java Config類到一個Java Config類, 或者你引入的第三方jar包中的Java Config類沒在你SpringBoot程序的子包下, 即沒有被掃描進Spring容器)
- 通過實現了ImportSelector接口的類, 導入多個class到Spring容器(SpringBoot的自動裝配@EnableAutoConfiguration)
- 通過實現ImportBeanDefinitionRegistrar接口的方式(MyBatis整合Spring: MapperScannerRegistrar.java和@MapperScan注解)
示例
1. 將普通Class加入到Spring容器
普通class
沒有使用@Component注解, 有一個實例方法.
/**
* 一個普通的class, 沒有被打上{@link org.springframework.stereotype.Component}注解, 后續使用@Import導入到Spring容器
*
* @author rhyme
*/
@Slf4j
public class ClassWithoutComponentAnnotation {
public boolean methodA() {
log.info("ClassWithoutComponentAnnotation對象的**實例方法**methodA被調用");
return true;
}
}
2. @Import Java Config
將該類也和上面一樣, 由@Import引入就行
@Configuration
public class ClassWithConfigurationAnnotation {
@Bean
public DemoClass demoClass() {
return new DemoClass();
}
}
3. 實現了ImportSelector接口的類, 導入多個class到Spring容器
實現了ImportSelector接口的類
/** @author rhyme */
public class ClassImplementsImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[] {
"java.basic.demos.springannotation.Import.classimplementsimportselector.ClassA",
"java.basic.demos.springannotation.Import.classimplementsimportselector.ClassB"
};
}
}
各種@EnableXXX注解, 比如SpringBoot源碼中的@EnableAutoConfiguration和@EnableCircuitBreaker
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
/**
* Exclude specific auto-configuration classes such that they will never be applied.
* @return the classes to exclude
*/
Class<?>[] exclude() default {};
/**
* Exclude specific auto-configuration class names such that they will never be
* applied.
* @return the class names to exclude
* @since 1.3.0
*/
String[] excludeName() default {};
}
/**
* Annotation to enable a CircuitBreaker implementation.
* https://martinfowler.com/bliki/CircuitBreaker.html
* @author Spencer Gibb
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(EnableCircuitBreakerImportSelector.class)
public @interface EnableCircuitBreaker {
}
4. 實現ImportBeanDefinitionRegistrar接口的方式
實現了ImportBeanDefinitionRegistrar接口, 注冊自己的bean
/** @author rhyme */
public class ClassImplementImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(
AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
RootBeanDefinition root = new RootBeanDefinition(ClassC.class);
registry.registerBeanDefinition("classC", root);
}
}
MyBatis整合Spring源碼
/**
* A {@link ImportBeanDefinitionRegistrar} to allow annotation configuration of
* MyBatis mapper scanning. Using an @Enable annotation allows beans to be
* registered via @Component configuration, whereas implementing
* {@code BeanDefinitionRegistryPostProcessor} will work for XML configuration.
*
* @author Michael Lanyon
* @author Eduardo Macarron
*
* @see MapperFactoryBean
* @see ClassPathMapperScanner
* @since 1.2.0
*/
public class MapperScannerRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware {
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(MapperScannerRegistrar.class)
public @interface MapperScan {
5. 使用@Import搭配@Configuration導入到Spring容器
/**
* @Import注解, 搭配@Configuration, 見ImportConfigTest.java<br>
* 1. 將沒有使用@Component注解的普通class加入到Spring容器, 由Spring管理<br>
* 2. 導入一個Configuration類 <br>
* 3. 通過實現了ImportSelector接口的類, 導入多個class到Spring容器(**SpringBoot的自動裝配@EnableAutoConfiguration**) <br>
* 4. 通過實現ImportBeanDefinitionRegistrar接口的方式(MyBatis整合Spring:MapperScannerRegistrar.java和@MapperScan注解)
*
* @author rhyme
*/
@Configuration
@Import({
ClassWithoutComponentAnnotation.class,
ClassWithConfigurationAnnotation.class,
ClassImplementsImportSelector.class,
ClassImplementImportBeanDefinitionRegistrar.class
})
public class ImportConfig {}
6. 測試
@RunWith(SpringRunner.class)
@SpringBootTest
public class ImportConfigTest {
@Autowired private ClassWithoutComponentAnnotation classWithoutComponentAnnotation;
@Autowired private DemoClass demoClass;
@Autowired private ClassA classA;
@Autowired private ClassB classB;
@Autowired private ClassC classC;
/** 通過@Autowired獲取@Import的類 */
@Test
public void importClass2SpringContainerTest() {
Assert.assertNotNull(classWithoutComponentAnnotation);
Assert.assertNotNull(demoClass);
Assert.assertNotNull(classA);
Assert.assertNotNull(classB);
Assert.assertNotNull(classC);
}
}
