电子商务加盟网站建设,北京企业做网站费用,html软件官方下载,如何写一个ios的app文章目录 介绍Import导入bean的三种方式普通类ImportSelector接口ImportBeanDefinitionRegistrar接口 源码解析总结 介绍 
今天主要介绍Spring Import注解#xff0c;在Spring中Import使用得比较频繁#xff0c;它得作用是导入bean#xff0c;具体的导入方式有多种#xff… 文章目录 介绍Import导入bean的三种方式普通类ImportSelector接口ImportBeanDefinitionRegistrar接口 源码解析总结 介绍 
今天主要介绍Spring Import注解在Spring中Import使用得比较频繁它得作用是导入bean具体的导入方式有多种特别在SpringBoot项目中很多地方都使用到了Import注解特别对于一些和SpringBoot整合的组件其实现都大量使用了Import 例如使用Feign集成SpringBoot时会加上注解EnableFeignClients 使用Dubbo时会使用EnableDubbo等这些注解里面都使用了Import注解来注册一些bean。 
Import导入bean的三种方式 
Import导入bean有三种方式分别是导入普通类实现ImportSelector接口的类实现ImportBeanDefinitionRegistrar接口的类。 
普通类 
在开放过程中尽量保持类不要太过于庞大类过于庞大的话会变得臃肿复杂不好维护一个配置类中需要配置很多bean且逻辑实现也比较复杂代码量大如果全部都放在同一个配置类中这显然不太理智这时候我们可以将每个bean单独拿出来放到一个类里面然后使用Import注解导入如下代码所示。 
定义一个bean 
Data
public class UserBean {private String username;private String sex;
}导入bean 
Configuration
Import(value  {UserBean.class})  //注入普通Bean
public class ImportConfiguration {}从上面可以看出只需要在配置类上面使用Import注解导入对应Java Bean然后这个bean就能注册进IOC容器中。 
ImportSelector接口 
ImportSelector是一个接口可以通过实现它来完成bean的注册它只有一个selectImports()方法它会返回一个bean的名称数组这个数组中的bean名称就会被注册进IOC容器中。 
public class MyImportSelector implements ImportSelector {Overridepublic String[] selectImports(AnnotationMetadata importingClassMetadata) {return new String[]{UserBean.class.getName()};}
}ImportBeanDefinitionRegistrar接口 
使用ImportBeanDefinitionRegistrar也可以注册bean它会传入BeanDefinitionRegistry接口然后进可以注册bean这里注册的是bean的元信息BeanDefinition。 
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {Overridepublic void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {String name  UserBean.class.getName();BeanDefinitionBuilder builder  BeanDefinitionBuilder.rootBeanDefinition(UserBean.class);builder.addPropertyValue(sex,男);AbstractBeanDefinition beanDefinition  builder.getBeanDefinition();registry.registerBeanDefinition(name, beanDefinition);}
}源码解析 
spring容器启动后会在ConfigurationClassParser解析类中解析Import注解解析出需要注册的bean下面就是最关键的代码通过调用processImports方法然后解析出对应的bean可以看出有几个判断分别判断是否是ImportSelector类型ImportBeanDefinitionRegistrar类型如果都不是则证明是直接导入普通java类如果是普通java类和ImportSelector类型那么就会将要注册的bean加入一个Map集合configurationClasses中后续会将它进行注册如果是ImportBeanDefinitionRegistrar类型那么会将其加入一个Map集合importBeanDefinitionRegistrars中后续在扩展点会对它进行再次处理。 
private void processImports(ConfigurationClass configClass, ConfigurationClassParser.SourceClass currentSourceClass,CollectionConfigurationClassParser.SourceClass importCandidates, PredicateString exclusionFilter,boolean checkForCircularImports) {if (candidate.isAssignable(ImportSelector.class)) {Class? candidateClass  candidate.loadClass();ImportSelector selector  ParserStrategyUtils.instantiateClass(candidateClass, ImportSelector.class,this.environment, this.resourceLoader, this.registry);PredicateString selectorFilter  selector.getExclusionFilter();if (selectorFilter ! null) {exclusionFilter  exclusionFilter.or(selectorFilter);}if (selector instanceof DeferredImportSelector deferredImportSelector) {this.deferredImportSelectorHandler.handle(configClass, deferredImportSelector);} else {String[] importClassNames  selector.selectImports(currentSourceClass.getMetadata());CollectionConfigurationClassParser.SourceClass importSourceClasses  asSourceClasses(importClassNames, exclusionFilter);processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false);}} else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {Class? candidateClass  candidate.loadClass();ImportBeanDefinitionRegistrar registrar ParserStrategyUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class,this.environment, this.resourceLoader, this.registry);configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());} else {this.importStack.registerImport(currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());processConfigurationClass(candidate.asConfigClass(configClass), exclusionFilter);}}经过上面解析后Spring会注册Bean的元信息会通过configClass.isImported()判断bean是否是通过Import方式导入的普通bean或者ImportSelector类型的导入的bean如果是则执行registerBeanDefinitionForImportedConfigurationClass里面主要就是组装成BeanDefinition然后注册进BeanFactory。 
private void loadBeanDefinitionsForConfigurationClass(ConfigurationClass configClass, ConfigurationClassBeanDefinitionReader.TrackedConditionEvaluator trackedConditionEvaluator) {if (trackedConditionEvaluator.shouldSkip(configClass)) {String beanName  configClass.getBeanName();if (StringUtils.hasLength(beanName)  this.registry.containsBeanDefinition(beanName)) {this.registry.removeBeanDefinition(beanName);}this.importRegistry.removeImportingClass(configClass.getMetadata().getClassName());return;}if (configClass.isImported()) {registerBeanDefinitionForImportedConfigurationClass(configClass);}for (BeanMethod beanMethod : configClass.getBeanMethods()) {loadBeanDefinitionsForBeanMethod(beanMethod);}loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());}如果是通过ImportBeanDefinitionRegistrar方式则会调用loadBeanDefinitionsFromRegistrars里面会循环去执行我们自定义的ImportBeanDefinitionRegistrar然后进行bean的元信息注册。 
private void loadBeanDefinitionsFromRegistrars(MapImportBeanDefinitionRegistrar, AnnotationMetadata registrars) {registrars.forEach((registrar, metadata) -registrar.registerBeanDefinitions(metadata, this.registry, this.importBeanNameGenerator));}从上面的源码解析中我们看出通过Import直接导入普通的java类和导入实现了ImportSelector接口的类是直接注册进BeanFactory这两者本质是一样的而通过实现ImportBeanDefinitionRegistrar接口方式的类则需要去实现我们自定义的注册bean元信息的逻辑。 总结 
上面我们介绍了Import的一些场景Import用得最多还是一些和Spring结合的中间件里面也介绍了它的几种使用方式还对它的源码进行解析当然只是从它最主要的逻辑去分析深入的逻辑就没去一一详解掌握Import有助于我们在使用一些其他框架的时候能够了解框架的实现原理然后更好的去使用框架