在没有接触微服务或者分布式项目之前,我们的项目时没有分层的,我们的服务也是没有分层的。
比如,我们有5台服务器使用 Nginx 做负载均衡,上面都是安装了我们的 Tomcat 服务器,部署的一样的项目。当用户访问某个请求的时候,按照负载均衡的机制(随机、轮询之类)来转发到对应的服务器上,然后在该服务器上先是到 Controller,然后 Service,再到 DAO,然后返回给 Service,返回给 Controller,最后返回给前台。似乎这样也行。
但是当我们网站访问量不断飙升的时候,似乎有点撑不住了,只能加服务器,成本也明显增加。我们能不能再分一分呢 ?
同时,我们发现真正比较耗费时间的是一些 IO 操作,比如数据库操作、上传文件之类的。为了方便开发,我们可以把 DAO 和 Service 层放在一起,暂且称为业务层。业务层耗费的远远大于 Controller 层的。我们可以在 5 台服务器中拿 1 台部署 Controller 层,另外 4 台部署业务层代码。
如果将他们连接起来呢?
Eureka + Feign!
Eureka 做注册中心,业务层和控制器层每一个实例可以作为一个服务,比如 UserService 是一个服务,UserController 也可以是一个服务,一个服务可以有多个状态(可以有多台机器注册到该服务)。
下面通过一个例子来讲解
源码地址:https://github.com/saysky/spring-cloud-demo
源码地址:https://github.com/saysky/spring-cloud-demo
1、eureka-server(一个 SpringBoot 项目)
2、cloud (一个多模块项目,API + 业务层)
(1)其中 cloud-api 是 api,里面有 model 和 service接口,cloud-core 和 cloud-web 将依赖它
到时候需要首先将该模块 install,即打包到本地仓库中
(2)其中 cloud-core,里面 dao 和 serviceImpl,作为生产者的存在
启动类在这里面
3、cloud-web( 一个 SpringBoot 项目)
只有控制器层,需要依赖 cloud-api ,作为消费者的存在(可以是其他人调用)
2、导入新项目,先后顺序随便(如eureka-server、cloud、cloud-web)
3、启动 eureka-server 项目,端口为 8761
4、对 cloud 项目中的 cloud-api 模块进行install,maven命令是 mvn clean install
5、启动 cloud-core 项目,端口为 8090
6、(可选)其实这时候我们可以在地址栏访问一下 localhost:8090/user 其实是可以访问的,如果你不行,说明有问题
7、启动 cloud-web 项目,端口为 8080
8、在地址栏访问 localhost:8080/user,如果可以看到数据,说明成功
ps:因为我是用本机测试,所以开了不同的端口表示不同的服务器
2、访问控制器层,然后 Feign 会帮我们在注册中心中找到对应的服务名和对应的方法
我们访问 localhost:8080/user/1 首先到的是控制器层,控制器层调用 userService,userService 是 Cloud-API 里的,添加了 @FeignClient(name="cloud-producer") 注解,然后找到在注册中心中寻找 cloud-producer 的服务,从一台(负载均衡)服务器中找到 userService 的实现类,即 userServiceImpl,也就是进入了 cloud-core,然后完成一系列 DAO 和 Service 操作,最后返回给 Controller。
其中 Service 和 Service 的实现都需要加 RequestMapping,Service 实现需要加 @RestController,否则会出现 404
所以,其实我们可以直接访问 cloud-core 这一层,在地址栏访问 localhost:8090/user/1
事实上,我们访问 控制器的时候,当需要某个 Service 的时候,Feign 帮我们向 Service 又发了一个同样的请求。我们可以直接访问这个 Service 请求
但是,通常我们会在生产环境中,不让别人直接访问到 Service,可以通过一些机制实现,比如内网啦。
解决方案:在 cloud-web 启动类上添加
@EnableFeignClients(basePackages = "com.liuyanzhao.cloud")
2、出现 404 错误
cloud-core 里的 userServiceImpl 也需要加 @RequestMapping,并且需要将 @Service 改成 @RestController
UserService(cloud-api)
UserServiceImpl(cloud-core)
比如,我们有5台服务器使用 Nginx 做负载均衡,上面都是安装了我们的 Tomcat 服务器,部署的一样的项目。当用户访问某个请求的时候,按照负载均衡的机制(随机、轮询之类)来转发到对应的服务器上,然后在该服务器上先是到 Controller,然后 Service,再到 DAO,然后返回给 Service,返回给 Controller,最后返回给前台。似乎这样也行。
但是当我们网站访问量不断飙升的时候,似乎有点撑不住了,只能加服务器,成本也明显增加。我们能不能再分一分呢 ?
同时,我们发现真正比较耗费时间的是一些 IO 操作,比如数据库操作、上传文件之类的。为了方便开发,我们可以把 DAO 和 Service 层放在一起,暂且称为业务层。业务层耗费的远远大于 Controller 层的。我们可以在 5 台服务器中拿 1 台部署 Controller 层,另外 4 台部署业务层代码。
如果将他们连接起来呢?
Eureka + Feign!
Eureka 做注册中心,业务层和控制器层每一个实例可以作为一个服务,比如 UserService 是一个服务,UserController 也可以是一个服务,一个服务可以有多个状态(可以有多台机器注册到该服务)。
下面通过一个例子来讲解
源码地址:https://github.com/saysky/spring-cloud-demo
一、下载源码
请上 Github 上下载本例子源码源码地址:https://github.com/saysky/spring-cloud-demo
二、项目结构
注意这是三个项目(不是一个项目),用 IDEA 打开分别打开三个项目,最终如图1、eureka-server(一个 SpringBoot 项目)
2、cloud (一个多模块项目,API + 业务层)
(1)其中 cloud-api 是 api,里面有 model 和 service接口,cloud-core 和 cloud-web 将依赖它
到时候需要首先将该模块 install,即打包到本地仓库中
(2)其中 cloud-core,里面 dao 和 serviceImpl,作为生产者的存在
启动类在这里面
3、cloud-web( 一个 SpringBoot 项目)
只有控制器层,需要依赖 cloud-api ,作为消费者的存在(可以是其他人调用)
三、如何启动
1、新建数据库 summer,导入 user.sql2、导入新项目,先后顺序随便(如eureka-server、cloud、cloud-web)
3、启动 eureka-server 项目,端口为 8761
4、对 cloud 项目中的 cloud-api 模块进行install,maven命令是 mvn clean install
5、启动 cloud-core 项目,端口为 8090
6、(可选)其实这时候我们可以在地址栏访问一下 localhost:8090/user 其实是可以访问的,如果你不行,说明有问题
7、启动 cloud-web 项目,端口为 8080
8、在地址栏访问 localhost:8080/user,如果可以看到数据,说明成功
四、补充
1、我这里模拟了四台注册了业务层服务(cloud-producer) 和 一台控制器层服务(cloud-consumer)ps:因为我是用本机测试,所以开了不同的端口表示不同的服务器
2、访问控制器层,然后 Feign 会帮我们在注册中心中找到对应的服务名和对应的方法
我们访问 localhost:8080/user/1 首先到的是控制器层,控制器层调用 userService,userService 是 Cloud-API 里的,添加了 @FeignClient(name="cloud-producer") 注解,然后找到在注册中心中寻找 cloud-producer 的服务,从一台(负载均衡)服务器中找到 userService 的实现类,即 userServiceImpl,也就是进入了 cloud-core,然后完成一系列 DAO 和 Service 操作,最后返回给 Controller。
其中 Service 和 Service 的实现都需要加 RequestMapping,Service 实现需要加 @RestController,否则会出现 404
所以,其实我们可以直接访问 cloud-core 这一层,在地址栏访问 localhost:8090/user/1
事实上,我们访问 控制器的时候,当需要某个 Service 的时候,Feign 帮我们向 Service 又发了一个同样的请求。我们可以直接访问这个 Service 请求
但是,通常我们会在生产环境中,不让别人直接访问到 Service,可以通过一些机制实现,比如内网啦。
六、学习过程中遇到的问题
1、cloud-web 中注入 userService,一直注入失败,无法扫描到 userServiceImpl解决方案:在 cloud-web 启动类上添加
@EnableFeignClients(basePackages = "com.liuyanzhao.cloud")
2、出现 404 错误
cloud-core 里的 userServiceImpl 也需要加 @RequestMapping,并且需要将 @Service 改成 @RestController
UserService(cloud-api)
UserServiceImpl(cloud-core)
2021年11月16日 16:36:48
运行时没有增,修改,删除
2020年04月03日 16:48:32
感谢楼主分享!
2019年09月30日 16:05:31
有两个问题 工程目录 放到的不对 cloud-web应该放到cloud文件夹下pom里module加下 第二个问题 访问数据库要加 ?serverTimezone=UTC 不然报错
2019年09月30日 15:26:54
test测试
2019年03月29日 13:31:26
思路清晰,一步一步引导的好文章,十分感谢!!!
2019年02月08日 10:47:55
看了你的源码,感觉学到了很多,但是有点不明白的地方,请问,为啥web作为消费者,在消费的时候还要指定包路径,@EnableFeignClients(basePackages = "com.cad.largescreen.cloud") ?