什么是Docker Compose

Docker Compose 是 Docker 的一个编排管理工具,它允许你使用一个 YAML 文件来配置应用程序的服务。通过这个文件,你可以定义多个容器如何通过网络相互连接,以及如何配置它们的环境变量、卷挂载、端口映射等。这使得在单个主机上运行复杂的多容器应用程序变得非常简单和直观。

Docker Compose主要解决了docker run指令以及docker build后需要手动运行docker run的问题。

Docker Compose主要概念

  • 服务(Services):在 Docker Compose 文件中,一个服务通常指的是一个容器。你可以定义多个服务,每个服务都运行一个或多个容器实例。例如,你的应用程序可能包含一个 Web 服务和一个数据库服务。

  • 网络(Networks):Docker Compose 可以创建和管理 Docker 网络,以便服务之间可以相互通信。默认情况下,Docker Compose 会为每个服务创建一个网络,但你也可以定义跨多个服务的自定义网络。

  • 卷(Volumes):卷是 Docker 中用于持久化数据的一种机制。在 Docker Compose 中,你可以定义卷,并将卷挂载到容器内的特定路径上,这样即使容器被删除,数据也不会丢失。

  • 环境变量(Environment Variables):你可以为服务定义环境变量,这些变量可以在容器内部被读取和使用。这对于配置应用程序的设置非常有用。

  • 依赖(Dependencies):你可以在 Docker Compose 文件中定义服务的依赖关系,确保在启动服务时按照正确的顺序进行。例如,你可能希望先启动数据库服务,然后再启动依赖于数据库的服务。

安装Docker Compose

Docker Compose项目地址:https://github.com/docker/compose

安装环境信息

IP 系统 规格
10.0.0.10 Ubuntu22.04 2c4g

安装前置准备:需要安装Docker

安装步骤:

# 下载Docker Compose
[root@lb ~]# wget https://github.com/docker/compose/releases/download/v2.35.0/docker-compose-linux-x86_64
[root@lb ~]# ll docker-compose-linux-x86_64
-rw-r--r-- 1 root root 73664588 Apr 19 14:42 docker-compose-linux-x86_64 # 移动至/usr/bin/docker-compose
[root@lb ~]# mv docker-compose-linux-x86_64 /usr/bin/docker-compose # 授予权限
[root@lb ~]# chmod +x /usr/bin/docker-compose
[root@lb ~]# ll /usr/bin/docker-compose
-rwxr-xr-x 1 root root 73664588 Apr 19 14:42 /usr/bin/docker-compose* # 检查
[root@lb ~]# docker-compose version
Docker Compose version v2.35.0

Docker Compose常用命令

Docker Compose的命令非常多,下面列举几个常用的,后文遇到新的命令继续讲解

容器相关

  • docker-compose up -d:相当于docker run -d,创建并后台运行容器
  • docker-compose ps:查看容器运行情况,只有-q选项
  • docker-compose down:删除容器,删除所有容器的所有内容(网络、数据卷)
  • docker-compose start:启动容器
  • docker-compose stop:容器关闭
  • docker-compose restart:重启容器
  • docker-compose top:查看容器进程信息
  • docker-compose logs:查看容器日志
  • docker-compose rm:删除容器
  • docker-compose exec:进入容器

镜像相关

  • docker-compose pull:拉取服务的镜像
  • docker-compose push:推送服务的镜像
  • docker-compose build:构建服务镜像

Docker Compose文件中常用指令

官网文章:https://docs.docker.com/reference/compose-file/services/

Docker Compose文件是一个yaml文件,且运行docker-compose命令时,所在的目录下必须有一个docker-compose.yaml或者compose.yaml文件。

services

Compose 文件必须将services设置为顶级元素,services指定运行容器的相关信息,可以理解成docker run指令的集合

示例:

# docker-compose文件
[root@lb ~/services]# cat docker-compose.yaml
services:
# 服务名称
web:
image: nginx:latest
ports:
- "8080:80" # 运行容器
[root@lb ~/services]# docker-compose up -d
[+] Running 1/1
Container services-web-1 Started # 查看运行的容器
[root@lb ~/services]# docker-compose ps
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
services-web-1 nginx:latest "/docker-entrypoint.…" web About a minute ago Up About a minute 0.0.0.0:8080->80/tcp, [::]:8080->80/tcp

