最近看自动注入的时候,发现很多的注解都见过,不知道到底是那块解析的。本篇文章将对springboot中的注解进行分析,主要是理清注解的功能,实现逻辑不会很详细分析。


@Configuration

@Configuration,将类作为配置,最主要的就是可以在类中使用@Bean注解,标注在方法上,可以将方法的返回值对象放入的容器中,对象的名称是方法名称。

@Component

此注解主要作用是将标注的类放入的容器,@controller,@service本质一样。

@ComponentScans

见名知意,就是扫描@Component注解的,给定包名,可以将包内的使用@Component注解标注的类放入到容器中。注意,这个注解不能单独使用,需要搭配@Configuration注解。

@PropertySource

这个注解的作用是加载一个属性文件,通常用法是加载属性文件,将属性文件值赋值给bean的属性。
使用方法可以参考使用方法,注意,这个注解不能单独使用,需要搭配@Configuration注解。

@ConfigurationProperties

这个注解通常是用来获取主配置文件的(application.yml或者application.properties)中的属性值,将其赋值给bean属性。

使用方法

以DataSourceProperties为例

@ConfigurationProperties(prefix = "spring.datasource")
public class DataSourceProperties implements BeanClassLoaderAware, InitializingBean {private ClassLoader classLoader;private String name;private boolean generateUniqueName;private Class<? extends DataSource> type;private String driverClassName;private String url;private String username;private String password;private String jndiName;。。。
}

配置文件中的属性:

spring:datasource:driver-class-name:url:password:username:

前缀+属性名称,如果可以对应上配置文件中的key,就把key对应的value,赋值给bean的属性。这个注解可以单独使用,但你想把这个类放入到容器中,就要搭配@Configuration。注意;这个的搭配和前面两个注解的搭配不一样。@PropertySource,@ComponentScans,如果不和@Configuration注解一起使用,那么其功能就不能实现。而@ConfigurationProperties注解,搭配@Configuration的目的仅仅是将其放入到容器中。如果单独使用功能是可以实现的。 为了方便,springboot还提供了一个注解,EnableConfigurationProperties,这个注解可以将配置的属性bean放入的容器中。

@EnableConfigurationProperties

这个注解可以把属性bean放入到容器中,将处理ConfigurationProperties注解的逻辑类放入到容器中。

使用方法

@EnableConfigurationProperties(JdbcProperties.class)
public class JdbcTemplateAutoConfiguration {

原理

直接看EnableConfigurationPropertiesImportSelector

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(EnableConfigurationPropertiesImportSelector.class)
public @interface EnableConfigurationProperties {

org.springframework.boot.context.properties.EnableConfigurationPropertiesImportSelector
实现了ImportSelector接口,直接看selectImports方法

 private static final String[] IMPORTS = {ConfigurationPropertiesBeanRegistrar.class.getName(),ConfigurationPropertiesBindingPostProcessorRegistrar.class.getName() };@Overridepublic String[] selectImports(AnnotationMetadata metadata) {return IMPORTS;}

返回了两个类ConfigurationPropertiesBeanRegistrar是将配置的属性bean放入到容器。ConfigurationPropertiesBindingPostProcessorRegistrar是处理ConfigurationProperties注解的,绑定逻辑。这两个类的逻辑自己看就可以了,了解大概流程。

@NestedConfigurationProperty

这个注解还是和属性相关,是嵌套类型的。使用方法使用方法,解析的逻辑应该还是在ConfigurationPropertiesBindingPostProcessorRegistrar类中。

@ImportResource

这个类是加载配置文件的,没有springboot之前,使用spring的时候要有spring.xml的文件,在里面陪各种信息。这个注解就是加载xml配置文件的。

下面重点分析条件注解

AutoConfigureBefore、AutoConfigureAfter、AutoConfigureOrder

在自动配置的时候,会找到这三个注解,注意,这三个注解是springboot自动配置专用的注解,我们开发的时候是用不上的。主要功能就是区分解析的的顺序,

org.springframework.context.annotation.ConfigurationClassParser.DeferredImportSelectorGroupingHandler#processGroupImports

