本篇文章,我将和大家分享关于 Spring 中的一个注解 @Configuration。下面,我将通过具体的实例源码来解析 Spring 注解 @Configuration 的具体作用和使用方法。

    一、@Configuration

    1.1 未加@Configuration

    <!--logback-test.xml,配置不打印日志-->
    <?xml version="1.0" encoding="UTF-8"?>
    <configuration>
        <include resource="org/springframework/boot/logging/logback/base.xml" />
        <logger name="org.springframework" level="OFF"/>
    </configuration>
    

    1.2 加上@Configuration

    1.3 Cglib动态代理

    二、源码跟踪

    2.1 AnnotationConfigApplicationContext

    2.2 AnnotationConfigApplicationContext#AnnotationConfigApplicationContext(Class<?>… annotatedClasses)

    2.3 AbstractApplicationContext#refresh()

    @Override
    	public void refresh() throws BeansException, IllegalStateException {
    		// 同步,线程安全; 防止 fresh还没结束  就又进入改方法 导致容器初始化错乱
    		synchronized (this.startupShutdownMonitor) {
    			// 准备刷新 记录开始时间  设置几个标志位  验证环境属性
    			prepareRefresh();
     
    			// 告诉子类刷新内部bean工厂  创建BeanFactory  并且获取BeanDefinition的定义信息
    			/**
    			 *	obtainFreshBeanFactory();方法
    			 *		解析为一个个beanDefinition 放在我们beanDefinitionMap中管理起来
    			 *  1. refreshBeanFactory(); 核心方法
    			 * 		AbstractRefreshableApplicationContext#refreshBeanFactory()
    			 * 		创建DefaultListableBeanFactory 并设置属性
    			 * 		加载BeanFactory; 根据不同的类型,调用不同的方法
    			 * 			org.springframework.context.support.AbstractXmlApplicationContext#loadBeanDefinitions(org.springframework.beans.factory.support.DefaultListableBeanFactory)
    			 */
    			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
     
    			// 准备在这种情况下使用的bean工厂  向beanFactory中设置一些属性  。对BeanFactory 进行各种功能填充
    			prepareBeanFactory(beanFactory);
     
    			try {
    				// 允许在上下文 的子类中对bean工厂进行后处理  由子类去实现; 主要是自定义去使用
    				postProcessBeanFactory(beanFactory);
     
    				// 第5步 【BeanFactoryPostProcessors ;bean工厂后置处理器】调用我们的bean工厂后置处理器 (所有实现接口BeanFactoryPostProcessor接口的)
    				//		主要是
    				// 		会在此将class扫描成BeanDefinition 并注册bean 到一个BeanDefinitionMap中 这个过程使用到代理
    				//BeanFactoryPostProcessor 可以 用于容器完成初始化()
    				// 此处可以 还没有实例化Bean之前读取Bean的信息,并作出一些修改。
    				// 例如修改Bean的属性,修改Bean的scope等
    				invokeBeanFactoryPostProcessors(beanFactory);
     
    				//https://blog.csdn.net/caihaijiang/article/details/35552859
    				// 【BeanPostProcessors ;bean后置处理器】 注册BeanPostProcessor
    				// BeanPostProcessor是Bean的后置处理器,
    				// 在Bean的初始化方法[InitializingBean 以及init-method]前,后执行。
    				registerBeanPostProcessors(beanFactory);
     
    				// 为上下文初始化Message 源, 即不同语言的消息体, 国际化处理 i18n
    				initMessageSource();
     
    				// 初始化事件传播器
    				//初始化应用消息广播器, 并放入"applicationEventMulticaster" bean 中
    				initApplicationEventMulticaster();
     
    				// 扩展的一个实现 ,留给子类来初始化其它的Bean。如springboot内嵌的tomcat在这个阶段完成
    				onRefresh();
     
    				// 注册监听器
    				// 在所有注册的bean 中查找Listener bean , 注册到消息广播报中
    				registerListeners();
     
    				/**第11步
    					对于非抽象类、非延迟初始化的单例bean,
    					在spring容器启动的时候调用getBean方法来实例化bean, 并进行相关初始化工作,
    					getBean方法最终调用AbstractAutowireCapableBeanFactory.doCreateBean方法
    				 */
    				// 在创建BeanFactory的过程中,BeanDefinition注册到了BeanFactory中的一个ConCurretHashMap对象中
    				// 以BeanName为key,BeanDefinition为value ; 实例化所有剩余的(非延迟初始化)单例。
    				finishBeanFactoryInitialization(beanFactory);
     
    				// 第12步 最后一步:发布相应的事件。
    				//完成刷新过程, 通知生命周期处现器lifecycleProcessor 刷新过程, 同时发出ContextRefreshEvent 通知别人
    				finishRefresh();
    			}
     
    			catch (BeansException ex) {
    				if (logger.isWarnEnabled()) {
    					logger.warn("Exception encountered during context initialization - " +
    							"cancelling refresh attempt: " + ex);
    				}
     
    				// 第13步 销毁以创建的Bean
    				destroyBeans();
     
    				//取消refresh操作,重置容器的同步标识
    				cancelRefresh(ex);
     
    				// Propagate exception to caller.
    				throw ex;
    			}
     
    			finally {
    				resetCommonCaches();
    			}
    		}
    	}
    

    2.4 AbstractApplicationContext#invokeBeanFactoryPostProcessors

    2.5 PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors

    public static void invokeBeanFactoryPostProcessors(
    			ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
     
    		Set<String> processedBeans = new HashSet<>();
     
    		// 对BeanDefinitionRegistry 类型的处理
    		if (beanFactory instanceof BeanDefinitionRegistry) {
    			BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
    			List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
    			// 用于存放BeanDefinitionRegistryPostProcessor
    			List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();
     
    			// 遍历所有的beanFactoryPostProcessors,将BeanDefinitionRegistryPostProcessor和普通BeanFactoryPostProcessor区分开
    			for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
    				if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
    					BeanDefinitionRegistryPostProcessor registryProcessor =
    							(BeanDefinitionRegistryPostProcessor) postProcessor;
    					/**
    						对于BeanDefinitionRegistryPostProcessor 类型, 在BeanFactoryPostProcessor 的
    						基础上还有自己定义的方法,需要先调用
    					 */
    					registryProcessor.postProcessBeanDefinitionRegistry(registry);
    					registryProcessors.add(registryProcessor);
    				}
    				else {
    					// 记录常规BeanFactoryPostProcessor
    					regularPostProcessors.add(postProcessor);
    				}
    			}
     
    			/**
    				不要在这里初始化FactoryBeans: 我们需要保留所有常规bean未初始化,让bean工厂后处理器应用到它们!
    				BeanDefinitionRegistryPostProcessors之间的分离实现排好序,点好,等等。
    				获取spring配置文件中定义的所有实现BeanFactoryPostProcessor接口的bean,然后根据优先级进行排序
    			 */
    			List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();
     
    			// 首先,调用实现优先排序的BeanDefinitionRegistryPostProcessors
    			String[] postProcessorNames =
    					beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
    			for (String ppName : postProcessorNames) {
    				// PriorityOrdered.class 优先排序
    				if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
    					currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
    					processedBeans.add(ppName);
    				}
    			}
    			sortPostProcessors(currentRegistryProcessors, beanFactory);
    			registryProcessors.addAll(currentRegistryProcessors);
    			invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
    			currentRegistryProcessors.clear();
     
    			// 接下来,调用实现Ordered的BeanDefinitionRegistryPostProcessors
    			postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
    			for (String ppName : postProcessorNames) {
    				// Ordered.class
    				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生成增强类
    			// 设置beanDefinition的beanClass为增强类,让@Bean生成的bean是单例
    			invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
    			invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
    		}
     
    		else {
    			// Invoke factory processors registered with the context instance.
    			invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
    		}
     
    		// BeanFactoryPostProcessor.class类型
    		// 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);
    		// 筛选出bean工程中存在的所有实现BeanFactoryPostProcessor类的类名称
     
    		// 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)) {
    				// 为PriorityOrdered类型
    				priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
    			}
    			else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
    				// 为Ordered类型
    				orderedPostProcessorNames.add(ppName);
    			}
    			else {
    				// 这个就是我们当前需要关心的PostProcessors
    				//nonOrderedPostProcessors添加的不是bean实例,而是BeanDefinition
    				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<>();
    		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<>();
    		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();
    	}
    

    2.6 PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors

    2.7 ConfigurationClassPostProcessor#postProcessBeanFactory

    2.8 ConfigurationClaassPostProcessor#enhanceConfigurationClasses

    public void enhanceConfigurationClasses(ConfigurableListableBeanFactory beanFactory) {
    		Map<String, AbstractBeanDefinition> configBeanDefs = new LinkedHashMap<>();
    		for (String beanName : beanFactory.getBeanDefinitionNames()) {
    			BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName);
    			// 判断是否是一个全注解类
    			// 扫描是全注解类?full和lite的关系
    			if (ConfigurationClassUtils.isFullConfigurationClass(beanDef)) {
    				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中
    				configBeanDefs.put(beanName, (AbstractBeanDefinition) beanDef);
    			}
    		}
    		if (configBeanDefs.isEmpty()) {
    			// nothing to enhance -> return immediately
    			return;
    		}
     
    		ConfigurationClassEnhancer enhancer = new ConfigurationClassEnhancer();
    		// 遍历这个map
    		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);
    			try {
    				// Set enhanced subclass of the user-specified bean class
    				Class<?> configClass = beanDef.resolveBeanClass(this.beanClassLoader);
    				if (configClass != null) {
    					// 进行cglib代理,为@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)修改beanDefinition的BeanClass属性,
    						// 在bean实例化阶段,会利用反射技术将beanClass属性对应的类实例化出来
    						// 所以最终实例化出来的@Configuration bean是一个代理类的实例
    						beanDef.setBeanClass(enhancedClass);
    					}
    				}
    			}
    			catch (Throwable ex) {
    				throw new IllegalStateException("Cannot load configuration class: " + beanDef.getBeanClassName(), ex);
    			}
    		}
    
    

    2.9 ConfigurationClassUtils#checkConfigurationClassCandidate

    1.在ConfigurationClassUtils类中的checkConfigurationClassCandidate标记是Full @Configuration还是lite @Bean mode

    2.通过”full”.equals(configClassAttr)判断是否是全类注解是全注解

    3.则将beandefinition放入map中configBeanDefs.put

    4.遍历这个map

    5.使用cglib技术为配置类生成一个enhancedClass

    6.通过enhancer.enhance进行cglib代理,为@Configuration注解的类生成增强类

    7.再通过beanDef.setBeanClass(enhancedClass)修改beanDefinition的BeanClass属性,在bean实例化阶段,会利用反射技术将beanClass属性对应的类实例化出来,所以最终实例化出来的@Configuration bean是一个代理类的实例

    使用了@Configuration注解的类,属于Full @Configuration。@Configuration类允许通过调用同一类中的其他@Bean方法来定义bean之间的依赖关系,保证@Bean的对象作用域受到控制,避免多例。

    @Configuration类中的@Bean地方会被CGLIB进行代理。Spring会拦截该方法的执行,在默认单例情况下,容器中只有一个Bean,所以我们多次调用user()方法,获取的都是同一个对象。

    对于@Configuration注解的类中@Bean标记的方法,返回的都是一个bean,在增强的方法中,Spring会先去容器中查看一下是否有这个bean的实例了,如果有了的话,就返回已有对象,没有的话就创建一个,然后放到容器中。

    2.10 ConfigurationClassEnhancer#enhance

    2.11 ConfigurationClassEnhancer#newEnhancer

    2.12 ConfigurationClassEnhancer#CallBacks

    2.13 ConfigurationClassEnhancer#intercept

    2.13.1 ConfigurationClassEnhancer#isCurrentlyInvokedFactoryMethod

    2.14 ConfigurationClassEnhancer#resolveBeanReference

    	private Object resolveBeanReference(Method beanMethod, Object[] beanMethodArgs,
    				ConfigurableBeanFactory beanFactory, String beanName) {
     
    			// The user (i.e. not the factory) is requesting this bean through a call to
    			// the bean method, direct or indirect. The bean may have already been marked
    			// as 'in creation' in certain autowiring scenarios; if so, temporarily set
    			// the in-creation status to false in order to avoid an exception.
    			// 判断他是否正在创建
    			boolean alreadyInCreation = beanFactory.isCurrentlyInCreation(beanName);
    			try {
    				if (alreadyInCreation) {
    					beanFactory.setCurrentlyInCreation(beanName, false);
    				}
    				boolean useArgs = !ObjectUtils.isEmpty(beanMethodArgs);
    				if (useArgs && beanFactory.isSingleton(beanName)) {
    					// Stubbed null arguments just for reference purposes,
    					// expecting them to be autowired for regular singleton references?
    					// A safe assumption since @Bean singleton arguments cannot be optional...
    					for (Object arg : beanMethodArgs) {
    						if (arg == null) {
    							useArgs = false;
    							break;
    						}
    					}
    				}
    				Object beanInstance = (useArgs ? beanFactory.getBean(beanName, beanMethodArgs) :
    						beanFactory.getBean(beanName));
    				if (!ClassUtils.isAssignableValue(beanMethod.getReturnType(), beanInstance)) {
    					// Detect package-protected NullBean instance through equals(null) check
    					if (beanInstance.equals(null)) {
    						if (logger.isDebugEnabled()) {
    							logger.debug(String.format("@Bean method %s.%s called as bean reference " +
    									"for type [%s] returned null bean; resolving to null value.",
    									beanMethod.getDeclaringClass().getSimpleName(), beanMethod.getName(),
    									beanMethod.getReturnType().getName()));
    						}
    						beanInstance = null;
    					}
    					else {
    						String msg = String.format("@Bean method %s.%s called as bean reference " +
    								"for type [%s] but overridden by non-compatible bean instance of type [%s].",
    								beanMethod.getDeclaringClass().getSimpleName(), beanMethod.getName(),
    								beanMethod.getReturnType().getName(), beanInstance.getClass().getName());
    						try {
    							BeanDefinition beanDefinition = beanFactory.getMergedBeanDefinition(beanName);
    							msg += " Overriding bean of same name declared in: " + beanDefinition.getResourceDescription();
    						}
    						catch (NoSuchBeanDefinitionException ex) {
    							// Ignore - simply no detailed message then.
    						}
    						throw new IllegalStateException(msg);
    					}
    				}
    				Method currentlyInvoked = SimpleInstantiationStrategy.getCurrentlyInvokedFactoryMethod();
    				if (currentlyInvoked != null) {
    					String outerBeanName = BeanAnnotationHelper.determineBeanNameFor(currentlyInvoked);
    					beanFactory.registerDependentBean(beanName, outerBeanName);
    				}
    				return beanInstance;
    			}
    			finally {
    				if (alreadyInCreation) {
    					beanFactory.setCurrentlyInCreation(beanName, true);
    				}
    			}
    		}
    

    三、总结

    •  lite @Bean mode :当@Bean方法在没有使用@Configuration注解的类中声明时称之为lite @Bean mode
    • Full @Configuration:如果@Bean方法在使用@Configuration注解的类中声明时称之为Full @Configuration

    Full @Configuration中的@Bean方法会被CGLIB所代理,而 lite @Bean mode中的@Bean方法不会被CGLIB代理

    @Configuration注解作用

    1.告诉spring这是一个配置类,相当于spring的xml配置文件

    2.被@Configuration 注解的类,会被cglib代理进行增强

    3.@Configuration类允许通过调用同一类中的其他@Bean方法来定义bean之间的依赖关系,保证@Bean的对象作用域受到控制,避免多例

    @Configuration注解底层是如何实现的,通过源码咱们可以反推并总结为以下几点:

    1.Spring首先会获取到所有的beanDefenition

    2.ConfigurationClassUtils类中checkConfigurationClassCandidate方法判断是Full @Configuration还是lite @Bean mode

    3.通过ConfigurationClassPostProcessor后置处理器遍历所有的beanDefenition

    4.将标记了Full @Configuration模式的beanDefenition,会对这个类进行cglib代理,生成一个代理类,并把这个类设置到BeanDefenition的Class属性中

    5.配置类会被CGLIB增强(生成代理对象),放进IoC容器内的是代理

    6.对于内部类是没有限制的:可以是Full模式或者Lite模式

    7.配置类内部可以通过方法调用来处理依赖,并且能够保证是同一个实例,都指向IoC内的那个单例

    8.需要用这个Bean实例的时候,从这个Class属性中拿到的Class对象进行反射,最终反射出来的是代理增强后的类

    9.通过@Configuration标注类的Bean,Spring会先去容器中查看是否有这个Bean实例,如果有就返回已有的对象,没有就创建一个,然后放到容器中

    本篇关于 Spring 中的 @Configuration 注解的详细内容就介绍到此结束了,想要了解更多相关 Spring 其他注解 以及 @Configuration 注解的其他详细内容请搜索W3Cschool以前的文章或继续浏览下面的相关文章,也希望大家以后多多支持!

    声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。