一、注解用法
1. 知识背景
lite @Bean mode
:当@Bean
方法在没有使用@Configuration
注解的类中声明时称之为lite @Bean mode
Full @Configuration
:如果@Bean
方法在使用@Configuration
注解的类中声明时称之为Full @Configuration
Full @Configuration
中的@Bean
方法会被CGLIB所代理,而 lite @Bean mode
中的@Bean
方法不会被CGLIB代理
2. @Configuration注解作用
- 告诉spring这是一个配置类,相当于spring的xml配置文件
- 被@Configuration 注解的类,会被cglib代理进行增强
- @Configuration类允许通过调用同一类中的其他@Bean方法来定义bean之间的依赖关系,保证@Bean的对象作用域受到控制,避免多例
二、实例分析
1. 案例
为了说明@Configuration注解的作用,我们先来看一个maven创建的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注解,我们运行启动类,可以看到如下打印信息:
image-20210115101414931
如果去掉配置类中的@Configuration注解会怎样呢,去掉之后,咱们来看看打印信息:
image-20210115101618212
分析:
- 在上面的代码中,并没有直接调用配置类和实体类,说明这些都在spring底层进行了封装
- 在配置类中User类是进行了两次实例化的,但加了@Configuration注解后,只进行一次实例化,说明@Configuration注解将@Bean的方法进行的增强,保证实例为单实例
2. 问题
问1:@Configuration注解是如何定义bean之间的依赖关系?
问2:@Configuration注解是如何将@Bean方法进行增强的?
下面将跟踪spring源码来回答这两个问题
三、源码追踪
启动类代码只有AnnotationConfigApplicationContext
类,所以咱们以这里为入口,点进去可以看到源码如下:
public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
this();
this.register(componentClasses);
this.refresh();
}
在这段源码中
-
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相关的,也就是截图中框出来的 ,查看源码:
image-20210115154241215
【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相关的
image-20210115201141656
四、总结
@Configuration注解底层是如何实现的,通过源码咱们可以反推并总结为以下几点:
- Spring首先会获取到所有的
beandefenition
-
ConfigurationClassUtils
类中checkConfigurationClassCandidate
方法判断是Full @Configuration还是lite @Bean mode - 通过ConfigurationClassPostProcessor后置处理器遍历所有的beandefenition
- 将标记了Full @Configuration模式的beandefenition,会对这个类进行cglib代理,生成一个代理类,并把这个类设置到BeanDefenition的Class属性中
- 配置类会被CGLIB增强(生成代理对象),放进IoC容器内的是代理
- 对于内部类是没有限制的:可以是Full模式或者Lite模式
- 配置类内部可以通过方法调用来处理依赖,并且能够保证是同一个实例,都指向IoC内的那个单例
- 需要用这个Bean实例的时候,从这个Class属性中拿到的Class对象进行反射,最终反射出来的是代理增强后的类
- 通过@Configuration标注类的Bean,Spring会先去容器中查看是否有这个Bean实例,如果有就返回已有的对象,没有就创建一个,然后放到容器中