image

指定容器运行时的基础镜像

ports

指定容器运行时的端口号,可以写多个

container_name

指定容器的名字,没有container_name标签时,会以services-[services_name]-[services_num]为容器名称

示例:

[root@lb ~/container_name]# cat docker-compose.yaml
services:
web:
image: nginx:latest
# 指定容器名称
container_name: nginx_1
ports:
- "8081:80" [root@lb ~/container_name]# docker-compose up -d
[+] Running 2/2
Network container_name_default Created 0.1s
Container nginx_1 Started 0.2s
[root@lb ~/container_name]# docker-compose ps -a
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
nginx_1 nginx:latest "/docker-entrypoint.…" web 5 seconds ago Up 5 seconds 0.0.0.0:8081->80/tcp, [::]:8081->80/tcp

build

运行Dockerfile,构建镜像使用,有几个子标签

context

指定Dockerfile所在的目录

dockerfile

指定Dockerfile的文件名,同docker build -f指令,该指令可以不写,默认是Dockerfile

示例:

[root@lb ~/build]# cat compose.yaml
services:
zrlog:
container_name: zrlog
# build指令使用
build:
context: ./zrlog
dockerfile: Dockerfile
ports:
- "8082:8080" # 构建镜像
[root@lb ~/build]# docker-compose build
Compose can now delegate builds to bake for better performance.
To do so, set COMPOSE_BAKE=true.
[+] Building 6.5s (9/9) FINISHED docker:default
=> [zrlog internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 409B 0.0s
=> [zrlog internal] load metadata for docker.io/library/tomcat:9.0.87-jdk8-corretto 6.3s
=> [zrlog internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [zrlog internal] load build context 0.1s
=> => transferring context: 10.80MB 0.1s
=> [zrlog 1/3] FROM docker.io/library/tomcat:9.0.87-jdk8-corretto@sha256:6928733a4f4c15d61c45a14b0197fe9a160f49f6f13b1b0b06310561cb320ef0
=> => writing image sha256:0d6bbaa1db8bf9d30e976c17f2991aca20e6b6e070be646b85240e1ec0ffdc71 0.0s
=> => naming to docker.io/library/build-zrlog 0.0s
=> [zrlog] resolving provenance for metadata file 0.0s
[+] Building 1/1
zrlog Built 0.0s
# 启动镜像
[root@lb ~/build]# docker-compose up -d
[+] Running 2/2
Network build_default Created 0.1s
Container build-zrlog-1 Started [root@lb ~/build]# docker-compose ps
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
zrlog build-zrlog "catalina.sh run" zrlog About a minute ago Up About a minute (healthy) 0.0.0.0:8082->8080/tcp, [::]:8082->8080/tcp

environment

docker run -e选项,指定容器运行后的环境变量

示例:

[root@lb ~/environment]# cat compose.yaml
services:
db:
image: mysql:5.7
container_name: mysql_db
ports:
- "3306:3306"
environment:
# 指定MySQL root的密码
- "MYSQL_ROOT_PASSWORD=root123"
# 指定创建一个zrlog的数据库
- "MYSQL_DATABASE=zrlog"
# 运行
[root@lb ~/environment]# docker-compose up -d
[+] Running 2/2
Network environment_default Created 0.1s
Container mysql_db Started # check
[root@lb ~/environment]# docker-compose ps -a
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
mysql_db mysql:5.7 "docker-entrypoint.s…" db 14 seconds ago Up 14 seconds 0.0.0.0:3306->3306/tcp, [::]:3306->3306/tcp, 33060/tcp

restart

指定容器的重启方式,和docker run --restart选项一致

重启方式:

  • always:自动重启
  • unless-stopped:只在容器关闭,停止的时候重启
  • on-failure:只在失败的时候重启

示例:

services:
db:
# 指定重启策略
restart: always
image: mysql:5.7
container_name: mysql_db
ports:
- "3306:3306"
environment:
# 指定MySQL root的密码
- "MYSQL_ROOT_PASSWORD=root123"
# 指定创建一个zrlog的数据库
- "MYSQL_DATABASE=zrlog"

volumes

官网文章:https://docs.docker.com/reference/compose-file/volumes/

volumes指令在Compose文件中有两个作用,作为顶级元素时,volume会创建一个数据卷,作为子级元素时,会为容器挂载数据卷。

示例:

[root@lb ~/volumes]# cat compose.yaml
services:
db:
# 指定重启策略
restart: always
image: mysql:5.7
container_name: mysql_db_1
ports:
- "3307:3306"
environment:
# 指定MySQL root的密码
- "MYSQL_ROOT_PASSWORD=root123"
# 指定创建一个zrlog的数据库
- "MYSQL_DATABASE=zrlog"
volumes:
- mysql_data:/var/lib/mysql # 创建mysql_data的数据卷
volumes:
mysql_data:
# 启动容器
[root@lb ~/volumes]# docker-compose up -d
[+] Running 1/1
Container mysql_db_1 Started # 检查 0.3s
[root@lb ~/volumes]# docker-compose ps -a
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
mysql_db_1 mysql:5.7 "docker-entrypoint.s…" db 4 seconds ago Up 4 seconds 33060/tcp, 0.0.0.0:3307->3306/tcp, [::]:3307->3306/tcp # 检查数据卷
[root@lb ~/volumes]# docker inspect mysql_data
[
{
"CreatedAt": "2025-04-12T15:42:17+08:00",
"Driver": "local",
"Labels": null,
"Mountpoint": "/var/lib/docker/volumes/mysql_data/_data",
"Name": "mysql_data",
"Options": null,
"Scope": "local"
}
]

当需要挂载到本机宿主机时,仅使用次级元素的volumes即可

示例:

services:
web:
image: nginx:latest
volumes:
- ./html:/usr/share/nginx/html

可以使用外部存储卷

示例:

services:
web:
image: nginx:latest
volumes:
- web_data:/usr/share/nginx/html
volumes:
web_data:
#external指定此卷已存在于平台上,并且其生命周期由应用程序之外的生命周期管理。如果卷不存在,Compose 将不会创建该卷并返回错误。
external: true

healthcheck

healthcheck用于定义服务的健康检查机制。通过健康检查,可以确保容器在启动后能够正常运行,并且在容器不可用时自动重启或重新调度.

其子元素有:

  • test:定义健康检查的命令。可以是一个命令或一个脚本。
  • interval:两次健康检查之间的间隔时间(默认单位为秒)。
  • timeout:单次健康检查的超时时间。
  • retries:健康检查失败后重试的次数。
  • start_period:容器启动后开始健康检查的延迟时间。

    示例:
services:
web:
image: nginx:latest
ports:
- "80:80"
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost"]
interval: 30s
timeout: 10s
retries: 3
start_period: 5s

depends_on

depends_on用于控制服务之间的启动顺序。它确保在启动某个服务之前,其依赖的服务已经启动。例如web服务依赖数据库服务,需要数据库服务先启动时可以使用depends_on。

虽然depends_on确保了服务的启动顺序,但它不会等待服务完全启动后再启动依赖的服务,例如,数据库服务可能还在初始化过程中,而web服务已经启动了,这可能会导致web应用程序无法连接到数据库服务,这个时候需要使用healthcheck

depends_on只会影响容器的启动顺序,不会影响容器的停止顺序

示例:

services:
web:
image: nginx:latest
ports:
- "80:80"
# 指定依赖db服务
depends_on:
db:
condition: service_healthy
db:
image: mysql:latest
environment:
- "MYSQL_ROOT_PASSWORD=root123"
# 健康检查
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 10s
timeout: 5s
retries: 5

links(在Docker Compose版本3以上已被废弃)

links 是一个用于定义服务之间网络连接的指令。它允许一个服务访问另一个服务的容器,并通过服务名称进行通信。虽然 links 在 Docker Compose 的早期版本中非常常用,但在 Docker Compose 版本 3 及以上中,links 已被废弃,推荐使用默认的网络功能来实现服务之间的通信。

links的作用:

  • 建立网络连接:links 用于在服务之间建立网络连接,允许一个服务访问另一个服务的容器。
  • 环境变量和 /etc/hosts:当使用 links 时,Docker 会自动设置环境变量和 /etc/hosts 条目,使得服务之间可以通过服务名称进行通信。

示例:

[root@lb ~/links]# cat compose.yaml
services:
web1:
container_name: nginx1
image: nginx:latest
links:
- web2:nginx
ports:
- "81:80"
web2:
container_name: nginx2
image: nginx:latest
ports:
- "82:80" # 运行容器
[root@lb ~/links]# docker-compose up -d
[+] Running 3/3
Network links_default Created 0.1s
Container nginx2 Started 0.4s
Container nginx1 Started 0.6s
# 检查
[root@lb ~/links]# docker-compose ps -a
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
nginx1 nginx:latest "/docker-entrypoint.…" web1 13 seconds ago Up 11 seconds 0.0.0.0:81->80/tcp, [::]:81->80/tcp
nginx2 nginx:latest "/docker-entrypoint.…" web2 13 seconds ago Up 12 seconds 0.0.0.0:82->80/tcp, [::]:82->80/tcp ###### 测试,进入nginx1的容器内部
[root@lb ~/links]# docker exec -it nginx1 bash
# 查看hosts解析
root@12b2517e712e:/# cat /etc/hosts
127.0.0.1 localhost
...
# web2的hosts解析
172.24.0.3 12b2517e712e root@12b2517e712e:/# curl
curl: try 'curl --help' or 'curl --manual' for more information
root@12b2517e712e:/# curl http://nginx
<!DOCTYPE html>
<html>
# 网页内容
</body>
</html>

在 Docker Compose 版本 3 及以上中,推荐使用默认网络功能来实现服务之间的通信。

示例:

services:
web1:
container_name: nginx1
image: nginx:latest
ports:
- "81:80"
web2:
container_name: nginx2
image: nginx:latest
ports:
- "82:80"

在这个示例中,web1和web2默认连接到同一个网络中,web1可以通过web2服务名称直接访问web2服务

networks

networks用于定义和管理服务之间的网络通信,通过networks可以创建自定义网络,将服务连接到这些网络中,从而实现灵活的网络结构。

在 Docker Compose 中,如果没有显式定义网络,Docker Compose 会自动为每个项目创建一个默认网络,并将所有服务连接到该网络。默认网络是桥接网络(bridge network),服务之间可以通过服务名称直接通信。

也可以自定义网络,并将服务连接到这些网络中,自定义网络可以是桥接网络(bridge)、主机网络(host)或覆盖网(overlay)。

示例:

services:
web:
image: nginx:latest
ports:
- "80:80"
networks:
- my_network
db:
image: mysql:latest
environment:
MYSQL_ROOT_PASSWORD: my-secret-pw
networks:
- my_network networks:
my_network:
driver: bridge

deploy

deploy 配置项用于定义服务在部署时的行为,包括资源限制、副本数量、更新策略、重启策略等

这里以资源限制为例

services:
web:
image: nginx:latest
ports:
- "80:80"
deploy:
resources:
limits:
cpus: '0.5' # 限制 CPU 使用量为 0.5 个核心
memory: 50M # 限制内存使用量为 50MB
reservations:
cpus: '0.2' # 保留 0.2 个核心
memory: 20M # 保留 20MB 内存

limits:定义容器可以使用的最大资源量。

  • cpus:浮点数,表示 CPU 核心数。例如,0.5 表示限制为 0.5 个核心。
  • memory:字符串,表示内存限制,单位可以是 B(字节)、K(千字节)、M(兆字节)、G(吉字节)。

reservations:定义容器启动时保留的资源量。

  • cpus:浮点数,表示 CPU 核心数。
  • memory:字符串,表示内存大小。

Docker Compose变量文件

Compose变量文件是在compose.yaml同级目录中创建.env文件,在.env文件中写入key=value的形式,然后在compose.yaml文件中以${key}的形式进行使用

示例:

[root@lb ~/var]# ll
total 16
## .env是变量文件
-rw-r--r-- 1 root root 8 Apr 19 21:25 .env
-rw-r--r-- 1 root root 73 Apr 19 21:26 compose.yaml
[root@lb ~/var]# cat .env
PORT=83
[root@lb ~/var]# cat compose.yaml
services:
web:
image: nginx:latest
ports:
## ${PORT}取值
- "${PORT}:80"
[root@lb ~/var]# docker-compose up -d
[+] Running 2/2
Network var_default Created 0.1s
Container var-web-1 Started 0.4s
[root@lb ~/var]# docker-compose ps
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
var-web-1 nginx:latest "/docker-entrypoint.…" web 7 seconds ago Up 6 seconds 0.0.0.0:83->80/tcp, [::]:83->80/tcp

使用多个compose文件

当我们具有多个compose文件时,我们应该怎么运行呢?

方式一:使用-f选项进行合并构建

当有多个 Docker Compose 文件时,可以使用 docker-compose 命令的 -f选项来指定多个 Compose 文件,并一起构建和管理服务。这种方式允许你将配置拆分到多个文件中,然后组合使用它们。

例如我们有以下两个compose文件:

docker-compose.yaml

services:
web:
image: nginx:latest
ports:
- "80:80"

docker-compose.admin.yaml

version: '3.8'
services:
web:
environment:
- NGINX_ENV=prod
db:
image: mysql:latest
environment:
MYSQL_ROOT_PASSWORD: my-secret-pw

我们可以使用下面的命令来进行构建

docker-compose -f docker-compose.yml -f docker-compose.override.yml up -d

文件合并规则:

Docker Compose 会按顺序加载指定的文件,并将它们的内容合并。合并规则如下:

  • 服务(Services):如果多个文件中定义了相同的服务,后者的配置会覆盖前者的配置。
  • 网络(Networks):如果多个文件中定义了相同的网络,后者的配置会覆盖前者的配置。
  • 卷(Volumes):如果多个文件中定义了相同的卷,后者的配置会覆盖前者的配置。

我们可以使用使用可以使用 docker-compose config 命令查看合并后的配置。这个命令会输出最终的配置内容,帮助你确认配置是否正确。

docker-compose -f docker-compose.yml -f docker-compose.override.yml config

方式二:使用include元素来引用其它的compose文件

include 指令可以在主 Compose 文件中引用其他 Compose 文件,从而实现配置的模块化和重用。被引用的文件可以定义服务、网络、卷等,主文件会将这些内容合并到最终的配置中。

示例:

include:
- my-compose-include.yaml
services:
serviceA:
build: .
depends_on:
- serviceB

也支持从远程URL加载Compose文件

include:
- https://example.com/services/web.yml
- https://example.com/services/db.yml
services:
serviceA:
build: .
depends_on:
- serviceB

文件合并规则

  • Docker Compose 会按顺序加载 include 中指定的文件,并将它们的内容合并到主文件中。合并规则如下:
  • 服务(Services):如果多个文件中定义了相同的服务,后者的配置会覆盖前者的配置。
  • 网络(Networks):如果多个文件中定义了相同的网络,后者的配置会覆盖前者的配置。
  • 卷(Volumes):如果多个文件中定义了相同的卷,后者的配置会覆盖前者的配置。

注意事项

  • 文件顺序:include 中文件的加载顺序很重要,后加载的文件会覆盖前加载的文件中的配置。
  • 本地优先:如果本地和远程文件有相同的路径或 URL,Docker Compose 会优先使用本地文件。

一文搞懂Docker Compose的更多相关文章

  1. 三文搞懂学会Docker容器技术(中)

    接着上面一篇:三文搞懂学会Docker容器技术(上) 6,Docker容器 6.1 创建并启动容器 docker run [OPTIONS] IMAGE [COMMAND] [ARG...] --na ...

  2. 三文搞懂学会Docker容器技术(下)

    接着上面一篇:三文搞懂学会Docker容器技术(上) 三文搞懂学会Docker容器技术(中) 7,Docker容器目录挂载 7.1 简介 容器目录挂载: 我们可以在创建容器的时候,将宿主机的目录与容器 ...

  3. 一文搞懂Google Navigation Component

    一文搞懂Google Navigation Component 应用中的页面跳转是一个常规任务, Google官方提供的解决方案是Android Jetpack的Navigation componen ...

  4. 一文搞懂RAM、ROM、SDRAM、DRAM、DDR、flash等存储介质

    一文搞懂RAM.ROM.SDRAM.DRAM.DDR.flash等存储介质 存储介质基本分类:ROM和RAM RAM:随机访问存储器(Random Access Memory),易失性.是与CPU直接 ...

  5. 基础篇|一文搞懂RNN(循环神经网络)

    基础篇|一文搞懂RNN(循环神经网络) https://mp.weixin.qq.com/s/va1gmavl2ZESgnM7biORQg 神经网络基础 神经网络可以当做是能够拟合任意函数的黑盒子,只 ...

  6. 一文搞懂 Prometheus 的直方图

    原文链接:一文搞懂 Prometheus 的直方图 Prometheus 中提供了四种指标类型(参考:Prometheus 的指标类型),其中直方图(Histogram)和摘要(Summary)是最复 ...

  7. Web端即时通讯基础知识补课:一文搞懂跨域的所有问题!

    本文原作者: Wizey,作者博客:http://wenshixin.gitee.io,即时通讯网收录时有改动,感谢原作者的无私分享. 1.引言 典型的Web端即时通讯技术应用场景,主要有以下两种形式 ...

  8. 【转帖】一文看懂docker容器技术架构及其中的各个模块

    一文看懂docker容器技术架构及其中的各个模块 原创 波波说运维 2019-09-29 00:01:00 https://www.toutiao.com/a6740234030798602763/ ...

  9. 后端技术杂谈9:先搞懂Docker核心概念吧

    本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutorial 喜欢的话麻烦点下 ...

  10. 一文搞懂vim复制粘贴

    转载自本人独立博客https://liushiming.cn/2020/01/18/copy-and-paste-in-vim/ 概述 复制粘贴是文本编辑最常用的功能,但是在vim中复制粘贴还是有点麻 ...

随机推荐

  1. oracle的新发现for语句

    今天为了解决一个查询结果想两次遍历的方法,去ORACLE官网文档中心 https://docs.oracle.com/en/database/oracle/,意外发现这个有意思的for语句.还是官方资 ...

  2. 管理虚拟机(libvirt)

    给我的理解就是与用户交互的"显示器" [root@kvm1 ~]# systemctl status libvirtd [root@kvm1 ~]# virsh virsh # l ...

  3. 动手学深度学习-python基础知识介绍part1

    基础详解-part1 import torch x=torch.arange(12) x x.shape x.numel() #数组中元素的总数 # 修改形状 x.reshape(3,4) torch ...

  4. 最小生成树可并行化的 Sollin(Boruvka)算法

    上期回顾:https://www.cnblogs.com/ofnoname/p/18715203 在前文中,我们剖析了最小生成树(MST)问题中的两大经典算法: Kruskal 以"边权平等 ...

  5. JUC并发—6.AQS源码分析二

    大纲 1.ReentractReadWriteLock的基本原理 2.基于AQS实现的ReentractReadWriteLock 3.ReentractReadWriteLock如何竞争写锁 4.R ...

  6. OpenLayers 绘制带箭头的LineString

    <!--******************************************************************** * Copyright 2000 - 2022 ...

  7. 植物大战僵尸杂交版最新版(PC+手机+苹果)+ 修改器+高清工具

    游戏介绍 <植物大战僵尸杂交版>在保留原作经典塔防玩法的基础上,进行了大胆创新和优化.潜艇伟伟迷通过融合多种植物和僵尸元素,创造了全新的游戏体验.玩家不仅能体验到熟悉的植物防御僵尸的乐趣, ...

  8. Java进阶 - [1-1] 六大设计原则

    不要因为某本书而去读,而是因为这本书让你读起来时常有共鸣而去读. 一.单一职责原则 [术语]:SRP,Single Reposibility Principle [定义]:一个类或者模块只负责完成一个 ...

  9. Scala查看源码

    package com.wyh.day01 /** * 1.代码格式化的快捷键 ctrl+alt+L\ * 2.scala查看源代码的快捷键 ctrl+b */ object ScalaLookSou ...

  10. Feedalyze - 让你听得见、听得清用户的反馈

    满足用户需求,解决用户问题,获得适当报酬是商业成功最为重要的因素.然而扪心自问,当您推出新产品后,您真的在听.听得见.听得清用户的反馈么? 当今信息传播迅猛,渠道繁多,优秀产品随口碑效应供不应求,劣质 ...