赞
踩
创建eureka-server的SpringBoot项目
①导入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
②启动类上添加注解@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
eureka作为注册中心,我们现在将服务注册到eureka
①导入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
②编写配置文件
spring:
application:
# 服务名称
name: userservice
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:10086/eureka
现在有两个模块: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这个服务名称,获取实例列表,而后完成负载均衡。
导入openfeign,openfeign中默认集成了ribbon
注意:
微服务之间调用用Feign,和第三方间交互使用RestTemplate等
RestTemplate是Spring提供的用于访问Rest服务的客户端,RestTemplate提供了多种便捷访问远程Http服务的方法,能够大大提高客户端的编写效率。
①导入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
②创建restTemplate,并添加上负载均衡注解
可以在启动类的main方法中创建,也可以单独写一个配置类,只要最后有bean标识被spring管理即可
/**
* 创建RestTemplate并注入Spring容器
*/
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
@LoadBalanced是以轮询方式访问
有两种方式:
①定义一个新的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可以精准对某个微服务进行处理
restTemplate是Spring提供给我们的用于调用rest服务的客户端
RestTemplate调用方式:
•代码可读性差,编程体验不统一
•参数复杂URL难以维护
说明:
Feign是一个声明式的HTTP客户端
①导入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
②开启注解
在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可以支持很多自定义配置
- 修改日志级别
- 响应结果的解析器(如:解析json为java对象)
- 请求参数编码(将请求参数编码,便于http发送请求)
- 支持的注解格式
- 失败重试机制(默认没有,但是会使用ribbon的重试)
一般情况下,默认值就能满足我们的使用,如果要自定义时,只需要创建自定义的@Bean覆盖默认Bean即可
以修改日志级别为例
方式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的性能主要手段就是使用连接池代替默认的URLConnection(不支持连接池)
- 以Apache的HttpClient来演示
①引入依赖
<!--httpClient的依赖 -->
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-httpclient</artifactId>
</dependency>
②配置连接池(配置文件)
feign:
client:
config:
default: # default全局的配置
loggerLevel: BASIC # 日志级别,BASIC就是基本的请求和响应信息
httpclient:
enabled: true # 开启feign对HttpClient的支持
max-connections: 200 # 最大的连接数
max-connections-per-route: 50 # 每个路径的最大连接数
①定义API接口
②FeignClient和controller都继承该接口
简单、实现了代码共享;但是服务提供方和消费方紧耦合,参数列表中的注解映射不会继承,因此controller中必须再此声明方法、参数列表、注解
将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等
详细链接:
https://editor.csdn.net/md/?articleId=126063863
①引入依赖
# 在父pom中引入
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2.2.6.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
# 在微服务中引入
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
②微服务配置文件中配置nacos地址
spring:
cloud:
nacos:
server-addr: localhost:8848
③启动类上添加注解
@EnableDiscoveryClient//要注册服务到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
- 共同点:
- 都支持服务注册和拉取
- 都支持服务提供者采用心跳方式做健康检测
- 区别:
- nacos支持服务端主动检测服务提供者状态。临时实例采用心跳模式,非临时实例采用主动检测模式
- nacos临时实例不正常会剔除,非临时实例则不剔除
- nacos支持服务列表变更推送
- Nacos集群默认采用AP方式,当集群中存在非临时实例时,采用CP模式;Eureka采用AP方式
在对应微服务中引入依赖
<!--nacos配置管理依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
指明nacos中的配置文件名称和地址
spring:
application:
name: userservice # 服务名称
profiles:
active: dev #开发环境,这里是dev
cloud:
nacos:
server-addr: localhost:8848 # Nacos地址
config:
file-extension: yaml # 文件后缀名
- 网关作用:
- 请求路由
- 权限控制
- 限流
- SpringCloud中的网关:
- gateway
- zuul
Zuul是基于Servlet的实现,属于阻塞式编程。而SpringCloudGateway则是基于Spring5中提供的WebFlux,属于响应式编程的实现,具备更好的性能。
详细文章:https://editor.csdn.net/md/?articleId=127762843
①依赖
引入gateway依赖同时将网关服务注册到nacos中
<!--网关-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!--nacos服务发现依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
②配置文件
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)
如:上面我们使用的path,是断言工厂中的一个。下面还有其他的:
修改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的请求有效。
在filter中编写自定义逻辑,可以实现下列功能:
- 登录状态判断
- 权限校验
- 请求限流等
自定义全局过滤器:
需求:定义全局过滤器,拦截请求,判断请求的参数是否满足下面条件:
- 参数中是否有authorization,
- authorization参数值是否为admin
如果同时满足则放行,否则拦截
@Order(-1) @Component public class AuthorizeFilter implements GlobalFilter { @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { // 1.获取请求参数 MultiValueMap<String, String> 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(); } }
跨域问题:
域名、端口、协议三者任一一个不同
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 # 这次跨域检测的有效期
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。