1. SpringCloud特點(diǎn)
SpringCloud專注于為典型的用例和擴(kuò)展機(jī)制提供良好的開箱即用體驗(yàn),以涵蓋其他情況:
- 分布式/版本化配置
- 服務(wù)注冊(cè)和發(fā)現(xiàn) Eureka
- 路由 Zuul
- 服務(wù)到服務(wù)的呼叫
- 負(fù)載均衡 Ribbon
- 斷路器 Hystrix
- 分布式消息傳遞
2. 分布式系統(tǒng)的三個(gè)指標(biāo)CAP
在介紹SpringCloud默認(rèn)使用的注冊(cè)中心前,先介紹分布式系統(tǒng)的三個(gè)指標(biāo),分別是:
- Consistency:一致性,在分布式系統(tǒng)中,更新操作執(zhí)行成功后所有的用戶的讀操作必須返回最新值;client寫入,server同步至整個(gè)系統(tǒng);
- Availability:可用性,只要收到用戶的請(qǐng)求,在一定的時(shí)間內(nèi)服務(wù)器就必須給出回應(yīng),回應(yīng)的結(jié)果可以是成功或是失敗;
- Partition tolerance:分區(qū)容錯(cuò),即區(qū)間通信可能失敗,在網(wǎng)絡(luò)中斷,消息丟失的情況下,仍對(duì)外提供服務(wù);一般無(wú)法避免,可以認(rèn)為CAP中的P總是成立
CAP定律說(shuō)的是,在一個(gè)分布式計(jì)算機(jī)系統(tǒng)中,一致性C,可用性A,分區(qū)容錯(cuò)性P這三種保證無(wú)法同時(shí)得到滿足,最多滿足兩個(gè):
1.放棄P
為了避免分區(qū)容錯(cuò)性問題的發(fā)生,一種做法是將所有與事務(wù)相關(guān)的數(shù)據(jù)都放在一臺(tái)服務(wù)器上,雖然不能保證100%系統(tǒng)不會(huì)出錯(cuò),但是不會(huì)碰到由分區(qū)帶來(lái)的負(fù)面效果,這樣的做法會(huì)嚴(yán)重影響系統(tǒng)的擴(kuò)展性。
2.放棄A
放棄可用性,一旦遇到分區(qū)容錯(cuò)故障,受到影響的服務(wù)器需要等待一定的時(shí)間,因此會(huì)導(dǎo)致在等待期間系統(tǒng)無(wú)法對(duì)外提供服務(wù)。
3.放棄C
這兒說(shuō)的放棄一致性,并不是完全放棄數(shù)據(jù)的一致性,而是放棄數(shù)據(jù)的強(qiáng)一致性,而保留數(shù)據(jù)的最終一致性。以網(wǎng)絡(luò)購(gòu)物為例,對(duì)只剩下一件庫(kù)存的商品,如果同時(shí)接受到了兩份訂單,那么較晚的訂單將被告知商品告罄。
文中部分CAP理論摘自:https://www.cnblogs.com/hxsyl/p/4381980.html
3. Eureka
基本介紹
Eureka是SpringCloud官方推薦用于服務(wù)注冊(cè)和發(fā)現(xiàn),一個(gè)基于REST的服務(wù)
SpringBoot實(shí)現(xiàn)了Netflix OSS的集成,使用Eureka的原因之一是因?yàn)槠淇梢岳肧pring Cloud Netflix的其他組件:智能路由(Zuul)、客戶端負(fù)載均衡(Ribbon)等
基本組成
Eureka由多個(gè)Instance(服務(wù)實(shí)例)組成,分為Eureka Server和Eureka Client
其中Eureka Client又可細(xì)分為:Service Provider、Service Consumer
- Eureka Server:服務(wù)端,提供服務(wù)的注冊(cè)和發(fā)現(xiàn);
- Eureka Client:客戶端
Service Provider:服務(wù)提供方,將自身服務(wù)注冊(cè)到Eureka,讓消費(fèi)方找到Service Consumer:服務(wù)消費(fèi)方,從Eureka獲取注冊(cè)服務(wù)列表,從而消費(fèi)服務(wù)
Eureka和Zookeeper
1)由CAP理論的角度來(lái)看
Zookeeper:ZK保證CP,突出強(qiáng)一致性,但無(wú)法保證每次訪問服務(wù)可用性,比如ZK會(huì)出現(xiàn)這樣一種情況:當(dāng)master節(jié)點(diǎn)因?yàn)榫W(wǎng)絡(luò)故障與其他節(jié)點(diǎn)失去聯(lián)系時(shí),剩余節(jié)點(diǎn)會(huì)重新進(jìn)行l(wèi)eader選舉,在ZK選舉leader期間整個(gè)ZK集群都是不可用的,這就導(dǎo)致了在選舉期間注冊(cè)服務(wù)癱瘓。在云部署的環(huán)境下,因網(wǎng)絡(luò)問題使得ZK集群失去master節(jié)點(diǎn)是較大概率會(huì)發(fā)生的事兒,雖然服務(wù)最終會(huì)恢復(fù),但是漫長(zhǎng)的選舉時(shí)間導(dǎo)致的注冊(cè)長(zhǎng)期不可用是難以容忍的。
Eureka:Eureka保證AP,Eureka在設(shè)計(jì)時(shí)就優(yōu)先保證可用性。對(duì)于Eureka中的節(jié)點(diǎn),每個(gè)節(jié)點(diǎn)都是平等的,幾個(gè)節(jié)點(diǎn)掛掉也不會(huì)影響正常節(jié)點(diǎn)的工作,剩余的節(jié)點(diǎn)依然可以提供注冊(cè)和查詢服務(wù)。但Eureka不保證強(qiáng)一致性,即查到的信息可能不是最新的。此外Eureka還有一種自我保護(hù)機(jī)制,如果在15分鐘內(nèi)超過85%的節(jié)點(diǎn)都沒有正常的心跳,那么Eureka就會(huì)認(rèn)為客戶端和注冊(cè)中心出現(xiàn)了網(wǎng)絡(luò)故障,但會(huì)保證當(dāng)前節(jié)點(diǎn)依然可用,不會(huì)像ZK導(dǎo)致整個(gè)注冊(cè)服務(wù)癱瘓。
2)由節(jié)點(diǎn)分工的角度來(lái)看
Zookeeper:ZK集群中節(jié)點(diǎn)分為三類,承擔(dān)不同的任務(wù)
- Leader:事務(wù)請(qǐng)求唯一的調(diào)度者和處理者(除了查詢請(qǐng)求)
- Follower:處理非事務(wù)請(qǐng)求,參與Leader選舉投票
- Observer:處理非事務(wù)請(qǐng)求,但不參與Leader選舉投票
Eureka:在Eureka集群中每個(gè)節(jié)點(diǎn)都是平等的,每個(gè)節(jié)點(diǎn)扮演相同的角色,它們通過相互注冊(cè)的方式來(lái)感知對(duì)方的存在,當(dāng)由注冊(cè)消息時(shí),它們會(huì)同步給集群內(nèi)的其他節(jié)點(diǎn)
中文文檔:https://www.springcloud.cc/spring-cloud-greenwich.html
4. SpringCloud Demo
Demo整體結(jié)構(gòu)(父子項(xiàng)目)
- api:Bean、DTO、POJO等以及Service接口
- controller:服務(wù)消費(fèi)方,前端交互
- provider:服務(wù)提供方,服務(wù)實(shí)現(xiàn)
- registry:服務(wù)注冊(cè)中心
4.1 registry
1)pom.xml
關(guān)鍵點(diǎn)在于導(dǎo)入eureka服務(wù)端依賴以及SpringCloud依賴
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
<dependencies> <!-- https: //mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-netflix-eureka-server --> <!-- eureka服務(wù)端 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> <version> 2.2 . 5 .RELEASE</version> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Hoxton.SR6</version> <type>pom</type> <scope> import </scope> </dependency> </dependencies> </dependencyManagement> |
2)application.properties
進(jìn)行Eureka服務(wù)端的相關(guān)配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
spring.application.name=SpringCloudDemoRegistry # server端口,自己喜歡 server.port= 8888 # Eureka Server服務(wù)url以及默認(rèn)zone,結(jié)尾必須eureka eureka.client.service-url.defaultZone= http: //127.0.0.1:8888/eureka/ # eureka的自我保護(hù)機(jī)制,k8s環(huán)境下建議 false eureka.server.enable-self-preservation= false # false 表示自己端就是注冊(cè)中心,我的功能就是維護(hù)服務(wù)實(shí)例,不需要從server獲取注冊(cè)的服務(wù)信息 eureka.client.fetch-registry= false # false 表示不將自己注冊(cè)到Eureka Server eureka.client.register-with-eureka= false |
3)EurekaregistryApplication
使用@EnableEurekaServer激活相關(guān)配置,使registry模塊作為注冊(cè)中心Server
1
2
3
4
5
6
7
|
@EnableEurekaServer //聲明為注冊(cè)中心服務(wù)端 @SpringBootApplication public class EurekaregistryApplication { public static void main(String[] args) { SpringApplication.run(EurekaregistryApplication. class , args); } } |
4.2 api
1)entity
實(shí)體類以部門和用戶信息為例,由于演示使用了Lombok省點(diǎn)代碼,用于實(shí)現(xiàn)基本的CRUD
Department.class
1
2
3
4
5
6
7
8
9
10
|
@Data @ToString @NoArgsConstructor @AllArgsConstructor public class Department { private Long id; private Integer dId; private String dName; private Date updateTime; } |
UserInfo.class
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
@Data @ToString @NoArgsConstructor @AllArgsConstructor public class UserInfo { private Long id; private Integer uId; private Integer dId; private String uName; private String uPhone; @Email (message = "非法郵件格式" ) //Validator格式校驗(yàn) private String uEmail; private String uAddress; private Date updateTime; private Department department; } |
2)UserService
UserService為服務(wù)接口,聲明需要提供和消費(fèi)的方法,寫了幾個(gè)簡(jiǎn)單查詢
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
public interface UserService { /** * 判斷用戶是否存在,0為不存在,返回值與uId相等則存在 * @param uId * @return */ Integer userExist(Integer uId); /** * 獲取用戶個(gè)人基本信息 * @param uId * @return */ UserInfo getUserInfo(Integer uId); /** * 獲取用戶個(gè)人詳情信息 * @param uId * @return */ UserInfo getUserDetailsInfo(Integer uId); } |
4.3 provider
1)pom.xml
關(guān)鍵點(diǎn)是引入eureka客戶端依賴、openfeign依賴、SpringCloud依賴
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
<dependencies> <!-- Springboot的依賴省略... --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Hoxton.SR6</version> <type>pom</type> <scope> import </scope> </dependency> </dependencies> </dependencyManagement> |
2)application.properties
配置Eureka、Mybatis以及DataSource數(shù)據(jù)源等信息
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
spring.application.name=SpringCloudDemoProvider # Server端口 server.port= 9999 # Eureka服務(wù)url eureka.client.service-url.defaultZone= http: //127.0.0.1:8888/eureka/ eureka.client.register-with-eureka= true eureka.client.fetch-registry= true # Mybatis mybatis.mapper-locations= classpath:com.maziyao.provider.mapper/*.xml mybatis.type-aliases- package = com.maziyao.common.entity # DataSource數(shù)據(jù)源配置 spring.datasource.type=com.zaxxer.hikari.HikariDataSource # DataSource spring.datasource.driver- class -name=com.mysql.cj.jdbc.Driver spring.datasource.url=jdbc:mysql: //localhost:3306/boot-demo?serverTimezone=UTC spring.datasource.username=root spring.datasource.password=root |
3)EurekaproviderApplication
provider啟動(dòng)類使用@EnableEurekaClient聲明為EurekaClient客戶端,作為ServiceProvider
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
@EnableEurekaClient @SpringBootApplication @EnableAspectJAutoProxy @MapperScan ( "com.maziyao.provider.mapper" ) @ComponentScan (basePackages = { "com.maziyao.provider.rest" , "com.maziyao.provider.redis" , "com.maziyao.provider.service" , "com.maziyao.provider.config" }) public class EurekaproviderApplication { public static void main(String[] args) { SpringApplication.run(EurekaproviderApplication. class , args); } } |
4)service
UserServiceImpl作為UserService接口實(shí)現(xiàn)類,@Service用于標(biāo)注業(yè)務(wù)層組件
自動(dòng)注入mapper層的mapper接口并調(diào)用,mapper的SQL語(yǔ)句下面就略了,很簡(jiǎn)單
需要注意的是,對(duì)于數(shù)據(jù)訪問層組件mapper,使用@Repository進(jìn)行標(biāo)注
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
@Service ( "userService" ) public class UserServiceImpl implements UserService { @Autowired private UserMapper userMapper; @Override public Integer userExist(Integer uId) { return userMapper.userExist(uId); } @Override public UserInfo getUserInfo(Integer uId) { return userMapper.getUserInfo(uId); } @Override public UserInfo getUserDetailsInfo(Integer uId) { return userMapper.getUserDetailsInfo(uId); } } |
5)rest
重點(diǎn)是rest包下的UserServer,要知道Eureka是一個(gè)基于REST的服務(wù)
使用@RestController標(biāo)注并聲明為userServer,這個(gè)是SpringBoot注解,用于標(biāo)注控制層組件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
@RestController ( "userServer" ) public class UserServer { public static final Logger logger = LoggerFactory.getLogger(UserServer. class ); @Autowired private UserService userService; @ResponseBody @RequestMapping (value = "/exist" ,method = RequestMethod.GET) public Integer existUserByUid( @RequestParam ( "uId" )Integer uId){ return userService.userExist(uId); } @ResponseBody @RequestMapping (value = "/userInfo" ,method = RequestMethod.GET) public UserInfo getUserInfo( @RequestParam ( "uId" )Integer uId){ return userService.getUserInfo(uId); } @ResponseBody @RequestMapping (value= "/userDetailsInfo" ,method = RequestMethod.GET) public UserInfo getUserDetailsInfo( @RequestParam ( "uId" )Integer uId){ return userService.getUserDetailsInfo(uId); } } |
4.4 consumer
1)pom.xml
在Controller的pom.xml中也需要導(dǎo)入EurekaClient的依賴,對(duì)于Provider和Controller都為Client
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
<dependencies> <!-- SpringBoot依賴省略... --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> <version> 2.2 . 5 .RELEASE</version> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> <version> 2.2 . 5 .RELEASE</version> </dependency> </dependencies> |
2)application.properties
在application.properties中配置Eureka相關(guān)信息
1
2
3
4
5
6
7
8
9
|
spring.application.name=springCloudDemoController # Server端口 server.port= 8899 # 注冊(cè)中心url eureka.client.service-url.defaultZone= http: //127.0.0.1:8888/eureka/ eureka.client.register-with-eureka= true eureka.client.fetch-registry= true |
3)EurekacontrollerApplication
與Provider的啟動(dòng)類一致,聲明啟動(dòng)類為Eureka的客戶端
并使用@EnableFeignClients開啟Feign,聲明性的web服務(wù)客戶端
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
@EnableEurekaClient @EnableFeignClients @SpringBootApplication @EnableAspectJAutoProxy @ComponentScan ({ "com.maziyao.controller.config" , "com.maziyao.controller.controller" , "com.maziyao.controller.rest" }) public class EurekacontrollerApplication { public static void main(String[] args) { SpringApplication.run(EurekacontrollerApplication. class , args); } } |
4)rest
controller作為前端交互層,即控制層,此處UserClient聲明調(diào)用方法
使用@FeignClient聲明服務(wù)提供方在application.properties中配置的spring.application.name
以及綁定服務(wù)提供方對(duì)應(yīng)rest包下的UserServer類的@RestController("userServer")
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
@FeignClient (name = "springCloudDemoProvider" ,contextId = "userServer" ) public interface UserClient { @ResponseBody @RequestMapping (value = "/exist" ,method = RequestMethod.GET) public Integer existUserByUid( @RequestParam ( "uId" )Integer uId); @ResponseBody @RequestMapping (value = "/userInfo" ,method = RequestMethod.GET) public UserInfo getUserInfo( @RequestParam ( "uId" )Integer uId); @ResponseBody @RequestMapping (value= "/userDetailsInfo" ,method = RequestMethod.GET) public UserInfo getUserDetailsInfo( @RequestParam ( "uId" )Integer uId); } |
5)UserController
控制層,使用@RestController標(biāo)注,并注入U(xiǎn)serClient進(jìn)行調(diào)用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
@RestController public class UserController { private static final Logger logger = LoggerFactory.getLogger(UserController. class ); @Autowired private UserClient userClient; @ResponseBody @RequestMapping (value = "/exist" ,method = RequestMethod.GET) public Integer existUserByUid( @RequestParam ( "uId" ) Integer uId){ return userClient.existUserByUid(uId); } @ResponseBody @RequestMapping (value = "/userInfo" ,method = RequestMethod.GET) public UserInfo getUserInfoByUid( @RequestParam ( "uId" )Integer uId){ return userClient.getUserInfo(uId); } @ResponseBody @RequestMapping (value = "/userDetailsInfo" ,method = RequestMethod.GET) public UserInfo getUserDetailsInfoByUid( @RequestParam ( "uId" )Integer uId){ return userClient.getUserDetailsInfo(uId); } } |
4.5 POSTMAN一下
注意:最后記得mvn install,需要先將registry運(yùn)行起來(lái),再分別運(yùn)行provider和controller
啟動(dòng)registry:
啟動(dòng)provider:
啟動(dòng)consumer:
result:
到此這篇關(guān)于SpringBoot整合SpringCloud的文章就介紹到這了,更多相關(guān)SpringBoot整合SpringCloud內(nèi)容請(qǐng)搜索服務(wù)器之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持服務(wù)器之家!
原文鏈接:https://www.cnblogs.com/torima/p/15277106.html
原文鏈接:https://www.cnblogs.com/torima/p/15277106.html