1.基础
2.服务与服务之间的远程调用
3.服务者-消费者
4.Eureka注册中心
5.Ribbon负载均衡
6.Nocos注册中心
7.Nocos配置管理
8.Feign实现远程调用http请求的发生
9.网关
单体项目:将业务的所有的功能集中在一个项目中开发,打包成一个包部署
分布式架构:根据业务功能对系统进行拆分,每一个业务模块作为独立项目开发,成为一个服务
微服务:
1.每一个服务对应唯一的业务功能
2.每个服务相互独立,当a要访问b的接口时,b要暴漏业务接口
3.每个微服务数据都是独立的,部署独立
4.服务做好隔离性(调用其他服务时,出现问题)容错、降级,避免出现联机错误
1.配置类注入bena RestTemplate
RestTemplate是Spring提供的用于访问Rest服务的客户端(调用其他请求)
package cn.itcast.order;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
@MapperScan("cn.itcast.order.mapper")
@SpringBootApplication
public class OrderApplication {
public static void main(String[] args) {
SpringApplication.run(OrderApplication.class, args);
}
/**
* 创建RestTemplate并注入spring容器 / 发送http请求
* @return
*/
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
2.自动注入 RestTemplate 对象,调用方法进行微服务之间的远程调用
@RestController
@RequestMapping("order")
public class OrderController {
@Autowired
private OrderService orderService;
@Autowired
private RestTemplate restTemplate;
@GetMapping("{orderId}")
public Order queryOrderByUserId(@PathVariable("orderId") Long orderId) {
// 1.根据id查询订单
Order order = orderService.queryOrderById(orderId);
// 2.调用RestTemplate发送http请求,查询用户
// 2-1:查询用户请求
String url = "http://localhost:8081/user/"+order.getUserId();
// 2-2:传入请求,实现远程调用 getForObject:GET请求 postForObject: 发送post请求
// 2-3:(url,user.class) restTemplate请求响应的json数据转化为实体对象
User forObject = restTemplate.getForObject(url, User.class);
order.setUser(forObject);
return order;
}
}
服务者:服务者暴漏端口给微服务调用
消费者:调用其他微服务提供的接口
一个服务既可以作为服务组,也可以作为消费者
消费者如何获取提供者的具体信息
多个服务者,消费者如何选中
消费者如何感知服务者将抗状态
Eureka服务端
Eureka客户端
1.pom文件导入jar包
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
</dependencies>
2.Eureka的启动类
@EnableEurekaServer // 加入Eureka自动装配的开关
@SpringBootApplication
public class EurekaApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaApplication.class, args);
}
}
3.eureka的配置文件 eureka将自己也注册到注册中心
server:
port: 10086 #服务端口
spring:
application:
name: eureka-server # eureka的服务名称
eureka:
client:
service-url: #eureka地址信息
defaultZone: http://127.0.0.1:10086/eureka
4.访问http://127.0.0.1:10086/就可以访问到
1.jar包
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
2.application.yaml配置服务
spring:
application:
name: order-server # eureka的服务名称
eureka:
client:
service-url: #eureka地址信息
defaultZone: http://127.0.0.1:10086/eureka
定义负载均衡规则 随机调用
方法1.配置全局 ->配置类中配置bean
@Bean // 调整为随机-> 全局
public IRule randomRule(){
return new RandomRule();
}
userservice: # 给某个微服务配置负载均衡规则,这里是userservice服务
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule # 负载均衡规则
ribbon:
eager-load:
enabled: true #开启饥饿加载
clients: userservice #集合,可以配置多个服务
# - xxx
# - xxx
1.安装
2.bin目录下启动命令行 输入 startup.cmd -m standalone
3.启动成功输入ip进入
1.父工程加入pom依赖
<!--nacos的服务管理依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2.2.5.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
2.子工程加入Pom依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
3.子工程修改yml文件
server:
port: 8080
spring:
cloud:
nacos:
discovery:
server-addr: localhost:8848 #nacos服务地址
application:
name: orderserver #设置nacos名称
4.访问http://192.168.1.8:8848/nacos/index.htm 账户密码均为 nacos
5.负载均衡策略为:轮循 (一个服务器一个)
spring:
cloud:
nacos:
discovery:
server-addr: localhost:8848 #nacos服务地址
cluster-name: HZ #集群名称
1.一级是服务 例如:userservice 用户模块
2.二级是集群 例如:模块再同一个地方部署了多个,称之为xx集群
3.三级是实例 多个实例,称之为集群 例如:将杭州机房部署了用户模块,部署了多个称之为杭州集群
1.优先选择同集群服务实例列表
2.本地集群找不到提供者,采取其他集群寻找,并且会报警告
3.确定了实例列表,再采用随机负载均衡的策略挑选实例
userservice:
ribbon:
NFLoadBalancerRuleClassName: com.alibaba.cloud.nacos.ribbon.NacosRule # 负载均衡规则 -> 优先选择本地集群,
spring:
cloud:
nacos:
discovery:
server-addr: localhost:8848 #nacos服务地址
cluster-name: HZ #集群名称
1.Nacos控制太可以设置实例权重值,0-1之间
2.集群中的多个实例,权重越高被访问的频率也就越高
3.权重设置为0则不会被访问
临时实例为默认,修改为非临时实例 -> ephemeral: false
spring:
cloud:
nacos:
discovery:
server-addr: localhost:8848 #nacos服务地址
cluster-name: HZ #集群名称
ephemeral: false #是否是临时实例
namespace: e770a314-ca1f-40d9-a25d-6607825b1866 #dev环境
步骤如下
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
spring:
application:
name: userservice #服务名称
profiles:
active: dev # 环境
cloud:
nacos:
server-addr: localhost:8848
config:
file-extension: yaml
namespace: 18ada1e3-9776-4110-8e95-89aaf1d03ee0 #dev环境
@RefreshScope
public class UserController {
}
@Data
@Component // bean注入
@ConfigurationProperties(prefix = "pattern")
public class PatternProperties {
public String dateformat;
}
@Autowired
PatternProperties patternProperties;
@GetMapping("/now")
public String now(){ // 根据配置信息进行返回
return LocalDateTime.now().format(DateTimeFormatter.ofPattern(patternProperties.getDateformat()));
}
优先级
设置相同的名称,访问,得知当前自己的环境nacos配置最大。
自己当前环境的nacos配置 > 当前环境nacos的共享配置 > 本地配置
多环境共享配置 不用的环境下(dev、Test等),相同的[服务名称].yaml,都可以访问这个文件
Feign使用声明式,基于Springmvc的注解声明远程调用的信息
1.引入依赖
<!-- 引入依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
2.启动类加注解
@EnableFeignClients
public class UserApplication {
public static void main(String[] args) {
SpringApplication.run(UserApplication.class, args);
}
}
3.编写客户端,做接口声明
@FeignClient("userservice") //服务者名称
public interface UserClient {
@GetMapping("/user/{id}") // 访问路径
User findyById(@PathVariable("id")Long id); //请求参数
}
4.注入bean,并且调用方法,实现远程调用
@Autowired
private UserClient userClient;
@GetMapping("{orderId}")
public Order queryOrderByUserId(@PathVariable("orderId") Long orderId) {
// 1.根据id查询订单
Order order = orderService.queryOrderById(orderId);
// 2.用feign远程调用
User user = userClient.findyById(order.getUserId());
order.setUser(user);
return order;
}
配置日志
feign:
client:
config:
default: #default 代表全局 userservice 代表某个服务开启日志
loggerLevel: FULL
启动类上代表全局
@MapperScan("cn.itcast.order.mapper")
@SpringBootApplication
@EnableFeignClients(defaultConfiguration = DefaultFeignConfiguration.class) // 代表全局
public class OrderApplication {
}
服务声明类上,代表此服务
@FeignClient(value = "userservice" , configuration = DefaultFeignConfiguration.class) //代表单个服务
public interface UserClient {
@GetMapping("/user/{id}") // 访问路径
User findyById(@PathVariable("id")Long id); //请求参数
}
1.使用HttpClient或者OkHttp代替URLCtion
2.配置文件开启HttpClient功能设置连接参数
1.日志级别尽量用basic
1.引入依赖
<!--httpClient的依赖 -->
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-httpclient</artifactId>
</dependency>
2.yaml配置
```java
feign:
client:
config:
default: # default全局的配置
loggerLevel: BASIC # 日志级别,BASIC就是基本的请求和响应信息
httpclient:
enabled: true # 开启feign对HttpClient的支持
max-connections: 200 # 最大的连接数
max-connections-per-route: 50 # 每个路径的最大连接数
操作步骤:
1.新建model引入依赖
2.添加jar包
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
</dependencies>
将代码抽离出来,放到fegin-api中
3.服务消费者引入fegin-api的jar包
4.扫描 fegin-api 下的所有的包
第一种方法:
第二种方法:
服务者将信息注册到那cos中,用户发送请求,网关接收请求,根据路由规则查看请求是否符合条件,符合条件去Nacos拉取对应的服务请求,再进行负载均衡的向该服务发送请求
gateway
属于响应式编程
zuul
属于阻塞式编程
1.新建model
引入依赖
<dependencies>
<!--网关-->
<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>
</dependencies>
配置路由:
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/开头就符合要求
- id: order-server
uri: lb://orderserver # 路由的目标地址 lb就是负载均衡,后面跟服务名称
predicates: # 路由断言,也就是判断请求是否符合路由规则的条件,符合规则就会代理到路由中
- Path=/order/** # 这个是按照路径匹配,只要以/user/开头就符合要求
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/开头就符合要求
filters:
- AddRequestHeader=Truth, Itcast is freaking awesome!
- id: order-server
uri: lb://orderserver # 路由的目标地址 lb就是负载均衡,后面跟服务名称
predicates: # 路由断言,也就是判断请求是否符合路由规则的条件,符合规则就会代理到路由中
- Path=/order/** # 这个是按照路径匹配,只要以/user/开头就符合要求
default-filters: #配置全局
# - AddRequestHeader=Truth, Itcast is freaking awesome!
/**
* 路径: /user/110
*
* @param id 用户id
* @return 用户
*/
@GetMapping("/{id}")
public User queryById(@PathVariable("id") Long id ,@RequestHeader(value = "truth" , required = false) String truth) {
System.out.println("truth:="+truth);
return userService.queryById(id);
}
package cn.itcast.gateway;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.util.MultiValueMap;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
@Component //定义组件
@Order(-1) //执行顺序
public class AuthorizeFilter implements GlobalFilter {
/**
* ServerWebExchange:获取请求参数
*/
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 1.获取请求参数
ServerHttpRequest request = exchange.getRequest();
// 2.获取请求种的 authorization
MultiValueMap<String, String> queryParams = request.getQueryParams();
// 根据authorization获取对应的值
String authorization = queryParams.getFirst("authorization");
// 3.判断参数是否等于admin
if ("admin".equals(authorization)){
// 4.是 放行
return chain.filter(exchange);
}
// 5.否 拦截
// 5-1.设置状态码
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().setComplete();
}
}
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 # 这次跨域检测的有效期