目录
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);
}
}