@Configuration 注解使用及源码解析
本文为博主原创,转载请注明出处:
@Configuration 注解对我们来说并不陌生,以javaConfig的方式定义spring IOC容器的配置类使用的就是这个@Configuration.
spring boot 社区推荐使用基于JavaConfig 的配置方式来定义Bean,其可以认为是一个spring IOC 容器的配置类。
指示一个类声明一个或多个@Bean方法,并且可以由Spring容器处理,以便在运行时为这些bean生成BeanDefinition和服务请求
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.client.RestTemplate; @Configuration public class TestConfiguration { /** * 初始化spring -restTemplate * @return restTemplate */ @Bean public RestTemplate getRestTemplate(){ System.out.println("获取bean ing"); return new RestTemplate(); } public TestConfiguration() { System.out.println("TestConfiguration容器启动初始化。。。"); } }
@Configuration 注解的工作过程与 ClassXmlPathApplicationContext 的工作过程相同,@Configuration 是通过注解的方式将 bean 注入到spring IOC容器。
ClassXmlPathApplicationContext 是通过xml配置文件,在项目启动加载xml 配置文件时,将其中的bean 标签解析为bena 并注入到 IOC 容器中。
通过 @Configuration 注解的配置类会通过 AnnotationConfigApplicationContext 类进行扫描,并构建扫描 bean ,并注册到spring IoC容器中。
可以通过以下测试方法,看到上面代码中的bean 初始化并调用相关过程的打印:
import com.example.test.config.TestConfiguration; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.web.client.RestTemplate; public class ConfigurationBeanTest { public static void main(String[] args) { ApplicationContext context = new AnnotationConfigApplicationContext(TestConfiguration.class); RestTemplate restTemplate = (RestTemplate) context.getBean("getRestTemplate"); String url = "https://www.baidu.com/?tn=62095104_19_oem_dg"; String result = restTemplate.getForObject(url,String.class); System.out.println(result); } }
上面test运行并进行正常的 http 请求,可以打印出相关的控制台日志如下:
可以查看下 AnnotationConfigApplicationContext 类的相关实现,该类的继承结构通过idea 查看如下:
其中主要涉及到的类和接口如下:
GenericApplicationContext
——通用应用上下文,内部持有一个DefaultListableBeanFactory
实例,这个类实现了BeanDefinitionRegistry
接口,可以在它身上使用任意的bean definition读取器。典型的使用案例是:通过BeanFactoryRegistry
接口注册bean definitions,然后调用refresh()
方法来初始化那些带有应用上下文语义(org.springframework.context.ApplicationContextAware
)的bean,自动探测org.springframework.beans.factory.config.BeanFactoryPostProcessor
等。关于这两个接口,在介绍bean的生命周期时进行详细讲解。BeanDefinitionRegistry
——用于持有像RootBeanDefinition
和ChildBeanDefinition
实例的bean definitions的注册表接口。DefaultListableBeanFactory
实现了这个接口,因此可以通过相应的方法向beanFactory
里面注册bean。GenericApplicationContext
内置一个DefaultListableBeanFactory
实例,它对这个接口的实现实际上是通过调用这个实例的相应方法实现的。AbstractApplicationContext
——ApplicationContext
接口的抽象实现,没有强制规定配置的存储类型,仅仅实现了通用的上下文功能。这个实现用到了模板方法设计模式,需要具体的子类来实现其抽象方法。自动通过registerBeanPostProcessors()
方法注册BeanFactoryPostProcessor
,BeanPostProcessor
和ApplicationListener
的实例用来探测bean factory里的特殊bean——对比1分析AnnotationConfigRegistry
——注解配置注册表。用于注解配置应用上下文的通用接口,拥有一个注册配置类和扫描配置类的方法。
AnnotationConfigApplicationContext 类的源码如下:
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by Fernflower decompiler) // package org.springframework.context.annotation; import java.util.Arrays; import java.util.function.Supplier; import org.springframework.beans.factory.config.BeanDefinitionCustomizer; import org.springframework.beans.factory.support.BeanNameGenerator; import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.context.support.GenericApplicationContext; import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.metrics.StartupStep; import org.springframework.lang.Nullable; import org.springframework.util.Assert; public class AnnotationConfigApplicationContext extends GenericApplicationContext implements AnnotationConfigRegistry { private final AnnotatedBeanDefinitionReader reader; private final ClassPathBeanDefinitionScanner scanner;
// 无参数的构造器,在application 启动的时候初始化一个读取器与扫描器 public AnnotationConfigApplicationContext() { StartupStep createAnnotatedBeanDefReader = this.getApplicationStartup().start("spring.context.annotated-bean-reader.create"); this.reader = new AnnotatedBeanDefinitionReader(this); createAnnotatedBeanDefReader.end(); this.scanner = new ClassPathBeanDefinitionScanner(this); } // 构造一个 bean 工厂的有参构造,并包含了读取器和扫描器 public AnnotationConfigApplicationContext(DefaultListableBeanFactory beanFactory) { super(beanFactory); this.reader = new AnnotatedBeanDefinitionReader(this); this.scanner = new ClassPathBeanDefinitionScanner(this); }
// 手动指定注解类 public AnnotationConfigApplicationContext(Class<?>... componentClasses) { this(); this.register(componentClasses); this.refresh(); }
// 通过指定的包名进行自动的扫描并刷新 public AnnotationConfigApplicationContext(String... basePackages) { this(); this.scan(basePackages); this.refresh(); } public void setEnvironment(ConfigurableEnvironment environment) { super.setEnvironment(environment); this.reader.setEnvironment(environment); this.scanner.setEnvironment(environment); } public void setBeanNameGenerator(BeanNameGenerator beanNameGenerator) { this.reader.setBeanNameGenerator(beanNameGenerator); this.scanner.setBeanNameGenerator(beanNameGenerator); this.getBeanFactory().registerSingleton("org.springframework.context.annotation.internalConfigurationBeanNameGenerator", beanNameGenerator); } public void setScopeMetadataResolver(ScopeMetadataResolver scopeMetadataResolver) { this.reader.setScopeMetadataResolver(scopeMetadataResolver); this.scanner.setScopeMetadataResolver(scopeMetadataResolver); } public void register(Class<?>... componentClasses) { Assert.notEmpty(componentClasses, "At least one component class must be specified"); StartupStep registerComponentClass = this.getApplicationStartup().start("spring.context.component-classes.register").tag("classes", () -> { return Arrays.toString(componentClasses); }); this.reader.register(componentClasses); registerComponentClass.end(); } public void scan(String... basePackages) { Assert.notEmpty(basePackages, "At least one base package must be specified"); StartupStep scanPackages = this.getApplicationStartup().start("spring.context.base-packages.scan").tag("packages", () -> { return Arrays.toString(basePackages); }); this.scanner.scan(basePackages); scanPackages.end(); } public <T> void registerBean(@Nullable String beanName, Class<T> beanClass, @Nullable Supplier<T> supplier, BeanDefinitionCustomizer... customizers) { this.reader.registerBean(beanClass, beanName, supplier, customizers); } }
Spring将被@Configuration注解的配置类定义为full configuration, 而将没有被@Configuration注解的配置类定义为lite configuration。full configuration能重定向从跨方法的引用,
从而保证上述代码中的b bean是一个单例.
调用 ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry 会将 AppConfig 的配置 类属性标注为full。其调用的流程图如下:
其判断是否full的代码如下:
Map<String, Object> config = metadata.getAnnotationAttributes(Configuration.class.getName()); if (config != null && !Boolean.FALSE.equals(config.get("proxyBeanMethods"))) { beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, "full"); } else { if (config == null && !isConfigurationCandidate(metadata)) { return false; } beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, "lite"); }
跟踪 AnnotationConfigApplicationContext.refresh() 方法:
public void refresh() throws BeansException, IllegalStateException {
synchronized(this.startupShutdownMonitor) {
StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");
// Prepare this context for refreshing.
this.prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
this.prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
//供上下文(Context)子类继承,允许在这里后置处理bean factory
this.postProcessBeanFactory(beanFactory);
StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
// Invoke factory processors registered as beans in the context.
//按顺序调用BeanFactoryPostProcessor,这里的按顺序仅实现了PriorityOrdered和Ordered的语意,未实现@Order注解的语意
//通过调用ConfigurationConfigPostProcessor#postProcessBeanDefinitionRegistry
//解析@Configuration配置类,将自定义的BeanFactoryPostProcessor、BeanPostProcessor注册到beanDefinitionMap
//接着实例化所有(包括开天辟地)的BeanFactoryPostProcessor,然后再调用BeanFactoryPostProcessor#postProcessBeanFactory
this.invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
//按顺序将BeanPostProcessor实例化成bean并注册到beanFactory的beanPostProcessors,
//这里的按顺序仅实现了PriorityOrdered和Ordered的语意,未实现@Order注解的语意
//因为BeanPostProcessor要在普通bean初始化()前后被调用,所以需要提前完成实例化并注册到beanFactory的beanPostProcessors
this.registerBeanPostProcessors(beanFactory);
beanPostProcess.end();
// Initialize message source for this context.
//注册国际化相关的Bean
this.initMessageSource();
// Initialize event multicaster for this context.
//为上下文注册应用事件广播器(用于ApplicationEvent的广播),如果有自定义则使用自定义的,如果没有则内部实例化一个
this.initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
this.onRefresh();
// Check for listener beans and register them.
//注册所有(静态、动态)的listener,并广播earlyApplicationEvents
this.registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
//实例化用户自定义的普通单例Bean(非开天辟地的、非后置处理器)
this.finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
this.finishRefresh();
} catch (BeansException var10) {
if (this.logger.isWarnEnabled()) {
this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var10);
}
this.destroyBeans();
this.cancelRefresh(var10);
throw var10;
} finally {
this.resetCommonCaches();
contextRefresh.end();
}
}
}
跟踪invokeBeanFactoryPostProcessors(beanFactory)
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, this.getBeanFactoryPostProcessors());
// Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
// (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
if (!IN_NATIVE_IMAGE && beanFactory.getTempClassLoader() == null && beanFactory.containsBean("loadTimeWeaver")) {
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是一个单例。
参考博客:热心市民小陈 https://www.cnblogs.com/think-in-java/p/11876997.html