@SpringBootApplication揭秘

一、SpringBoot初体验

一个典型的SpringBoot应用长什么样子呢?如果我们使用http://start.spring.io/创建一个最简单的依赖Web模块的SpringBoot应用,一般情况下, 我们会得到一个SpringBoot应用的启动类,如下面代码所示:

import org.springframework.boot.SpringApplicationimport org.springframework.boot.autoconfigure.SpringBootApplication;©SpringBootApplication
public class DemoApplication {public static void main(String[] args) {SpringApplication.run(DemoApplication.class, args)}
}

所有的SpringBoot无论怎么定制,本质上与上面的启动类代码是一样的,而以上代码示例中,**Annotation定义(@SpringBootApplication)类定义 (SpringApplication.run)**最为耀眼,那么要揭开SpringBoot应用的奥秘,很明显的,我们只要先从这两位开始就可以了。

二、@SpringBootApplication背后的秘密

@SpringBootApplication是一个"三体”结构,实际上它是一个复合 Annotation:

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(...)
public @interface SpringBootApplication{
...
}

虽然定义使用了多个Annotation进行了原信息标注,但实际上重要的只有三个Annotation:

  • @Configuration(@SpringBootConfiguration点开查看发现里面还是应用了@Configuration)
  • @EnableAutoConfiguration
  • @ComponentScan

所以,如果我们使用如下的SpringBoot启动类,整个SpringBoot应用依然可以与之前的启动类功能对等:

@Configuration
@EnableAutoConfiguration
@ComponentScan
public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);}
}

但每次都写三个Annotation显然过于繁琐,所以写一个@SpringBoot-Application这样的一站式复合Annotation显然更方便些。

1、@Configuration 创世纪

很多SpringBoot的代码示例都喜欢在启动类上直接标注@Configuration或者@SpringBootApplication,对于初接触SpringBoot的开发者来说,其实这种做法不便于理解,如果我们将上面的SpringBoot启动类拆分为两个独立的Java类,整个形势就明朗了:

@Configuration
@EnableAutoConfiguration
@ComponentScan
public class DemoConfiguration {@Beanpublic Controller controller() {return new Controller();}
}
public class DemoApplication {public static void main(String[] args) {SpringApplication.run(DemoConfiguration.class, args);}
}

2、@EnableAutoConfiguration的功效

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";Class<?>[] exclude() default {};String[] excludeName() default {};
}

其中最关键的要属@Import(AutoConfigurationImportSelector.class),借助AutoConfigurationImportSelector@EnableAutoConfiguration可以帮助SpringBoot应用将所有符合条件的@Configuration配置都加载到当前SpringBoot创建并使用的IoC容器。

借助于Spring框架原有的一个工具类:SpringFactoriesLoader的支持,@EnableAutoConfiguration可以智能的自动配置功效才得以大功告成!

SpringFactoriesLoader 自动配置幕后英雄

Spring的SpringFactoriesLoader工厂的加载机制类似java提供的SPI机制一样,是Spring提供的一种加载方式。只需要在classpath路径下新建一个文件META-INF/spring.factories,并在里面按照Properties格式填写好接口和实现类即可通过SpringFactoriesLoader来实例化相应的Bean。配置的格式为Key = Value形式,其中key可以是接口、注解、或者抽象类的全名。value为相应的实现类,当存在多个实现类时,用“,”进行分割。

对于 @EnableAutoConfiguration 来说,SpringFactoriesLoader 的用途稍 微不同 一些,其本意是为了提供SPI扩展的场景,而在@EnableAutoConfiguration的场景 中,它更多是提供了一种配置查找的功能支持,即根据@EnableAutoConfiguration 的完整类名 org.springframework.boot.autoconiigure.EnableAutoConfiguration 作为查找 的Key,获取对应的一组©Configuration类。

所以,@EnableAutoConfiguration自动配置的魔法其实就变成了:从 classpath 中搜寻所有 META-INF/spring.factories 配置文件,并将其中 org.spring・ framework.boot.autoconfigure.EnableAutoConfiguration 对应的配置项通过反射 (Java Reflection)实例化为对应的标注了 ©Configuration的JavaConfig形式的 IoC容器配置类,然后汇总为一个并加载到IoC容器。

