@mapperscan注解_Spring的@Import注解详解

首先看下@Import的javadoc文档:

Provides functionality equivalent to the <import/> element in Spring XML. Allows for importing @Configuration classes, ImportSelector and ImportBeanDefinitionRegistrar implementations, as well as regular component classes (as of 4.2; analogous to AnnotationConfigApplicationContext.register).
@Bean definitions declared in imported @Configuration classes should be accessed by using @Autowired injection. Either the bean itself can be autowired, or the configuration class instance declaring the bean can be autowired. The latter approach allows for explicit, IDE-friendly navigation between @Configuration class methods.
May be declared at the class level or as a meta-annotation.

简单翻译一下,这里面说了3个点:

(1)@Import就是用来向容器中导入bean的,导入的方式有三种:导入@Configuration、导入ImportSelector、导入ImportBeanDefinitionRegistrar。

(2)被@Import的类是被加载到了Spring容器当中,因此无论是类本身还是类里面用@Bean注解定义的bean都可以被@Autowired注入。

(3)@Import可以加在类上面,也可以作为元注解加在注解上面

下面就来分别举例说明下。

1.导入@Configuration举例

//这是个普通的类
public class Service1 {
    public Service1(){
        System.out.println("Service1");
    }
}
//这是个配置类
@Configuration
public class DemoConfig {
    @Bean
    public Service2 service2(){
        return new Service2();
    }
}
@SpringBootApplication
//这样可以导入Service1和Service2这两个Bean
@Import({Service1.class, DemoConfig.class})
public class ImportDemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(ImportDemoApplication.class, args);
    }
}

2.导入ImportSelector举例

public class DemoImportSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        //这里返回bean的完整的名字
        return new String[]{"com.github.xjs.importdemo.service.Service3"};
    }
}
@SpringBootApplication
//这样就可以导入Service3这个bean
@Import({DemoImportSelector.class})
public class ImportDemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(ImportDemoApplication.class, args);
    }
}

3.导入ImportBeanDefinitionRegistrar举例

public class DemoRegistrar implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        //可以直接向容器注册bean
        GenericBeanDefinition bd = new GenericBeanDefinition();
        bd.setBeanClass(Service4.class);
        registry.registerBeanDefinition("service4", bd);
    }
}
@SpringBootApplication
//这样就可以导入Service4这个bean
@Import({DemoRegistrar.class})
public class ImportDemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(ImportDemoApplication.class, args);
    }
}

4.@Import作为元注解使用举例

因为@Import可以作为元注解使用,因此可以用这个特性来做组件扫描,比如:

//首先定义一个用于扫描的注解,上面添加@Import元注解:
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Import({DemoImportSelector.class})
public @interface DemoScan {
    /**
     * 要扫描的根路径
     * */
    String basePackage() default "";
}

然后在启动类或者配置类上添加这个注解:

@SpringBootApplication
//首先添加这个注解
@DemoScan(basePackage="com.github.xjs")
@Import({DemoImportSelector.class, DemoRegistrar.class})
public class ImportDemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(ImportDemoApplication.class, args);
    }
}

无论是ImportSelector还是ImportBeanDefinitionRegistrar在回调中都可以使用AnnotationMetadata获取@DemoScan里面的属性:

public class DemoImportSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        //读取DemoScan的属性
        AnnotationAttributes annoAttrs = AnnotationAttributes.fromMap(
          importingClassMetadata.getAnnotationAttributes(DemoScan.class.getName()));
        String basePackage = annoAttrs.getString("basePackage");
        System.out.println("basePackage:"+basePackage);
        return new String[]{"com.github.xjs.importdemo.service.Service3"};
    }
}

拿到了要扫描的路径如何去扫描可以参考上一篇如何去扫描Mapper接口的,在Spring的源码中有大量的这种用法,比如:ServletComponentScan与ServletComponentScanRegistrar、MapperScan与MapperScannerRegistrar等等。

5.@Import解析的源码

// org.springframework.context.annotation.ConfigurationClassParser:
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
      Collection<SourceClass> importCandidates, boolean checkForCircularImports) {
  ...
  for (SourceClass candidate : importCandidates) {
    if (candidate.isAssignable(ImportSelector.class)) {
      // Candidate class is an ImportSelector -> delegate to it to determine imports
      Class<?> candidateClass = candidate.loadClass();
      ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class);
      ParserStrategyUtils.invokeAwareMethods(
      selector, this.environment, this.resourceLoader, this.registry);
      if (selector instanceof DeferredImportSelector) {
        this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
      }else {
        String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
        Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
        processImports(configClass, currentSourceClass, importSourceClasses, false);
      }
    }else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
      // Candidate class is an ImportBeanDefinitionRegistrar ->
      // delegate to it to register additional bean definitions
      Class<?> candidateClass = candidate.loadClass();
      ImportBeanDefinitionRegistrar registrar = BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class);
      ParserStrategyUtils.invokeAwareMethods(registrar, this.environment, this.resourceLoader, this.registry);
      configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
    }else {
      // Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->
      // process it as an @Configuration class
      this.importStack.registerImport(currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
      processConfigurationClass(candidate.asConfigClass(configClass));
    }
  }
  ...
}
}

完整的源码下载:

https://github.com/xjs1919/enumdemo 下的 import-demo

欢迎扫码加关注:

ae540b540f6e97d615170f7519965810.png
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值