简介
Spring Boot来简化Spring应用开发的一个框架,约定大于配置。去繁从
简,just run就能创建一个独立的,产品级别的应用。
整个Spring技术栈的一个大整合。
J2EE开发的一站式解决方案。
1 SpringBoot简介
1.背景:
J2EE笨重的开发,繁多的配置,底下的开发效率,复杂的部署流程,第三
方技术集成难度大。
2.解决
“Spring全家桶”时代
Spring Boot --> J2EE一站式解决方案
Spring Cloud --> 分布式整体解决方案。
3.优点
--快速创建独立运行的Spring项目以及主流框架集成
--使用嵌入式的Servlet容器,应用无需打成WAR包。
--starters自动依赖与版本控制
--大量的自动配置,简化开发,也可修改默认值
--无需配置XML,无代码生成,开箱即用。
--准生产环境的运行时应用监控
--与云计算的天然集成。
入门容易,精通难。
2. 微服务
1.2014年MartinFowler在其博客详细介绍了微服务的概念。
微服务是一种架构风格,提倡我们在开发一个应用时,这个应用应该是作
为一系列小服务的组合。也就是说,开发的应用应该是一组小型服务。
每个小心服务都运行在自己的进程内,它们之间可以通过HTTP的方式进行
沟通。一种轻量级的工程方式。
2.以前的开发方式:单体应用:ALL IN ONE
所有的东西都写在一个应用里面。水平扩展,当应用的负载能力不行时,
将相同的应用复制若干份放到若干服务器中。这若干个服务器,都来运行这个
程序,通过负载均衡机制来提高并发能力。
3.带来的问题:牵一发而动全身的问题。
某一处小小的修改,整个应用都可能需要应用重新部署,运行。
4.面临的问题:
日益增长的软件需求,现在随便一个应用,都可能要成为一个大型应用。
针对大型应用我们再用ALL IN ONE的方式全都写在一个大的应用,这明显
不合理。
5. 引入微服务:spring可以快速的构建一个微服务应用。
每一个功能元素都应该是一个可替换的,可独立升级的软件单元。
单元和单元之间的互相调用通过HTTP方式。
一个微服务架构把每个功能元素放进一个独立的服务中,并且通过跨服务
器分发这些服务进行扩展,只在需要时才进行复制。
那么我们要继续思考,服务到底要多“微”,我们要怎么微化它们。
[详细参照微服务文档](https://martinfowler.com/microservices/)
会给部署和运维带来非常大的挑战。
3 环境约束
--JDK1.8:SpringBoot推荐1.7以上
--Maven3.x
--IntelliJ IDEA
--Spring Boot 1.5.9.RELEASE
1.Maven设置:
给maven的settings.xml配置文件的profiles标签添加
<profile>
<id>jdk-1.8</id>
<activation>
<activeByDefault>true </activeByDefault>
<jdk>1.8</jdk>
</activation>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion>
</properties>
</profile>
2.IDEA设置
将安装的Maven整合进来,不然IDEA会用自己的Maven
4. Spring Boot HelloWorld
一个功能:
浏览器发送hello请求,服务器接受请求并处理,响应Hello World字符串。
1. 创建一个maven工程(jar)
2. 导入spring boot相关的依赖。
注意:这里如果jar包导入不进去,可以将本地仓库中的相关jar包删除掉,再重新导入。
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.9.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
3. 编写一个主程序,启动springboot应用
/**
* @SpringBootApplication
* 来标注一个主程序类,说明这是一个Spring Boot 应用
*/
@SpringBootApplication
public class HelloWorldMainApplication {
public static void main(String[] args) {
//spring应用启动起来
SpringApplication.run(HelloWorldMainApplication.class, args);
}
}
4.编写相关的Controller,Service
@Controller
public class HelloController {
@ResponseBody //作用是将hello world quick写给浏览器
@RequestMapping("/hello" )
public String hello (){
return "hello world!" ;
}
}
5.RESTAPI的方式:
写一个数据,直接返回给浏览器,而不是页面跳转的方式。
5. 运行主程序测试
6. 简化部署
1.不需要配置tomcat等服务器,直接注入一个插件,可以将程序打成一个可
执行的jar包。
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
打好的jar放在了target目录下:
Building jar:
E:\Idea_Project\day0624_\target\day0624_springboot01_helloworld-1.0-SNAPSHOT.jar
2.这是一个可执行的jar包,我们可以直接运行。
(注意:命令敲下后,还要在敲一次enter)
3.小结
只要导入一个插件,将应用打成jar包,直接用java -jar的命令进行
执行。即使所在服务器中没有tomcat环境也没事,springboot自身继承了
tomcat环境。
jar里面有很多jar包,其中就有嵌入式的tomcat这些都是导入maven
依赖时导入进来的。
7. SpringBoot入门案例HelloWorld细节
注意:涉及到的源码分析SpringBoot版本时1.5.9
从该案例我们发现SpringBoot的确非常便捷,只需要写一个主程序,来启
动SpringBoot的应用。然后再按照业务逻辑,来编写一写Controller和Service。
根本不需要做任何配置。
那为什么会有这么神奇的实现呢?
7.1 我们从该项目的pom.xml分析一下
父项目:spring-boot-starter-parent的父项目spring-boot-dependencies
作为SpringBoot的版本仲裁中心。
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.9.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
1. 我们导入了一个父项目:spring-boot-starter-parent
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.9.RELEASE</version>
</parent>
我们以前做的父项目都是来做依赖管理。
2. 点进去我们发现这个父项目还导入了一个父项目:
spring-boot-dependencies
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>1.5.9.RELEASE</version>
<relativePath>../../spring-boot-dependencies</relativePath>
</parent>
3.再次点进去:
里面锁定了很多的依赖jar包的版本。
所以这个父项目是来真正管理Spring Boot应用里面的所有依赖。
4. 称为:SpringBoot的版本仲裁中心
所以我们导入依赖默认是不需要写版本的。
(没有在spring-boot-dependencies里面管理的依赖自然要声明版本号)
7.2 运行所需的jar包是由谁导进来的呢?
我们除了导入一个父项目,还有一个依赖:spring-boot-starter-web
没有写版本号,springboot帮我们自动仲裁。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
1.什么是spring-boot-starter?
发现无论是spring-boot-starter-parent还是spring-boot-starter-web
都有spring-boot-starter。那么什么是spring-boot-starter?
spring-boot-starter:spring-boot的场景启动器。
点进去里面依赖了若干jar包。帮我们导入了web模块正常运行所依赖的
组件。以来的版本都受父项目仲裁,
2. SpringBoot将所有功能都抽取成了一个个场景,每个场景都对应着一
个启动器starter。
那么显然除了web还有很多适用其他场景的启动器。只需要在项目里面引
这些starter,相关场景的所有依赖都会导入进来。依赖版本由springboot
自动控制。
要用什么功能就导入什么场景启动器。
8. SpringBoot入门案例 分析一下主程序。
8.1 主程序类,主配置类,主入口类
@SpringBootApplication
public class HelloWorldMainApplication {
public static void main(String[] args) {
//spring应用启动起来
SpringApplication.run(HelloWorldMainApplication.class, args);
}
}
1.运行main方法,在SpringApplication.run()时,需要传入一个类参数。
SpringApplication.run(HelloWorldMainApplication.class, args);
这个类一定要是一个@SpringBootApplication标注的类。
@SpringBootApplication:SpringBoot应用标注在某个类上说明这个类
就是SpringBoot的主配置类,SpringBoot就会运行这个类的main方法来启动
SpringBoot应用。
2. 分析@SpringBootApplication注解
打开该注解,是一个组合注解。
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
excludeFilters = {@Filter(
type = FilterType.CUSTOM,
classes = {TypeExcludeFilter.class}
), @Filter(
type = FilterType.CUSTOM,
classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication {}
@SpringBootApplication是一个组合注解。
8.2 分析两个子注解
1.组合中的第一个注解:@SpringBootConfiguration
1.@SpringBootConfiguration:SpringBoot配置类
标注在某个类上:表示这是一个SpringBoot的配置类。
1.1.@Configuration:标注在配置类上。
是@SpringBootConfiguration中的一个注解
1.1.1.@Component:被标注的类要加载到IOC中
是@Configuration注解中的一个注解。
SpringBoot的主入口类:@SpringBootApplication
其中有一个子注解:@SpringBootConfiguration
子注解的子注解:@Configuration
子注解的子子注解:@Component
所以配置了@SpringBootApplication一个注解,也就配置了以上4个注解。
2.组合中的第二个注解:@EnableAutoConfiguration
开启自动配置功能。
我们整个SpringBoot项目中没有进行任何配置,但是我们SpringMVC启
动起来了,@Controller也扫描进去了,整个应用也能用了。那这些功能
是怎么做的呢?
就是靠这个注解:@EnableAutoConfiguration。开启自动配置。
以前我们需要配置的东西,SpringBoot帮我们自动配置了。同时这个
配置告诉SpringBoot开启自动配置功能。这样自动配置的东西才能生效。
3.分析一下原理:@EnableAutoConfiguration
3.1.其中有一个子注解:@AutoConfigurationPackage
自动配置包
3.1.1.自动配置包中有一个注解@Import({Registrar.class})
由这个注解来完成@AutoConfigurationPackage自动配置包的功能。
@Import是Spring的底层注解:给容器中导入一个组件。
由Registrar.class来指定具体的组件。
到这一步,可以理解:@AutoConfigurationPackage标注的类给我们
IOC容器中到了一些组件。
3.1.1.1 导入了哪些组件呢?
点开Registrar.class,里面有一个方法:
A:registerBeanDefinitions()方法:注册一些bean并定义一些信息。
这是给容器中导入组件。
怎么导呢?我们在该处打断点:
register(registry, (new AutoConfigurationPackages.PackageImport(metadata)).getPackageName());
B:这一段代码中的metadata:就是注解的原信息。
该注解和注解标注的类即
@SpringBootApplication注解和其所标注的SpringBoot程序的主入口类。
C:其中这段表达式的意思是拿到一个包名。
我们发现拿到的包名是主程序所在的包名。
(new AutoConfigurationPackages.PackageImport(metadata)).getPackageName()
D:通过断点调试,然后计算这个表达式的值
选中表达式,右键选择Evaluate。
发现得到的包名是主入口类所在的包名。
3.2 @EnableAutoConfiguration的另一个子注解
A:@Import({EnableAutoConfigurationImportSelector.class})
该注解的意思还是:给容器中导入一些组件。导入哪些组件由
EnableAutoConfigurationImportSelector.class来指定。
(开启自动配置类的的导包的选择器)
B:点进来看看想给我们导入哪些组件。
里面有一个isEnable判断是否开启的方法,我们不管。
看它的父类AutoConfigurationImportSelector
C:里面有一个selectImports方法
告诉我们导入哪些选择器组件。
将所有需要导入的组建的选择器以全类名的方式返回,这些组件
会以反射的方式放到IOC容器中。
D:selectImports方法到底添加了哪些组件呢?
断点分析。
参数annotationMetadata还是注解的原信息,即
@SpringBootApplication注解和其所标注的SpringBoot
程序的主入口类。
E:放行,继续调试
发现一个List<String> configurations出现的非常频繁,
并且最会转成一个字符串数组返回。
那么显然这个configurations就是要导入的组件
F:放行,分析configurations
发现会给容器中导入非常多的自动配置类:
xxxAutoConfiguration。
这些自动配置类的作用,就是给容器中导入这个场景需要的所
有组件,并配置这些组件。
比如要做AOP功能,SpringBoot会将相应的组件配置好...
即这些自动配置都是靠这些自动配置来实现的。有了自动配置
类,就免去了手动编写配置和注入功能组件等工作。
3.3 这些自动配置类,他怎么扫描到的?
List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
getCandidateConfigurations()方法得到候选的配置文件
3.3.1 点进去:
SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());
主要调用了这么一个方法loadFactoryNames():
参数1getSpringFactoriesLoaderFactoryClass()
它的值:EnableAutoConfiguration.class;
参数2this.getBeanClassLoader() 类加载器
3.3.2进入loadFactoryNames()
classLoader.getResources("META-INF/spring.factories")
发现他会加载"META-INF/spring.factories"目录下的资源。
然后把它当成一个properties配置文件
然后从这个properties中种得到工厂的名字:factoryClassNames.
从类路径下的META-INF/spring.factories获取EnableAutoConfiguration
指定的值。
这些EnableAutoConfiguration指定的值,就是我们导入的自动配置类。
8.3 两个子注解小结
@SpringBootApplication的两个子注解
1.第一个子注解:@SpringBootConfiguration
@SpringBootConfiguration:SpringBoot配置类
标注在某个类上:表示这是一个SpringBoot的配置类。
1.1.@Configuration:标注在配置类上。
是@SpringBootConfiguration中的一个注解
1.1.1.@Component:被标注的类要加载到IOC中
是@Configuration注解中的一个注解。
所以第一个子注解相当于有以下作用:
1.指明HelloWorldMainApplication是一个SpringBoot主配置类
2.而且HelloWorldMainApplication的对象要放到IOC中。
2.@EnableAutoConfiguration
其中有两个子类:
2.1 @AutoConfigurationPackage:
这个注解将主配置类(@SpringBootApplication标注的类)所在的包
下面所有的子包下面的组件都扫描到IOC容器中。
这就是为什么我们没有配置文件仍然能将Controller扫描进去(在主
配置类的子包下)。
2.2 @Import({EnableAutoConfigurationImportSelector.class})
给容器中导入一些组件。导入哪些组件由
EnableAutoConfigurationImportSelector.class来指定。
会加载"META-INF/spring.factories"目录下的资源。
获取EnableAutoConfiguration指定的值。
根据指定的值会给容器中导入非常多的自动配置类:xxxAutoConfiguration。
这些自动配置类的作用,就是给容器中导入这个场景需要的所有
组件,并配置这些组件。即这些自动配置都是靠这些自动配置来实现
的。有了自动配置类,就免去了手动编写配置和注入功能组件等工作。
以前我们需要自己配置的东西(XML),自动配置类都帮我们做了。
这些自动配置类都在:springboot-autoconfigure包下
小结:J2EE的整体整合解决方案和自动配置都在:
spring-boot-autoconfigure-1.5.9.RELEASE.jar包下。
9 如何快速的创建一个SpringBoot项目
IEAD支持使用一个Spring的项目创建向导帮我们快速创建SpringBoot项目
1.使用Spring Initializer快速创建SpringBoot项目
选择我们需要的模块(启动器):向导会联网创建SrpingBoot项目。
可以删除这三个无用的文件。
2. 创建好的项目中自动生成了一个被@SpringBootApplication标注的
主程序类/主配置类/主入口类。
@SpringBootApplication
public class Day0624SpringbootQuickhelloApplication {
public static void main(String[] args) {
SpringApplication.run(Day0624SpringbootQuickhelloApplication.class, args);
}
}
3.我们写一个业务:controller
/*@ResponseBody 作用是:这个类的所有方法返回的数据直接写给浏览器,如果是对象转成json数据(也能写出去)
@Controller*/
//我又嫌上面两个麻烦: @RestController有上面两个注解的所有功能,
@RestController
public class HelloController {
@RequestMapping("/hello" )
public String hello (){
return "hello world quick" ;
}
}
@ResponseBody 作用:
这个类的所有方法返回的数据直接写给浏览器,如果是对象转成json
数据(也能写出去)。
RESTAPI的方式:
写一个数据,直接返回给浏览器,而不是页面跳转的方式。由@ResponseBody来实现。
由于我们以后可能经常用RESTAPI的方式,所以将它放到类上。
@RestController:
我又嫌上面写两个麻烦: @RestController有上面两个注解的所有功能。
点进去看一下:
@RestController其实就是@Controller和@ResponseBody的组合注解
4. 默认生成的SpringBoot项目:
* 主程序已经生成好了,我们只需要编写业务逻辑即可。
* 配置文件夹resources目录结构:
1.static:保存所有的静态资源:js/css/images
2.templates:保存所有的模版页面
SpringBoot默认jar包使用嵌入式的Tomcat,默认不支持JSP页面;
可以用模版引擎(thymeleaf,freemarker)
3.application.properties:SpringBoot应用的配置文件。
SpringBoot一切都是默认配置的,我们可以在application.properties
中修改这些默认配置。
比如默认配置的tomcat是8080,我们可以在里面改成8081.