SpringBoot中的自动装载测试

Posted 天宇轩-王

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SpringBoot中的自动装载测试相关的知识,希望对你有一定的参考价值。

ImportSelector
ImportSelector接口是Spring导入外部配置的核心接口,在SpringBoot的自动化配置和@EnableXXX(功
能性注解)中起到了决定性的作用。当在@Configuration标注的Class上使用@Import引入了一个
ImportSelector实现类后,会把实现类中返回的Class名称都定义为bean。
DeferredImportSelector接口继承ImportSelector,他和ImportSelector的区别在于装载bean的时机
上,DeferredImportSelector需要等所有的@Configuration都执行完毕后才会进行装载

这个在我之前的博客也有写道:https://www.cnblogs.com/dalianpai/p/11722850.html


下面就写一个它的流程:

1)定义Bean对象

/**
 * bean对象
 */
@Data
public class User {
    private String username;
    private Integer age;
}

2)定义配置类Configuration

/**
 * 没有spring注解
 */
public class UserConfiguration {
    @Bean
    public User getUser() {
        User user = new User();
        user.setAge(12);
        user.setUsername("阿黄");
        return user;
    }
}

3 ) 定义ImportSelector

public class UserImportSelector implements ImportSelector {

    //@Configuration
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        //获取配置类的名称
        return new String[]{UserConfiguration.class.getName()};
    }
}

4) 定义EnableXXX注解

@Retention(RetentionPolicy.RUNTIME)
@Documented
@Target(ElementType.TYPE)
@Import(UserImportSelector.class)
public @interface EnableUserBean {
}

5 ) 测试

@EnableUserBean
public class TestApplication {

    /**
     *   --> EnableUserBean --> UserImportSelector --> UserConfiguration --> User
     * @param args
     */
    public static void main(String[] args) {
        //获取spring容器
        AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(TestApplication.class);
        User bean = ac.getBean(User.class);
        System.out.println(bean);
    }
}

由此可见,HelloWorldConfiguration对象并没有使用Spring的对象对象创建注解声明
(@Controller,@Service,@Repostiroty),而是使用编程的方式动态的载入bean。
我们可以来看一下ConfigurationClassParser这个类的processImports方法。

private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
            Collection<SourceClass> importCandidates, 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) {
                    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));
                    }
                }
            }
            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();
            }
        }
    }

 

以上是关于SpringBoot中的自动装载测试的主要内容,如果未能解决你的问题,请参考以下文章

Springbooy-自动装载

Springboot自动装配的原理

SpringBoot自动装配原理

Flask 编写http接口api及接口自动化测试

为啥片段恢复后再次调用onLoadFinished?

SpringBoot集成mybatis以及自动化测试代码实现