lite @Bean mode
:當@Bean
方法在沒有使用@Configuration
註解的類中聲明時稱之爲lite @Bean mode
Full @Configuration
:若是@Bean
方法在使用@Configuration
註解的類中聲明時稱之爲Full @Configuration
Full @Configuration
中的@Bean
方法會被CGLIB所代理,而 lite @Bean mode
中的@Bean
方法不會被CGLIB代理java
- 告訴spring這是一個配置類,至關於spring的xml配置文件
- 被@Configuration 註解的類,會被cglib代理進行加強
- @Configuration類容許經過調用同一類中的其餘@Bean方法來定義bean之間的依賴關係,保證@Bean的對象做用域受到控制,避免多例
爲了說明@Configuration註解的做用,咱們先來看一個maven建立的spring項目spring
// 啓動類
public class MainTest {
@Test
public void TestMain(){
new AnnotationConfigApplicationContext(AppConfig.class);
}
}
// 配置類
@Configuration
public class AppConfig {
@Bean
public User user(){
return new User();
}
@Bean
public User2 user2() {
user();
return new User2();
}
}
// 兩個實體類
public class User {
public User() {
System.out.println("User對象");
}
}
public class User2 {
public User2() {
System.out.println("User2對象");
}
}
複製代碼
這是一個最簡單的spring項目,在配置類中有@Configuration註解,咱們運行啓動類,能夠看到以下打印信息:緩存
若是去掉配置類中的@Configuration註解會怎樣呢,去掉以後,我們來看看打印信息:markdown
分析:app
- 在上面的代碼中,並無直接調用配置類和實體類,說明這些都在spring底層進行了封裝
- 在配置類中User類是進行了兩次實例化的,但加了@Configuration註解後,只進行一次實例化,說明@Configuration註解將@Bean的方法進行的加強,保證明例爲單實例
問1:@Configuration註解是如何定義bean之間的依賴關係?jvm
問2:@Configuration註解是如何將@Bean方法進行加強的?maven
下面將跟蹤spring源碼來回答這兩個問題ide
啓動類代碼只有AnnotationConfigApplicationContext
類,因此我們以這裏爲入口,點進去能夠看到源碼以下:源碼分析
public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
this();
this.register(componentClasses);
this.refresh();
}
複製代碼
在這段源碼中post
this()
:這個無參構造是和bean相關的register(componentClasses)
:將componentClasses註冊到beanDefinitionMap集合中去refresh()
:和@Configuration註解相關因此我們跟蹤refresh()
,點進去查看源碼:
【AbstractApplicationContext
類中refresh
方法】
public void refresh() throws BeansException, IllegalStateException {
synchronized(this.startupShutdownMonitor) {
StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");
this.prepareRefresh();
// 告訴子類加載內部bean工廠
ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
// 準備在上下文中使用的bean工廠
this.prepareBeanFactory(beanFactory);
try {
// 容許在上下文子類中對bean工廠進行後置處理
this.postProcessBeanFactory(beanFactory);
StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
// 這個方法是源碼分析裏面比較重要的一個入口,這裏只講和@Configuration註解相關的
// 解析@Configuration配置類,將自定義的BeanFactoryPostProcessor、BeanPostProcessor註冊到beanDefinitionMap
this.invokeBeanFactoryPostProcessors(beanFactory);
// 將BeanPostProcessor實例化成bean並註冊到beanFactory的beanPostProcessors
this.registerBeanPostProcessors(beanFactory);
beanPostProcess.end();
// 註冊國際化相關的Bean
this.initMessageSource();
// 爲上下文註冊應用事件廣播器(用於ApplicationEvent的廣播),若是有自定義則使用自定義的,若是沒有則內部實例化一個
this.initApplicationEventMulticaster();
this.onRefresh();
// 註冊全部(靜態、動態)的listener,並廣播earlyApplicationEvents
this.registerListeners();
// 實例化用戶自定義的普通單例Bean
this.finishBeanFactoryInitialization(beanFactory);
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 {
// 在Spring的核心中重置公共緩存
this.resetCommonCaches();
contextRefresh.end();
}
}
}
複製代碼
上面的源碼給出了部分註釋,咱們能夠看到,和@Configuration註解相關的是invokeBeanFactoryPostProcessors
方法,我們繼續跟蹤,點進去看源碼:
【AbstractApplicationContext
類中invokeBeanFactoryPostProcessors
方法】
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
// getBeanFactoryPostProcessors(): 拿到當前應用上下文beanFactoryPostProcessors變量中的值
// invokeBeanFactoryPostProcessors: 實例化並調用全部已註冊的BeanFactoryPostProcessor
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, this.getBeanFactoryPostProcessors());
if (!IN_NATIVE_IMAGE && beanFactory.getTempClassLoader() == null && beanFactory.containsBean("loadTimeWeaver")) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
}
複製代碼
繼續跟蹤invokeBeanFactoryPostProcessors(beanFactory, this.getBeanFactoryPostProcessors())
,進入源碼查看:
【PostProcessorRegistrationDelegate
中invokeBeanFactoryPostProcessors
方法】
public static void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
Set<String> processedBeans = new HashSet();
ArrayList regularPostProcessors;
ArrayList registryProcessors;
int var9;
ArrayList currentRegistryProcessors;
String[] postProcessorNames;
// 判斷beanFactory是否爲BeanDefinitionRegistry,beanFactory爲DefaultListableBeanFactory
if (beanFactory instanceof BeanDefinitionRegistry) {
BeanDefinitionRegistry registry = (BeanDefinitionRegistry)beanFactory;
// 用於存放普通的BeanFactoryPostProcessor
regularPostProcessors = new ArrayList();
// 用於存放BeanDefinitionRegistryPostProcessor
registryProcessors = new ArrayList();
Iterator var6 = beanFactoryPostProcessors.iterator();
// 遍歷全部的beanFactoryPostProcessors, 將BeanDefinitionRegistryPostProcessor和普通BeanFactoryPostProcessor區分開
while(var6.hasNext()) {
BeanFactoryPostProcessor postProcessor = (BeanFactoryPostProcessor)var6.next();
if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
BeanDefinitionRegistryPostProcessor registryProcessor = (BeanDefinitionRegistryPostProcessor)postProcessor;
registryProcessor.postProcessBeanDefinitionRegistry(registry);
registryProcessors.add(registryProcessor);
} else {
regularPostProcessors.add(postProcessor);
}
}
currentRegistryProcessors = new ArrayList();
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
String[] var16 = postProcessorNames;
var9 = postProcessorNames.length;
int var10;
String ppName;
// 遍歷postProcessorNames
for(var10 = 0; var10 < var9; ++var10) {
ppName = var16[var10];
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
// 解析配置類,爲配置中的bean定義生成對應beanDefinition,並注入到registry的beanDefinitionMap
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
currentRegistryProcessors.clear();
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
var16 = postProcessorNames;
var9 = postProcessorNames.length;
for(var10 = 0; var10 < var9; ++var10) {
ppName = var16[var10];
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, beanFactory.getApplicationStartup());
currentRegistryProcessors.clear();
boolean reiterate = true;
while(reiterate) {
reiterate = false;
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
String[] var19 = postProcessorNames;
var10 = postProcessorNames.length;
for(int var26 = 0; var26 < var10; ++var26) {
String ppName = var19[var26];
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, beanFactory.getApplicationStartup());
currentRegistryProcessors.clear();
}
// 調用ConfigurationClassPostProcessor#postProcessBeanFactory加強配置類
// 經過cglib生成加強類,加載到jvm內存
// 設置beanDefinition的beanClass爲加強類,讓@Bean生成的bean是單例
invokeBeanFactoryPostProcessors((Collection)registryProcessors, (ConfigurableListableBeanFactory)beanFactory);
invokeBeanFactoryPostProcessors((Collection)regularPostProcessors, (ConfigurableListableBeanFactory)beanFactory);
} else {
invokeBeanFactoryPostProcessors((Collection)beanFactoryPostProcessors, (ConfigurableListableBeanFactory)beanFactory);
}
String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);
regularPostProcessors = new ArrayList();
registryProcessors = new ArrayList();
currentRegistryProcessors = new ArrayList();
postProcessorNames = postProcessorNames;
int var20 = postProcessorNames.length;
String ppName;
for(var9 = 0; var9 < var20; ++var9) {
ppName = postProcessorNames[var9];
if (!processedBeans.contains(ppName)) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
regularPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
} else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
registryProcessors.add(ppName);
} else {
currentRegistryProcessors.add(ppName);
}
}
}
sortPostProcessors(regularPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors((Collection)regularPostProcessors, (ConfigurableListableBeanFactory)beanFactory);
List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList(registryProcessors.size());
Iterator var21 = registryProcessors.iterator();
while(var21.hasNext()) {
String postProcessorName = (String)var21.next();
orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
sortPostProcessors(orderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors((Collection)orderedPostProcessors, (ConfigurableListableBeanFactory)beanFactory);
List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList(currentRegistryProcessors.size());
Iterator var24 = currentRegistryProcessors.iterator();
while(var24.hasNext()) {
ppName = (String)var24.next();
nonOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
}
invokeBeanFactoryPostProcessors((Collection)nonOrderedPostProcessors, (ConfigurableListableBeanFactory)beanFactory);
beanFactory.clearMetadataCache();
}
複製代碼
這裏和@Configuration註解相關的方法是invokeBeanFactoryPostProcessors((Collection)registryProcessors, (ConfigurableListableBeanFactory)beanFactory);
,繼續跟蹤,進入源碼查看:
【PostProcessorRegistrationDelegate
中invokeBeanFactoryPostProcessors
方法】
private static void invokeBeanFactoryPostProcessors(Collection<? extends BeanFactoryPostProcessor> postProcessors, ConfigurableListableBeanFactory beanFactory) {
Iterator var2 = postProcessors.iterator();
while(var2.hasNext()) {
BeanFactoryPostProcessor postProcessor = (BeanFactoryPostProcessor)var2.next();
StartupStep var10000 = beanFactory.getApplicationStartup().start("spring.context.bean-factory.post-process");
postProcessor.getClass();
StartupStep postProcessBeanFactory = var10000.tag("postProcessor", postProcessor::toString);
// 調用ConfigurationClassPostProcessor#postProcessBeanFactory加強配置類
postProcessor.postProcessBeanFactory(beanFactory);
postProcessBeanFactory.end();
}
}
複製代碼
繼續跟蹤postProcessor.postProcessBeanFactory(beanFactory);
,進入源碼查看,發現是一個接口,我們找到和@Configuration相關的,也就是截圖中框出來的 ,查看源碼:
【ConfigurationClassPostProcessor
類中postProcessBeanFactory
方法】
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);
} else {
this.factoriesPostProcessed.add(factoryId);
if (!this.registriesPostProcessed.contains(factoryId)) {
this.processConfigBeanDefinitions((BeanDefinitionRegistry)beanFactory);
}
// 進行代理,爲@Configuration註解的類生成加強類
this.enhanceConfigurationClasses(beanFactory);
beanFactory.addBeanPostProcessor(new ConfigurationClassPostProcessor.ImportAwareBeanPostProcessor(beanFactory));
}
}
複製代碼
該方法會去判斷咱們的bean工廠當中是否有bean須要進行cglib代理,並在enhanceConfigurationClasses(beanFactory)
方法中進行代理,爲@Configuration註解的類生成加強類,繼續跟蹤,點進enhanceConfigurationClasses
,以下:
【ConfigurationClassPostProcessor
類中enhanceConfigurationClasses
方法】
public void enhanceConfigurationClasses(ConfigurableListableBeanFactory beanFactory) {
StartupStep enhanceConfigClasses = this.applicationStartup.start("spring.context.config-classes.enhance");
Map<String, AbstractBeanDefinition> configBeanDefs = new LinkedHashMap();
String[] var4 = beanFactory.getBeanDefinitionNames();
int var5 = var4.length;
for(int var6 = 0; var6 < var5; ++var6) {
String beanName = var4[var6];
BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName);
// 在ConfigurationClassUtils中標記是Full @Configuration仍是lite @Bean mode
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) {
AbstractBeanDefinition abd = (AbstractBeanDefinition)beanDef;
if (!abd.hasBeanClass()) {
try {
abd.resolveBeanClass(this.beanClassLoader);
} catch (Throwable var13) {
throw new IllegalStateException("Cannot load configuration class: " + beanDef.getBeanClassName(), var13);
}
}
}
// 1.判斷是不是全類註解
if ("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");
}
if (this.logger.isInfoEnabled() && beanFactory.containsSingleton(beanName)) {
this.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'.");
}
// 2.是全註解則將beandefinition放入map中
configBeanDefs.put(beanName, (AbstractBeanDefinition)beanDef);
}
}
if (!configBeanDefs.isEmpty() && !IN_NATIVE_IMAGE) {
ConfigurationClassEnhancer enhancer = new ConfigurationClassEnhancer();
Iterator var15 = configBeanDefs.entrySet().iterator();
// 3.而後遍歷這個map
while(var15.hasNext()) {
Entry<String, AbstractBeanDefinition> entry = (Entry)var15.next();
AbstractBeanDefinition beanDef = (AbstractBeanDefinition)entry.getValue();
beanDef.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE);
Class<?> configClass = beanDef.getBeanClass();
// 4.進行cglib代理,爲@Configuration註解的類生成加強類
Class<?> enhancedClass = enhancer.enhance(configClass, this.beanClassLoader);
if (configClass != enhancedClass) {
if (this.logger.isTraceEnabled()) {
this.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);
}
}
enhanceConfigClasses.tag("classCount", () -> {
return String.valueOf(configBeanDefs.keySet().size());
}).end();
} else {
enhanceConfigClasses.end();
}
}
複製代碼
在ConfigurationClassUtils
類中聲明瞭是Full @Configuration仍是lite @Bean mode,能夠看看源碼:
【ConfigurationClassUtils
類中checkConfigurationClassCandidate
方法】
Map<String, Object> config = metadata.getAnnotationAttributes(Configuration.class.getName());
// 若是存在@Configuration註解,則爲BeanDefinition設置configurationClass屬性爲full
if (config != null && !Boolean.FALSE.equals(config.get("proxyBeanMethods"))) {
beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, "full");
} else {
if (config == null && !isConfigurationCandidate(metadata)) {
return false;
}
// 若是沒有@Configuration註解或者有Component,ComponentScan,Import,ImportResource 註解中的任意一個,
// 或者存在 被@bean 註解的方法,則返回true.
// 則設置configurationClass屬性爲lite
beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, "lite");
}
Integer order = getOrder(metadata);
if (order != null) {
beanDef.setAttribute(ORDER_ATTRIBUTE, order);
}
複製代碼
跟蹤到這裏,基本上就比較明朗了,能夠獲得咱們想要的答案
- 在
ConfigurationClassUtils
類中的checkConfigurationClassCandidate
標記是Full @Configuration仍是lite @Bean mode- 經過
"full".equals(configClassAttr)
判斷是不是全類註解- 是全註解則將beandefinition放入map中
configBeanDefs.put
- 遍歷這個map
- 使用cglib技術爲配置類生成一個enhancedClass
- 經過
enhancer.enhance
進行cglib代理,爲@Configuration註解的類生成加強類- 再經過
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的實例了,若是有了的話,就返回已有對象,沒有的話就建立一個,而後放到容器中。
是如何進行代理的,我們還能夠繼續跟蹤:點開enhancer.enhance
,進入ConfigurationClassEnhancer
類,在這個類中會去執行cglib代理類中的代理方法,以下:
【ConfigurationClassEnhancer
類中static
靜態方法】
static {
CALLBACKS = new Callback[]{new ConfigurationClassEnhancer.BeanMethodInterceptor(),
new ConfigurationClassEnhancer.BeanFactoryAwareMethodInterceptor(), NoOp.INSTANCE};
CALLBACK_FILTER = new ConfigurationClassEnhancer.ConditionalCallbackFilter(CALLBACKS);
logger = LogFactory.getLog(ConfigurationClassEnhancer.class);
objenesis = new SpringObjenesis();
}
複製代碼
cglib代理主要就是callBacks中的方法,點進去能夠看到是一個接口,其中有一個實現類就是和cglib相關的
@Configuration註解底層是如何實現的,經過源碼我們能夠反推並總結爲如下幾點:
beandefenition
ConfigurationClassUtils
類中checkConfigurationClassCandidate
方法判斷是Full @Configuration仍是lite @Bean mode