     public void processGroupImports() {for (DeferredImportSelectorGrouping grouping : this.groupings.values()) {Predicate<String> exclusionFilter = grouping.getCandidateFilter();// 得到所有的配置类,之后遍历grouping.getImports().forEach(entry -> {ConfigurationClass configurationClass = this.configurationClasses.get(entry.getMetadata());try {// 分别调用processImports,走导入类的逻辑。processImports(configurationClass, asSourceClass(configurationClass, exclusionFilter),Collections.singleton(asSourceClass(entry.getImportClassName(), exclusionFilter)),exclusionFilter, false);}catch (BeanDefinitionStoreException ex) {throw ex;}catch (Throwable ex) {throw new BeanDefinitionStoreException("Failed to process import candidates for configuration class [" +configurationClass.getMetadata().getClassName() + "]", ex);}});}}

下面看看grouping.getImports()方法做了什么操作。

     public Iterable<Group.Entry> getImports() {for (DeferredImportSelectorHolder deferredImport : this.deferredImports) {// 这块是从配置文件中读取出配置类(注意,这里的配置类是过滤之后的,过滤逻辑可以可以自己看看),this.group.process(deferredImport.getConfigurationClass().getMetadata(),deferredImport.getImportSelector());}// return this.group.selectImports();}
     public Iterable<Entry> selectImports() {if (this.autoConfigurationEntries.isEmpty()) {return Collections.emptyList();}Set<String> allExclusions = this.autoConfigurationEntries.stream().map(AutoConfigurationEntry::getExclusions).flatMap(Collection::stream).collect(Collectors.toSet());Set<String> processedConfigurations = this.autoConfigurationEntries.stream().map(AutoConfigurationEntry::getConfigurations).flatMap(Collection::stream).collect(Collectors.toCollection(LinkedHashSet::new));processedConfigurations.removeAll(allExclusions);// 这步,排序了,看看是怎么排序的return sortAutoConfigurations(processedConfigurations, getAutoConfigurationMetadata()).stream().map((importClassName) -> new Entry(this.entries.get(importClassName), importClassName)).collect(Collectors.toList());}
 List<String> getInPriorityOrder(Collection<String> classNames) {AutoConfigurationClasses classes = new AutoConfigurationClasses(this.metadataReaderFactory,this.autoConfigurationMetadata, classNames);List<String> orderedClassNames = new ArrayList<>(classNames);// 默认是按照字母的顺序Collections.sort(orderedClassNames);// 之后再按照order的顺序orderedClassNames.sort((o1, o2) -> {int i1 = classes.get(o1).getOrder();int i2 = classes.get(o2).getOrder();return Integer.compare(i1, i2);});// 之后处理@AutoConfigureBefore @AutoConfigureAfter注解的配置。orderedClassNames = sortByAnnotation(classes, orderedClassNames);return orderedClassNames;}

ConditionalOnClass,ConditionalOnBean,ConditionalOnMissingBean,ConditionalOnMissingClass,ConditionalOnProperty

这些都是属于同一类的,都是过滤配置类的条件。首先要明白我们自己的配置类是先放入到org.springframework.context.annotation.ConfigurationClassParser#configurationClasses中的,之后才是自动配置类。

org.springframework.context.annotation.ConfigurationClassParser#processConfigurationClass

 protected void processConfigurationClass(ConfigurationClass configClass, Predicate<String> filter) throws IOException {// 在这步进行条件判断,符合的才会继续解析。if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {return;}。。。

进入方法。
遍历每一个条件类,如果不匹配,就返回true,跳过该配置类,不再解析。

for (Condition condition : conditions) {ConfigurationPhase requiredPhase = null;if (condition instanceof ConfigurationCondition) {requiredPhase = ((ConfigurationCondition) condition).getConfigurationPhase();}if ((requiredPhase == null || requiredPhase == phase) && !condition.matches(this.context, metadata)) {return true;}}

condition.matches自己分析吧,不算难。就是有没有类,bean工厂中有没有对应类型。


注意

看博客的时候,发现这么一遍文章。条件注解 @ConditionalOnBean 的正确使用姿势。
没有触发解析的主要原因是没有了解配置类的加载顺序。我们自己写的配置类,是按照包名顺序->类名顺序(如果有内部类的,先解析内部类的)->@Bean方法顺序,也就是说,以idea的类结构看,上面的配置类一定不要在@ConditionalOnBean里面配置下面类中的@bean类。

springboot-注解汇总相关推荐

  1. SpringBoot笔记汇总【动力节点SpringBoot全套教程完整版】

    前言 动力节点的springboot笔记汇总,公开免费. Spring Boot教程 学习地址 动力节点springboot视频教程-专为springboot初学者打造的教程_哔哩哔哩_bilibil ...

  2. 十、springboot注解式AOP(@Aspect)统一日志管理

    springboot注解式AOP(@Aspect)统一日志管理 简介 AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功 ...

  3. SpringBoot注解大全(转)

    原文链接:[springBoot系列]--springBoot注解大全 一.注解(annotations)列表  @SpringBootApplication:包含了@ComponentScan.@C ...

  4. spring-boot注解详解(三)

    1.SpringBoot/spring @SpringBootApplication: 包含@Configuration.@EnableAutoConfiguration.@ComponentScan ...

  5. spring-boot注解详解(一)

    spring-boot注解详解(一) @SpringBootApplication @SpringBootApplication = (默认属性)@Configuration + @EnableAut ...

  6. @configuration注解_超级全面的 SpringBoot 注解介绍,每一个用途都应该清晰

    一.注解(annotations)列表 1.@SpringBootApplication 包含了@ComponentScan.@Configuration和@EnableAutoConfigurati ...

  7. 【SpringBoot 】SpringBoot注解详解

    [SpringBoot ]SpringBoot注解详解 一.注解(annotations)列表  @SpringBootApplication:包含了@ComponentScan.@Configura ...

  8. SpringBoot : 注解@Resource

    1.美图 2.概述 在项目开发中,@Autowired和@Resource之争,一直搞不清楚,反正也不想搞清楚到底什么时候用@Autowired,什么场景下用@Resource,就一直用@Autowi ...

  9. SpringBoot注解把配置文件自动映射到属性和实体类实战

    SpringBoot注解把配置文件自动映射到属性和实体类实战 简介:讲解使用@value注解配置文件自动映射到属性和实体类 1.配置文件加载 方式一 1.Controller上面配置 @Propert ...

  10. java开发常用注解汇总

    lombok整理 @Data 注解在类上:提供类所有属性的 getting 和 setting 方法,此外还提供了equals.canEqual.hashCode.toString 方法 @Sette ...

最新文章

  1. 双节棍「大师」鱼佬亲传武功秘籍:如何进行一场数据挖掘算法竞赛?
  2. html5拖动图像的关键字,6.7 拖放图像 - HTML5 Canvas 实战
  3. mysql uncompress_如何在php中实现mysql compress()函数
  4. php 5.6.29,源码编译安装PHP 5.6.29
  5. 如何二值图转化为灰度图_AAAI 2020 | 时序转化为图用于可解释可推理异常检测
  6. “LINQ已死”论 为言论1 致歉 [Java | .Net | 致歉 ]
  7. GitHub 遭黑客攻击勒索;苹果夸大 iPhone 电池续航时间;全球第二大暗网被摧毁 | 极客头条...
  8. 好用的HTML文本编辑器BBEdit for Mac
  9. bug管理工具之禅道的测试模块的使用
  10. OPENJDK8 32位版本,JAVA启动时Xmx参数的影响
  11. 高德地图,百度地图,腾讯地图,谷歌地图,坐标拾取器
  12. 珠海华润银行网银密码控件
  13. 征集开始!2022年湖北省人工智能 大数据十大优秀应用案例征集申报时间要求及征集范围、注意事项
  14. 红米手机使用应用沙盒一键修改cpu信息
  15. word删除空白页删不了怎么办?Word怎么删除空白页?
  16. C语言|控制台小游戏|打飞机(基础功能版)
  17. 在输入框输入时限制输入框只能输入正整数以及两位小数正则表达式
  18. 拉格朗日乘数和KTT条件
  19. 解决Cadence 17.4软件无法启动,capture cis启动缓慢,打开项目缓慢,allegro 打开程序未响应(即使微软拼音切换兼容模式也无法解决的情况)
  20. 智能车牌识别停车场系统方案

热门文章

  1. gitee java pdf转图片_openOffice word转pdf,pdf转图片优化版
  2. 自动驾驶1-4 驾驶分类Taxonomy of Driving
  3. 解析极限编程--Kent Beck, Cynthia Andres读后感
  4. java内省_聊聊Java内省Introspector
  5. DST(对话状态追踪)常用方法
  6. 不使用任何判断比较两个整数
  7. python 求当前小时前n个小时
  8. php 调用dll静态库,vue-cli 2.x 项目优化之引入本地静态库文件
  9. flutter能开发游戏吗_Flutter开发游戏初体验,喜大普奔
  10. 【Nowcoder - 5670 B Graph】2020 牛客暑期多校训练营(第五场)【最小异或生成树、Boruvka 思想】