SpringCloud全家桶— — 组件搭建

1 Eureka

1.1 Eureka-server

创建eureka-server的SpringBoot项目

①导入依赖

org.springframework.cloud

spring-cloud-starter-netflix-eureka-server

②启动类上添加注解@EnableEurekaServer

@SpringBootApplication

@EnableEurekaServer

public class EurekaApplication {

public static void main(String[] args) {

SpringApplication.run(EurekaApplication.class, args);

}

}

③编写配置文件,指明eureka地址

eureka本身也需要注册上去

server:

port: 10086

spring:

application:

name: eureka-server

eureka:

client:

service-url:

defaultZone: http://127.0.0.1:10086/eureka

启动eureka所在SpringBoot项目,浏览器输入http://127.0.0.1:10086

1.2 Eureka-client

eureka作为注册中心,我们现在将服务注册到eureka

①导入依赖

org.springframework.cloud

spring-cloud-starter-netflix-eureka-client

②编写配置文件

spring:

application:

# 服务名称

name: userservice

eureka:

client:

service-url:

defaultZone: http://127.0.0.1:10086/eureka

1.3 服务发现

现在有两个模块:user-service和order-service;我们都将他们注册到eureka,现在order-service通过RPC远程调用user-service

order-service与user-service注册到eureka过程同上 ①order配置restTemplate

可以单独在一个配置类写,或者直接写到SpringBootApplication中,只要注入到Spring容器中就行

/**

* 创建RestTemplate并注入Spring容器

*/

@Bean

@LoadBalanced

public RestTemplate restTemplate() {

return new RestTemplate();

}

②service中注入restTemplate

restTemplate是Spring提供的给我们操作rest服务的客户端

@Autowired

private RestTemplate restTemplate;

public Order queryOrderById(Long orderId) {

// 1.查询订单

Order order = orderMapper.findById(orderId);

// 2.利用RestTemplate发起http请求,查询用户

// 2.1.url路径【需要使用userservice对应的服务名】

String url = "http://userservice/user/" + order.getUserId();

// 2.2.发送http请求,实现远程调用

User user = restTemplate.getForObject(url, User.class);

// 3.封装user到Order

order.setUser(user);

// 4.返回

return order;

}

spring会自动帮助我们从eureka-server端,根据userservice这个服务名称,获取实例列表,而后完成负载均衡。

2 Ribbon(以restTemplate为例)

导入openfeign,openfeign中默认集成了ribbon 注意:微服务之间调用用Feign,和第三方间交互使用RestTemplate等

2.1 restTemplate集成ribbon

RestTemplate是Spring提供的用于访问Rest服务的客户端,RestTemplate提供了多种便捷访问远程Http服务的方法,能够大大提高客户端的编写效率。

①导入依赖

org.springframework.cloud

spring-cloud-starter-openfeign

②创建restTemplate,并添加上负载均衡注解

可以在启动类的main方法中创建,也可以单独写一个配置类,只要最后有bean标识被spring管理即可

/**

* 创建RestTemplate并注入Spring容器

*/

@Bean

@LoadBalanced

public RestTemplate restTemplate() {

return new RestTemplate();

}

@LoadBalanced是以轮询方式访问

2.1 自定义负载均衡

有两种方式: ①定义一个新的IRule

@Bean

public IRule randomRule(){

return new RandomRule();

}

无法精准对某个微服务进行处理

②在配置文件中编写

userservice: # 给某个微服务配置负载均衡规则,这里是userservice服务

ribbon:

NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule # 负载均衡规则

注意,一般用默认的负载均衡规则,不做修改。

Ribbon默认是懒加载,也就是第一次访问的时候才会创建LoadBalanceClient,这样会导致请求时间会变得很长推荐开启饥饿加载(项目启动时创建)

ribbon:

eager-load:

enabled: true

clients: userservice

clients可以精准对某个微服务进行处理

3 Feign、OpenFeign

3.1 Feign

restTemplate是Spring提供给我们的用于调用rest服务的客户端

RestTemplate调用方式:

•代码可读性差,编程体验不统一 •参数复杂URL难以维护

说明:Feign是一个声明式的HTTP客户端 ①导入依赖

org.springframework.cloud

spring-cloud-starter-openfeign

②开启注解

在SpringBootApplication上开启对应注解

@EnableFeignClients

③编写Feign的客户端

# userservice是服务名称

# @GetMapping()中填写对应controller访问路径

@FeignClient("userservice")

public interface UserClient {

@GetMapping("/user/{id}")

User findById(@PathVariable("id") Long id);

}

Feign主要是通过SpringMVC的注解来声明远程调用信息

服务名称:userservice请求方式:GET请求路径:/user/{id}请求参数:Long id返回值类型:User

④在service中调用feignClient

@Service

public class OrderService {

@Autowired

private UserClient userClient;

public Order queryOrderById(Long orderId) {

// 1.查询订单

Order order = orderMapper.findById(orderId);

// 2.用Feign远程调用

User user = userClient.findById(order.getUserId());

// 3.封装user到Order

order.setUser(user);

// 4.返回

return order;

}

}

