本文為博主原創,轉載請注明出處:
@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