微服务技术栈
springcloud 整合技术栈
服务端调用
注册中心
1.Eureka注册中心
Eureka搭建步骤(重点)
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
eureka:
client:
service-url: # eureka的地址信息
defaultZone: http://127.0.0.1:10086/eureka
注册中心代码
@EnableEurekaServer
@SpringBootApplication
public class EurekaApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaApplication.class, args);
}
}
server:
port: 10086 # 服务端口
spring:
application:
name: eurekaserver # eureka的服务名称
eureka:
client:
service-url: # eureka的地址信息
defaultZone: http://127.0.0.1:10086/eureka
order_uservice中
1.在application.yml中
eureka:
client:
service-url: # eureka的地址信息
defaultZone: http://127.0.0.1:10086/eureka
2…在启动类
/**
* 创建RestTemplate并注入Spring容器
*/
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
3.在orderService中url可以用别的服务名称替换
@Autowired
private RestTemplate restTemplate;
public Order queryOrderById(Long orderId) {
// 1.查询订单
Order order = orderMapper.findById(orderId);
// 2.利用RestTemplate发起http请求,查询用户
// 2.1.url路径
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;
}
当有两个相同业务的服务时,需要进行负载均衡
默认为ZoneAvoidanceRule
在order-service中配置user-service负载均衡规则
userservice:
ribbon:
NFLoadBalancerRuleClassName:com.netflix.loadbalancer.RandomRule # 负载均衡规则
2.Nacos注册中心
1.使用
父工程的管理依赖
<!--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>
<!-- nacos客户端依赖包 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
cloud:
nacos:
server-addr: http://47.120.0.38:8848
discovery:
cluster-name: BJ
userService:
ribbon:
NFLoadBalancerRuleClassName: com.alibaba.cloud.nacos.ribbon.NacosRule # 负载均衡规则
ribbon:
eager-load:
enabled: true # 开启饥饿加载
clients: # 指定饥饿加载的服务名称
- userservice
nacos分级存储
orderService会优先采用本机的服务
application:
name: orderService
cloud:
nacos:
server-addr: http://47.120.0.38:8848
discovery:
cluster-name: BJ
application:
name: userService
cloud:
nacos:
server-addr: http://47.120.0.38:8848
discovery:
cluster-name: SH
会采用我,因为我也是BJ
application:
name: userService
cloud:
nacos:
server-addr: http://47.120.0.38:8848
discovery:
cluster-name: BJ
userService:
ribbon:
NFLoadBalancerRuleClassName: com.alibaba.cloud.nacos.ribbon.NacosRule # 负载均衡规则
ribbon:
eager-load:
enabled: true # 开启饥饿加载
clients: # 指定饥饿加载的服务名称
- userservice
环境隔离
nacos与eureka的区别
nacos统一配置管理
<!--nacos的配置管理依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
多环境配置共享
名字为userservice.yaml这个文件一定会被读取
那个dev只能在开发环境被读取到
Feign
<!--feign客户端依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
在启动类orderServer上添加如下注解
@EnableFeignClients
新建包及其接口文件
按照springmvc的方式书写远程调用方法
在orderservice中注入并实现远程接口的调用
Feign已经集成了ribbon,实现了负载均衡
feign性能优化
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-httpclient</artifactId>
</dependency>
feign:
client:
config:
userService:
loggerLevel: basic
httpclient:
enabled: true #支持httpClient开关
max-connections: 200 #最大连接数
max-connections-per-route: 50 #单个路径的最大连接数
Feign的最佳实践
方式二
抽取一个模块
在orderService中,加入相关依赖。
<dependency>
<groupId>cn.itcast.demo</groupId>
<artifactId>feign-api</artifactId>
<version>1.0</version>
</dependency>
在orderService启动类中,加入相关注解参数
@EnableFeignClients(clients = UserClient.class,defaultConfiguration = DefaultFeignConfiguration.class)
统一网关Gateway
什么是网关
搭建网关服务
<!--nacos服务注册发现依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--网关gateway依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
server:
port: 10010
spring:
application:
name: gateway
cloud:
nacos:
server-addr: http://47.120.0.38:8848 #nacos地址
gateway:
routes:
- id: userService #路由标识,必须唯一
uri: lb://userService #路由目标地址
predicates: #路由断言,判断请求是否符合规则
- Path=/user/** #路由断言,判断路径是否以/user/开头,如果符合规则 P要大写
- id: order-service
uri: lb://orderservice
predicates:
- Path=/order/**
网关配置的断言Predicate
网关配置的过滤器
具体的去官网查看
server:
port: 10010
spring:
application:
name: gateway
cloud:
nacos:
server-addr: http://47.120.0.38:8848 #nacos地址
gateway:
routes:
- id: userService #路由标识,必须唯一
uri: lb://userService #路由目标地址
predicates: #路由断言,判断请求是否符合规则
- Path=/user/** #路由断言,判断路径是否以/user/开头,如果符合规则 P要大写
# filters:
# - AddRequestHeader=Truth, blue
- id: order-service
uri: lb://orderservice
predicates:
- Path=/order/**
filters:
- AddRequestHeader=Truth, blue
default-filters:
- AddRequestHeader=Truth,Itcast is freaking awesome!
全局过滤器GlobalFilter
@Order(-1) //值越小,优先级越高
@Component
public class AuthorizeFilter implements GlobalFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 1.获取请求参数
// exchange.getRequest().getQueryParams().getFirst("authorization")
ServerHttpRequest request = exchange.getRequest();
MultiValueMap<String, String> params = request.getQueryParams();
// 2.获取参数中的 authorization 参数
String auth = params.getFirst("authorization");
// 3.判断参数值是否等于 admin
if ("admin".equals(auth)) {
// 4.是,放行
return chain.filter(exchange);
}
// 5.否,拦截
// 5.1.设置状态码
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
// 5.2.拦截请求
return exchange.getResponse().setComplete();
}
网关中的跨域处理
server:
port: 10010
spring:
application:
name: gateway
cloud:
nacos:
server-addr: http://47.120.0.38:8848 #nacos地址
gateway:
routes:
- id: userService #路由标识,必须唯一
uri: lb://userService #路由目标地址
predicates: #路由断言,判断请求是否符合规则
- Path=/user/** #路由断言,判断路径是否以/user/开头,如果符合规则 P要大写
# filters:
# - AddRequestHeader=Truth, blue
- id: order-service
uri: lb://orderservice
predicates:
- Path=/order/**
filters:
- AddRequestHeader=Truth, blue
globalcors:
add-to-simple-url-handler-mapping: true
cors-configurations:
'[/**]':
allowedOrigins: #允许哪些网站
- "http://localhost:8090"
- "http://localhost:8090"
allowedMethods:
- "GET"
- "POST"
- "DELETE"
allowedHeaders: "*" #允许携带请求头信息
allowedCredentials: true #是否允许携带cookie
maxAge: 360000 #这次跨域的有效期1,预检请求的允许时间
Docker
删除Docker
yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine
安装yum工具
yum install -y yum-utils device-mapper-persistent-data 1vm2 --skip-broken
然后更新本地镜像源:
yum-config-manager \
--add-repo \
https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
sed -i 's/download.docker.com/mirrors.aliyun.com\/docker-ce/g' /etc/yum.repos.d/docker-ce.repo
yum makecache fast
设置docker镜像源加速器
去阿里云服务器上看镜像加速器
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://omgw7ydy.mirror.aliyuncs.com"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker
安装docker-ce
因为ce版为免费版本
yum install -y docker-ce
查看防火墙状态
systemctl status firewalld
关闭防火墙
systemcctl stop firewalld
开启防火墙
systemctl start firewalld
启动docker
systemctl start docker
重启
systemctl restart docker
![在这里插入图片描述](https://img-blog.csdnimg.cn/eda3d1b91d914b0a80310268d54a7cbd.png)
## docker操作命令
![在这里插入图片描述](https://img-blog.csdnimg.cn/1f45006bdb074bd799949d9f5c35479e.png)
可以通过 docker --help查看docker命令帮助
## 拉取一个镜像流程
1.首先去dockerHub中搜索镜像
![在这里插入图片描述](https://img-blog.csdnimg.cn/eda150e5154541f2bc050701323a2f84.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/c88dcb983cbd447c84bb25b669bdfbf9.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/6b074e8238644ed293054b2bec3bca10.png)
将镜像导出到磁盘
docker save -o 文件名 镜像名
删除本地镜像需要添加版本信息
docker rmi nginx:latest
如果有在运行的容器要删除再删除镜像
加载本地镜像文件
docker load -i 本地文件名
## 容器相关命令
![在这里插入图片描述](https://img-blog.csdnimg.cn/d0b054456e8c42d3aaedfa5818265157.png)
在dockerHUb官网中可以查看docker镜像的具体使用方法
![在这里插入图片描述](https://img-blog.csdnimg.cn/69aa3be61a2a431e89902fb8b5e8a609.png)
docker容器的参数的具体解析
1.创建容器,并运行容器
![在这里插入图片描述](https://img-blog.csdnimg.cn/69ccf176ef044d4fa616cdeca9991c77.png)
成功之后返回容器id
然后就可以访问nginx了,云服务器记得开安全组
![在这里插入图片描述](https://img-blog.csdnimg.cn/4283f624d0f04dd8af3f0281ae110dab.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/46a436adf245441187682dd66a91258c.png)
2.进入容器
![在这里插入图片描述](https://img-blog.csdnimg.cn/063534c92a644532bbfec44b98e95403.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/e1d43d9129064dd888f8c37606e5c5f6.png)
因为容器内部没有vim指令,如果想要修改容器内文件的内容,需要使用相关操作,不建议修改,如果必须修改,去下面数据卷处找答案。
![在这里插入图片描述](https://img-blog.csdnimg.cn/7cee1e9b7d044f33828e7e3e62ab4dfc.png)
删除容器指令区别于删除镜像指令,没有i
![在这里插入图片描述](https://img-blog.csdnimg.cn/6a590825e4dc499f8acd0e7d70228d84.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/6bbe48ecafea406a9ad5475c8c8a8e65.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/e120b2aeb5144efebd256838dc62d531.png)
docker run --name myRedis -p 6379:6379 -d redis redis-server --save 60 1 --loglevel warning
进入容器
docker exec -it myRedis bash
退出容器
exit
## 数据卷
![在这里插入图片描述](https://img-blog.csdnimg.cn/84d7088fd6b8497baa9ca211319b6f9f.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/8642bd84b72e45b6813bbc4460776c71.png)
这个映射,相当于热更新操作,只要容器挂载到数据卷上,就能够实现资源共享
![在这里插入图片描述](https://img-blog.csdnimg.cn/71c6d3412eb24948a4c4088b173ec67f.png)
查看操作数据卷命令
docker volume --help
创建数据卷
docker volume create html
显示数据卷
docker volume inspect html
列出数据卷
docker volume ls
![在这里插入图片描述](https://img-blog.csdnimg.cn/137be3d673af4f88aaeb77480e310970.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/c86f02e14412417aabd14da291f3328a.png)
## 挂载数据卷
docker run --name myNginx -v html:/usr/share/nginx/html -d nginx
![在这里插入图片描述](https://img-blog.csdnimg.cn/b7bdc0e1db4243daaa6f9b41ee7b7bf4.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/f995f606d40c4cf4805e858c29815159.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/367796e76a0e4dd2a84752ee020d6029.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/ee5e3bfc53234c738dee435f4fc07301.png)
挂载数据卷方式二
![在这里插入图片描述](https://img-blog.csdnimg.cn/5314ecca7b35462cae8c94acd352c273.png)
docker run --name mysql
-e MYSQL_ROOT_PASSWORD=0071hanxiaolei
-p 3306:3306
-v /temp/mysql/conf/hmy.cnf:/etc/mysql/conf.d/hmy.cnf
-v /tmp/mysql/data:/var/lib/mysql
-d mysql:5.7.42
![在这里插入图片描述](https://img-blog.csdnimg.cn/b46926fd2a7d4fbca021415c5e77eae6.png)
## 自定义镜像
![在这里插入图片描述](https://img-blog.csdnimg.cn/75d91e460da94d1abae2b68667e46f13.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/2c44d89e86604925bf9c69297c758c61.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/8cf1fd9c7cc149e3937ea487be96c283.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/dc456a672bd94fbca5734267c144474c.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/85d78d44497946e4b0953f133b440b98.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/d53613824bfc4c119030e3fab23f39a8.png)
现在java:8已经不存在了,使用openjdk:8作为基础镜像
![在这里插入图片描述](https://img-blog.csdnimg.cn/fe553dc27d594a2f8cfcb1050301c850.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/6870eaec5729451fb5f9dbedf2faa77a.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/8a913d567eab44c0ac91ee41e443819b.png)
在终端中导航到包含Dockerfile的项目目录,并运行以下命令来构建Docker镜像:
docker build -t javaweb .
![在这里插入图片描述](https://img-blog.csdnimg.cn/cf8def29d5924ae88329f165e729095e.png)
运行镜像
docker run --name web -p 8999:8999 -d javaweb:latest
## DockerCompose
![在这里插入图片描述](https://img-blog.csdnimg.cn/184487e9ca6f4d4e90187edcc096134b.png)
官网
https://github.com/docker/compose/releases
配置域名解析
echo “192.232.68.133 raw.githubusercontent.com” >>/etc/hosts
下载docker-compose
curl -L https://github.com/docker/compose/releases/download/2.20.1/docker-compose-uname -s
-uname -m
-o /usr/local/bin/docker-compose
查看下载路径
whereis docker-compose
![在这里插入图片描述](https://img-blog.csdnimg.cn/cc19e89a0f014fe0a339c4cb747e3174.png)
给docker-compose添加权限
chmod +x docker-compose
![在这里插入图片描述](https://img-blog.csdnimg.cn/a201671ad7d845629d14d0ce14e558b1.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/b4be654ebbc1471abaebbdc9bb7d6229.png)
1.配置网关
![在这里插入图片描述](https://img-blog.csdnimg.cn/aff33504ef1b429eb02560f46394f4f4.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/9c7641c1006b492ca7c047fcdc70c741.png)
2.其他userService与orderService都与网关相同
![在这里插入图片描述](https://img-blog.csdnimg.cn/68e65af9683e432aae0c896030ad823e.png)
## Docker镜像仓库
![在这里插入图片描述](https://img-blog.csdnimg.cn/c221376692c44a0cab1ed4f5dbed41d0.png)
我们的私服采用的是http协议,默认不被Docker信任,所以需要做一个配置:
打开要修改的文件
vi /etc/docker/daemon.json
添加内容:
“insecure-registries”:[“http://47.120.0.38:8080”]
重加载
systemctl daemon-reload
重启docker
systemctl restart docker
查看docker-compose是否安装成功
docker-compose -v
然后在tmp目录下创建registry-ui文件
mkdir registry-ui
然后在registry-ui中新建文件docker-compose.yml
touch docker-compose.yml
docker-compose.yml里面添加内容为
version: ‘3.0’
services:
registry:
image: registry
volumes:
- ./registry-data:/var/lib/registry
ui:
image: joxit/docker-registry-ui:static
ports:
- 8080:80
environment:
- REGISTRY_TITLE=某某某的私有仓库
- REGISTRY_URL=http://registry:5000
depends_on:
- registry
![在这里插入图片描述](https://img-blog.csdnimg.cn/e862669288d4480f9146fc59157d773e.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/bbcf33da58b943589cbf8b6fbe7f1ae7.png)
生成本地镜像版本
docker tag nginx:latest 47.120.0.38:8080/nginx:1.0
推送镜像
docker push 47.120.0.38:8080/nginx:1.0
拉取镜像
docker pull 47.120.0.38/nginx:1.0
![在这里插入图片描述](https://img-blog.csdnimg.cn/4c82fa0db41b4b1fb14fcff54a3fec61.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/e48b37275f7245599c7010f632848ae1.png)
# RabbitMQ
![在这里插入图片描述](https://img-blog.csdnimg.cn/1e548c80468a41b08e6ae6fc5f97c9b1.png)
## 同步调用
![在这里插入图片描述](https://img-blog.csdnimg.cn/984097c95e6942a5a3ab6238a29eeeda.png)
同步调用会请求等待,造成请求时间过长
![在这里插入图片描述](https://img-blog.csdnimg.cn/4f4ba0f7da6e46c59de7c41045681e53.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/adb859069c2a44c1a8da79ec4b159552.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/32aa6661cd0041f3a2b26360797401db.png)
## 异步调用
![在这里插入图片描述](https://img-blog.csdnimg.cn/78abf411703146f9a17192d8781c0054.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/8ad9246a71ad4ff2b1b2d57711ac4731.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/9d0eeb29382f4351a98cdb5f7d96643f.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/b4504511f44f4a5f95cfe1be9628d549.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/63050d632a9c4b64a25984ac03b6578d.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/de25b76e8b224812b7a6392103c520a6.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/1462fa0fa9ae490f92cffdd346181047.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/ce024720212046a1b79ecae26641ee9f.png)
## RabbitMQ的安装
docker run -d --hostname my-rabbit --name rabbit
-p 5672:5672 -p 15672:15672 -e \
RABBITMQ_DEFAULT_USER=root
-e RABBITMQ_DEFAULT_PASS=0071hanxiaolei
rabbitmq:3-management
若访问不了控制台
进入rabbitmq容器内部,然后执行
rabbitmq-plugins enable rabbitmq_management
cd /etc/rabbitmq/conf.d/
echo management_agent.disable_metrics_collector = false > management_agent.disable_metrics_collector.conf
## 常见的MQ消息模型
![在这里插入图片描述](https://img-blog.csdnimg.cn/da209f515caa4809ba551beb07e59072.png)
## HelloWord案例
![在这里插入图片描述](https://img-blog.csdnimg.cn/81b52001c74e48afb1a60ddd9ea3b2e2.png)
public class PublisherTest {
@Test
public void testSendMessage() throws IOException, TimeoutException {
// 1.建立连接
ConnectionFactory factory = new ConnectionFactory();
// 1.1.设置连接参数,分别是:主机名、端口号、vhost、用户名、密码
factory.setHost(“47.120.0.38”);
factory.setPort(5672);
factory.setVirtualHost(“/”);
factory.setUsername(“root”);
factory.setPassword(“0071hanxiaolei”);
// 1.2.建立连接
Connection connection = factory.newConnection();
// 2.创建通道Channel
Channel channel = connection.createChannel();
// 3.创建队列
String queueName = "simple.queue";
channel.queueDeclare(queueName, false, false, false, null);
// 4.发送消息
String message = "hello, rabbitmq!";
channel.basicPublish("", queueName, null, message.getBytes());
System.out.println("发送消息成功:【" + message + "】");
// 5.关闭通道和连接
channel.close();
connection.close();
}
}
public class ConsumerTest {
public static void main(String[] args) throws IOException, TimeoutException {
// 1.建立连接
ConnectionFactory factory = new ConnectionFactory();
// 1.1.设置连接参数,分别是:主机名、端口号、vhost、用户名、密码
factory.setHost("47.120.0.38");
factory.setPort(5672);
factory.setVirtualHost("/");
factory.setUsername("root");
factory.setPassword("0071hanxiaolei");
// 1.2.建立连接
Connection connection = factory.newConnection();
// 2.创建通道Channel
Channel channel = connection.createChannel();
// 3.创建队列
String queueName = "simple.queue";
channel.queueDeclare(queueName, false, false, false, null);
// 4.订阅消息
channel.basicConsume(queueName, true, new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope,
AMQP.BasicProperties properties, byte[] body) throws IOException {
// 5.处理消息
String message = new String(body);
System.out.println("接收到消息:【" + message + "】");
}
});
System.out.println("等待接收消息。。。。");
}
}
![在这里插入图片描述](https://img-blog.csdnimg.cn/0dd113c635cf478fa977db90a4a8167d.png)
## springAMQP
![在这里插入图片描述](https://img-blog.csdnimg.cn/29742021c8be470aa267518840b602c3.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/ced50cddc76b4b24859ffc20515d4f8f.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/df30ffe2ee9445f3a7ddea7c8d401791.png)
org.springframework.boot spring-boot-starter-amqp ``` ![在这里插入图片描述](https://img-blog.csdnimg.cn/315e336ed20a4c69a7073345221486ba.png)
spring:
rabbitmq:
host: 47.120.0.38
port: 5672
username: root
password: 0071hanxiaolei
virtual-host: /
@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringAmqpTest {
@Autowired
private RabbitTemplate rabbitTemplate;
@Test
public void testSendMessageSimpleQueue(){
String queueName="simple.queue";
String message="hello word";
rabbitTemplate.convertAndSend(queueName,message);
}
}
spring:
rabbitmq:
host: 47.120.0.38
port: 5672
username: root
password: 0071hanxiaolei
virtual-host: /
@Component
public class SpringAmqpListener {
@RabbitListener(queues = "simple.queue")
public void listenerSimpleQueue(String arg){
System.out.println("消费者接受到simple.queue的消息:"+arg);
}
}
Work Queue
多个消费者,会进行消息队列的预取,但是预取完之后做不完,会产生消息的堆积
spring:
rabbitmq:
host: 47.120.0.38
port: 5672
username: root
password: 0071hanxiaolei
virtual-host: /
listener:
direct:
prefetch: 1
消息的订阅与发布
Fanout广播
@Configuration
public class FanoutConfig {
//声明一个交换机
@Bean
public FanoutExchange fanoutExchange(){
return new FanoutExchange("itcast.fanout");
}
//声明一个队列
@Bean
public Queue fanoutQueue1(){
return new Queue("fanout.queue1");
}
//声明一个队列
@Bean
public Queue fanoutQueue2(){
return new Queue("fanout.queue2");
}
//绑定队列1到交换机
@Bean
public Binding fanoutBinding1(Queue fanoutQueue1,FanoutExchange fanoutExchange){
return BindingBuilder.bind(fanoutQueue1).to(fanoutExchange);
}
//绑定队列2到交换机
@Bean
public Binding fanoutBinding2(Queue fanoutQueue2,FanoutExchange fanoutExchange){
return BindingBuilder.bind(fanoutQueue2).to(fanoutExchange);
}
}
@RabbitListener(queues = "fanout.queue1")
public void listenerFanoutQueue1(String arg) throws InterruptedException {
System.err.println("消费者1.....接受到fanout.queue1的消息:"+arg+"*******"+ LocalTime.now());
}
@RabbitListener(queues = "fanout.queue2")
public void listenerFanoutQueue2(String arg) throws InterruptedException {
System.err.println("消费者2.....接受到fanout.queue2的消息:"+arg+"*******"+ LocalTime.now());
}
public void testSendFanoutExchange(){
//交换机名称
String exchangeName="itcast.fanout";
//消息
String message="hello one";
//发送消息
rabbitTemplate.convertAndSend(exchangeName,"",message);
}
Direct路由
/**
* direct
* @param arg
*/
@RabbitListener(bindings = @QueueBinding(
value = @Queue(name = "direct.queue1"),
exchange = @Exchange(name = "itcast.direct",type = ExchangeTypes.DIRECT),
key = {"red","blue"}
))
public void listenerDirectQueue(String arg){
System.out.println("消费者red与blue.....接受到direct.queue1的消息:"+arg);
}
@RabbitListener(bindings = @QueueBinding(
value = @Queue(name = "direct.queue2"),
exchange = @Exchange(name = "itcast.direct",type = ExchangeTypes.DIRECT),
key = {"red","yellow"}
))
public void listenerDirectQueue2(String arg){
System.out.println("消费者red与yellow.....接受到direct.queue2的消息:"+arg);
}
@Test
public void testSendDirectExchange(){
//交换机名称
String exchangeName="itcast.direct";
//消息
String message="hello yellow";
//发送消息
rabbitTemplate.convertAndSend(exchangeName,"yellow",message);
}
Topic主题
/**
* topic
*/
@RabbitListener(bindings = @QueueBinding(
value = @Queue(name = "topic.queue1"),
exchange = @Exchange(name = "itcast.topic",type = ExchangeTypes.TOPIC),
key = "china.#"
))
public void listenerTopicQueue(String arg){
System.out.println("china的所有消息"+arg);
}
@RabbitListener(bindings = @QueueBinding(
value = @Queue(name = "topic.queue1"),
exchange = @Exchange(name = "itcast.topic",type = ExchangeTypes.TOPIC),
key = "china.sjz"
))
public void listenerTopic2Queue(String arg){
System.out.println("china.sjz的消息"+arg);
}
@Test
public void testSendTopicExchange(){
//交换机名称
String exchangeName="itcast.topic";
//消息
String message="我在石家庄学习springCloud";
//发送消息
rabbitTemplate.convertAndSend(exchangeName,"china.sjz",message);
}
@Test
public void testSendTopic2Exchange(){
//交换机名称
String exchangeName="itcast.topic";
//消息
String message="我在中国学习springCloud";
//发送消息
rabbitTemplate.convertAndSend(exchangeName,"china",message);
}
消息转换器
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
@Bean
public MessageConverter messageConverter(){
return new Jackson2JsonMessageConverter();
}
@Test
public void testSendObjectQueue(){
Map<String, Object> stringObjectHashMap = new HashMap<>();
stringObjectHashMap.put("柳岩","柳岩");
stringObjectHashMap.put("age",18);
rabbitTemplate.convertAndSend("object.queue",stringObjectHashMap);
}
@Bean
public Queue objectQueue(){
return new Queue("object.queue");
}
@RabbitListener(queues = "object.queue")
public void listenerObjectQueue(Map<String,Object> msg){
System.out.println(msg);
}
Elasticsearch
什么是elasticsearch
倒排索引
文档
索引
概念对比
架构
安装elasticsearch
部署单点es
因为我们还需要部署kibana,因此我们需要让es和kibana容器互联。这里先创建一个网路
docker network create es-net
加载镜像
docker load -i es.tar
docker pull elasticsearch
启动elasticsearch
docker run -d \
--name es \
-e "ES_JAVA_OPTS=-Xms512m -Xmx512m" \
-e "discovery.type=single-node" \
-v es-data:/usr/share/elasticsearch/data \
-v es-plugins:/usr/share/elasticsearch/plugins \
--privileged \
--network es-net \
-p 9200:9200 \
-p 9300:9300 \
elasticsearch:latest
访问9200端口
安装kibana
docker run -d --name kibana \
-e ELASTICSEARCH_URL=http://es:9200 \
--network=es-net -p 5601:5601 kibana:latest
访问5601
分词器
处理这种中文分词器我们使用IK分词器
离线安装ik分词器
安装插件需要知道elasticsearch的plugins目录位置,而我们使用了数据卷挂载,因此需要查看elasticsearch的数据卷目录,通过以下命令查看
docker volume inspect es-plugins
将下载好的ik分词器上传到该目录下
重启es模块
docker restart es
测试分词效果
两种分词模式
-
ik_smart
:最少切分 -
ik_max_word
:最细切分
GET /_analyze
{
"analyzer": "ik_max_word",
"text": "黑马程序员学习java太棒了"
}
显示结果
{
"tokens" : [
{
"token" : "黑马",
"start_offset" : 0,
"end_offset" : 2,
"type" : "CN_WORD",
"position" : 0
},
{
"token" : "程序员",
"start_offset" : 2,
"end_offset" : 5,
"type" : "CN_WORD",
"position" : 1
},
{
"token" : "程序",
"start_offset" : 2,
"end_offset" : 4,
"type" : "CN_WORD",
"position" : 2
},
{
"token" : "员",
"start_offset" : 4,
"end_offset" : 5,
"type" : "CN_CHAR",
"position" : 3
},
{
"token" : "学习",
"start_offset" : 5,
"end_offset" : 7,
"type" : "CN_WORD",
"position" : 4
},
{
"token" : "java",
"start_offset" : 7,
"end_offset" : 11,
"type" : "ENGLISH",
"position" : 5
},
{
"token" : "太棒了",
"start_offset" : 11,
"end_offset" : 14,
"type" : "CN_WORD",
"position" : 6
},
{
"token" : "太棒",
"start_offset" : 11,
"end_offset" : 13,
"type" : "CN_WORD",
"position" : 7
},
{
"token" : "了",
"start_offset" : 13,
"end_offset" : 14,
"type" : "CN_CHAR",
"position" : 8
}
]
}
GET /_analyze
{
"analyzer": "ik_smart",
"text": "学习java太棒了"
}
{
"tokens": [
{
"token": "学习",
"start_offset": 0,
"end_offset": 2,
"type": "CN_WORD",
"position": 0
},
{
"token": "java",
"start_offset": 2,
"end_offset": 6,
"type": "ENGLISH",
"position": 1
},
{
"token": "太棒了",
"start_offset": 6,
"end_offset": 9,
"type": "CN_WORD",
"position": 2
},
{
"token": "eeee",
"start_offset": 9,
"end_offset": 13,
"type": "ENGLISH",
"position": 3
}
]
}
分词扩展
文件位置
/var/lib/docker/volumes/es-plugins/_data/ik/config/IKAnalyzer.cfg.xml
其中ext.dic是添加扩展词,同级目录下没有该文件,新建一个
其中stopword.dic是忽略的词,同级目录下存在,往里面加相应的词语即可
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
<comment>IK Analyzer 扩展配置</comment>
<!--用户可以在这里配置自己的扩展字典 -->
<entry key="ext_dict">ext.dic</entry>
<!--用户可以在这里配置自己的扩展停止词字典-->
<entry key="ext_stopwords">stopword.dic</entry>
<!--用户可以在这里配置远程扩展字典 -->
<!-- <entry key="remote_ext_dict">words_location</entry> -->
<!--用户可以在这里配置远程扩展停止词字典-->
<!-- <entry key="remote_ext_stopwords">words_location</entry> -->
</properties>
索引库操作
创建索引库
每个版本的创建方式不同,添加方式也不同,这里版本是5.6.8
PUT heima3
{
"mappings": {
"person": {
"properties": {
"info": {
"type": "text",
"analyzer": "ik_smart"
},
"email": {
"type": "keyword",
"index": false
},
"name": {
"type": "object",
"properties": {
"firstName": {
"type": "keyword"
},
"lastName": {
"type": "keyword"
}
}
}
}
}
}
}
查看删除索引库
修改索引库
不能够修改已有索引库,只能添加新字段。
向索引库中添加字段
PUT /heima/person/_mapping
{
"properties": {
"age1": {
"type": "long"
}
}
}
添加文档
如果以后版本不同,请查看不同版本如何使用
POST /hiema/person/1
{
"info":"黑马此程序黑马此程序黑马",
"email":"9100",
"name":{
"lastNAme":"wg",
"firstName":"bbb"
}
}