引入Feign的步骤:

1. 导入依赖

2. 添加@EnableFeignClients注解

3. 编写FeignClient接口

4. service中调用feignClient

Feign可以支持很多自定义配置

修改日志级别响应结果的解析器(如:解析json为java对象)请求参数编码(将请求参数编码,便于http发送请求)支持的注解格式失败重试机制(默认没有,但是会使用ribbon的重试)

一般情况下,默认值就能满足我们的使用,如果要自定义时,只需要创建自定义的@Bean覆盖默认Bean即可

修改feign的默认配置

以修改日志级别为例 方式1:修改配置文件

feign:

client:

config:

default: # 这里用default就是全局配置,如果是将default改为具体服务名称,则是针对某个微服务的配置

loggerLevel: FULL # 日志级别

方式2:编写代码

先声明一个类,然后声明一个Logger.Level的对象

日志配置类:

public class DefaultFeignConfiguration {

@Bean

public Logger.Level feignLogLevel(){

return Logger.Level.BASIC; // 日志级别为BASIC

}

}

全局生效:将其放到启动类的@EnableFeignClients这个注解中

@EnableFeignClients(defaultConfiguration = DefaultFeignConfiguration .class)

局部生效:把它放到对应的@FeignClient这个注解中

@FeignClient(value = "userservice", configuration = DefaultFeignConfiguration .class)

Feign的使用优化

提高Feign的性能主要手段就是使用连接池代替默认的URLConnection(不支持连接池)

以Apache的HttpClient来演示

①引入依赖

io.github.openfeign

feign-httpclient

②配置连接池(配置文件)

feign:

client:

config:

default: # default全局的配置

loggerLevel: BASIC # 日志级别,BASIC就是基本的请求和响应信息

httpclient:

enabled: true # 开启feign对HttpClient的支持

max-connections: 200 # 最大的连接数

max-connections-per-route: 50 # 每个路径的最大连接数

最佳使用Feign的编写方式

1. 继承方式

①定义API接口 ②FeignClient和controller都继承该接口

简单、实现了代码共享;但是服务提供方和消费方紧耦合,参数列表中的注解映射不会继承,因此controller中必须再此声明方法、参数列表、注解

2. 抽取方式

将Feign的Client抽取为独立模块,并且把接口有关的POJO、默认的Feign配置都放到这个模块中,提供给所有消费者使用。

例如,将UserClient、User、Feign的默认配置都抽取到一个feign-api包中,所有微服务引用该依赖包,即可直接使用。

各个微服务引用feign-api模块,然后调用对应方法,直接接收返回值即可

注意:order-service模块引用feign-api之后需要修改order-service启动类上的扫描包路径

因为UserClient现在在cn.itcast.feign.clients包下而order-service的@EnableFeignClients注解是在cn.itcast.order包下,不在同一个包,无法扫描到UserClient。

# 方法1:指定扫描的包

@EnableFeignClients(basePackages = "cn.itcast.feign.clients")

# 方法2:指定需要加载的Client接口

@EnableFeignClients(clients = {UserClient.class})

注意:微服务之间调用用Feign,和第三方间交互使用RestTemplate等

4 Nacos

详细链接:https://editor.csdn.net/md/?articleId=126063863

4.1 nacos注册管理

①引入依赖

# 在父pom中引入

com.alibaba.cloud

spring-cloud-alibaba-dependencies

2.2.6.RELEASE

pom

import

# 在微服务中引入

com.alibaba.cloud

spring-cloud-starter-alibaba-nacos-discovery

②微服务配置文件中配置nacos地址

spring:

cloud:

nacos:

server-addr: localhost:8848

③启动类上添加注解

@EnableDiscoveryClient//要注册服务到nacos必须加该注解

4.2 nacos其他功能

分级存储模型

为了灾备,防止"鸡蛋都碎在一个篮子里"

spring:

cloud:

nacos:

server-addr: localhost:8848

discovery:

cluster-name: HZ # 集群名称

设置集群负载均衡

userservice:

ribbon:

NFLoadBalancerRuleClassName: com.alibaba.cloud.nacos.ribbon.NacosRule # 负载均衡规则

设置权重 环境隔离

namespace

spring:

cloud:

nacos:

server-addr: localhost:8848

discovery:

cluster-name: HZ

namespace: 492a7d5d-237b-46a1-a99a-fa8e98e4b0f9 # 命名空间,填ID

4.3 nacos与eureka对比

共同点:

都支持服务注册和拉取都支持服务提供者采用心跳方式做健康检测

区别:

nacos支持服务端主动检测服务提供者状态。临时实例采用心跳模式,非临时实例采用主动检测模式nacos临时实例不正常会剔除,非临时实例则不剔除nacos支持服务列表变更推送Nacos集群默认采用AP方式,当集群中存在非临时实例时,采用CP模式;Eureka采用AP方式

