1. 程式人生 > 其它 >Spring@Import註解的三種用法

Spring@Import註解的三種用法

技術標籤:Springspring

目錄

1.直接引入

2.引入ImportSelector的實現

3.引入ImportBeanDefinitionRegistrar的實現

4.Import原始碼解析

4.1如果引入的類是ImportBeanDefinitionRegistrar.class的實現類

4.2如果引入的類是ImportSelector.class的實現類

4.3如果引入的類是其他的類

4.4從配置類載入beanDefinition

4.4.1普通引入類註冊

4.4.2ImportBeanDefinitionRegistrar註冊bean


服務介面
public interface IUserService {
void sayHello();
}

服務實現

public class UserServiceImpl implements IUserService {
@Override
public void sayHello() {
System.out.println("xxx");
}
}

1.直接引入

@Import({UserServiceImpl.class})

@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}

2.引入ImportSelector的實現

public class MyImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
return new String[]{UserServiceImpl.class.getName()};
}
}

引入selector
@Import(MyImportSelector.class)
@SpringBootApplication
public class DemoApplication {

public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}

3.引入ImportBeanDefinitionRegistrar的實現

@Import(MyImportBeanDefinitionRegistrar.class)
@SpringBootApplication
public class DemoApplication {

public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}

註冊引入類的beanDefinition
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
registry.registerBeanDefinition("userService", new RootBeanDefinition(UserServiceImpl.class));
}
}

4.Import原始碼解析

以springBoot的啟動容器 AnnotationConfigApplicationContext為例,容器建立的時候,會建立bean定義閱讀器 AnnotatedBeanDefinitionReader,會往 beanFactorybeanDefinitionMap中註冊 ConfigurationClassPostProcessor的beanDefinition【Spring IOC載入過程】。他是 BeanDefinitionRegistryPostProcessor的實現類,所以他在容器呼叫 invokeBeanFactoryPostProcessors方法的時候會被提前例項化出來,並呼叫。 入口
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
int registryId = System.identityHashCode(registry);
if (this.registriesPostProcessed.contains(registryId)) {
throw new IllegalStateException(
"postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);
}
if (this.factoriesPostProcessed.contains(registryId)) {
throw new IllegalStateException(
"postProcessBeanFactory already called on this post-processor against " + registry);
}
this.registriesPostProcessed.add(registryId);


processConfigBeanDefinitions(registry);
}

解析配置類上所有import匯入的類getImports(sourceClass),找到候選類

private void collectImports(SourceClass sourceClass, Set<SourceClass> imports, Set<SourceClass> visited)
throws IOException {

 // 使用set跳過迴圈import
if (visited.add(sourceClass)) {
for (SourceClass annotation : sourceClass.getAnnotations()) {
String annName = annotation.getMetadata().getClassName();
if (!annName.equals(Import.class.getName())) {
    // 遞迴解析非import註解,處理深層次的import
collectImports(annotation, imports, visited);
}
}
  // 解析import註解的value屬性 
imports.addAll(sourceClass.getAnnotationAttributes(Import.class.getName(), "value"));
}
}

解析所有import直接引入的類

private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
Collection<SourceClass> importCandidates, Predicate<String> exclusionFilter,
boolean checkForCircularImports) {

 // 解析的配置類為空
if (importCandidates.isEmpty()) {
return;
}

 // 處理迴圈引入
if (checkForCircularImports && isChainedImportOnStack(configClass)) {
this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
}
else {
this.importStack.push(configClass);
try {
for (SourceClass candidate : importCandidates) {
    // 如果引入的類是ImportSelector.class的實現類
if (candidate.isAssignable(ImportSelector.class)) {
// Candidate class is an ImportSelector -> delegate to it to determine imports
    // 根據類名載入class
Class<?> candidateClass = candidate.loadClass();
    // 例項化selector
ImportSelector selector = ParserStrategyUtils.instantiateClass(candidateClass, ImportSelector.class,
this.environment, this.resourceLoader, this.registry);
Predicate<String> selectorFilter = selector.getExclusionFilter();
if (selectorFilter != null) {
exclusionFilter = exclusionFilter.or(selectorFilter);
}
    // 延遲引入
if (selector instanceof DeferredImportSelector) {
this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
}
else {
      // 呼叫自定義的selectImports方法,傳入了@Import註解所在類的元資料,拿到匯入的bean的類名
String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames, exclusionFilter);
      // 遞迴呼叫,如果引入的類也是importSelector或者ImportBeanDefinitionRegistrar也要解析
processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false);
}
}
    // 如果引入的類是ImportBeanDefinitionRegistrar.class的實現類
else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
// Candidate class is an ImportBeanDefinitionRegistrar ->
// delegate to it to register additional bean definitions
     // 載入實現類class
Class<?> candidateClass = candidate.loadClass();
    // 例項化實現類
ImportBeanDefinitionRegistrar registrar =
ParserStrategyUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class,
this.environment, this.resourceLoader, this.registry);
     // 放進map裡面存放起來importBeanDefinitionRegistrars等待呼叫
configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
}
else {
     // 直接引入的類 存入importStack
// 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), exclusionFilter);
}
}
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to process import candidates for configuration class [" +
configClass.getMetadata().getClassName() + "]", ex);
}
finally {
this.importStack.pop();
}
}
}

