SpringBoot 源码解析 (一)----- SpringBoot核心原理入门
spring boot 概述
build anything with spring boot:spring boot is the starting point for building all spring-based applications. spring boot is designed to get you up and running as quickly as possible, with minimal upfront configuration of spring.
上面是引自官网的一段话,大概是说: spring boot 是所有基于 spring 开发的项目的起点。spring boot 的设计是为了让你尽可能快的跑起来 spring 应用程序并且尽可能减少你的配置文件。
什么是 spring boot
- 它使用 “习惯优于配置” (项目中存在大量的配置,此外还内置一个习惯性的配置,让你无须手动配置)的理念让你的项目快速运行起来。
- 它并不是什么新的框架,而是默认配置了很多框架的使用方式,就像 maven 整合了所有的 jar 包一样,spring boot 整合了所有框架
使用 spring boot 有什么好处
回顾我们之前的 ssm 项目,搭建过程还是比较繁琐的,需要:
- 1)配置 web.xml,加载 spring 和 spring mvc
- 2)配置数据库连接、配置日志文件
- 3)配置家在配置文件的读取,开启注解
- 4)配置mapper文件
- .....
而使用 spring boot 来开发项目则只需要非常少的几个配置就可以搭建起来一个 web 项目,并且利用 idea 可以自动生成生成
- 划重点:简单、快速、方便地搭建项目;对主流开发框架的无配置集成;极大提高了开发、部署效率。
spring boot helloworld
导入依赖spring boot相关的依赖
<?xml version="1.0" encoding="utf-8"?> <project xmlns="http://maven.apache.org/pom/4.0.0" xmlns:xsi="http://www.w3.org/2001/xmlschema-instance" xsi:schemalocation="http://maven.apache.org/pom/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelversion>4.0.0</modelversion> <groupid>cn.chenhao</groupid> <artifactid>springboot</artifactid> <version>1.0.0-snapshot</version> <packaging>jar</packaging> <name>springboot</name> <description>demo project for spring boot</description> <parent> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-parent</artifactid> <version>2.0.1.release</version> <relativepath/> </parent> <dependencies> <dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-web</artifactid> </dependency> </dependencies> <build> <plugins> <plugin> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-maven-plugin</artifactid> </plugin> </plugins> </build> </project>
编写主程序
/** * @springbootapplication来标注一个主程序类,说明这是一个springboot应用 */ @springbootapplication public class helloworldmainapplication { public static void main(string[] args) { //spring应用启动 springapplication.run(helloworldmainapplication.class, args); } }
编写controller、service
@restcontroller public class hellocontroller { @requestmapping("/hello") public string hello(){ return "hello world"; } }
运行主程序测试
使用maven打包命令将其打包成jar包后,直接使用命令:
java -jar xxx.jar
hello world探究
pom文件
父项目
<parent> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-parent</artifactid> <version>2.0.1.release</version> <relativepath/> </parent>
其父项目是
<parent> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-dependencies</artifactid> <version>2.0.1.release</version> <relativepath>../../spring-boot-dependencies</relativepath> </parent>
该父项目是真正管理spring boot应用里面的所有依赖的版本:spring boot的版本仲裁中心,所以以后导入的依赖默认是不需要版本号。如下
还有很多版本号没有截图出来
启动器
<dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-web</artifactid> </dependency>
spring-boot-starter : spring boot场景启动器;帮助导入web模块正常运行所依赖的组件;
spring boot将所有的功能场景抽取出来,做成一个个的starter(启动器),只需要在项目中引入这些starter,那么相关的场景的所有依赖都会导入进项目中。要用什么功能就导入什么场景的启动器。
<dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-tomcat</artifactid> </dependency> <dependency> <groupid>org.springframework</groupid> <artifactid>spring-web</artifactid> </dependency> <dependency> <groupid>org.springframework</groupid> <artifactid>spring-webmvc</artifactid> </dependency>
添加了 spring-boot-starter-web 依赖,会自动添加 tomcat 和 spring mvc 的依赖
spring-boot-starter-web中又引入了spring-boot-starter-tomcat
主程序类(主入口类)
@springbootapplication public class helloworldmainapplication { public static void main(string[] args) { //spring应用启动 springapplication.run(helloworldmainapplication.class, args); } }
@springbootapplication
- spring boot应用标注在某个类上,说明这个类是springboot的主配置类,springboot就应该运行这个类的main方法来启动springboot应用。
注解定义如下:
@springbootconfiguration @enableautoconfiguration @componentscan(excludefilters = { @filter(type = filtertype.custom, classes = typeexcludefilter.class), @filter(type = filtertype.custom, classes = autoconfigurationexcludefilter.class) }) public @interface springbootapplication {}
@springbootconfiguration
- spring boot的配置类
- 标注在某个类上,表示这是一个spring boot的配置类
注解定义如下:
@configuration public @interface springbootconfiguration {}
其实就是一个configuration配置类,意思是helloworldmainapplication最终会被注册到spring容器中
@enableautoconfiguration
- 开启自动配置功能
- 以前使用spring需要配置的信息,spring boot帮助自动配置;
- @enableautoconfiguration通知springboot开启自动配置功能,这样自动配置才能生效。
注解定义如下:
@autoconfigurationpackage @import(enableautoconfigurationimportselector.class) public @interface enableautoconfiguration {}
@autoconfigurationpackage
- 自动配置包注解
@import(autoconfigurationpackages.registrar.class) public @interface autoconfigurationpackage {}
@order(ordered.highest_precedence) static class registrar implements importbeandefinitionregistrar, determinableimports { @override public void registerbeandefinitions(annotationmetadata metadata, beandefinitionregistry registry) { //默认将会扫描@springbootapplication标注的主配置类所在的包及其子包下所有组件 register(registry, new packageimport(metadata).getpackagename()); } @override public set<object> determineimports(annotationmetadata metadata) { return collections.<object>singleton(new packageimport(metadata)); } }
@import(enableautoconfigurationimportselector.class)
enableautoconfigurationimportselector: 导入哪些组件的选择器,将所有需要导入的组件以全类名的方式返回,这些组件就会被添加到容器中。
1 //enableautoconfigurationimportselector的父类:autoconfigurationimportselector 2 @override 3 public string[] selectimports(annotationmetadata annotationmetadata) { 4 if (!isenabled(annotationmetadata)) { 5 return no_imports; 6 } 7 try { 8 autoconfigurationmetadata autoconfigurationmetadata = autoconfigurationmetadataloader 9 .loadmetadata(this.beanclassloader); 10 annotationattributes attributes = getattributes(annotationmetadata); 11 list<string> configurations = getcandidateconfigurations(annotationmetadata, attributes); 12 configurations = removeduplicates(configurations); 13 configurations = sort(configurations, autoconfigurationmetadata); 14 set<string> exclusions = getexclusions(annotationmetadata, attributes); 15 checkexcludedclasses(configurations, exclusions); 16 configurations.removeall(exclusions); 17 configurations = filter(configurations, autoconfigurationmetadata); 18 fireautoconfigurationimportevents(configurations, exclusions); 19 return configurations.toarray(new string[configurations.size()]); 20 } 21 catch (ioexception ex) { 22 throw new illegalstateexception(ex); 23 } 24 }
我们主要看第11行list<string> configurations = getcandidateconfigurations(annotationmetadata, attributes);
会给容器中注入众多的自动配置类(xxxautoconfiguration),就是给容器中导入这个场景需要的所有组件,并配置好这些组件。我们跟进去看看
protected list<string> getcandidateconfigurations(annotationmetadata metadata, annotationattributes attributes) { list<string> configurations = springfactoriesloader.loadfactorynames( getspringfactoriesloaderfactoryclass(), getbeanclassloader()); //... return configurations; } protected class<?> getspringfactoriesloaderfactoryclass() { return enableautoconfiguration.class; } public static final string factories_resource_location = "meta-inf/spring.factories"; public static list<string> loadfactorynames(class<?> factoryclass, classloader classloader) { string factoryclassname = factoryclass.getname(); try { //从类路径的meta-inf/spring.factories中加载所有默认的自动配置类 enumeration<url> urls = (classloader != null ? classloader.getresources(factories_resource_location) : classloader.getsystemresources(factories_resource_location)); list<string> result = new arraylist<string>(); while (urls.hasmoreelements()) { url url = urls.nextelement(); properties properties = propertiesloaderutils.loadproperties(new urlresource(url)); //获取enableautoconfiguration指定的所有值,也就是enableautoconfiguration.class的值 string factoryclassnames = properties.getproperty(factoryclassname); result.addall(arrays.aslist(stringutils.commadelimitedlisttostringarray(factoryclassnames))); } return result; } catch (ioexception ex) { throw new illegalargumentexception("unable to load [" + factoryclass.getname() + "] factories from location [" + factories_resource_location + "]", ex); } }
最终有96个自动配置类被加载并注册进spring容器中
j2ee的整体整合解决方案和自动配置都在spring-boot-autoconfigure-xxx.jar中。在这些自动配置类中会通过@conditionalonclass等条件注解判断是否导入了某些依赖包,从而通过@bean注册相应的对象进行自动配置。后面我们会有单独文章讲自动配置的内容
推荐阅读
-
SpringBoot 源码解析 (七)----- Spring Boot的核心能力 - SpringBoot如何实现SpringMvc的?
-
SpringBoot 源码解析 (六)----- Spring Boot的核心能力 - 内置Servlet容器源码分析(Tomcat)
-
SpringBoot 源码解析 (一)----- SpringBoot核心原理入门
-
源码系列【springboot之@Import注解多个类引入同一个类源码解析】
-
mybatis plus源码解析(一) ---基于springboot配置加载和SqlSessionFactory的构造
-
有关 springboot 加载原理解析的一些心得
-
SpringBoot 源码解析 (九)----- Spring Boot的核心能力 - 整合Mybatis
-
SpringBoot 源码解析 (五)----- Spring Boot的核心能力 - 自动配置源码解析
-
SpringBoot 源码解析 (六)----- Spring Boot的核心能力 - 内置Servlet容器源码分析(Tomcat)
-
SpringBoot静态资源配置原理(源码一步步分析,详细易懂)