3、@ComponentScan

@ComponentScan的功能其实就是自动扫描并加载符合条件的组件或bean定义,最终将这些bean定义加载到容器中。加载bean定义到Spring的IoC容器,当然我们也可以手工单个注册

参考:

  • 《SpringBoot揭秘+快速构建微服务体系》 第三章

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/535540.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SpringApplication:SpringBoot程序启动的一站式解决方案

我们说SpringBoot是Spring框架对“约定优先于配置(Convention Over Configuration)"理念的最佳实践的产物&#xff0c;一个典型的SpringBoot应用本质上其 实就是一个基于Spring框架的应用 如果非说SpringBoot微框架提供了点儿自己特有的东西&#xff0c;在核心类层面&…

了解spring-boot-starter

SpringBoot提供了针对日常企业应用研发各种场景的spring-boot-starter自动配置 依赖模块&#xff0c;如此多“开箱即用”的依赖模块&#xff0c;使得开发各种场景的Spring应用 更加快速和高效&#xff0c;本文会就几个常见的通用spring-boot-starter模块进行了解 一、约定优先于…

常用脚本

mysql状态收集 #! /bin/bash#mysql for zabbixUptime() {mysqladmin status I awk [print $2]}Slow_ queries() {mysqladmin status | awk [print $9]} ICom_ insert() {mysqladmin extended-status |awk /<Com_ insertl>/[print $4]}Com_ delete() {mysqladmi…

linux产生随机数方法

如果产生的数据长短格式不统一&#xff0c;使用md5sum命令&#xff0c;并使用cut截取相应位数echo $RANDOM openssl rand -base64 openssl rand -base64 10 date %s%N /dev/random设备&#xff0c;存储着系统当前运行的环境的实时数据。它可以看作是系统某个时候&#x…

oracle视图等

视图 视图是基于其他表或视图创建的逻辑表 视图不包含自己的数据&#xff0c;它基于的表称为基表 使用视图是为了: 限制对数据的访问 使复杂的查询简单化 提供数据的独立性 相同的数据展现不同的视图 不能删除行不能修改行不能添加行 --分组函数 - -GRoUP BY子句 -…

Java集合:关于 ArrayList 的内容盘点

本篇内容包括&#xff1a;ArrayList 概述、ArrayList 的扩容机制&#xff08;包含源码部分&#xff09;、如何在遍历 ArrayList 时正确的移除一个元素、ArrayList 的构造方法及常用方法、关于 Array 与 ArrayList 的区别、关于 CopyOnWriteArrayList、关于 Fail Fast 与 Fail S…

Java集合:关于 LinkedList 的内容盘点

本篇内容包括&#xff1a;LinkedList 的概述、LinkedList 的结构既双向链表实现与LinkedList-Node 结构、LinkedList 的使用&#xff08;构造方法&常用方法&#xff09;、关于 Queue 队列的介绍、关于 ArrayList 和 LinkedList 的区别以及算法&#xff1a;翻转链表&#xf…

shell自动化巡检

#!/bin/bash #主机信息每日巡检IPADDR$(ifconfig eth0|grep inet addr|awk -F [ :] {print $13}) #环境变量PATH没设好&#xff0c;在cron里执行时有很多命令会找不到 export PATH/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin source /etc/profile…

Java集合:关于 Vector 的内容盘点

Vector 与 ArrayList 一样&#xff0c;也是通过数组实现的&#xff0c;不同的是它支持线程的同步&#xff0c;即某一时刻只有一个线程能够写 Vector&#xff0c;避免多线程同时写而引起的不一致性&#xff0c;但实现同步需要很高的花费&#xff0c;因此&#xff0c;访问它比访问…

memcached 的基本命令

memcached 的基本命令(安装、卸载、启动、配置相关)&#xff1a; -p 监听的端口 -l 连接的 IP 地址, 默认是本机 -d start 启动 memcached 服务 -d restart 重起 memcached 服务 -d stop|shutdown 关闭正在运行的 memcached 服务 -d install 安装 memcached 服务 -d uninstall …

Java集合:关于 HashSet 的内容盘点

哈希表存放的是哈希值&#xff0c; HashSet 存储元素的顺序并不是按照存入时的顺序&#xff08;和 List 显然不同&#xff09; 而是按照哈希值来存的所以取数据也是按照哈希值取得。 &#xff5e; 本篇内容包括&#xff1a;HashSet 概述、HashSet 与 HashMap 的关系以及HashSet…

mysql备份脚本

#!/bin/bash #保留备份个数&#xff0c;会删除时间较早的.dump备份 number3 #设置备份保存路径&#xff0c;yourpath替换成自己的备份保存路径 backup_diryourpath #日期格式 dddate %Y%m%d #备份工具 toolmysqldump #数据库用户名 usernameroot #数据库密码&#xff0c;由于密…

Java集合:关于 TreeSet 的内容盘点

TreeSet() 是使用二叉树的原理对新 add() 的对象按照指定的顺序排序&#xff08;升序、降序&#xff09;&#xff0c;每增加一个对象都会进行排序&#xff0c;将对象插入的二叉树指定的位置&#xff1b; ~ 本篇内容包括&#xff1a;TreeSet 概述、TreeSet 的使用以及其他知识点…

python求素数

口求100内的素数 -个数能被从2开始到自己的平发根的正整数整数整除,就是合数 import math n100 for X in range(2, n): for i in range(2, math.ceil(math.sqrt(x))): if x %i 0: break else: print(x)口求100内的素数 合数一定可以分解为几个质数的乘积 import math n100 pri…

svn钩子脚本

REP0S"$1" REV"$2"export LANGen_US.UTF-8 LOGPATH"/app/log" [ !-d ${LOGPATH}] && mkdir $[LOGPATH) -p #update content from svn↓14 SVN/usr/bin/svn↓ SVN update --username test --password test /data/ if[ $? -eq ] then /us…

shell判断字符串是否为数字

#1.组合语法判断1: [ -n "echo $num|sed s/[0-9]//g" -a -n "echo $2|sed s/[0-9]//g"] &&\echo”两个参数都必须为数字”&& exit 1#2.组合语法判断2:[ -n "echo $num|sed s/[0-9]//g" -a -n "echo $2|sed s/[0-9]//g&…

MySQL:DQL 数据查询语句盘点

本篇内容包括&#xff1a;DQL 的简介、SELECT 语句、WHERE 条件语句、JOIN 连接查询(多表查询)和分组、过滤、排序、分页、子查询的使用。 一、DQL 简介 DQL&#xff08;Data QueryLanguage&#xff09;语句&#xff0c;即数据查询语句 常用的语句关键字有&#xff1a;SELECT…

MySQL:DML 数据操作语句盘点

本篇内容包括&#xff1a;DML 的简介、INSERT 命令、UPDATE 命令、DELETE 命令以及 TRUNCATE 命令的使用。 一、DML 简介 DML&#xff08;Data Manipulation Language&#xff09;语句&#xff0c;即数据操作语句&#xff0c;用于操作数据库对象中所包含的数据。 常用关键字包…

MySQL:DDL 数据定义语句盘点

本篇内容包括&#xff1a;DDL 的简介、SHOW 查看语句、CREATE 创建语句、ALTER 修改语句以及 DROP 删除语句的使用。 一、DDL 简介 DDL&#xff08;Data Definition Language&#xff09;&#xff0c;即数据定义语句&#xff0c;功能就是定义数据库DATabase、表table、索引ind…

MySQL:DCL 数据控制语句盘点

本篇内容包括:DCL 简介、GRANT、REVOKE、COMMIT、ROLLBACK、SAVEPOINT、LOCK命令的使用。 一、DCL 简介 DCL&#xff08;Data Control Language&#xff09;语句&#xff0c;即数据控制语句&#xff0c;用于设置或更改数据库用户或角色权限的语句 常用关键字包括&#xff1a;…