Spring Boot(2.x)
Spring 简史
Spring 1.x时代
在ISpringl.x时代,都是通过xml文件配置bean ,随着项目的不断扩大,需要将xml配置分放到不同的配置文件中,需要频繁的在java类和xml配置文件中切换。
Spring 2.x时代
随着JDK 1.5带来的注解支持,Spring2.x可以使用注解对Bean进行申明和注入,大大的减少了xml配置文件,同时也大大简化了项目的开发。
那么,问题来了,究竟是应该使用xml还是注解呢?
最佳实践:
- 应用的基本配置用xml,比如:数据源、资源文件等
- 业务开发用注解,比如: Service中注入bean等
Spring 3.x时代
从Spring3.x开始提供了Java 配置方式,使用Java配置方式可以更好的理解你配置的Bean,现在我们就处于这个时代,并且Spring4.x和Spring boot都推荐使
用java配置的方式。
Spring 5.x时代
Spring5.x 是Java界首个支持响应式的Web框架,是Spring的一个重要版本 ,距离Spring4.x差不多四年。在此期间,大多数增强都是在SpringBoot项目中完
成的,其最大的亮点就是提供了完整的端到端响应式编程的支持(新增Spring WebFlux模块)。
Spring WebFlux同时支持使用旧的Spring MVC注解声明Reactive Controller。和传统的MVC Controller 不同,Reactive Controller操作的是非阻塞的ServerHttpRequest 和ServerHttpResponse , 而不再是Spring MVC里的HttpServletRequest和HttpServletResponse。
至此也代表着Java正式迎来了响应式异步编程的时代。
Spring Boot 简介
随着动态语言的流行(Ruby、Groovy、 Scala、 Node.js) ,Java的开发显得格外的笨重繁多的配置、低下的开发效率、复杂的部署流程以及第三方技术集成难度
大。
在上述环境下,Spring Boot应运而生。它使用“习惯优于配置”(项目中存在大量的配置,此外还内置了一个习惯性的配置 ,让你无需手动进行配置)的理念让你的项目快速的运行起来。使用Spring Boot很容易创建一个独立运行 (运行Jar,内嵌Servlet容器)准生产级别的基于Spring 框架的项目,使用Spring Boot你可以不用或者只需很少的Spring配置。
Spring Boot优缺点
优点
- 快速构建项目
- 对主流开发框架的无配置集成
- 项目可独立运行,无需外部依赖Servlet容器
- 提供运行时的应用监控
- 极大地提高了开发、部署效率
- 与云计算的天然集成
缺点
- 版本迭代速度很快,一些模块改动很大
- 由于不用自己做配置,报错时很难定位
- 网上现成的解决方案比较少
第一个Spring Boot 应用程序
这里我们使用Intellij IDEA 来新建一个 Spring Boot 项目。
打开IDEA - > New Project - > Spring Initializr
工程目录结构
创建完成后的工程目录结构如下:
- gitignore : Git过滤配置文件
- pom.xml : Maven的依赖管理配置文件
- HelloSpringBootApplication.java :程序入口
- resources :资源文件目录
- static:静态资源文件目录
- templates :模板资源文件目录
- application.properties : Spring Boot的配置文件,实际开发中会替换成 YAML语言配置( application.yml)
pom.xml
- parent:结成了Spring Boot 的 Parent ,表示我们是一个 Spring Boot 工程
- spring-boot-starter-web:包含了spring-boot-starter还自动帮我们开启了Web支持
功能演示
我们创建一个 Controller 来演示一下 Spring Boot 的神奇功能
启动HelloSpringBootApplication的==main()==方法,浏览器访问http://localhost:8080可以看到:
Hello Spring Boot
神奇之处
- 没有配置 web.xml
- 没有配置 application.xml,Spring Boot 帮你配置了
- 没有配置 application-mvn.xml,Spring Boot 帮你配置了
- 没有配置 Tomcat,Spring Boot 内嵌了 Tomcat 容器
Spring Boot 单元测试
Spring Boot 单元测试
主要是通过==@RunWith和@SpringBootTest==注解来开启单元测试功能
运行它会先启动 Spring Boot 工程,再启动单元测试
在测试类类名上方加上一句@SpringBootTest(classes = HelloSpringBootApplication.class,webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
Spring Boot 常用配置
自定义Banner
在Spring Boot 启动的时候会有一个默认的启动图案
我们在src/main/resources目录下新建一个banner.txt
通过http://patorjk.com/software网站生成字符串,将网站生成的字符复制到banner.txt中
再次运行这个程序
Spring Boot 配置文件
Spring Boot 项目使用一个全局的配置文件application.properties或者是application.yml,在resources目录下或者类路径下的==/config下,一般我们放到resources下。
修改Tomcat端口号为9090,并将默认的访问路径“/”修改为“boot”,可以在application.properties==中添加:
server.port=9090
server.context-path=/boot
或在application.yml==中添加:
server:
port:9090
server:
context-path:/boot
Spring Boot Starter POM
Starter POM
Spring Boot 为我们提供了简化企业级开发绝大多数场景的starter pom,只要使用了应用场景所需要的的starter pom,相关的技术配置将会消除,就可以得到Spring Boot 为我们提供的自动配置的Bean。
官方提供的starter pom
Spring Boot 日志配置
Spring Boot 日志配置
Spring Boot 对各种日志框架都做了支持,我们可以通过配置来修改默认的日志的配置
默认情况下,Spring Boot 使用 Logback 作为日志框架
配置日志文件
logging:
file:../logs/spring-boot-hello.log
level.org.springframework.web:DEBUG
关闭特定的自动配置
关闭铁定的自动配置使用==@SpringBootApplication注解的exclude==参数即可,这里以关闭数据源的自动配置为例
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
Spring Boot整合Thymeleaf
Thymeleaf 简介
Thymeleaf 是一个跟 Velocity、FreeMarker 类似的模板引擎,它可以完全替JSP。相较与其他的模板引擎,它有如下三个极吸引人的特点
- Thymeleaf在有网络和无网络的环境下皆可运行,即它可以让美工在浏览器查看页面的静态效果,也可以让程序员在服务器查看带数据的动态页面效果。这是由于它支持html原型,然后在html标签里增加额外的属性来达到模板+数据的展示方式。浏览器解释html时会忽略未定义的标签属性,所以thymeleaf的
模板可以静态地运行;当有数据返回到页面时, Thymeleaf标签会动态地替换掉静态内容,使页面动态显示。 - Thymeleaf开箱即用的特性。它提供标准和Spring标准两种方言,可以直接套用模板实现JSTL、 OGNL表达式效果,避免每天套模板、改JSTL、 改标签的困扰。同时开发人员也可以扩展和创建自定义的方言。
- Thymeleaf提供Spring标准方言和一个与SpringMVC 完美集成的可选模块,可以快速的实现表单绑定、属性编辑器、国际化等功能。
为什么使用 Thymeleaf
如果希望以Jar形式发布模块则尽不要使用JSP相关知识,这是因为JSP在内嵌的Servlet容器上运行有一些问题(内嵌Tomcat、Jetty 不支持Jar形式运行JSP,Undertow不支持JSP)。
Spring Boot中推荐使用Thymeleaf作为模板引擎,因为Thymeleaf提供了完美的Spring MVC支持
Spring Boot提供了大量模板引擎,包括:
- FreeMarker
- Groovy
- Mustache
- Thymeleaf
- Velocity
- Beetl
第一个 Thymeleaf 模板页
引入依赖
主要增加spring-boot-starter-thymeleaf和nekohtml这两个依赖
- spring-boot-starter-thymeleaf:Thymeleaf 自动配置
- nekohtml:允许使用非严格的 HTML 语法
pom.xml如下:
在application.yml中配置 Thymeleaf
spring:
thymeleaf:
cache:false #开发时关闭缓存,不然没法看到实时页面
mode:LEGACYHTMLS #用非严格的 HTML
encoding:UTF-8
servlet:
content-type:text/html
创建测试用JavaBean
创建一个测试效果的JavaBean,简单封装一下即可
创建测试用Controller
创建一个 Controller,造一些测试数据并设置跳转
创建测试页面
在templates目录下创建index.html文件,代码如下:
修改html标签用于引入 thymeleaf 引擎,这样才可以在其他标签里使用==th:*==语法,声明如下:
<!DOCTYPE html SYSTEM "http://www.thymeleaf.org/dtd/xhtml1-strict-thymeleaf-spring4-4.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
测试访问
启动成功后,访问:http://localhost:9090/thymeleaf/index 即可看到效果
Thymeleaf 常用语法
Thymeleaf 参考手册
Thymeleaf 声明
Thymeleaf 使用文本
Thymeleaf 其他th标签
Thymeleaf 表达式语法
Thymeleaf 内置对象
Thymeleaf 循环
Thymeleaf 判断
Thymeleaf 模板布局
Thymeleaf th:block
Thymeleaf th:inline
Spring Boot整合MyBatis
Spring Boot整合Druid
Druid 简介
Druid是阿里巴巴开源平台上的一个项目,整个项目由数据库连接池、插件框架和SQL解析器组成。该项目主要是为了扩展JDBC的一些限制,可以让程序员实现一些特殊的需求,比如向密钥服务请求凭证、统计SQL信息、SQL 性能收集、SQL 注入检查、SQL 翻译等,程序员可以通过定制来实现自己需要的功能。
Druid是目前最好的数据库连接池,在功能、性能、扩展性方面,都超过其他数据库连接池,包括DBCP、C3P0、 BoneCP、 Proxool、 JBoss DataSource。
Druid已经在阿里巴巴部署了超过600个应用,经过多年生产环境大规模部署的严苛考验。Druid 是阿里巴巴开发的号称为监控而生的数据库连接池!
引入依赖
在pom.xml文件中引入druid-spring-boot-starter依赖
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
</dependency>
引入数据库连接依赖
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
配置 application.yml
在application.yml中配置数据库连接
spring:
datasource:
url:jdbc:mysql://ip:port/dbname?useUnicode=true&characterEncoding=utf-8&useSSL=false
username:root
password:123456
initial-size:1
min-idle:1
max-active:20
test-on-borrow:true
driver-class-name:com.mysql.jdbc.Driver
**PS:**具体使用方法在测试MyBatis操作数据库章节中进行介绍,本章节仅为准备环节。
Spring Boot整合tk.mybatis
tk.mybatis 简介
tk.mybatis 是在 MyBatis 框架的基础上提供了很多工具,让开发更加高级
引入依赖
在pom.xml文件中引入mapper-spring-boot-starter依赖,该依赖会自动引入 MyBatis 相关依赖
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper-spring-boot-starter</artifactId>
<version>2.0.2</version>
</dependency>
配置 application.yml
配置MyBatis
mybatis:
type-aliases-package:实体类的存放路径,如:com.funtl.hello.spring.boot.entity
mapper-localtions:classpath:mapper/*.xml
创建一个通用的父级接口
主要作用是让 DAO 层的接口继承该接口,以达到使用 tk.mybatis 的目的
**PS:**具体使用方法在测试MyBatis操作数据库章节中进行介绍,本章节仅为准备环节。
Spring Boot整合PageHelper
PageHelper简介
PageHelper是Mybatis的分页插件,支持多数据库、多数据源。可以简化数据库的分页查询操作,整合过程也极其简单,只需引入依赖即可。
引入依赖
在pom.xml文件中引入pagehelper-spring- boot -starter依赖
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot- starter</artifactId>
<version>1.2.5</version>
</dependency>
**PS:**具体使用方法在测试MyBatis操作数据库章节中进行介绍,本章节仅为准备环节。
使用MyBatis的Maven插件生成代码
我们无需手动编写 实体类、DAO、XML 配置文件,只需要使用MyBatis 提供的一个Maven 插件就可以自动生成所需的各种文件便能够满足基本的业务需求,如果业务比较复杂只需要修改相关文件即可。
配置插件
在pom.xml文件中增加mybatis-generator-maven-plugin插件
<build>
<plugins>
<plugin>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.3.5</version>
<configuration>
<configurationFile>${basedir}/src/main/resources/generator/generatorConfig.xml</configurationFile>
<overwrite>true</overwrite>
<verbose>true</verbose>
</configuration>
<dependencies>
<dependency>
<groupId>mysq1</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper</artifactId>
<version>3.4.4</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
- configurationFile:自动生成所需的配置文件路径
自动生成配置
在src/main/resources/generator/目录下创建generatorConfig.xml配置文件:
<?xml version="1.0" encoding="UTF-8"?>
< !DOCTYPE generatorConfiguration
PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis . org/ dtd/ mybatis-generator-config.1 0.dtd">
<generatorConfiguration>
<!-- 引入数据库连接配置-->
<properties resource="jdbc.properties"/>
<context id="Mysql" targetRuntime="MyBatis3Simple" defaultModelType= flat">
<property name= "beginningDelimiter" value="` "/>
<property name="endingDelimiter" value="`"/>
<!--配置tk.mybatis插件-->
<plugin type="tk.mybatis.mapper.generator.MapperPlugin">
<property name= ”mappers" value=" com.funtl.utils.MyMapper"/>
</plugin>
<!--配置数据库连接-->
<jdbcConnection
driverClass="${jdbc.driverClass}"
connectionURL="${jdbc.connectionURL}"
userId="${ jdbc.username }
password="${jdbc.password}">
</jdbcConnection>
<!--配置实体类存放路径-->
<javaModelGenerator targetPackage="com.futl.hello.spring.boot.entity" targetProject="src/main/java" />
<!--配置XML存放路径-->
<sqIMapGenerator targetPackage= mapper" targetProject=" src/main/resources"/>
<!--配置DAO存放路径-->
<javaCl ientGenerator
targetPackage="com.funtl.hello.spring.boot.mapper"
targetProject="src/main/java"
type="XMLMAPPER"/>
<!--配置需要生成的表,%代表所有-->
<table tableName="%">
<!-- mysql配置-->
<generatedKey column="id" sqlStatement= "Mysql" identity="true"/>
</table>
</context>
</generatorConfiguration>
配置数据源
在src/main/resources目录下创建jdbc.properties数据源配置:
jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.connectionURL=jdbc:mysql://ip:port/dbname?useUnicode=true&characterEncoding=utf-8&useSSL=false
jdbc.username=root
jdbc.password=123456
插件自动生成命令
mvn mybatis-generator:generate
成功生成控制台打印的消息,如:
测试MyBatis操作数据
使用 tk.mybatis 操作数据库
经过之前章节一系列的配置之后,我们已经满足了使用MyBatis 操作数据库的必要条件,下面是使用 tk.mybatis 操作数据库的例子。
我们以测试操作用户表为例(tb_user)
修改入口类
需要使用==@MapperScan== 注解来指定Mapper接口的路径
**PS:**注意这里的==@MapperScan注解是tk.mybatis.spring-annotation.MapperScan;==包下的
package com.funtl.hello.spring.boot;
import org.springframework.boot.SpringApplication;
import org.springframework. boot.autoconfigure.SpringBootApplication;
import tk.mybatis.spring.annotation.MapperScan;
@SpringBootApplication
@MapperScan(basePackages = "com.funtl.hello.spring.boot.mapper")
public class HelloSpringBootApplication {
public static void main(String[] args) {
SpringApplication.run(HelloSpringBootApplication.class, args);
}
}
创建测试类
Spring Cloud (Finchley.RC1)
Spring Cloud 简介
Spring Cloud是一个相对比较新的微服务框架 ,2016才推出1.0的Release版本.但是其更新特别快,几乎每1-2个月就有一次更新,虽然Spring Cloud时间最短,但是相比Dubbo等RPC框架,Spring Cloud提供的全套的分布式系统解决方案。
Spring Cloud为开发者提供了在分布式系统(配置管理,服务发现,熔断,路由,微代理,控制总线,一次性 Token,全居琐,Leader选举,分布式Session,集群状态)中快速构建的工具,使用Spring Cloud的开发者可以快速的启动服务或构建应用、同时能够快速和云平台资源进行对接。
Spring Cloud 创建统一的依赖管理
简介
Spring Cloud 项目都是基于 Spring Boot 进行开发,并且都是使用 Maven 做项目管理工具。在实际开发中,我们一般都会创建一个依赖管理项目作为 Maven 的 Parent 项目使用,这样做可以极大的方便我们对 Jar 包版本的统一管理。
创建依赖管理项目
新建一个名为hello-spring-cloud的文件夹,用IDEA打开。
一个目录一个工程。
创建一个工程名为hello-spring-cloud-dependencies的项目(directory),新建pom.xml配置文件,内容如下:
- parent:继承了Spring Boot 的 Parent ,表示我们是一个Spring Boot 工程
- package:pom,表示该项目仅当做依赖项目,没有具体的实现代码
- spring-cloud-dependencies:在properties配置中预定义了版本号为Finchley.RC1,表示我们的Spring Cloud 使用的是F版
- build:配置了项目所需的各种插件
- repositories:配置项目下载依赖时的第三方库
在实际开发中,我们所有的项目都会依赖这个dependencies项目,整个项目周期中的所有第三方依赖的版本也都由该项目进行管理。
Spring Cloud 服务注册与发现
服务注册与发现
在这里,我们需要用的组件是Spring Cloud Netflix 的 Eureka , Eureka 是一个服务注册和发现的模式。
创建服务注册中心
其pom.xml文件配置如下:
主要增加了下面这一部分:
Application
启动一个服务注册中心,只需要一个注解==@EnableEurekaServer==
package com.funtl.hello.spring.cloud.eureka;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer:
@SpringBootApplication
@EnableEurekaServer
public class EurekaApplication {
public static void main(String[] args) {
SpringApplication. run(EurekaApplication.class, args);
}
}
application.yml
Eureka是一个高可用的组件,它没有后端缓存,每一个实例注册之后需要向注册中心发送心跳(因此可以在内存中完成),在默认情况下 Eureka Server 也是一个 Eureka Client ,必须要指定一个 Server。
spring:
application:
name:hello-spring-cloud-eureka
server:
port:8761
eureka:
instance:
hostname:localhost
client:
registerWithEureka:false
fetchRegistry:false
serviceUrl:
defaultZone:http://${eureka.instance.hostname}:${server.port}/eureka/
操作界面
Eureka Server 是有界面的,启动工程,打开浏览器访问:
http://localhost:8761
Spring Cloud 创建服务提供者
当 Client 向 Server 注册时,它会提供一些元数据,例如主机和端口,URL,主页等。Eureka Server 从每个 Client 实例接收心跳信息。如果心跳超时,则通常将该实例从注册Server中删除。
POM
与上节相同
Application
通过注解==@EnableEurekaClient== 表明自己是一个 Eureka Client。
package com.funtl.hello.spring.cloud.eureka;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaClient;
@SpringBootApplication
@EnableEurekaClient
public class ServiceAdminApplication {
public static void main(String[] args) {
SpringApplication. run(ServiceAdminApplication.class, args);
}
}
application.yml
spring:
application:
name:hello-spring-cloud-service-admin
server:
port:8762
eureka:
client:
serviceUrl:
defaultZone://http:localhost:8761/eureka/
**注意:**需要指明spring.application.name,这个很重要,这在以后的服务与服务之间相互调用一般都是根据这个name
Controller
启动工程,打开http://localhost:8761,即 Eureka Server 的网址:
你会发现一个服务已经注册在服务中了,服务名为HELLO-SPRING-CLOUD-SERVICE-ADMIN,端口为8762
这时打开http://localhost:8762/hi?message=HelloSpring,你会在浏览器上看到:
Hi,your message is:"HelloSpring" i am from port : 8762
Spring Cloud 创建服务消费者 (Ribbon)
在微服务架构中,业务都会被拆分成-个独立的服务,服务与服务的通讯是基于http restful的。Spring cloud有两种服务调用方式, 一种是ribbon + restTemplate,另一种是feign。 在这一篇文章首先讲解下基于ribbon + rest。
Ribbon简介
Ribbon是一个负载均衡客户端,可以很好的控制http 和tcp 的一些行为。
准备工作
- 启动服务提供者(本教程案例工程为: hello-spring-cloud-service-admin ),端口号为: 8762
- 修改配置文件的端口号为: 8763 ,启动后在Eureka中会注册两个实例,这相当于一个小集群
创建服务消费者
创建一个工程名为hello-spring-cloud-web-admin-ribbon 的服务消费项目,pom.xml配置同上,
主要增加了 Ribbon 的依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
Application
通过==@EnableDiscovertClient==注解注册到服务中心
application.yml
设置程序端口号为:8764
spring:
application:
name:hello-spring-cloud-web-admin-ribbon
thymeleaf:
cache:false
mode:LEGAYHTML5
encoding:UTF-8
servlet:
content-type:text/html
sercer:
port:8764
eureka:
client:
serviceUrl:
defaultZone:http://localhost:8761/eureka/
Configuration
配置注入RestTemplate 的Bean,并通过==@LoadBalanced== 注解表明开启负载均衡功能
创建测试用的 Controller
测试访问
在浏览器上多次访问 http://localhost:8764/hi?message=HelloRibbon
浏览器交替显示:
Hi,your message is :"HelloRibbon" i am from port :8762
Hi,your message is :"HelloRibbon" i am from port :8763
请求成功则表示我们已经成功实现了负载均衡功能来访问不同端口的实例
此时的架构
- 一个服务注册中心,Eureka Server,端口号为: 8761
- service-admin 工程运行了两个实例,端口号分别为:== 8762== ,8763
- web- admin-ribbon工程端口号为: 8764
- web- admin-ribbon通过RestTemplate调用service-admin接口时因为启用了负载均衡功能故会轮流调用它的8762和8763端口
在IDEA中配置一个工程启动多个实例
步骤一
点击Run -> Edit Configuration…
步骤二
选择需要启动多实例的项目并去掉Single Instance only 前面的勾
Spring Cloud 创建服务消费者 (Feign)
Feign简介
Feign是一个声明式的伪Http客户端,它使得写Http客户端变得更简单。使用Feign,只需要创建一个接口并注解。 它具有可插拔的注解特性,可使用Feign注解和JAX-RS注解。Feign 支持可插拔的编码器和解码器。Feign 默认集成了Ribbon,并和Eureka结合,默认实现了负载均衡的效果
- Feign采用的是基于接口的注解
- Feign整合了ribbon
创建服务消费者
创建一个工程名为hello-spring-cloud-web-admin-feign 的服务消费者项目,pom.xml 配置如下:
主要是增加了Feign的依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
Application
通过==@EnableFeignClients== 注解开启 Feign 功能
application.yml
spring:
application:
name:hello-spring-cloud-web-admin-feign
thymeleaf:
cache:false
mode:LEGAYHTML5
encoding:UTF-8
servlet:
content-type:text/html
sercer:
port:8765
eureka:
client:
serviceUrl:
defaultZone:http://localhost:8761/eureka/
创建 Feign 接口
通过==@FeignClient(“服务名”)== 注解来指定调用哪个服务。代码如下:
创建测试用的 Controller
测试访问
在浏览器上多次访问 http://localhost:8765/hi?message=HelloFeign
浏览器交替显示:
Hi,your message is :"HelloFeign" i am from port :8762
Hi,your message is :"HelloFeign" i am from port :8763
请求成功则表示我们已经成功实现了 Feign 功能来访问不同端口的实例。
Spring Cloud使用熔断器防止服务雪崩
熔断器简介
在微服务架构中,根据业务来拆分成一个个的服务 ,服务与服务之间可以通过RPC相互调用,在Spring Cloud中可以用RestTemplate + Ribbon 和Feign 来调用。为了保证其高可用,单个服务通常会集群部署。由于网络原因或者自身的原因,服务并不能保证100%可用,如果单个服务出现问题,调用这个服务就会出现线程阻塞,此时若有大量的请求涌入,Servlet 容器的线程资源会被消耗完毕,导致服务瘫痪。服务与服务之间的依赖性,故障会传播, 会对整个微服务系统造成灾难性的严重后果,这就是服务故障的“雪崩”效应。
为了解决这个问题,业界提出了熔断器模型。
Netflix开源了Hystrix 组件,实现了熔断器模式,Spring Cloud对这一组件进行了整合。在微服务架构中,一个请求需要调用多个服务是非常常见的,如下图:
较底层的服务如果出现故障,会导致连锁故障。当对特定的服务的调用的不可用达到一个阀值(Hystrix 是 5秒 20 次)熔断器将会被打开。
熔断器打开后,为了避免连锁故障,通过fallback 方法可以直接返回一个固定值。
Ribbon 中使用熔断器
在pom.xml 中增加依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
在Application中增加==@EnableHystrix==注解
在Service中增加 @HystrixCommand注解
在Ribbon调用方法上增加==@HystrixCommand== 注解并指定fallbackMethod熔断方法
测试熔断器
此时我们关闭服务提供者,再次请求 http://localhost:8764/hi?message=HelloRibbon浏览器会显示:
Hi, your message is : "HelloRibbon" but request error.
Feign中使用熔断器
Feign是自带熔断器的,但默认是关闭的。需要在配置文件中配置打开它,在配置文件增加以下代码:
feign:
hystrix:
enabled:true
在Service中增加fallback指定类
创建熔断器类并实现对应的Feign接口
测试熔断器
此时我们关闭服务提供者,再次请求http://localhost:8765/hi?message=HelloFeign 浏览器会显示:
Hi, your message is : "HelloFeign" but request error.
Spring Cloud 使用熔断器仪表盘监控
使用熔断器仪表盘监控
在 Ribbon 和 Feign 项目增加 Hystrix 仪表盘功能,两个项目的改造方式相同
在pom.xml中增加依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>
在Application中增加==@EnableHystirxDashboard==注解
创建hystrix.stream的Servlet配置
Spring Boot 2.x 版本开启 Hystrix Dashboard 与 Spring Boot 1.x 的方式略有不同,需要增加一个 HystrixMetricsStreamServlet 的配置,代码如下:
测试 Hystrix Dashboard
浏览器端访问 http://localhost:8764/hystrix界面如下:
点击 Monitor Stream,进入下一个界面,访问http://localhost:8764/hi?message=HelloRibbon 此时会出现监控界面:
Spring Cloud 使用路由网关统一访问接口
使用路由网关统一访问接口
在微服务架构中,需要几个基础的服务治理组件,包括服务注册与发现、服务消费、负载均衡、熔断器、智能路由、配置管理等,由这几个基础组件相互协作,共同组建了一个简单的微服务系统。一个简单的微服务系统如下图:
在 Spring Cloud 微服务系统中,一种常见的负载均衡方式是,客户端的请求首先经过负载均衡(Zuul、Ngnix),再到达服务网关(Zuul集群),然后再到具体的服。服务统一注册到高可用的服务注册中心集群,服务的所有的配置文件由配置服务管理,配置服务的配置文件放在GIT仓库,方便开发人员随时改配置。
Zuul简介
Zuul的主要功能是路由转发和过滤。路由功能是微服务的一部分,比如==/api/user转发到User服务,/api/user==转发到Shop服务。Zuul默认和Ribbon结合实现了负载均衡的功能。
创建路由网关
pom.xml文件同上节,主要增加了Zuul的依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
Application
增加@EnableZuulProxy,注解开启Zuul功能
application.yml
- 设置端口号为:8769
- 增加Zuul配置
spring:
application:
name:hello-spring-cloud-zuul
sercer:
port:8765
eureka:
client:
serviceUrl:
defaultZone:http://localhost:8761/eureka/
zuul:
routes:
api-a:
path:/api/a/**
serviceId:hello-spring-cloud-web-admin-ribbon
api-b:
path:/api/b/**
serviceId:hello-spring-cloud-web-admin-feign
路由说明:
- 以==/api/a开头的请求都转发给hello-spring-cloud-web-admin-ribbon==服务
- 以==/api/b开头的请求都转发给hello-spring-cloud-web-admin-feign==服务
测试访问
一次运行EurekaApplication、ServiceAdminApplication、WebAdminRibbonApplication、WebAdminFeignApplication、ZuulApplication
打开浏览器访问:http://localhost:8769/api/a/hi?message=HelloZuul 浏览器显示
Hi,your message is : "HelloZuul" i am from port:8763
打开浏览器访问:http://localhost:8769/api/b/hi?message=HelloZuul 浏览器显示
Hi,your message is : "HelloZuul" i am from port:8763
至此说明 Zuul 的路由功能配置成功
配置网关路由失败时的回调
Spring Cloud 使用路由网关的服务过滤功能
使用路由网关的服务过滤功能
Zuul 不仅仅只是路由,还有很多强大的功能,本节演示一下它的服务过滤功能,比如用在安全验证方面。
创建服务过滤器
继承ZuulFilter 类并在类上增加@Component注解就可以使用服务过滤功能了,非常简单方便
filterType
返回一个字符串代表过滤器的类型,在 Zuul 中定义了四种不同生命周期的过滤器类型
- pre:路由之前
- routing:路由之时
- post:路由之后
- error:发送错误调用
filterOrder
过滤的顺序
shouldFilter
是否需要过滤,这里是true,需要过滤
run
过滤器的具体业务代码
测试过滤器
通过浏览器访问 http://localhost:8769/api/b/hi?message=HelloSpring
Spring Cloud 服务配置
Spring Cloud 分布式配置中心
分布式配置中心服务端
在分布式系统中,由于服务数量巨多,为了方便服务配置文件统一管理,实时更新,所以需要分布式配置中心组件。在Spring Cloud中,有分布式配置中心组件Spring Cloud Config,它支持配置服务放在配置服务的内存中(即本地),也支持放在远程 Git仓库中。在Spring Cloud Config组件中,分两个角色,一是Config Server,二是Config Client。
创建一个工程名为hello-spring-cloud-config 的项目,pom.xml 配置文件如下:
主要增加了spring-cloud-config-server 依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
Application
通过@EnableConfigServer注解,开启配置服务器功能
application.yml
增加 Config 相关配置,并设置端口号为:8888
spring:
application:
name:hello-spring-cloud-config
cloud:
config:
label:master
server:
git:
url:https//github.com/topsale/spring-cloud-config
search-paths:respo
username:
password:
server:
port:8888
eureka:
client:
serviceUrl:
defaultZone:http://localhost:8761/eureka/
相关配置说明,如下:
- spring.cloud.config.label:配置仓库的分支
- spring.cloud.config.server.git.uri:配置Git仓库地址(GitHub、GitLab、码云…)
- spring.cloud.config.sercer.git.search-paths:配置仓库路径(存放配置文件的目录)
- spring.cloud.config.sercer.git.username:访问Git仓库的账号
- spring.cloud.config.sercer.git.password:访问Git仓库的密码
注意事项:
- 如果使用GitLab作为仓库的话,git.uri 需要在结尾加上==.git==,GitHub 则不用
测试
浏览器端访问:http://localhost:8888/config-client/dev/master 显示如下:
证明配置服务中心可以从远程程序获取配置信息
附:HTTp请求地址和资源文件映射
- http://ip:port/{application}/{profile}/{label}
- http://ip:port/{application}-{profile}.yml
- http://ip:port/{label}/{application}-{profile}.yml
- http://ip:port/{application}-{profile}.properties
- http://ip:port/{label}/{application}-{profile}.properties
分布式配置中心客户端
创建一个工程名为hello-spring-cloud-config-client的项目,pom.xml 文件配置如下:
主要增加了spring-cloud-starter-config 依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
Application
入口类没有需要特殊处理的地方,代码如下:
application.yml
增加 ConfigClient 相关配置,并设置端口号为:8889
spring:
application:
name:hello-spring-cloud-config-client
cloud:
config:
uri:http://localhost:8888
name:config-client
label:master
profile:dev
server:
port:8889
eureka:
client:
serviceUrl:
defaultZone:http://localhost:8761/eureka/
相关配置说明,如下:
- spring-cloud-config.uri:配置服务中心的网址
- spring-cloud-config.name:配置文件名称的前缀
- spring-cloud-config.label:配置仓库的分支
- spring-cloud-config.profile:配置文件的环境标识
- dev:表示开发环境
- test:表示测试环境
- prod:表示生产环境
注意事项:
- 配置服务器的默认端口为8888,如果修改了默认端口,则客户端项目就不能再application.yml或application.properties中配置spring.cloud.config.uri,必须在bootstrap.yml或是bootstrap.properties中配置,原因是bootstarp开头的配置文件会被优先加载和配置,切记。
创建测试用 Controller
我们创建一个 Controller 来测试一下通过远程仓库的配置文件注入foo属性
一般情况下,能够正常启动服务就说明注入是成功的。
测试访问
浏览器端访问:http://localhost:8889/hi 显示如下:
foo version 1
附:开启 Spring Boot Profile
我们在做项目开发的时候,生产环境和测试环境的一些配置可能会不一样,有时候一些功能也可能会不一 样,所以我们可能会在上线的时候手工修改这些配置信息。但是Spring中为我们提供了Profile 这个功能。我们只需要在启动的时候添加一个虚拟机参数,激活自己环境所要用的Profile 就可以了。
操作起来很简单,只需要为不同的环境编写专门的配置文件,如: application-dev.yml、application-prod.yml,启动项目时只需要增加一个命令参数 –spring.profiles.active=环境配置即可,启动命令如下:
java -jar hello-spring-cloud-web-admin-feign-1.0.0-SNAPSHOT.jar --spring.profiles.active=prod
Spring Cloud 服务追踪
Spring Cloud 服务链路追踪
这篇文章主要讲解服务追踪组件ZipKin。
ZipKin简介
ZipKin是一个开放源代码的分布式跟踪系统 ,由Twitter公司开源,它致力于收集服务的定时数据,以解决微服务架构中的延迟问题,包括数据的收集、存储、查找和展现。它的理论模型来自于Google Dapper论文。
每个服务向ZipKin报告计时数据, ZipKin会根据调用关系通过ZipKin UI生成依赖关系图,显示了多少跟踪请求通过每个服务,该系统让开发者可通过一个 Web前端轻松的收集和分析数据,例如用户每次请求服务的处理时间等,可方便的监测系统中存在的瓶颈。
服务追踪说明
微服务架构是通过业务来划分服务的,使用REST调用。对外暴露的一个接口,可能需要很多个服务协同才能完成这个接口功能,如果链路上任何一个服务出现问题或者网络超时,都会形成导致接口调用失败。随着业务的不断扩张,服务之间互相调用会越来越复杂。
随着服务越来越多,对调用链的分析会越来越复杂。它们之间的调用关系也许如下:
术语解释
- Span:基本工作单元,例如,在一个新建的Span中发送一个RPC等同于发送一个回应请求给RPC,Span通过一个64位ID唯一标识,Trace以另一个64位ID表示。
- Trace:一些流Spans组成的一个树状结构,例如,如果你正在运行一个分布式大数据工程,你可能需要创建一个Trace。
- Annotation:用来即使记录一个事件的存在,一些核心 Annotations 用来定义一个请求的开始和结束
- cs:Client Sent ,客户端发起一个请求,这个 Annotation 描述了这个 Span 的开始
- sr:Server Recrived , 服务端获得请求并准备开始处理它,如果将其sr减去cs时间戳便可得到网络延迟
- ss:Server Sent 表明请求处理的完成(当请求返回客户端),如果ss减去sr时间戳便可得到服务端需要的处理请求时间
- cr:Client Received 表明Span的结束,客户端成功接收到服务端的回复,如果cr减去cs时间戳便可得到客户端从服务端获取回复的所有所需时间
将Span和Trace在一个系统中使用ZipKin注解的过程图形化:
创建ZipKin服务端
创建一个工程名为hello-spring-cloud-zipkin的项目,pom.xml文件如下:
主要增加了3个依赖,io.zipkin.java:zipkin、io.zipkin.java:zipkin-server、io.zipkin.java:zipkin-autoconfigure-ui
<dependency>
<groupId>io.zipkin.java</groupId>
<artifactId>zipkin</artifactId>
</dependency>
<dependency>
<groupId>io.zipkin.java</groupId>
<artifactId>zipkin-server</artifactId>
</dependency>
<dependency>
<groupId>io.zipkin.java</groupId>
<artifactId>zipkin-autoconfigure-ui</artifactId>
</dependency>
注意版本号为:2.10.1,这里没写版本号是因为我已将版本号托管到dependencies项目中
Application
通过@EnableZipkinServer注解开启Zipkin Server功能
application.yml
设置端口号为:9411,该端口号Zipkin Server的默认端口号
spring:
application:
name:hello-spring-cloud-zipkin
server:
port:9411
eureka:
client:
serviceUrl:
defaultZone:http://localhost:8761/eureka/
management:
metrices:
web:
server:
auto-time-requests:false
追踪服务
在所有需要被追踪的项目(就当前教程而言,除了dependencies项目外都需要被追踪,包括Eureka Server) 中增加spring-cloud-starter-zipkin依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud</artifactId>
</dependency>
在这些项目的application.yml配置文件中增加Zipkin Server的地址即可
spring:
zipkin:
base-url:http://localhost:9411
测试追踪
启动全部项目,打开浏览器访问:http://localhost:9411/会出现以下界面:
刷新之前项目中的全部测试接口(刷多几次)
Spring Boot Admin 服务监控 (2.x)
随着开发周期的推移,项目会不断变大,切分出的服务也会越来越多,这时一个个的微服务构成了错综复杂的系统。对于各个微服务系统的健康状态、会话数量、并发数、服务资源、延迟等度星信息的收集就成为了一个挑战。Spring Boot Admin应运而生,它正式基于这些需求开发出的一套功能强大的监控管理系统。
Spring Boot Admin有两个角色组成,一个是 Spring Boot Admin Server ,一个是 Spring Boot Admin Client,本章节将带领大家实现Spring Boot Admin的搭建。
Spring Boot Admin 服务端
创建Spring Boot Admin Server
创建一个工程名为hello-spring-cloud-admin的项目,pom.xml文件如下:
主要增加了2个依赖,org.jolokia:jolokia-core、de.codecentric:spring-boot-admin-starter-server
<dependency>
<groupId>org.jolokia</groupId>
<artifactId>jolokia-core</artifactId>
</dependency>
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-server</artifactId>
</dependency>
其中spring-boot-admin-starter-server的版本号为:2.0.0,这里没写版本号是因为我已经将版本号托管到了dependencies项目中。
Application
通过@EnableAdminServer注解开启Admin功能
application.yml
设置端口号:8084
spring:
application:
name:hello-spring-cloud-admin
zipkin:
base-url:http://localhost:9411
server:
port:8084
management:
endpoint:
health:
show-details:always
endpoints:
web:
exposure:
include:["health","info"]
eureka:
client:
serviceUrl:
defaultZone:http://localhost:8761/eureka/
主要增加了Spring Boot Admin Server的相关配置
Spring Boot Admin 客户端
创建一个工程名为hello-srping-cloud-admin-client的项目,pom.xml文件如下:
主要增加了2个依赖,org.jolokia:jolokia-core、de.codecentric:spring-boot-admin-starter-client
<dependency>
<groupId>org.jolokia</groupId>
<artifactId>jolokia-core</artifactId>
</dependency>
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-client</artifactId>
</dependency>
其中spring-boot-admin-starter-client的版本号为:2.0.0,这里没写版本号是因为我已经将版本号托管到了dependencies项目中。
Application
程序入口类没有特别需要修改的地方
application.yml
设置端口号为:8085,并设置Spring Boot Admin的服务端地址
spring:
application:
name:hello-spring-cloud-admin-client
boot:
admin:
client:
url:http://localhost:8084
zipkin:
base-url:http://localhost:9411
server:
port:8085
eureka:
client:
serviceUrl:
defaultZone:http://localhost:8761/eureka/
主要增加了Spring Boot Admin Client相关配置
spring:
boot:
admin:
client:
url:http://localhost:8084
测试服务监控
依次启动两个应用,打开浏览器访问:http://localhost:8084界面如下
启动顺序
- Eureka:服务注册与发现
- Config :分布式配置中心
- 服务提供者
- 服务消费者
- API网关