4.4 nacos配置管理

依赖

在对应微服务中引入依赖

com.alibaba.cloud

spring-cloud-starter-alibaba-nacos-config

创建bootstrap.yml文件【优先级比application.yml高】

指明nacos中的配置文件名称和地址

spring:

application:

name: userservice # 服务名称

profiles:

active: dev #开发环境,这里是dev

cloud:

nacos:

server-addr: localhost:8848 # Nacos地址

config:

file-extension: yaml # 文件后缀名

5 服务网关

网关作用:

请求路由权限控制限流

SpringCloud中的网关:

gatewayzuul Zuul是基于Servlet的实现,属于阻塞式编程。而SpringCloudGateway则是基于Spring5中提供的WebFlux,属于响应式编程的实现,具备更好的性能。

详细文章:https://editor.csdn.net/md/?articleId=127762843

5.1 搭建网关(以gateway为例)

①依赖

引入gateway依赖同时将网关服务注册到nacos中

org.springframework.cloud

spring-cloud-starter-gateway

com.alibaba.cloud

spring-cloud-starter-alibaba-nacos-discovery

②配置文件

server:

port: 10010 # 网关端口

spring:

application:

name: gateway # 服务名称

cloud:

nacos:

server-addr: localhost:8848 # nacos地址

gateway:

routes: # 网关路由配置

- id: user-service # 路由id,自定义,只要唯一即可

# uri: http://127.0.0.1:8081 # 路由的目标地址 http就是固定地址

uri: lb://userservice # 路由的目标地址 lb就是负载均衡,后面跟服务名称

predicates: # 路由断言,也就是判断请求是否符合路由规则的条件

- Path=/user/** # 这个是按照路径匹配,只要以/user/开头就符合要求

我们将符合Path 规则的一切请求,都代理到 uri参数指定的地址。

本例中,我们将 /user/**开头的请求,代理到lb://userservice,lb是负载均衡,根据服务名拉取服务列表,实现负载均衡。

总结:搭建步骤 ①引入nacos和gateway依赖 ②配置application.yml,包括服务基本信息、nacos地址、路由 ③路由信息包括:路由id、路由目标(uri)、路由断言(predicates)、路由过滤器(filters)

5.2 断言工厂

如:上面我们使用的path,是断言工厂中的一个。下面还有其他的:

After(是某个时间点后的请求)Before(某个节点之前)Between(是某两个时间点之前的请求)Cookie(请求必须包含某些cookie)Header(请求必须包含某些header)Host(请求必须是访问某个host(域名))Method(请求方式必须是指定方式)Path(请求路径必须符合指定规则)Query(请求参数必须包含指定参数)RemoteAddr(请求者的ip必须是指定范围)Weight(权重处理)

5.3 过滤器工厂

修改application.yml配置文件即可 需求:给所有进入userservice的请求添加一个请求头:Truth=itcast is freaking awesome!

spring:

cloud:

gateway:

routes:

- id: user-service

uri: lb://userservice

predicates:

- Path=/user/**

filters: # 过滤器

- AddRequestHeader=Truth, Itcast is freaking awesome! # 添加请求头

#default-filters: # 默认过滤项

# - AddRequestHeader=Truth, Itcast is freaking awesome!

当前过滤器写在userservice路由下,因此仅仅对访问userservice的请求有效。

5.4 全局过滤器

在filter中编写自定义逻辑,可以实现下列功能:

登录状态判断权限校验请求限流等

自定义全局过滤器:

需求:定义全局过滤器,拦截请求,判断请求的参数是否满足下面条件:

参数中是否有authorization,authorization参数值是否为admin 如果同时满足则放行,否则拦截

@Order(-1)

@Component

public class AuthorizeFilter implements GlobalFilter {

@Override

public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {

// 1.获取请求参数

MultiValueMap params = exchange.getRequest().getQueryParams();

// 2.获取authorization参数

String auth = params.getFirst("authorization");

// 3.校验

if ("admin".equals(auth)) {

// 放行

return chain.filter(exchange);

}

// 4.拦截

// 4.1.禁止访问,设置状态码

exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN);

// 4.2.结束处理

return exchange.getResponse().setComplete();

}

}

5.5 跨域问题

跨域问题:

域名、端口、协议三者任一一个不同 No access control allow origin

直接通过配置文件解决跨域问题:

spring:

cloud:

gateway:

# 。。。

globalcors: # 全局的跨域处理

add-to-simple-url-handler-mapping: true # 解决options请求被拦截问题

corsConfigurations:

'[/**]':

allowedOrigins: # 允许哪些网站的跨域请求

- "http://localhost:8090"

allowedMethods: # 允许的跨域ajax的请求方式

- "GET"

- "POST"

- "DELETE"

- "PUT"

- "OPTIONS"

allowedHeaders: "*" # 允许在请求中携带的头信息

allowCredentials: true # 是否允许携带cookie

maxAge: 360000 # 这次跨域检测的有效期

文章来源

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: