zoukankan      html  css  js  c++  java
  • 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();
                }
            }
        }
  • 相关阅读:
    HashMap 和HashTable
    两种方式获得键盘录入
    打印流 printStream
    对象操作流--存储对象
    内存输出流
    序列流
    装饰设计模式
    递归
    IO流(使用指定的码表读写字符)
    IO-字符流 练习
  • 原文地址:https://www.cnblogs.com/dalianpai/p/12262878.html
Copyright © 2011-2022 走看看