为什么使用springcloud呢?
最开始我们用的都是单一架构(all in one),为什么会演变成垂直架构应用(vertical application)呢,由于我们最开始的用户本来就少,10几年前20年前貌似电脑没有多少人家有的把,网页也都是静态页面,访问量根本不用担心,而且所有业务都在同一里面,当我们修改了一个地方,哪怕仅仅是一个页面的一个汉字,整个系统都要重新部署修改,系统模块之间耦合度太高,慢慢的就想到能不能把系统各个模块分开呢,也就出现了垂直架构,但是使用着慢慢也发现,尽管界面+业务逻辑实现了逻辑的分离,但是应用不可能完全独立,大量的应用之间需要交互,耦合度还是比较高,而且用户也逐渐增多,部署在一个机器上承受不了这么大的访问量,这也就出现了SOA架构,SOA架构对系统又进行了粒度细化,将一个大的系统服务拆分成多个子服务,部署到不同机器上,通过rpc或者webservice实现模块之间的交互,而现在逐渐演变的微服务架构(microservice),则是将服务更加颗粒化,使之耦合度更低,因此微服务是现在的趋势,而springcloud则是微服务的一个代表。
eureka注册中心
由于上面我们所说的,将一个大的系统服务拆分成多个小的子系统,那么系统之间通信就比较困难,我们以前通过webservice啥的进行通信,这样我们就需要知道要调用的服务的ip还有端口号信息,而且例如我子服务a知道b服务的ip端口,但是当b服务的ip或者端口修改后,我们还需要修改子服务a的信息,当我们系统足够大,并且子服务足够多的时候,系统之间通信就变得非常乱,不好维护,而eureka则解决了这一问题,所有子服务都将自己的ip端口信息都注册给eureka,由eureka帮我们实现统一管理,比如服务a需要与服务b进行通信,服务a不需要知道b服务的ip及端口了,因为服务b已经将自己的信息注册到了eureka上了,我们只需要在eureka上查就可以了,当服务b信息修改了,服务b会自动提交给eureka最新的信息,服务a完全不受影响。
搭建项目结构
在此之前,我们可以先把简单的项目结构搭建起来,无非就是用maven创建多模块项目,不会的可以参考maven多模块搭建步骤这篇文章,完成后大致结构如下图所示:
由于demo_parent作为整个项目的父项目,作用: 同一项目版本和公共依赖的引入,所以先将依赖在pom文件中引入。
1
2<project xmlns="http://maven.apache.org/POM/4.0.0"
3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5 <modelVersion>4.0.0modelVersion>
6 <groupId>com.lytw13groupId>
7 <artifactId>demo_parentartifactId>
8 <packaging>pompackaging>
9 <version>1.0-SNAPSHOTversion>
10 <modules>
11 <module>../demo_apimodule>
12 <module>../demo_sysmodule>
13 <module>../demo_configurationmodule>
14 <module>../demo_webmodule>
15 modules>
16
17 <properties>
18 <project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
19 <maven.compiler.encoding>UTF-8maven.compiler.encoding>
20 <java.version>11java.version>
21 <maven.compiler.source>11maven.compiler.source>
22 <maven.compiler.target>11maven.compiler.target>
23 <spring-boot-version>2.1.9.RELEASEspring-boot-version>
24 <spring-cloud.version>Greenwich.SR3spring-cloud.version>
25 <project.version>1.0-SNAPSHOTproject.version>
26 properties>
27 <dependencyManagement>
28 <dependencies>
29
30 <dependency>
31 <groupId>org.springframework.bootgroupId>
32 <artifactId>spring-boot-dependenciesartifactId>
33 <version>${spring-boot-version}version>
34 <type>pomtype>
35 <scope>importscope>
36 dependency>
37
38 <dependency>
39 <groupId>org.springframework.cloudgroupId>
40 <artifactId>spring-cloud-dependenciesartifactId>
41 <version>${spring-cloud.version}version>
42 <type>pomtype>
43 <scope>importscope>
44 dependency>
45 dependencies>
46 dependencyManagement>
47 <dependencies>
48
49 <dependency>
50 <groupId>org.springframework.bootgroupId>
51 <artifactId>spring-boot-starter-webartifactId>
52 dependency>
53
54 <dependency>
55 <groupId>org.springframework.bootgroupId>
56 <artifactId>spring-boot-starter-testartifactId>
57 <scope>testscope>
58 dependency>
59
60 <dependency>
61 <groupId>org.springframework.bootgroupId>
62 <artifactId>spring-boot-starter-actuatorartifactId>
63 dependency>
64
65 <dependency>
66 <groupId>com.alibabagroupId>
67 <artifactId>fastjsonartifactId>
68 <version>1.2.62version>
69 dependency>
70
71 <dependency>
72 <groupId>org.springframework.bootgroupId>
73 <artifactId>spring-boot-starter-mailartifactId>
74 dependency>
75 dependencies>
76project>
eureka注册中心搭建步骤
- 由上面的结构图可以看出,eureka_parent是所有项目的父项目,而demo_configuration则又是demo_eureka,demo_config、demo_zuul的父项目,所以可以将这3个子项目的依赖放在demo_configuration中。
1
2<project xmlns="http://maven.apache.org/POM/4.0.0"
3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5 <parent>
6 <artifactId>demo_parentartifactId>
7 <groupId>com.lytw13groupId>
8 <version>1.0-SNAPSHOTversion>
9 parent>
10 <modelVersion>4.0.0modelVersion>
11 <artifactId>demo_configurationartifactId>
12 <packaging>pompackaging>
13 <modules>
14 <module>../demo_eurekaServermodule>
15 <module>../demo_configmodule>
16 <module>../demo_zuulmodule>
17 modules>
18 <dependencies>
19
20 <dependency>
21 <groupId>org.springframework.cloudgroupId>
22 <artifactId>spring-cloud-starter-netflix-eureka-serverartifactId>
23 dependency>
24 dependencies>
25project>
- demo_eureka用于eureka注册中心相关的配置。
(1) 添加eureka主启动类
1package com.lytw13.demo;
2import org.springframework.boot.SpringApplication;
3import org.springframework.boot.autoconfigure.SpringBootApplication;
4import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
5
6@EnableEurekaServer
7@SpringBootApplication
8public class EurekaApplication {
9 public static void main(String[] args) {
10 SpringApplication.run(EurekaApplication.class,args);
11 }
12}
(2) 新建eureka配置文件application.yml。
1server:
2 port: 6001
3
4spring:
5 application:
6 name: eureka
7eureka:
8 instance:
9 ip-address: true
10 instance-id: eureka01
11 client:
12 fetch-registry: false
13 register-with-eureka: false
14 service-url:
15 defaultZone: http://localhost:6001/eureka/
- 启动eureka,测试是否成功。
(1) 启动项目。
(2) 启动完成后,访问配置的路径 localhost:端口号,查看是否启动成功。
springcloud_eureka_ceshi.png
服务注册到eureka
现在尽管我们有了eureka注册中心,但是没有任何服务,我们需要将我们项目中的服务注册到注册中心上,这样我们才能实现服务之前的通信。
这里以demo_sys_user用户服务为例,其他步骤类似。因为demo_sys_user是demo_sys的子模块,所以我们只需要将依赖添加到demo_sys上即可,这样demo_sys下的其他子模块也就可以同时使用,比如连接数据库的相关依赖,这样就实现了依赖的统一管理。
- demo_sys POM文件
1
2<project xmlns="http://maven.apache.org/POM/4.0.0"
3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5 <parent>
6 <artifactId>demo_parentartifactId>
7 <groupId>com.lytw13groupId>
8 <version>1.0-SNAPSHOTversion>
9 parent>
10 <modelVersion>4.0.0modelVersion>
11
12 <artifactId>demo_sysartifactId>
13 <packaging>pompackaging>
14 <modules>
15 <module>../demo_sys_usermodule>
16 <module>../demo_sys_rolemodule>
17 <module>../demo_sys_menumodule>
18 <module>../demo_sys_noticemodule>
19 modules>
20 <dependencies>
21
22 <dependency>
23 <groupId>com.lytw13groupId>
24 <artifactId>demo_apiartifactId>
25 <version>1.0-SNAPSHOTversion>
26 dependency>
27
28 <dependency>
29 <groupId>org.springframework.cloudgroupId>
30 <artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
31 dependency>
32
33 <dependency>
34 <groupId>mysqlgroupId>
35 <artifactId>mysql-connector-javaartifactId>
36 dependency>
37 <dependency>
38 <groupId>org.mybatis.spring.bootgroupId>
39 <artifactId>mybatis-spring-boot-starterartifactId>
40 <version>2.1.1version>
41 dependency>
42 <dependency>
43 <groupId>com.alibabagroupId>
44 <artifactId>druid-spring-boot-starterartifactId>
45 <version>1.1.20version>
46 dependency>
47 dependencies>
48project>
- demo_sys_user添加主启动类
1package com.lytw13.demo;
2
3import org.springframework.boot.SpringApplication;
4import org.springframework.boot.autoconfigure.SpringBootApplication;
5import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
6
7@SpringBootApplication
8@EnableEurekaClient //开启eureka客户端
9public class UserApplication {
10 public static void main(String[] args) {
11 SpringApplication.run(UserApplication.class,args);
12 }
13}
- demo_sys_user yml配置文件
1server:
2 port: 7001
3
4spring:
5 application:
6 name: user
7 datasource:
8 driver-class-name: com.mysql.cj.jdbc.Driver
9 url: jdbc:mysql://localhost:3306/db_demo_sys?serverTimezone=Asia/Shanghai
10 username: root
11 password: 123456
12 type: com.alibaba.druid.pool.DruidDataSource
13 druid:
14 # 连接池的配置信息
15 # 初始化大小,最小,最大
16 initial-size: 5
17 min-idle: 5
18 maxActive: 20
19 # 配置获取连接等待超时的时间
20 maxWait: 60000
21 filters: stat,wall,slf4j
22
23mybatis:
24 mapper-locations: classpath:mapper/*.xml
25 config-location: classpath:mybatis/mybatis.xml
26
27
28
29info:
30 name: lytw13
31 web: lytw13.top
32eureka:
33 client:
34 service-url:
35 defaultZone: http://localhost:6001/eureka/
36 fetch-registry: true
37 register-with-eureka: true
38 instance:
39 instance-id: user01
40 ip-address: true
41
42logging:
43 level:
44 com:
45 lytw13:
46 microservice:
47 dao: debug
启动该项目,查看eureka上是否有了该服务。
可以看到user已经注册到了eureka上,其他服务注册相同,不再赘述。
eureka服务注册的大概结构如下:
springcloud_eureka_jiegoutu.png尽管这样,还是需要修改一些内容,我们将服务注册到eureka上,不仅仅是为了注册到上面,而是为了让其他服务可以调用,而我们上面的项目结构图可以看到demo_api项目是为了将公共接口,实体类,工具类抽取出来,因此我们可以将userservice接口还有实体类工具类的创建到demo_api里,下面接口代码列在下面,实体类就不用了吧,方法的返回值BaseResult是自己封装好的,当然可以直接返回实体类或者list啥的,这里是为了统一返回结果,方便处理。
- UserService
1package com.lytw13.demo.service;
2
3import com.lytw13.demo.model.BaseResult;
4import org.springframework.web.bind.annotation.*;
5
6@RequestMapping(value = "/user")
7public interface UserService {
8 @GetMapping("/get/{id}")
9 public BaseResult get(@PathVariable("id") Integer id);
10 @GetMapping("/list")
11 public BaseResult list();
12}
- BaseReuslt
1package com.lytw13.demo.model;
2
3import lombok.*;
4
5@AllArgsConstructor
6@NoArgsConstructor
7@Getter
8@Setter
9@ToString
10public class BaseResult {
11 private Integer resultCode;
12 private String resultMsg;
13 private Object resultData;
14}
- ResponseResult
1package com.lytw13.demo.utils;
2
3
4import com.lytw13.demo.model.BaseResult;
5
6public class ResponseResult {
7 public BaseResult setResult(Integer resultCode, String resultMsg, Object resultData){
8 return new BaseResult(resultCode, resultMsg, resultData);
9 }
10 public BaseResult setResultSuccess(Object resultData) {
11 return new BaseResult(200,"success",resultData);
12 }
13 public BaseResult setResultFail(String msg) {
14 return new BaseResult(400,msg,null);
15 }
16}
接着我们只需要编写demo_sys_user类了,具体无非也是实现上面的UserService接口,通过usermapper调用数据库,这里不再赘述了。编写完成后启动项目,通过application.yml中设置的端口访问方法,看看能否访问成功。
user_ceshi1.png user_ceshi2.png以前我们通过ip加端口访问,可以通过spring中的自带的RestTemplete进行访问。
这里我们使用demo_web作为消费者,调用demo_sys_user服务。
1package com.lytw13.demo.controller;
2
3import com.lytw13.demo.model.BaseResult;
4import org.springframework.beans.factory.annotation.Autowired;
5import org.springframework.web.bind.annotation.*;
6import org.springframework.web.client.RestTemplate;
7
8@RestController
9@RequestMapping("/user")
10public class UserController {
11 @Autowired
12 RestTemplate restTemplate;
13 @GetMapping("getUser")
14 public BaseResult getUser(Integer id) {
15 BaseResult baseResult = restTemplate.getForObject("http://localhost:7001/user/get/"+id, BaseResult.class);
16 return baseResult;
17 }
18}
我们可以看到端口还有ip都是暴露的,这样肯定是不好的,因此我们就需要添加Ribbon来实现本地负载均衡,将上面的ip端口用在eureka注册中心的服务名来写。
1package com.lytw13.demo.controller;
2
3import com.lytw13.demo.model.BaseResult;
4import org.springframework.beans.factory.annotation.Autowired;
5import org.springframework.web.bind.annotation.*;
6import org.springframework.web.client.RestTemplate;
7
8@RestController
9@RequestMapping("/user")
10public class UserController {
11 @Autowired
12 RestTemplate restTemplate;
13 @GetMapping("getUser")
14 public BaseResult getUser(Integer id) {
15 BaseResult baseResult = restTemplate.getForObject("http://USER/user/get/"+id, BaseResult.class);
16 return baseResult;
17 }
18}
eureka服务之间调用的大概结构如下:
springcloud_eureka_diaoyong_jiegoutu.png