zoukankan      html  css  js  c++  java
  • Spring源码解析之@Configuration

    @Configuration简介

    用于标识一个类为配置类,与xml配置效果类似

    用法简介

    public class TestApplication {
    
        public static void main(String args[]) {
            AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
    
        }
    }
    
    @Configuration
    public class AppConfig {
    
    	@Bean
    	public A a(){
    		return new A();
    	}
    	@Bean
    	public B b(){
    		return new B();
    	}
    } 
    
    
    
    
    public class A {
    
    	public A(){
    		System.out.println("Call A constructor");
    	}
    }
    
    
    
    public class B {
    
    	public B(){
    		System.out.println("Call B constructor");
    	}
    }
    

    上面的例子应该是@Configuration最普遍一种使用场景了,在@Configuration class下面配置@Bean method,用于想Spring Ioc容器注入bean.但其实我们把AppConfig的@Configuration注解去掉,对应的Bean也是可以被注入到容器中去的。

    那么问题来了@Configuration到底有什么作用?

    我们给AppConfig改写一下,如下:

    @Configuration
    @EnableAspectJAutoProxy
    public class AppConfig {
    
       @Bean
       public A a(){
          b();
          return new A();
       }
       @Bean
       public B b(){
          return new B();
       }
    

    再去执行TestApplication#main,那么执行结果会是什么样呢?

    Call A constructor
    Call B constructor
    

    嗯哼?按照Java的语法,B的构造函数应该是被调用了两次啊?为什么只有输出一句Call B constructor?

    这其实就是@Configuration再发挥作用啦,不信你去掉@Configuration,再去运行一下,就会发现B的构造函数被执行了两次。

    官方给出了这样一段解释对于被@Configuration注解的类

    In common scenarios, @Beanmethods are to be declared within@Configurationclasses, ensuring that “full” mode is always used and that cross-method references therefore get redirected to the container’s lifecycle management.

    在一般情况下,@Bean method 是被声明在@Configuration类中的,以确保 full mode总是被使用,并且跨方法的引用会被重定向到容器生命周期管理。

    怎么理解呢?

    原来Spring将被@Configuration注解的配置类定义为full configuration, 而将没有被@Configuration注解的配置类定义为lite configuration。full configuration能重定向从跨方法的引用,从而保证上述代码中的b bean是一个单例.

    源码中是如何实现@Configuration语意

    public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
       /**
        * 调用无参构造函数,实例化AnnotatedBeanDefinitionReader和ClassPathBeanDefinitionScanner
        * 同时会调用父类GenericApplicationContext无参构造函数实例化一个关键的工厂DefaultListableBeanFactory
        * 同时还会注册一些开天辟地的后置处理器到beanDefinitionMap,这些后置处理器有bean工厂后置处理器;有bean后置处理器
        */
       this();
       //将componentClasses注册到beanDefinitionMap集合中去
       register(componentClasses);
      
       refresh();
    }
    

    跟踪refresh()

    @Override
    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.
             //供上下文(Context)子类继承,允许在这里后置处理bean factory
             postProcessBeanFactory(beanFactory);
    
             // Invoke factory processors registered as beans in the context.
             //按顺序调用BeanFactoryPostProcessor,这里的按顺序仅实现了PriorityOrdered和Ordered的语意,未实现@Order注解的语意
             //通过调用ConfigurationConfigPostProcessor#postProcessBeanDefinitionRegistry
             //解析@Configuration配置类,将自定义的BeanFactoryPostProcessor、BeanPostProcessor注册到beanDefinitionMap
             //接着实例化所有(包括开天辟地)的BeanFactoryPostProcessor,然后再调用BeanFactoryPostProcessor#postProcessBeanFactory
             invokeBeanFactoryPostProcessors(beanFactory);
    
             // Register bean processors that intercept bean creation.
             //按顺序将BeanPostProcessor实例化成bean并注册到beanFactory的beanPostProcessors,
             //这里的按顺序仅实现了PriorityOrdered和Ordered的语意,未实现@Order注解的语意
             //因为BeanPostProcessor要在普通bean初始化()前后被调用,所以需要提前完成实例化并注册到beanFactory的beanPostProcessors
             registerBeanPostProcessors(beanFactory);
    
             // Initialize message source for this context.
             //注册国际化相关的Bean
             initMessageSource();
    
             // Initialize event multicaster for this context.
             //为上下文注册应用事件广播器(用于ApplicationEvent的广播),如果有自定义则使用自定义的,如果没有则内部实例化一个
             initApplicationEventMulticaster();
    
             // Initialize other special beans in specific context subclasses.
             onRefresh();
    
             // Check for listener beans and register them.
             //注册所有(静态、动态)的listener,并广播earlyApplicationEvents
             registerListeners();
    
             // Instantiate all remaining (non-lazy-init) singletons.
             //实例化用户自定义的普通单例Bean(非开天辟地的、非后置处理器)
             finishBeanFactoryInitialization(beanFactory);
    
             // Last step: publish corresponding event.
             finishRefresh();
          }
    
          catch (BeansException ex) {
             if (logger.isWarnEnabled()) {
                logger.warn("Exception encountered during context initialization - " +
                      "cancelling refresh attempt: " + ex);
             }
    
             // Destroy already created singletons to avoid dangling resources.
             destroyBeans();
    
             // Reset 'active' flag.
             cancelRefresh(ex);
    
             // Propagate exception to caller.
             throw ex;
          }
    
          finally {
             // Reset common introspection caches in Spring's core, since we
             // might not ever need metadata for singleton beans anymore...
             resetCommonCaches();
          }
       }
    }
    

    跟踪invokeBeanFactoryPostProcessors(beanFactory)

    protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
       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()));
       }
    }
    

    跟踪invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());

    public static void invokeBeanFactoryPostProcessors(
    			ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
    
    		// Invoke BeanDefinitionRegistryPostProcessors first, if any.
    		Set<String> processedBeans = new HashSet<>();
    
    		if (beanFactory instanceof BeanDefinitionRegistry) {
    			BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
    			List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
    			List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();
    
    			for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
    				if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
    					BeanDefinitionRegistryPostProcessor registryProcessor =
    							(BeanDefinitionRegistryPostProcessor) postProcessor;
    					registryProcessor.postProcessBeanDefinitionRegistry(registry);
    					registryProcessors.add(registryProcessor);
    				}
    				else {
    					regularPostProcessors.add(postProcessor);
    				}
    			}
    
    			// Do not initialize FactoryBeans here: We need to leave all regular beans
    			// uninitialized to let the bean factory post-processors apply to them!
    			// Separate between BeanDefinitionRegistryPostProcessors that implement
    			// PriorityOrdered, Ordered, and the rest.
    			List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();
    
    			// First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
    			String[] postProcessorNames =
    					beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
    			for (String ppName : postProcessorNames) {
    				if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
    					currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
    					processedBeans.add(ppName);
    				}
    			}
    			sortPostProcessors(currentRegistryProcessors, beanFactory);
    			registryProcessors.addAll(currentRegistryProcessors);
    			//此处调用ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry,
    			//解析配置类,为配置中的bean定义生成对应beanDefinition,并注入到registry的beanDefinitionMap
    			invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
    			currentRegistryProcessors.clear();
    
    			// Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.
    			postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
    			for (String ppName : postProcessorNames) {
    				if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
    					currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
    					processedBeans.add(ppName);
    				}
    			}
    			sortPostProcessors(currentRegistryProcessors, beanFactory);
    			registryProcessors.addAll(currentRegistryProcessors);
    			invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
    			currentRegistryProcessors.clear();
    
    			// Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.
    			boolean reiterate = true;
    			while (reiterate) {
    				reiterate = false;
    				postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
    				for (String ppName : postProcessorNames) {
    					if (!processedBeans.contains(ppName)) {
    						currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
    						processedBeans.add(ppName);
    						reiterate = true;
    					}
    				}
    				sortPostProcessors(currentRegistryProcessors, beanFactory);
    				registryProcessors.addAll(currentRegistryProcessors);
    				invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
    				currentRegistryProcessors.clear();
    			}
    
    			// Now, invoke the postProcessBeanFactory callback of all processors handled so far.
    			//调用ConfigurationClassPostProcessor#postProcessBeanFactory增强配置类(通过cglib生成增强类,load到jvm内存,
    			//设置beanDefinition的beanClass为增强类)
    			//为什么要增强配置类?主要是为了让@Bean生成的bean是单例,
    			invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
    			invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
    		}
    
    		else {
    			// Invoke factory processors registered with the context instance.
    			invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
    		}
    
    		// Do not initialize FactoryBeans here: We need to leave all regular beans
    		// uninitialized to let the bean factory post-processors apply to them!
    		String[] postProcessorNames =
    				beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);
    
    		// Separate between BeanFactoryPostProcessors that implement PriorityOrdered,
    		// Ordered, and the rest.
    		List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
    		List<String> orderedPostProcessorNames = new ArrayList<>();
    		List<String> nonOrderedPostProcessorNames = new ArrayList<>();
    		for (String ppName : postProcessorNames) {
    			if (processedBeans.contains(ppName)) {
    				// skip - already processed in first phase above
    			}
    			else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
    				priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
    			}
    			else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
    				orderedPostProcessorNames.add(ppName);
    			}
    			else {
    				nonOrderedPostProcessorNames.add(ppName);
    			}
    		}
    
    		// First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.
    		sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
    		invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);
    
    		// Next, invoke the BeanFactoryPostProcessors that implement Ordered.
    		List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
    		for (String postProcessorName : orderedPostProcessorNames) {
    			orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
    		}
    		sortPostProcessors(orderedPostProcessors, beanFactory);
    		invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);
    
    		// Finally, invoke all other BeanFactoryPostProcessors.
    		List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
    		for (String postProcessorName : nonOrderedPostProcessorNames) {
    			nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
    		}
    		invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);
    
    		// Clear cached merged bean definitions since the post-processors might have
    		// modified the original metadata, e.g. replacing placeholders in values...
    		beanFactory.clearMetadataCache();
    	}
    

    跟踪invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);

    private static void invokeBeanFactoryPostProcessors(
          Collection<? extends BeanFactoryPostProcessor> postProcessors, ConfigurableListableBeanFactory beanFactory) {
    
       for (BeanFactoryPostProcessor postProcessor : postProcessors) {
          postProcessor.postProcessBeanFactory(beanFactory);
       }
    }
    

    跟踪ConfigurationClassPostProcessor#postProcessBeanFactory

    @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);
       }
       //为@Configuration注解的类生成增强类(如果有必要),并替换bd中的beanClass属性,
       enhanceConfigurationClasses(beanFactory);
       beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
    }
    

    到了这一步谜底几乎已经揭晓了,@Configuration class是通过增强来实现它的语义的。通过增强把跨方法的引用调用重定向到Spring生命周期管理.我们近一步探索下这个enhanceConfigurationClasses方法

    public void enhanceConfigurationClasses(ConfigurableListableBeanFactory beanFactory) {
       Map<String, AbstractBeanDefinition> configBeanDefs = new LinkedHashMap<>();
       for (String beanName : beanFactory.getBeanDefinitionNames()) {
          BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName);
          Object configClassAttr = beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE);
          MethodMetadata methodMetadata = null;
          if (beanDef instanceof AnnotatedBeanDefinition) {
             methodMetadata = ((AnnotatedBeanDefinition) beanDef).getFactoryMethodMetadata();
          }
          if ((configClassAttr != null || methodMetadata != null) && beanDef instanceof AbstractBeanDefinition) {
             // Configuration class (full or lite) or a configuration-derived @Bean method
             // -> resolve bean class at this point...
             AbstractBeanDefinition abd = (AbstractBeanDefinition) beanDef;
             if (!abd.hasBeanClass()) {
                try {
                   abd.resolveBeanClass(this.beanClassLoader);
                }
                catch (Throwable ex) {
                   throw new IllegalStateException(
                         "Cannot load configuration class: " + beanDef.getBeanClassName(), ex);
                }
             }
          }
          //在ConfigurationClassUtils.checkConfigurationClassCandidate方法中会标记Configuration is full or lite
          if (ConfigurationClassUtils.CONFIGURATION_CLASS_FULL.equals(configClassAttr)) {
             if (!(beanDef instanceof AbstractBeanDefinition)) {
                throw new BeanDefinitionStoreException("Cannot enhance @Configuration bean definition '" +
                      beanName + "' since it is not stored in an AbstractBeanDefinition subclass");
             }
             else if (logger.isInfoEnabled() && beanFactory.containsSingleton(beanName)) {
                logger.info("Cannot enhance @Configuration bean definition '" + beanName +
                      "' since its singleton instance has been created too early. The typical cause " +
                      "is a non-static @Bean method with a BeanDefinitionRegistryPostProcessor " +
                      "return type: Consider declaring such methods as 'static'.");
             }
             configBeanDefs.put(beanName, (AbstractBeanDefinition) beanDef);
          }
       }
       if (configBeanDefs.isEmpty()) {
          // nothing to enhance -> return immediately
          return;
       }
    
       ConfigurationClassEnhancer enhancer = new ConfigurationClassEnhancer();
       for (Map.Entry<String, AbstractBeanDefinition> entry : configBeanDefs.entrySet()) {
          AbstractBeanDefinition beanDef = entry.getValue();
          // If a @Configuration class gets proxied, always proxy the target class
          beanDef.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE);
          // Set enhanced subclass of the user-specified bean class
          Class<?> configClass = beanDef.getBeanClass();
          //为@Configuration注解的类生成增强类
          Class<?> enhancedClass = enhancer.enhance(configClass, this.beanClassLoader);
          if (configClass != enhancedClass) {
             if (logger.isTraceEnabled()) {
                logger.trace(String.format("Replacing bean definition '%s' existing class '%s' with " +
                      "enhanced class '%s'", entry.getKey(), configClass.getName(), enhancedClass.getName()));
             }
             beanDef.setBeanClass(enhancedClass);
          }
       }
    }
    

    看到有那么一句话Class<?> enhancedClass = enhancer.enhance(configClass, this.beanClassLoader);

    很明显了,使用cglib技术为config class生成一个enhancedClass,再通过beanDef.setBeanClass(enhancedClass);修改beanDefinition的BeanClass属性,在bean实例化阶段,会利用反射技术将beanClass属性对应的类实例化出来,所以最终实例化出来的@Configuration bean是一个代理类的实例。这里稍微提一下为什么要使用cglib,而不是jdk动态代理,主要是因为jdk动态代理是基于接口的,而这里AppConfig并没有实现任何接口,所以必须用cglib技术。

    总结

    被@Configuration 注解的类,是 full configuration class,该类会被增强(通过cglib),从而实现跨方法引用调用被重定向到Spring 生命周期管理,最终保证@Bean method生成的bean是一个单例。

  • 相关阅读:
    解决Mac连接移动硬盘为只读状态 转载: https://blog.csdn.net/adsl624153/article/details/99094809
    一文读懂Python web框架和web服务器之间的关系 转载:https://mp.weixin.qq.com/s/xgZ6ZkARrhtId0kBdbmgNA
    用 Python 登录主流网站 转载:https://mp.weixin.qq.com/s/QqYAXTxj2gK0ehXfpdNrOA
    k8s 面试题
    postman 转载:https://mp.weixin.qq.com/s/GscJGcR-2luk5N5Z7797dw
    Scrapy 如何正确 Post 发送 JSON 数据 转载:https://mp.weixin.qq.com/s/sy8pi9CdIRNEgCMgdJH87Q
    vgpu
    scray cookiejar
    登录接口的设计 转载:https://mp.weixin.qq.com/s/n44yNet6VtQsj4XDQJkeKA
    3D旋转图片、视频
  • 原文地址:https://www.cnblogs.com/think-in-java/p/11876997.html
Copyright © 2011-2022 走看看