1. 程式人生 > 實用技巧 >Spring的@Import註解簡單介紹

Spring的@Import註解簡單介紹

Spring的@Import註解

作用

  1. 將沒有使用@Component註解的普通class加入到Spring容器, 由Spring管理
  2. 匯入一個Configuration類
  3. 通過實現了ImportSelector介面的類, 匯入多個class到Spring容器(SpringBoot的自動裝配@EnableAutoConfiguration)
  4. 通過實現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"
    };
  }
}

SpringBoot原始碼中使用了該方式

@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 {};

}

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匯入普通class到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);
  }
}