七、Spring-注解开发实现原理
大家在spring开发的过程中,肯定使用了大量的注解,比如@ComponentScan、@Import、@Bean、@Configuration、@Conditional等大量注解来帮助我们快速开发,但是大家想过没有,他们底层是如何实现的。
比如之前大家注册一个bean需要在spring.xml配置文件里面配置一堆,现在只需要一个注解就可以完成了。
<bean id="cat" class="com.amarsoft.code.spring.pojo.Cat"></bean>
@Component
public class Cat {int age;public Cat() {System.err.println("Cat初始化成功");}public int getAge() {return age;}public void setAge(int age) {this.age = age;}
}
上面是如何做到的?它是依靠ConfigurationClassPostProcessor实现的。
ConfigurationClassPostProcessor是一个实现BeanDefinitionRegistryPostProcessor接口的类,在spring容器初始化的时候,调用BeanFactory的后置处理器实现注解扫描的,注册bean定义信息的。
public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor,PriorityOrdered, ResourceLoaderAware, ApplicationStartupAware, BeanClassLoaderAware, EnvironmentAware {.............
}
方法如何跟入:
AbstractApplicationContext类:
refresh() ---- invokeBeanFactoryPostProcessors(beanFactory) --- 找到实现BeanDefinitionRegistryPostProcessor和PriorityOrdered接口的方法进行调用invokeBeanDefinitionRegistryPostProcessors方法到ConfigurationClassPostProcessor类进行处理。
核心处理逻辑代码:
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter)throws IOException {if (configClass.getMetadata().isAnnotated(Component.class.getName())) {// Recursively process any member (nested) classes firstprocessMemberClasses(configClass, sourceClass, filter);}// Process any @PropertySource annotationsfor (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(sourceClass.getMetadata(), PropertySources.class,org.springframework.context.annotation.PropertySource.class)) {if (this.environment instanceof ConfigurableEnvironment) {processPropertySource(propertySource);}else {logger.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +"]. Reason: Environment must implement ConfigurableEnvironment");}}// Process any @ComponentScan annotationsSet<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);if (!componentScans.isEmpty() &&!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {for (AnnotationAttributes componentScan : componentScans) {// The config class is annotated with @ComponentScan -> perform the scan immediatelySet<BeanDefinitionHolder> scannedBeanDefinitions =this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());// Check the set of scanned definitions for any further config classes and parse recursively if neededfor (BeanDefinitionHolder holder : scannedBeanDefinitions) {BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();if (bdCand == null) {bdCand = holder.getBeanDefinition();}if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {parse(bdCand.getBeanClassName(), holder.getBeanName());}}}}// Process any @Import annotationsprocessImports(configClass, sourceClass, getImports(sourceClass), filter, true);// Process any @ImportResource annotationsAnnotationAttributes importResource =AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);if (importResource != null) {String[] resources = importResource.getStringArray("locations");Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");for (String resource : resources) {String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);configClass.addImportedResource(resolvedResource, readerClass);}}// Process individual @Bean methodsSet<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);for (MethodMetadata methodMetadata : beanMethods) {configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));}// Process default methods on interfacesprocessInterfaces(configClass, sourceClass);// Process superclass, if anyif (sourceClass.getMetadata().hasSuperClass()) {String superclass = sourceClass.getMetadata().getSuperClassName();if (superclass != null && !superclass.startsWith("java") &&!this.knownSuperclasses.containsKey(superclass)) {this.knownSuperclasses.put(superclass, configClass);// Superclass found, return its annotation metadata and recursereturn sourceClass.getSuperClass();}}// No superclass -> processing is completereturn null;}
下面挑选几个注解说明一下,其他的注解也大同小异。
@ComponentScan
它的出现主要是对标component-scan标签,标签只能使用在xml的配置文件中,而现在越来越流行使用注解的形式注册bean。
- 首先检查传入的bean定义是否实现ComponentScan,如果实现了拿出ComponentScan信息。
- 判断如果不为空 和 是否符合注入条件,这里shouldSkip方法里面应用了@Conditional注解判断条件。
- 进行遍历ComponentScan注解信息,使用componentScanParser解析,找出符合条件的bean定义信息。
- 对找到的bean定义信息进行递归调用,防止找到的bean定义信息上面还有注解信息。
// Process any @ComponentScan annotationsSet<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);if (!componentScans.isEmpty() &&!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {for (AnnotationAttributes componentScan : componentScans) {// The config class is annotated with @ComponentScan -> perform the scan immediatelySet<BeanDefinitionHolder> scannedBeanDefinitions =this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());// Check the set of scanned definitions for any further config classes and parse recursively if neededfor (BeanDefinitionHolder holder : scannedBeanDefinitions) {BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();if (bdCand == null) {bdCand = holder.getBeanDefinition();}if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {parse(bdCand.getBeanClassName(), holder.getBeanName());}}}}
特别说明一下这个寻找bean定义信息过程方法:
这里扫描使用的ClassPathBeanDefinitionScanner这个扫描器,它的作用是指定过滤条件,在指定的classpath下寻找符合条件的bean定义信息,并且之后注册到registerBeanDefinition集合中。
mybatis框架的@MapperScan扫描mapper也是使用的这个扫描器来实现的。
参考:org.mybatis.spring.mapper.ClassPathMapperScanner
七、Spring-注解开发实现原理相关推荐
- 关于Spring注解开发教程,打包全送你
摘要:spring是我们web开发中必不可少的一个框架,基于传统的xml方式配置bean总觉得太过繁琐,从spring2.5之后注解的出现可以大大简化我们的配置. 本文分享自华为云社区<如何高效 ...
- spring注解开发:容器中注册组件方式
1.包扫描+组件标注注解 使用到的注解如下,主要针对自己写的类 @Controller @Service @Repository @Component @ComponentScan 参考 spring ...
- spring注解开发配置spring父子容器
spring注解开发配置spring父子容器 官网 https://docs.spring.io/spring-framework/docs/current/spring-framework-refe ...
- 第二章 ---- spring注解开发
文章目录 参考视频 注解驱动的意义 常用注解(重点) 启动注解驱动 IoC bean定义(@Component .@Controller.@Service. @Repository) @Scope b ...
- 二、Java框架之Spring注解开发
文章目录 1. IOC/DI注解开发 1.1 Component注解 @Component @Controller @Service @Repository 1.2 纯注解开发模式 1.3 注解开发b ...
- Spring注解开发【源码分析】
一.注册组件 @ComponentScan 扫描指定包下的组件. String[] value():扫描基础包范围 Filter[] includeFilters():扫描并获取符合过滤规则的组件 F ...
- 尚硅谷Spring注解开发学习笔记
文章目录 前言 1.课程安排 1.1.容器 1.2.扩展原理 1.3.Web 2.配置文件开发 2.1.导入Spring-context依赖包 2.2.编写Spring配置文件 2.3.编写Perso ...
- Spring注解开发-Bean注册
1.使用注解开发我们需要在applicationContext.xml文件中添加context标签. 在配置文件中开启注解扫描. <?xml version="1.0" en ...
- Spring—注解开发
Spring原始注解 Spring是轻代码而重配置的框架,配置比较繁重,影响开发效率,所以注解开发是一种趋势,注解代替xml配置文 件可以简化配置,提高开发效率. @Component 使用在类上用于 ...
- Spring注解开发入门教程
注解开发: 什么是驱动注解? 注解启动时使用注解的形式替代xml配置,将繁杂的spring配置文件从工程中彻底消除掉,简化书写 注解驱动的弊端 为了达成注解驱动的目的,可能会将原先很简单的书写,变的更 ...
最新文章
- 程序是一座城,八年来我深陷其中
- ppt 简单动画制作
- To handle Unhandled Exception
- c#语言中读取txt文件,简单的c#文本文件读写-.NET教程,C#语言
- Linux网络不可达解决方法
- 微信整人假红包图片_警惕:千万别点!这些红包是假的
- tableau货架图制作_3小时精通Tableau图表制作(18类)
- 运行php程序cpu 100%,php 应用 cpu 100% 调试方法
- ECS入门之Hello World
- php如何数字转字符串,php如何实现数字转字符串
- 发布Drools Workbench到Tomcat on Linux
- 2060 super和5700xt哪个值得买?
- 大理,徐娘半老的蝴蝶泉
- android ListView 九大重要属性详细分析
- 安装Lync Server 2013
- 怎么制作自己的数据集
- sublime 格式化Json
- 小米路由器显示DNS服务器设置错误,小米路由器dns地址怎么设置
- python编写一个简单的程序验证码_遇到验证码怎么办?Python编写一个验证码图片数据标注GUI程序!...
- 一、初学计算机——认识键盘布局及快捷键使用
热门文章
- SSRS从入门到放弃?? 零基础:教你5分钟内轻松制作一张报表(Intouch、IFix、WinCC、组态王等均适用)
- papaparse 使用_插件 jQuery.Papa Parse 中文 API 文档
- 传感器阵列波束优化设计与应用_传感器阵列波束优化设计及应用
- 成人高等教育计算机,成人高等教育计算机实验教学研究
- Xmind思维导图软件2023下载安装教程【附海量模板素材】
- 二、JAVA调用海康威视SDK实现摄像头预览完整版
- 微信小程序 自助停车,输入车牌号功能实现
- 黄山游记(三):登黄山
- Python游戏设计案例实战 夏敏捷 (第一本专著),国内这方面著作少有
- android 仿蘑菇街效果,Vue项目-仿蘑菇街移动端Web开发