Spring@Configrationのクラス構成に基づく内部ソースコードの実現

29197 ワード

概要
  • Spring容器起動時、Appliation Contectインターフェース実現類のオブジェクトインスタンスでrefresh方法を実行する場合、主にCofigrationClass PostProcessorというBeanFactoryPostProcessorを実行することによって、@Configration注釈のシリーズ類全体のロードを開始します.つまり、@Configrationによるクラス構成がbeansラベルの容器配置に代わる関連beanのロードを開きます.
  • でConfigrationClass PostProcessorがSpring容器に登録されているBeanFactory PostProcessorリストは、主にAnnotationConfigUtilsのregister AnnotationConfigProcessで定義されています.
    /**
     * Register all relevant annotation post processors in the given registry.
     * @param registry the registry to operate on
     * @param source the configuration source element (already extracted)
     * that this registration was triggered from. May be {@code null}.
     * @return a Set of BeanDefinitionHolders, containing all bean definitions
     * that have actually been registered by this call
     */
    public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
    		BeanDefinitionRegistry registry, @Nullable Object source) {
    
        ...
        
    	Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);
    
    	if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
    	
    	    //   ConfigurationClassPostProcessor
    	    //     @Configuration    
    	    
    		RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
    		def.setSource(source);
    		beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
    	}
    
    	if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
    	
    	    //   AutowiredAnnotationBeanPostProcessor
    	    
    		RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
    		def.setSource(source);
    		beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
    	}
    
    	// Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.
    	if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
    	
    	    //   CommonAnnotationBeanPostProcessor
    	    
    		RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
    		def.setSource(source);
    		beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
    	}
    }
    
  • AnnotationConfigUtilsのregister AnnotationConfigProcessの呼び出しは、様々な方法で行われます.
  • ComponentScann DefinitionParter:対応context:component-scan、parseメソッドで呼び出します.
  • AnnotationConfigBenDefinitionParter:対応context:annotationn config、parseメソッドで呼び出します.
  • Class PathBeanDefinitionScanner:scanメソッドで呼び出して、この種類はAnnotationConfigAplication Contectで使用します.
  • AnnotatedBeanDefinitionReader:構造関数で呼び出して、この種類はAnnotationConfigAplicationControtextで使用します.
  • は以上の4つの方法で分かります.xmlファイルにcontextが配置されています.component-scanまたはcontext:annotationn config.あるいはAnnotationConfigAplicationControtextをspring容器として使用するAppplicationControtextは、このような方式は一般的にWebAppliation Initializerインターフェースを結合して実現し、Java類の構成に基づく全ての時に使用される.@Configrationシリーズの構成類は自動的に活性化され、その内部の@Beanメソッドはbeanのロードに対応します.
  • クラス構造設計
    1.ConfigrationClass PostProcessor
  • は、BenFactoryPostProcessorとして、spring容器Application Contact起動時にrefshメソッドを呼び出す時に、BenFactory PostProcessorを巡回して呼び出し、postProcession DefinitionRegistry方法を実行します.
  • は、この方法の中からまず、@Configration注釈を使用したクラスに対応するbeanDefinitionsのセット、すなわちconfigCadidatesを取得する.configCadidatesをCofigrationClass Paserに渡します.
  • ConfigrationClass Paser処理は、これらの対応するConfigrationClassタイプのセットを取得し、ConfigrationClass BeanDefinitionReader処理に渡します.そこから@Beanメソッドを処理して、対応するbeanをBenFactoryに登録します.
  • ConfigrationClass PostProcessorのprocess ConfigBenDefinitions関連コードは以下の通りです.この中で最初にBenFactoryから@Configrationのクラスに対応するbeanDefinitionを取得できるのは、@Configrationが@Componentのサブクラスなので、一般的にcomponent-scanを配置する時にConfigrationクラスをロードする必要があります.
    public void refresh() throws BeansException, IllegalStateException {
    	synchronized (this.startupShutdownMonitor) {
    		// Prepare this context for refreshing.
    		prepareRefresh();
    
    		// Tell the subclass to refresh the internal bean factory.
    		ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
    
    		// Prepare the bean factory for use in this context.
    		prepareBeanFactory(beanFactory);
    
    		try {
    			// Allows post-processing of the bean factory in context subclasses.
    			postProcessBeanFactory(beanFactory);
    
                //   BeanFactoryPostProcessor
                
    			// Invoke factory processors registered as beans in the context.
    			invokeBeanFactoryPostProcessors(beanFactory);
    
    			// Register bean processors that intercept bean creation.
    			registerBeanPostProcessors(beanFactory);
        
        ...
        
    	}
    }
    
  • 2.ConfigrationClass Paraser
  • 巡回してconfigCadidatesのセットを処理する:
  • は、セット中の@Configration毎に注釈されているクラスに対して、@ComponentScanなどの他の注釈を同時に配置し、指定されたパケットをスキャンしてビーンFactoryに登録する.他の注釈の処理も含まれています.例えば@Import、@ProptySourceなどです.
  • は同時にこの@Configration注释のクラスに対応するオブジェクトを作成し、このクラスの@Bean注解の方式をBenMethodとして生成し、ConfigrationClassの対象の内部の集合beanMethodsに入れる.このタイプをConfigrationClassの対象とし、ConfigrationClass Paraserのmap(Linked HashMapタイプ)に置く.ここでkeyとvalueは、このタイプがConfigrationClassの対象となる.
  • 処理方法のソースコードは以下の通りです.
    /**
     * Instantiate and invoke all registered BeanFactoryPostProcessor beans,
     * respecting explicit order if given.
     * 

    Must be called before singleton instantiation. */

    protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) { // // ConfigurationClassPostProcessor postProcessBeanDefinitionRegistry PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors()); // Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime // (e.g. through an @Bean method registered by ConfigurationClassPostProcessor) if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) { beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory)); beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader())); } }
  • 3.ConfigrationClass BeanDefinitionReader
  • は、ConfigrationClass Paraserのget ConfigrationClass方法を呼び出し、前述のmapのkeySet、つまりconfigCadidatesに対応するタイプはConfigrationClassのリストを取得する.
  • は、このConfigrationClassリストを巡回し、各ConfigrationClassに対して、ConfigrationClass BeanDefinitionReaderのloadBenDefinitions方法を使用して、その内部の@Bean注釈をConfigrationsのリストに取得します.つまり、BenMethoddリスト、またはConfinitionsのリストに含まれます.ビーンファクトリーに登録します.
  • ソースコードは以下の通りです.
    /**
     * Build and validate a configuration model based on the registry of
     * {@link Configuration} classes.
     */
    public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
    	List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
    	String[] candidateNames = registry.getBeanDefinitionNames();
        
        //  BeanFactory     @Configuration    
        
    	for (String beanName : candidateNames) {
    		BeanDefinition beanDef = registry.getBeanDefinition(beanName);
    		if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||
    				ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {
    			if (logger.isDebugEnabled()) {
    				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
    	configCandidates.sort((bd1, bd2) -> {
    		int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
    		int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
    		return Integer.compare(i1, i2);
    	});
    
    	...
    	
    	//   ConfigurationClassParser          ,
    	//  @ComponentScan,@Import,@PropertySource 
    	//          ConfigurationClass     
    
    	// Parse each @Configuration class
    	ConfigurationClassParser parser = new ConfigurationClassParser(
    			this.metadataReaderFactory, this.problemReporter, this.environment,
    			this.resourceLoader, this.componentScanBeanNameGenerator, registry);
    
    	Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
    	Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
    	do {
    	
    	    //     
    	    
    		parser.parse(candidates);
    		parser.validate();
    
    		Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
    		configClasses.removeAll(alreadyParsed);
    
            //   ConfigurationClassBeanDefinitionReader
            //   @Configuration           
            //  @Bean,  @Configuration 。
            
    		// Read the model and create bean definitions based on its content
    		if (this.reader == null) {
    			this.reader = new ConfigurationClassBeanDefinitionReader(
    					registry, this.sourceExtractor, this.resourceLoader, this.environment,
    					this.importBeanNameGenerator, parser.getImportRegistry());
    		}
    		
    		//   @Bean     bean BeanFactory
    		
    		this.reader.loadBeanDefinitions(configClasses);
    	
    	...
    	
    }