Spring boot 소스 코드 분석 - SpringBootApplication 주석 (8)

26518 단어 spring-boot
Spring boot 소스 코드 분석 - SpringBootApplication 주석 (8)
우 리 는 분명히 매우 이상 할 것 이다. SpringApplication. run (Chapter Profiles Application. class, args) 을 호출 할 것 이다.의 코드 는 어떻게 spring 을 시작 하고 모든 bean 을 불 러 오 는 지, 사실은 관건 은 SpringBootApplication 주석 입 니 다. 오늘 우 리 는 이 주 해 를 설명 하 겠 습 니 다.
  • 이 주해 의 원본 코드 를 먼저 보 세 요. 주요 구성 은 @ SpringBootConfiguration, @ EnableAutoConfiguration, @ ComponentScan, scanBasePackages (), scanBasePackageClasses () 등 매개 변수
  • 가 있 습 니 다.
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Inherited
    @SpringBootConfiguration
    @EnableAutoConfiguration
    @ComponentScan(excludeFilters = @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class))
    public @interface SpringBootApplication {
    
        Class>[] exclude() default {};
    
        String[] excludeName() default {};
    
        @AliasFor(annotation = ComponentScan.class, attribute = "basePackages")
        String[] scanBasePackages() default {};
    
    
        @AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses")
        Class>[] scanBasePackageClasses() default {};
    
    }
  • 그리고 @ SpringBootConfiguration 주 해 를 보십시오. 사실은 @ Configuration 에 대한 포장 입 니 다. @ Configuration 주해
  • 라 고 볼 수 있 습 니 다.
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Configuration
    public @interface SpringBootConfiguration {
    
    }
  • @ EnableAutoConfiguration 주 해 는 사실 두 개의 Import 클래스 를 포함 하고 있 습 니 다. 하 나 는 EnableAutoConfiguration ImportSelector. class 이 고 다른 하 나 는 AutoConfiguration Packages. Registrar. class
  • 입 니 다.
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Inherited
    @AutoConfigurationPackage
    @Import(EnableAutoConfigurationImportSelector.class)
    public @interface EnableAutoConfiguration {
    
        String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
    
        Class>[] exclude() default {};
    
        String[] excludeName() default {};
    
    }
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Inherited
    @Import(AutoConfigurationPackages.Registrar.class)
    public @interface AutoConfigurationPackage {
    
    }
  • 그리고 @ ComponentScan (excludeFilters = @ Filter (type = FilterType. CUSTOM, classes = TypeExcludeFilter. class) 을 보면 ComponentScan 주석
  • 이 추 가 됩 니 다.
  • 그래서 결론 적 으로 @ SpringBootConfiguration 주 해 는 주석 을 한 번 에 조합 한 것 입 니 다. 1. @ Configuration 2. @ Componentscan 3. EnableAutoConfiguration ImportSelector. class 4. AutoConfiguration Packages. Registrar. class
  • @ Configuration 의 역할
    spring 3.0 부터 자바 Config 방식 으로 설정 할 수 있 습 니 다. 구체 적 으로 spring 은 자바 류 를 프로필 로 처리 하여 코드 를 큰 설정 파일 의 어려움 에서 벗 어 날 수 있 습 니 다.
    springboot 에 Bean DefinitionLoader 가 있 습 니 다. 바로 앞에서 말 한 Bean DefinitionReader 외관 모드 입 니 다. 자바 Config 방식 으로 설정 할 때 Annotated Bean DefinitionReader 를 사용 하여 register 방법 을 호출 했 습 니 다.
      //  AnnotatedBeanDefinitionReader
        this.annotatedReader = new AnnotatedBeanDefinitionReader(registry);
      //  bean  
        this.annotatedReader.register(source);
  • 우 리 는 위의 등록 방법 을 살 펴 보면 최종 호출 된 일 registerBean 을 발견 할 수 있 습 니 다. 우 리 는 그 가 class 를 통 해 bean 등록 을 하 는 전 과정
  • 을 볼 수 있 습 니 다.
        public void register(Class>... annotatedClasses) {
            for (Class> annotatedClass : annotatedClasses) {
                registerBean(annotatedClass);
            }
        }
    
        public void registerBean(Class> annotatedClass) {
            registerBean(annotatedClass, null, (Class extends Annotation>[]) null);
        }
        @SuppressWarnings("unchecked")
        public void registerBean(Class> annotatedClass, String name, Class extends Annotation>... qualifiers) {
            //      beandefinition    
            AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);
            //this is new StandardAnnotationMetadata(beanClass, true);
            //                               true               
            //                                               
            //abd.getMetadata()           
            if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
                return;
            }
            //       scopeMetadata                    
            ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
            abd.setScope(scopeMetadata.getScopeName());
            String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
            AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
            if (qualifiers != null) {
                for (Class extends Annotation> qualifier : qualifiers) {
                    if (Primary.class == qualifier) {
                        abd.setPrimary(true);
                    }
                    else if (Lazy.class == qualifier) {
                        abd.setLazyInit(true);
                    }
                    else {
                        abd.addQualifier(new AutowireCandidateQualifier(qualifier));
                    }
                }
            }
    
            BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
            //  ScopedProxyMode  
            definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
            BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
        }
  • 그 중에서 새로 만 든 AnnotatedBeanDefinitionReader 의 동작 에서 구조 함수 에는 매우 중요 한 코드 인 AnnotationConfigUtils. register AnnotationConfigProcessors (this. registry) 가 있 습 니 다.이 코드 는 spring 용기 에 ConfigurationClassPostProcessor. class 류 를 등록 하고 싶 습 니 다. 이 용 기 는 refresh () 방법, 즉 springboot 호출 run () 방법 에서 refreshContext (context) 를 호출 합 니 다.나중에 invokeBean Factory PostProcessors 를 호출 하여 모든 bean 을 초기 화 합 니 다 (관심 있 는 것 은 spring 의 전체 로드 과정 과 생명 주 기 를 볼 수 있 습 니 다)
  •     public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
            Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
            Assert.notNull(environment, "Environment must not be null");
            this.registry = registry;
            //Conditional     
            this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
            //          AnnotationConfigProcessor
            AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
        }
  • 자바 Config 의 매개 변수 류 는 Annotated GenericBeanDefinition 으로 BeanFactory 용기 에 등록 되 며, 다음은 Annotated GenericBeanDefinition 의 구조
  • 입 니 다.
    * 우선 클 라 스 설정 을 Annotated GenericBean Definition 으로 봉 합 니 다. 우 리 는 이러한 역할 을 봅 니 다.
    1.      GenericBeanDefinition            Bean   ,        bean   ,BeanFactory              bean 
    2.                          
    
        this.metadata = new StandardAnnotationMetadata(beanClass, true);
    
    
        public StandardAnnotationMetadata(Class> introspectedClass, boolean nestedAnnotationsAsMap) {
            super(introspectedClass);
            this.annotations = introspectedClass.getAnnotations();
            this.nestedAnnotationsAsMap = nestedAnnotationsAsMap;
        }
    
  • ConfigurationClassPostProcessor. class 의 방법 을 다시 봅 니 다. 이 안 에는 spring 이 주석 을 통 해 모든 bean 을 분석 하고 등록 하 는 과정 입 니 다. 관심 이 있 으 면 spring 의 코드
  • 를 보 세 요.
    @Override
        public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
            int factoryId = System.identityHashCode(beanFactory);
            if (this.factoriesPostProcessed.contains(factoryId)) {
                throw new IllegalStateException(
                        "postProcessBeanFactory already called on this post-processor against " + beanFactory);
            }
            this.factoriesPostProcessed.add(factoryId);
            if (!this.registriesPostProcessed.contains(factoryId)) {
                // BeanDefinitionRegistryPostProcessor hook apparently not supported...
                // Simply call processConfigurationClasses lazily at this point then.
                processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory);
            }
            enhanceConfigurationClasses(beanFactory);
        }
    public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
            //      List  
            List configCandidates = new ArrayList();
            String[] candidateNames = registry.getBeanDefinitionNames();
    
            for (String beanName : candidateNames) {
                BeanDefinition beanDef = registry.getBeanDefinition(beanName);
                if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||
                        ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {
                    if (logger.isDebugEnabled()) {
                        //bean                            
                        logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
                    }
                }
                else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
                    configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
                }
            }
    
            // Return immediately if no @Configuration classes were found
            if (configCandidates.isEmpty()) {
                return;
            }
    
            // Sort by previously determined @Order value, if applicable
            // Configuration             
            Collections.sort(configCandidates, new Comparator() {
                @Override
                public int compare(BeanDefinitionHolder bd1, BeanDefinitionHolder bd2) {
                    int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
                    int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
                    return (i1 < i2) ? -1 : (i1 > i2) ? 1 : 0;
                }
            });
    
            // Detect any custom bean name generation strategy supplied through the enclosing application context
            SingletonBeanRegistry singletonRegistry = null;
            if (registry instanceof SingletonBeanRegistry) {
                singletonRegistry = (SingletonBeanRegistry) registry;
                if (!this.localBeanNameGeneratorSet && singletonRegistry.containsSingleton(CONFIGURATION_BEAN_NAME_GENERATOR)) {
                    BeanNameGenerator generator = (BeanNameGenerator) singletonRegistry.getSingleton(CONFIGURATION_BEAN_NAME_GENERATOR);
                    this.componentScanBeanNameGenerator = generator;
                    this.importBeanNameGenerator = generator;
                }
            }
    
            // Parse each @Configuration class
            /*
             * metadataReaderFactory = new CachingMetadataReaderFactory();
             * problemReporter = new FailFastProblemReporter();
             * environment
             * resourceLoader = new DefaultResourceLoader();
             * componentScanBeanNameGenerator = new AnnotationBeanNameGenerator();
             *          
             * 
             */
            ConfigurationClassParser parser = new ConfigurationClassParser(
                    this.metadataReaderFactory, this.problemReporter, this.environment,
                    this.resourceLoader, this.componentScanBeanNameGenerator, registry);
            //      
            Set candidates = new LinkedHashSet(configCandidates);
            Set alreadyParsed = new HashSet(configCandidates.size());
            do {
                //    
                parser.parse(candidates);
                parser.validate();
    
                Set configClasses = new LinkedHashSet(parser.getConfigurationClasses());
                configClasses.removeAll(alreadyParsed);
    
                // Read the model and create bean definitions based on its content
                if (this.reader == null) {
                    //     beandefinitionreader
                    this.reader = new ConfigurationClassBeanDefinitionReader(
                            registry, this.sourceExtractor, this.resourceLoader, this.environment,
                            this.importBeanNameGenerator, parser.getImportRegistry());
                }
                //            --              bean     
                this.reader.loadBeanDefinitions(configClasses);
                alreadyParsed.addAll(configClasses);
    
                candidates.clear();
                if (registry.getBeanDefinitionCount() > candidateNames.length) {
                    String[] newCandidateNames = registry.getBeanDefinitionNames();
                    Set oldCandidateNames = new HashSet(Arrays.asList(candidateNames));
                    Set alreadyParsedClasses = new HashSet();
                    for (ConfigurationClass configurationClass : alreadyParsed) {
                        alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
                    }
                    for (String candidateName : newCandidateNames) {
                        if (!oldCandidateNames.contains(candidateName)) {
                            BeanDefinition beanDef = registry.getBeanDefinition(candidateName);
                            if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory) &&
                                    !alreadyParsedClasses.contains(beanDef.getBeanClassName())) {
                                candidates.add(new BeanDefinitionHolder(beanDef, candidateName));
                            }
                        }
                    }
                    candidateNames = newCandidateNames;
                }
            }
            while (!candidates.isEmpty());
    
            // Register the ImportRegistry as a bean in order to support ImportAware @Configuration classes
            if (singletonRegistry != null) {
                if (!singletonRegistry.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
                    singletonRegistry.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
                }
            }
    
            if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {
                ((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();
            }
        }

    @ Componentscan 의 역할
    또한 ConfigurationClassPostProcessor. class 에서 분석 할 때 @ ComponentScan 주 해 를 만 나 설명 설정 아래 의 모든 종 류 를 스 캔 한 다음 bean 을 등록 합 니 다.
    EnableAutoConfiguration ImportSelector. class 의 역할
    ConfigurationClassPostProcessor. class 라 는 등록 절단면 은 ConfigurationClassParser 류 의 parser. parse (candidates) 를 호출 할 때 EnableAutoConfiguration 의 설정 을 spring - boot - autoconfigure 프로젝트 아래 에 있 는 spring. factories 를 가 져 옵 니 다.그리고 스 캔 된 Configraution 을 모두 분석 합 니 다.
    public void parse(Set configCandidates) {
            this.deferredImportSelectors = new LinkedList();
    
            for (BeanDefinitionHolder holder : configCandidates) {
                BeanDefinition bd = holder.getBeanDefinition();
                try {
                    if (bd instanceof AnnotatedBeanDefinition) {
                        parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
                    }
                    else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
                        parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
                    }
                    else {
                        parse(bd.getBeanClassName(), holder.getBeanName());
                    }
                }
                catch (BeanDefinitionStoreException ex) {
                    throw ex;
                }
                catch (Throwable ex) {
                    throw new BeanDefinitionStoreException(
                            "Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);
                }
            }
    
            processDeferredImportSelectors();
        }
    private void processDeferredImportSelectors() {
            List deferredImports = this.deferredImportSelectors;
            this.deferredImportSelectors = null;
            Collections.sort(deferredImports, DEFERRED_IMPORT_COMPARATOR);
    
            for (DeferredImportSelectorHolder deferredImport : deferredImports) {
                ConfigurationClass configClass = deferredImport.getConfigurationClass();
                try {
                    String[] imports = deferredImport.getImportSelector().selectImports(configClass.getMetadata());
                    processImports(configClass, asSourceClass(configClass), asSourceClasses(imports), false);
                }
                catch (BeanDefinitionStoreException ex) {
                    throw ex;
                }
                catch (Throwable ex) {
                    throw new BeanDefinitionStoreException(
                            "Failed to process import candidates for configuration class [" +
                            configClass.getMetadata().getClassName() + "]", ex);
                }
            }
        }

    따라서 spring. factories 에서 설명 하면 EnableAutoConfiguration 의 스 캔 류 는 상 자 를 열 고 해당 하 는 기능 을 사용 할 수 있 습 니 다.
    AutoConfiguration Packages. Registrar. class 의 역할
    자바 설정 확장 을 지원 하 는 관건 은 @ Import 주해 입 니 다. Spring 3.0 은 Configuration 류 에 다른 설정 류 를 도입 하 는 것 을 지원 합 니 다. ImportSelector 와 ImportBeanDefinitionRegistrar 의 실현 류 를 포함 합 니 다.

    좋은 웹페이지 즐겨찾기