内容介绍:简易版springcloud组件快速使用介绍
springcloud微服务架构快速应用
springcloud综述:使服务的提供者和消费者之间的交互变得便捷,方便相互之间的请求交互;使服务变得更可靠(高可用);使请求变得更随机(不需要写请求的具体地址,写个服务id即可)
总结起来就是6个字:便捷,可靠,高效
一、springboot-项目的构建
1.综述:
springboot的出现,改变了项目的管理和配置结构(只是配置少了),但我们业务核心代码的编写不会变。
2.核心理念:约定大于配置
1.在springboot中提供了一个启动器,在其中写好了大量的默认配置。引入启动器的依赖,就可以实现这些 默认配置 和 配置自动化 。具体配置在Mate-INF/spring.factory
中
2.所谓约定:就是指公共的,大家都相同的东西,可以约定。但是个性化的东西还是必须配置的
a.公共的配置(可以默认)例如:
MySQL端口号:3306
redis端口号:6379
Tomcat端口号:8080
b.个性化的配置(必须配置)例如:
1.数据库(使用数据库相关的启动器一定要配置):ip地址,用户名,密码
- 在springboot项目中,所有的组件功能开启都需要在项目启动类上加一个@Enable…注解来实现,但是Eureka客户端发现(注册)功能注解(@EnableDiscoveryClient)可以不用添加。
二、Eureka注册中心
1.综述:
服务的注册、发现、监控中心,属于被动营业者。需要服务的提供者和调用者注册为Eureka客户端,提供者主动到Eureka服务端定时推送(注册)自己的服务信息、调用者主动到Eureka服务端定时拉取已经注册的服务信息
Eureka注册中心高可用的实现方法:多个Eureka Server之间也会互相注册为服务,当服务提供者注册到Eureka Server集群中的某个节点时,该节点会把服务的信息同步给集群中的每个节点,从而实现高可用集群。因此,无论客户端访问到Eureka Server集群中的任意一个节点,都可以获取到完整的服务列表信息。
三、ribbo负载均衡
1.所有服务都应该可以集群,既然集群了就要实现负载均衡
2.ribbon实现服务之间相互调用的负载均衡。网关、feign都通过ribbon实现负载均衡。而网关的负载均衡由Nginx实现,Nginx的负载均衡由Nginx集群内部模拟一台虚拟服务器来实现
3.ribbon默认的负载均衡策略是轮询
四、hystrix熔断器
1.简介:Hystix是Netflix开源的一个延迟和容错库,用于隔离访问远程服务、第三方库,防止出现级联失败
2.具体的应用场景:
微服务中,服务间调用关系错综复杂,一个请求,可能需要调用多个微服务接口才能实现,会形成非常复杂的调用链路。
例如:一次业务请求,需要调用A、B、C、D四个服务,这四个服务又可能调用其它服务。
如果微服务D发生异常,请求阻塞,用户不会得到响应,则tomcat的这个线程不会释放,于是越来越多的用户请求到来,越来越多的线程会阻塞
服务器支持的线程和并发数有限,请求一直阻塞,会导致服务器资源耗尽,从而导致所有其它服务都不可用,形成雪崩效应。
Hystix解决雪崩问题的手段主要是服务降级,包括:
- 线程隔离
- 服务熔断
五、zuul网关(或APIGateway)
1.综述:
Zuul作为网关的其中一个重要功能,就是实现请求的鉴权。而这个动作我们往往是通过Zuul提供的过滤器来实现的。
1.1.接收请求,解析请求
1.2.根据请求,选取请求实例 (ip:port)
1.3.重新封装请求:头、参数
1.4.请求发起
2.1解析响应(排雷,过滤敏感信息)
2.2重新封装(网管认为安全的)
2.3将响应返回给客户端
2.核心:zuul核心是一个servlet
3.应用
Zuul中默认就已经集成了Ribbon负载均衡和Hystix熔断机制。但是所有的超时策略都是走的默认值,比如熔断超时时间只有1S,很容易就触发了。因此建议我们手动进行配置:
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 6000
ribbon:
ConnectTimeout: 1000
ReadTimeout: 2000
MaxAutoRetries: 0
MaxAutoRetriesNextServer: 0
六、feign(rest服务封装)
1.简介:Feign可以把Rest的请求进行隐藏,伪装成类似SpringMVC的Controller一样。你不用再自己拼接url,拼接参数等等操作,一切都交给Feign去做。
2.负载均衡:Feign中本身已经集成了Ribbon依赖和自动配置:
3.Hystix支持(了解):Feign默认也有对Hystix的集成。只不过,默认情况下是关闭的。我们需要通过下面的参数来开启:
feign:
hystrix:
enabled: true # 开启Feign的熔断功能
七、ConfigServer配置中心
八、构建web项目步骤
1.构建springboot父工程:例如cloud_parent
1.打包方式改成pom
<packaging>pom</packaging>
2.引入Springboot父启动器
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.6.RELEASE</version>
<relativePath/>
</parent>
3.锁定基本要用的依赖版本
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<spring-cloud.version>Finchley.SR2</spring-cloud.version>
<mapper.starter.version>2.0.4</mapper.starter.version>
<mysql.version>5.1.46</mysql.version>
<pageHelper.starter.version>1.2.5</pageHelper.starter.version>
</properties>
<dependencyManagement>
<dependencies>
<!-- springCloud -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- 通用Mapper启动器 -->
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper-spring-boot-starter</artifactId>
<version>${mapper.starter.version}</version>
</dependency>
<!-- mysql驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
3.引入web打包插件
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
2.构建子工程-Eureka注册中心
2.1.单机版Eureka注册中心
1.编辑pom文件,引入依赖
1.继承父工程 cloud_parent
2.引入Eureka服务端依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
2.编写启动类
@SpringBootApplication
@EnableEurekaServer // 声明这个应用是一个EurekaServer
public class EurekaServer {
public static void main(String[] args) {
SpringApplication.run(EurekaServer.class, args);
}
}
3.编写配置
server:
port: 10086
spring:
application:
name: eureka-server # 应用名称,会在Eureka中作为服务的id标识(serviceId)
#配置Eureka客户端相关
eureka:
client:
service-url: # EurekaServer的地址,现在是自己的地址,如果是集群,需要写其它Server的地址。
defaultZone: http://127.0.0.1:10086/eureka
register-with-eureka: false # 不注册自己
fetch-registry: false #不拉取服务
2.2.实现高可用Eureka注册中心
1.如果有三个Eureka,则每一个EurekaServer都需要注册到其它几个Eureka服务中,例如:有三个分别为10086、10087、10089,则:
- 10086要注册到10087和10088上
- 10087要注册到10086和10088上
- 100898要注册到10086和10087上
2.修改原来的EurekaServer配置:
注:三台EurekaServer的开发步骤一样,只是配置的不同
第一台
server:
port: 10086 # 端口
spring:
application:
name: eureka-server # 应用名称,会在Eureka中显示
eureka:
client:
service-url: # 配置其他Eureka服务的地址,而不是自己,比如10087
defaultZone: http://127.0.0.1:10087/eureka,http://127.0.0.1:10088/eureka
第二台
server:
port: 10087 # 端口
spring:
application:
name: eureka-server # 应用名称,会在Eureka中显示
eureka:
client:
service-url: # 配置其他Eureka服务的地址,而不是自己,比如10087
defaultZone: http://127.0.0.1:10086/eureka,http://127.0.0.1:10088/eureka
第三台
server:
port: 10088 # 端口
spring:
application:
name: eureka-server # 应用名称,会在Eureka中显示
eureka:
client:
service-url: # 配置其他Eureka服务的地址,而不是自己,比如10087
defaultZone: http://127.0.0.1:10086/eureka,http://127.0.0.1:10087/eureka
3.构建子工程-服务的提供者:例如user_service
1.编辑pom文件,引入依赖
1.继承父工程 cloud_parent
2.引入web启动器依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
3.引入数据库依赖
<!-- mysql驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--mybatis启动器-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.0</version>
</dependency>
4.引入Eureka客户端依赖
<!-- Eureka客户端 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
2.编写启动类
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@EnableDiscoveryClient // 开启Eureka客户端发现功能
public class UserApplication {
public static void main(String[] args) {
SpringApplication.run(UserApplication.class, args);
}
}
3.编写application.yml文件
#1.tomcat端口覆盖
server:
port: 8081
#2.养成给所有springboot项目命名的习惯
spring:
application:
name: user-service
#3.配置数据源
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mybatis://127.0.0.1:3306/mydb01
username: root
password: root
#4.配置mybatis
mybatis:
mapper-locations: mapper/**/*.xml # mapper文件地址
# 还可以配置 实体类别名映射,驼峰匹配 等
#5.#配置Eureka客户端相关
eureka:
client:
# 5.1EurekaServer地址,多个地址以','隔开
service-url:
defaultZone: http://127.0.0.1:10086/eureka,http://127.0.0.1:10087/eureka,
http://127.0.0.1:10088/eureka
# 5.2服务注册
instance:
ip-address: 127.0.0.1 # ip地址
prefer-ip-address: true # 更倾向于使用ip,而不是host名
# 5.3服务续约:维持心跳(定时向EurekaServer发起Rest请求),告诉EurekaServer:“我还活着”
lease-expiration-duration-in-seconds: 90
lease-renewal-interval-in-seconds: 30
4.编写业务代码。。。
4.1对外查询的接口UserController:
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/{id}")
public User queryById(@PathVariable("id") Long id) {
return userService.queryById(id);
}
}
4.2 UserService:
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
public User queryById(Long id) {
return userMapper.queryById(id);
}
}
4.3 UserMapper
public interface UserMapper{
User queryById(@Param("id") Long id);
}
4.4 sqly语句
<select id="queryById" resultType="user">
SELECT FROM t_user WHERE id=#{id}
</select>
4.5 实体类
@Data
public class User {
private Long id;
private String userName; // 用户名
private String password; // 密码
}
4.构建子工程-服务的调用者:例如consumer_demo
1.编辑pom文件,引入依赖
1.继承父工程 cloud_parent
2.引入web启动器依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
3.引入Eureka客户端依赖
<!-- Eureka客户端 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
4.ribbon:因为Eureka中已经集成了Ribbon,所以我们无需引入新的依赖
5.hystrix
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
6.引入feign依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
2.编写启动类
@SpringBootApplication
@EnableDiscoveryClient // 开启Eureka客户端
@EnableCircuitBreaker //开启hystrix熔断
@EnableFeignClients // 开启Feign功能
public class ConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class, args);
}
}
3.编写配置
server:
port: 8080
spring:
application:
name: consumer-demo # 应用名称
eureka:
client:
service-url: # EurekaServer地址
defaultZone: http://127.0.0.1:10086/eureka,http://127.0.0.1:10087/eureka,
http://127.0.0.1:10088/eureka
# 在服务的调用端实施对服务提供方访问的负载均衡控制
ribbon:
ConnectTimeout: 1000 # 连接超时时长
ReadTimeout: 2000 # 数据通信超时时长
MaxAutoRetries: 0 # 当前服务器的重试次数
MaxAutoRetriesNextServer: 0 # 重试多少次服务
OkToRetryOnAllOperations: false # 是否对所有的请求方式都重试
4.编写业务代码
4.1 编写ConsumerController使用UserClient访问目标服务(user-service):
@RestController
@RequestMapping("consumer")
@Slf4j
public class ConsumerController {
@Autowired
private UserClient userClient;
@GetMapping("{id}")
@HystrixCommand(fallbackMethod = "queryByIdFallBack")
public User queryById(@PathVariable("id") Long id){
log.info("查询方法执行了");
return userClient.queryById(id);
}
public User queryByIdFallBack(Long id){
log.error("查询用户信息失败,id:{}", id);
return new User(id,"","对不起,网络太拥挤了!");
}
}
4.2 Feign的客户端UserClient
/**
* 1.这是一个接口,Feign会通过动态代理,帮我们生成实现类。这点跟mybatis的mapper很像
* 2.`@FeignClient`,声明这是一个Feign客户端,同时通过`value`属性指定服务名称
* 3.接口中的定义方法,完全采用SpringMVC的注解,Feign会根据注解帮我们生成URL,并访问获取结果
* 4.feign的客户端已经集成了ribbon负载均衡功能,因此通过feign客户端调用服务提供者时会自动实现负载均
* 衡
*/
@FeignClient("user-service")
public interface UserClient {
@GetMapping("/user/{id}")
User queryById(@PathVariable("id") Long id);
}
- 3实体类
@Data
public class User {
private Long id;
private String userName; // 用户名
private String password; // 密码
}
5.构建子工程-zuul网关:例如zuul-demo
1.编辑pom文件,引入依赖
1.继承父工程 cloud_parent
2.引入zuul启动器依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
2.编写启动类
@SpringBootApplication
@EnableDiscoveryClient // 开启Eureka客户端
@EnableZuulProxy // 开启Zuul的网关功能
public class ZuulApplication {
public static void main(String[] args) {
SpringApplication.run(ZuulApplication.class, args);
}
}
3.编写配置
server:
port: 10060 #服务端口
spring:
application:
name: api-zuul #指定服务名
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:10086/eureka,http://127.0.0.1:10087/eureka,
http://127.0.0.1:10088/eureka
instance:
prefer-ip-address: true
ip-address: 127.0.0.1
# 添加zuul网关映射规则
zuul:
routes:
consumer-demo: # 这里是路由id,随意写
path: /consumer-demo/** # 这里是映射路径
serviceId: consumer-demo # 映射路径对应的实际服务名称
4.编写自定义过滤器类LoginFilter进行鉴权(拦截所有路径)
Zuul作为网关的其中一个重要功能,就是实现请求的鉴权。而这个动作我们往往是通过Zuul提供的过滤器来实现的。
/**
* 1.模拟一个登录的校验。基本逻辑:如果请求中有token参数,则认为请求有效,放行。
* 2.ZuulFilter是过滤器的顶级父类。在这里我们看一下其中定义的4个最重要的方法
* filterType:返回字符串,代表过滤器的类型
* filterOrder:通过返回的int值来定义过滤器的执行顺序,数字越小优先级越高
* shouldFilter:返回一个Boolean值,判断该过滤器是否需要执行。返回true执行,返回false不执行。
* run:过滤器的具体业务逻辑
*/
@Component
public class LoginFilter extends ZuulFilter {
@Override
public String filterType() {
return FilterConstants.PRE_TYPE;
}
@Override
public int filterOrder() {
return FilterConstants.PRE_DECORATION_FILTER_ORDER - 1;
}
@Override
public boolean shouldFilter() {
return true;
}
@Override
public Object run() throws ZuulException {
// 获取请求上下文
RequestContext context = RequestContext.getCurrentContext();
// 获取request对象
HttpServletRequest request = context.getRequest();
// 获取请求参数
String token = request.getParameter("token");
// 判断是否存在
if(StringUtils.isBlank(token)){
// 不存在,未登录,拦截
context.setSendZuulResponse(false);
// 设置返回状态码
context.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value());
}
return null;
}
}
5.浏览器请求网关进行测试。分别请求如下地址:
不带token的路径,拦截: localhost:10060/consumer-demo/consumer/3
带token的路径,成功: localhost:10060/consumer-demo/consumer/3?token=aaa