4.1如果引入的類是ImportBeanDefinitionRegistrar.class的實現類

把它載入並例項化出來,然後把它暫存到importBeanDefinitionRegistrars裡面,等待後續的解析

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 =
ParserStrategyUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class,
this.environment, this.resourceLoader, this.registry);
configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
}

4.2如果引入的類是ImportSelector.class的實現類

載入並例項化

else {
 // 呼叫實現類的selectImports方法,拿到需要引入的類名
String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames, exclusionFilter);
 // 遞迴處理引入的類,最終轉化為引入普通的類,從4.3出口出去
processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false);
}

4.3如果引入的類是其他的類

繫結引入的類和當前配置類,建立ConfigurationClass,等待後續解析

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), exclusionFilter);
}

候選類(引入的類)作為配置類來進行處理,等待後面的解析。candidate.asConfigClass(configClass),

在ConfigurationClass中會把當前類和引入類通過importedBy進行繫結,表示這是一個被引入的類。 後續在載入beanDefiniton的時候,通過configClass.isImported來判斷,如果是被引入的類,那麼就註冊到beanDefinitionMap中
public ConfigurationClass(MetadataReader metadataReader, @Nullable ConfigurationClass importedBy) {
this.metadata = metadataReader.getAnnotationMetadata();
this.resource = metadataReader.getResource();
this.importedBy.add(importedBy);
}

4.4從配置類載入beanDefinition

把bean定義寫入到beanDefinitionMap中

this.reader.loadBeanDefinitions(configClasses);
private void loadBeanDefinitionsForConfigurationClass(
ConfigurationClass configClass, 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);
}
 // 處理@Bean工廠方法引入
for (BeanMethod beanMethod : configClass.getBeanMethods()) {
loadBeanDefinitionsForBeanMethod(beanMethod);
}

 // 處理引入其他的配置檔案
loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
 // 解析前面的importBeanDefinitionRegistrars,註冊需要引入的beanDefinition
loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
}

4.4.1普通引入類註冊

private void registerBeanDefinitionForImportedConfigurationClass(ConfigurationClass configClass) {
AnnotationMetadata metadata = configClass.getMetadata();
AnnotatedGenericBeanDefinition configBeanDef = new AnnotatedGenericBeanDefinition(metadata);


ScopeMetadata scopeMetadata = scopeMetadataResolver.resolveScopeMetadata(configBeanDef);
configBeanDef.setScope(scopeMetadata.getScopeName());
String configBeanName = this.importBeanNameGenerator.generateBeanName(configBeanDef, this.registry);
AnnotationConfigUtils.processCommonDefinitionAnnotations(configBeanDef, metadata);


BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(configBeanDef, configBeanName);
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
this.registry.registerBeanDefinition(definitionHolder.getBeanName(), definitionHolder.getBeanDefinition());
configClass.setBeanName(configBeanName);


if (logger.isDebugEnabled()) {
logger.debug("Registered bean definition for imported class '" + configBeanName + "'");
}
}

4.4.2ImportBeanDefinitionRegistrar註冊bean

private void loadBeanDefinitionsFromRegistrars(Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> registrars) {
for (Map.Entry<ImportBeanDefinitionRegistrar, AnnotationMetadata> entry : registrars.entrySet()) {
entry.getKey().registerBeanDefinitions(entry.getValue(), this.registry);
}
}