写点什么

@Configuration 注解 -【Spring 底层原理

  • 2022 年 4 月 19 日
  • 本文字数:4407 字

    阅读完需:约 14 分钟

2. @Configuration 注解作用

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


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


  1. @Con?guration 类允许通过调用同一类中的其他 @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(v Java 开源项目【ali1024.coding.net/public/P7/Java/git】 ar10);


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()),进入源码查看:


PostProcessorRegistrationDelegateinvokeBeanFactoryPostProcessors方法】


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?(!pro 《一线大厂 Java 面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义》开源 cessedBeans.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);

最后

由于篇幅有限,这里就不一一罗列了,20 道常见面试题(含答案)+21 条 MySQL 性能调优经验小编已整理成 Word 文档或 PDF 文档



还有更多面试复习笔记分享如下



用户头像

还未添加个人签名 2022.04.13 加入

还未添加个人简介

评论

发布
暂无评论
@Configuration注解 -【Spring底层原理_Java_爱好编程进阶_InfoQ写作平台