- 添加依赖
<!-- Nacos注册依赖 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacosdiscovery</artifactId>
</dependency>
2.添加配置信息
spring:
application:
name: nacos-cart # 定义当前服务名称
cloud:
nacos:
discovery:
server-addr: localhost:8848 # 指定正在运行的Nacos服务器的位置
ephemeral: false #默认是true(临时) false(永久)
3.nacos启动命令
startup.cmd -m standalone
5、远程过程调用RPC
RPC
实现方式:
dubbo,RestTemplate
-
创建对象交个spring管理
@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}
2.直接远程调用
//在service层调用远程方法
@Autowired
private RestTemplate restTemplate;
public User findByUserById(int id){
String url = "http://nacos-cart/user/findUser?id={1}";
User user = restTemplate.getForObject(url,User.class,id);
return user;
}
- 添加依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-dubbo</artifactId>
</dependency>
<dependency>
<groupId>cn.tedu</groupId>
<artifactId>csmall-cart-service</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
2.添加配置
dubbo:
protocol:
port: -1
name: dubbo
registry:
address: nacos://localhost:8848
consumer:
check: false
3.标记服务接口
//被调用方法的实现类前面加(生产者)
@DubboService
//在被调用的服务的主启动类前加
@EnableDubbo
//在调动远程服务的业务层添加被调用的接口
@DubboReference
private ICartService cartService;
6、负载均衡
将请求平均、合理的分配到每一个服务器,尽量让请求去相对空闲的服务器
负载均衡策略:
-
random loadbalance: 随机分配
-
round Robin loadbalance: 权重平均分配
-
leastactive loadbalance: 活跃度自动感知
-
consistanthash loadbalance:一致性hash算法(使用的少)
7、Seata 分布式事务解决方案
分布式事务解决方案,在微服务架构下提供高性能和简单易用的分布式服务
Seata提供4种事务模式
Seata的构成部分
-
TC: 事务协调器
-
TM: 事务管理器
-
RM: 资源管理器
Seata使用
添加依赖(
生产者添加
3
个,消费者添加第一个就可以了)
<!-- Seata和SpringBoot整合依赖 -->
<dependency>
<groupId>io.seata</groupId>
<artifactId>seata-spring-boot-starter</artifactId>
</dependency>
<!-- Seata 完成分布式事务的两个相关依赖(Seata会自动使用其中的资源) -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
</dependency>
添加配置
(
生产者和消费者都要添加
)
seata:
# 定义事务的分组,一般是以项目为单位的,不同项目用它来区分
tx-service-group: csmall_group
service:
vgroup-mapping:
# 设置csmall_group分组使用默认(default)的seata配置
csmall_group: default
grouplist:
# 设置seata的ip和端口号位置
default: localhost:8091
添加一个注解
(
在事务开始的方法上
)
@GlobalTransactional
Seata
启动命令
seata-server.bat -h 127.0.0.1 -m file
8、Sentinel
流量控制,降级,熔断,系统负载保护,保证在设计的请求数内的请求能够稳定的完成处理。
- 添加依赖
<!-- Sentinel 整合SpringCloud依赖 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
2.添加配置
spring:
cloud:
sentinel:
transport:
# 配置sentinel提供的仪表台服务器的位置
dashboard: localhost:8080
# 执行限流的端口号,每个项目必须设置不同的端口号,例如cart模块要限流就可以设
置为8722
port: 8721
3.启动服务
windows直接双击: start-sentinel.bat
- 直接限流
- 关联限流
- 链路限流
9、SpringGateway
程序中的网关就是当前微服务项目对外界开放的统一入口
所有外界的请求都需要先经过网关才能访问到我们的程序
提供了统一入口之后
,
方便对所有请求进行统一的检查和管理
<dependencies>
<!-- SpringGateway的依赖 -->
<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-nacosdiscovery</artifactId>
</dependency>
<!-- 网关负载均衡依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
</dependencies>
server:
port: 9000
spring:
application:
name: gateway
cloud:
nacos:
discovery:
# 网关也是微服务项目的一部分,所以也要注册到Nacos
server-addr: localhost:8848
gateway:
# discovery:
# locator:
# # 开启网关动态路由的配置
# # 默认的路由规则:在网关端口号后,先编写要路由到的目标服务器
# # 注册到Nacos的名称,再编写要访问的具体路径
# # 例如 localhost:9001/bj/show -> localhost:9000/beijing/bj/show
# enabled: true
# routes就是路由的意思,下面的内容就是配置路由,它是一个数组类型的属性
routes:
- id: gateway-shanghai
uri: lb://shanghai
predicates:
- Path=/sh/**
# 数组类型属性赋值时,每个数组元素都要以"-"开头,一个"-"之后的所有内容,都是这个元素
包含的值
# id表示当前路由的名称,和之前出现过的任何名字没有关联,唯一的要求就是不能和之后出现
的路由id重复
- id: gateway-beijing
# uri配置路由的目标服务器,beijing是服务器注册到nacos的名称
# lb就是LoadBalance的缩写
uri: lb://beijing
# predicates是断言的意思,指满足某些条件的之后执行某些操作
predicates:
# predicates属性也是数组类型,赋值要以"-"开头
# 这个断言的含义就是如果访问网关项目的路径以/bj/开头,路由访问beijing服务器
# ↓ P要大写 **是通配任何路径
- Path=/bj/**
10、Elasticsearch
<!-- spring data elasticsearch 依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
# 配置ES所在的ip地址和端口号
spring.elasticsearch.rest.uris=http://localhost:9200
# 设置日志门槛,用于显示ES运行信息
logging.level.cn.tedu.search=debug
# SpringDataElasticsearch框架中有一个专门的类来输出运行信息,也要设置为debug
logging.level.org.elasticsearch.client.RestClient=debug
// Repository是Spring家族框架对持久层的命名
@Repository
public interface ItemRepository extends ElasticsearchRepository<Item,Long> {
// ItemRepository接口要继承SpringData提供的ElasticsearchRepository父接口
// 一旦继承,当前接口就可以编写连接ES进行操作的代码了,继承了这个父接口之后
// 会自动生成对Item数据的基本增删改查方法,无需我们自己编写
// ElasticsearchRepository<[关联的实体类的名称],[实体类主键的类型]>
}
// 必须添加下面的注解,否则无法运行
@SpringBootTest
public class SpringDataTest {
@Autowired
private ItemRepository itemRepository;
// 执行单增
@Test
void addOne(){
// 实例化一个item对象并赋值
Item item=new Item()
.setId(1L)
.setTitle("罗技激光无线游戏鼠标")
.setCategory("鼠标")
.setBrand("罗技")
.setPrice(188.0)
.setImgPath("/1.jpg");
// 利用SpringData提供的新增方法,完成Item新增到ES
itemRepository.save(item);
System.out.println("ok");
}
// 单查
@Test
void getOne(){
// SpringDataElasticsearch提供了按id查询数据的方法
// Optional是一个容器,但是只能存放一个元素,Springdata返回包含查询结果的
Optional对象
// 可以将Optional理解为一个只能保存一个元素的List
Optional<Item> optional=itemRepository.findById(1L);
Item item=optional.get();
System.out.println(item);
}
// 批量增
@Test
void addList(){
// 实例化一个List对象,用于保存要新增到ES中对象
List<Item> list=new ArrayList<>();
list.add(new Item(2L,"罗技激光有线办公鼠标","鼠标",
"罗技",98.0,"/2.jpg"));
list.add(new Item(3L,"雷蛇机械无线游戏键盘","键盘",
"雷蛇",278.0,"/3.jpg"));
list.add(new Item(4L,"微软有线静音办公鼠标","鼠标",
"微软",197.0,"/4.jpg"));
list.add(new Item(5L,"罗技机械有线背光键盘","键盘",
"罗技",226.0,"/5.jpg"));
itemRepository.saveAll(list);
System.out.println("OK list");
}
// 全查
@Test
void getAll(){
// SpringData提供的全查ES中对应实体类的所有数据的方法
Iterable<Item> items=itemRepository.findAll();
for(Item item : items){
System.out.println(item);
}
System.out.println("--------------------------------");
items.forEach(item -> System.out.println(item));
}
}
//在接口中添加方法
// SpringData实现自定义查询
// 我们要编写遵循SpringData给定格式的方法名
// SpringData会根据我们编写的方法名自动完成数据操作
// query(查询):表示当前方法是一个查询方法,类似sql语句中的select
// Item/Items:确定要查询哪一个实体类,不带s的是单个对象,带s是集合
// By(通过/根据):标识开始设置查询条件,类似sql语句中的where
// Title:要查询的字段,可以根据查询条件修改为Item中的任何字段
// Matches:执行查询的操作,Matches表示字符串的匹配,而且这个匹配是支持分词的,类似sql语句
的like
//但条件查询
Iterable<Item> queryItemsByTitleMatches(String title);
// 多条件查询
// 多个条件之间要使用逻辑运算符and或or来分隔,表示多个条件间的逻辑关系
// 我们如果要查询title包含某个关键字的同时指定品牌的查询
// 多个参数时,SpringData会按照参数声明的顺序向需要参数的位置赋值,和参数名无关
Iterable<Item> queryItemsByTitleMatchesAndBrandMatches(
String title,String brand);
// 排序查询
Iterable<Item> queryItemsByTitleMatchesOrBrandMatchesOrderByPriceDesc(
String title,String brand);
// 分页查询
// 返回值类型修改为Page类型,这个类型中包含了查询到的当前页数据和本次查询的相关分页信息
// 分页信息指:当前页码,总页数,总条数,每页条数,是否有上一页,是否有下一页等
// 方法参数要添加Pageable,在所有的参数后再添加一个新的参数类型 Pageable
Page<Item> queryItemsByTitleMatchesOrBrandMatchesOrderByPriceDesc(
String title, String brand, Pageable pageable);
//------------------------------------------------------------------------
//测试类添加方法
// 单条件查询
@Test
void queryOne(){
// 查询ES中items索引里,title字段包含"游戏"分词的数据
Iterable<Item> items=itemRepository.queryItemsByTitleMatches("游戏");
items.forEach(item -> System.out.println(item));
}
// 多条件查询
@Test
void queryTwo(){
// 查询ES中items索引里,title字段包含"游戏"并且品牌是"罗技"的数据
Iterable<Item> items=itemRepository
.queryItemsByTitleMatchesAndBrandMatches("游戏","罗技");
items.forEach(item -> System.out.println(item));
}
// 排序查询
@Test
void queryOrder(){
Iterable<Item> items=itemRepository
.queryItemsByTitleMatchesOrBrandMatchesOrderByPriceDesc(
"游戏","罗技");
items.forEach(item -> System.out.println(item));
}
// 分页查询
@Test
void queryPage(){
int page=2; //要查询的页码
int pageSize=2; //每页的数据条数
Page<Item> pages=itemRepository
.queryItemsByTitleMatchesOrBrandMatchesOrderByPriceDesc(
"游戏","罗技", PageRequest.of(page-1,pageSize));
pages.forEach(item -> System.out.println(item));
// pages对象的分页信息输出
System.out.println("总页数:"+pages.getTotalPages());
System.out.println("总条数:"+pages.getTotalElements());
System.out.println("当前页码:"+(pages.getNumber()+1));
System.out.println("每页条数:"+pages.getSize());
System.out.println("是否为首页:"+pages.isFirst());
System.out.println("是否为末页:"+pages.isLast());
}
### 三个#是注释,也是分隔符,http文件要求每个请求必须以分隔符开始,否则会报错
GET http://localhost:9200
### 测试ES的分词功能,运行请求,查看分词结果
POST http://localhost:9200/_analyze
Content-Type: application/json
{
"text": "周杰伦出新专辑了",
"analyzer": "ik_max_word"
}
### 创建 index
PUT http://localhost:9200/questions
### 删除一个Index
DELETE http://localhost:9200/questions
### 设置index中的文档属性采用ik分词
POST http://localhost:9200/questions/_mapping
Content-Type: application/json
{
"properties": {
"title": {
"type": "text",
"analyzer": "ik_max_word",
"search_analyzer": "ik_max_word"
},
"content": {
"type": "text",
"analyzer": "ik_max_word",
"search_analyzer": "ik_max_word"
}
}
}
### questions 中添加文档
POST http://localhost:9200/questions/_create/1
Content-Type: application/json
{
"id":1,
"title":"Java基本数据类型有哪些",
"content":"面时候为啥要问基本类型这么简单问题呀,我们要如何回答呢?"
}
### questions 中添加文档
POST http://localhost:9200/questions/_create/2
Content-Type: application/json
{
"id":2,
"title":"int类型的范围",
"content":"为啥要了解int类型的范围呢?"
}
### questions 中添加文档
POST http://localhost:9200/questions/_create/3
Content-Type: application/json
{
"id":3,
"title":"常用集合类有哪些",
"content":"为啥企业经常问集合呀?该如何回复呢"
}
### questions 中添加文档
POST http://localhost:9200/questions/_create/4
Content-Type: application/json
{
"id":4,
"title":"线程的run方法和start方法有啥区别",
"content":"run方法可以执行线程的计算过程, start也可以执行线程的计算过程,用途一样
么?"
}
### 更新questions索引中的文档
POST http://localhost:9200/questions/_doc/4/_update
Content-Type: application/json
{
"doc": {
"title": "Java线程的run方法和start方法有啥区别"
}
}
### 删除questions中的一个文档
DELETE http://localhost:9200/questions/_doc/2
### 查询数据
GET http://localhost:9200/questions/_doc/4
### 搜索 ES
POST http://localhost:9200/questions/_search
Content-Type: application/json
{
"query": { "match": {"title": "java类型" } }
}
### 多字段搜索
POST http://localhost:9200/questions/_search
Content-Type: application/json
{
"query": {
"bool": {
"should": [
{ "match": { "title": "java类型" }},
{ "match": { "content": "java类型"}}
]
}
}
}