SpringCloud將如今一些流行的技術整合到一塊兒,實現如:配置管理,服務發現,智能路由,負載均衡,熔斷器,控制總線,集羣狀態等等功能。主要涉及的組件有html
java
Eureka:註冊中心 mysql
Zuul:服務網關git
Ribbon:負載均衡web
Feign:服務調用spring
Hystix:熔斷器sql
環境準備:一個數據庫和表tb_user數據庫
1.建立一個父工程,和子模塊consumer-demo,eureka-server,eureka-server2(兩個是eureka的高可用性練習),user-server,(user-server2是對user server的集羣練習能夠不要)zuul-Demo。json
(完整代碼:https://gitee.com/mountaincold/cloudDemo)api
2. 建立註冊中心 eureka-server
1.pom.xml 導入依賴 eureka服務端
2. 建立啓動類 eureka1
3. 設置application.yml
eureka-server2相同把端口換成10087,註冊地址換成10086就好了
2.建立服務提供者userservice
1. pom.xml的配置 導入依賴
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>tk.mybatis</groupId> <artifactId>mapper-spring-boot-starter</artifactId> </dependency> <!-- Eureka客戶端 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> </dependencies>
2. 設置application.yml配置文件
server: port: 8081 spring: datasource: url: jdbc:mysql://localhost:3306/mybatis username: root password: 960326 application: name: userservice logging: level: com.practice: debug eureka: client: service-url: #eurekaServer 地址 defaultZone: http://127.0.0.1:10086/eureka,http://127.0.0.1:10087/eureka instance: prefer-ip-address: true #當調用getHostname獲取實例的hostname時 返回ip而不是host名稱 ip-address: 127.0.0.1 #指定本身的ip信息 不指定的話會本身尋找 lease-expiration-duration-in-seconds: 10 #服務失效時間 默認90秒 lease-renewal-interval-in-seconds: 5 #服務續約時間的間隔,默認30秒 instance-id: ${spring.application.name}:${server.port} #設置id
2.建立啓動類,和pojo對象類
@Table(name = "tb_user") public class User implements Serializable { private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; // 用戶名 private String userName; // 密碼 private String password; // 姓名 private String name; // 年齡 private Integer age; // 性別,1男性,2女性 private Integer sex; // 出生日期 private Date birthday; // 建立時間 private Date created; // 更新時間 private Date updated; // 備註 // private String note; // 。。。省略getters和setters //TODO 須要手動添加getter,setter }
3.建立controller,service ,mapper
package com.practice.controller; import com.practice.pojo.User; import com.practice.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RequestMapping; @RestController @RequestMapping("user") public class UserController { @Autowired private UserService userService; @GetMapping("/{id}") public User queryById(@PathVariable("id") Long id) { return this.userService.queryById(id); } } /** *設置睡眠是爲了測試熔斷器 */ package com.practice.service; import com.practice.mapper.UserMapper; import com.practice.pojo.User; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service public class UserService { @Autowired private UserMapper userMapper; private static final Logger logger = LoggerFactory.getLogger(UserService.class); public User queryById(Long id) { Long startTime = System.currentTimeMillis(); int time = (int)(Math.random()*2000+1); try { Thread.sleep(time); } catch (InterruptedException e) { e.printStackTrace(); } User user = this.userMapper.selectByPrimaryKey(id); Long endTime = System.currentTimeMillis(); logger.info("本次查詢:{},花費時間爲{}ms",id,endTime-startTime); return user; } } /** *通用mapper的使用,能夠動態生成實現子類和查詢語言適用於單表查詢 */ package com.practice.mapper; import com.practice.pojo.User; import tk.mybatis.mapper.common.Mapper; public interface UserMapper extends Mapper<User> { }
3建立服務消費者cosumer-demo
1.pom.xml配置 須要的依賴
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- 添加OkHttp支持 --> <dependency> <groupId>com.squareup.okhttp3</groupId> <artifactId>okhttp</artifactId> <version>3.9.0</version> </dependency> <!-- Eureka客戶端 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <!--測試--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> </dependency> <!--Hystrix依賴--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> </dependency> <!--Feign的依賴--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> </dependencies>
2. application.xml的配置
Spring: application: name: consumer eureka: client: service-url: #eurekaServer地址 defaultZone: http://127.0.0.1:10086/eureka,http://127.0.0.1:10087/eureka registry-fetch-interval-seconds: 5 #獲取更新服務列表 默認時間爲30秒 instance: prefer-ip-address: true #當其它服務獲取地址時提供ip而不是hostname ip-address: 127.0.0.1 #指定本身的ip信息 不指定的話會本身尋找 ribbon: #修改服務負載均衡的分流規則 NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule #隨機 默認爲輪詢 ConnectTimeout: 250 # ribbon 鏈接超時時間 ReadTimeout: 1000 #Ribbon 數據讀取超時時間 feign: hystrix: enabled: true #開啓feign的熔斷支持默認關閉 compression: request: enabled: true # 開啓請求壓縮 mime-types: text/html,application/xml,application/json # 設置壓縮的數據類型 min-request-size: 2048 # 設置觸發壓縮的大小下限 logging: level: com.consumer: debug
3. 建立啓動類 和pojo對象類
package com; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.openfeign.EnableFeignClients; @EnableDiscoveryClient @SpringBootApplication //@EnableHystrix @EnableFeignClients public class Consumer { // @Bean // @LoadBalanced //開啓負載均衡 // public RestTemplate restTemplate(){ // // 使用OKHTTP客戶端,只需注入工廠 // return new RestTemplate(new OkHttp3ClientHttpRequestFactory()); // } // 由於Feign 中自動集成 Ribbon 負載均衡 因此不須要自定義RestTemplate public static void main(String[] args) { SpringApplication.run(Consumer.class); } } /** *屬性類型和user-service中相同可是不用加@table之類的註解 */ public class User { private static final long serialVersionUID = 1L; private Long id; // 用戶名 private String userName; // 密碼 private String password; // 姓名 private String name; // 年齡 private Integer age; // 性別,1男性,2女性 private Integer sex; // 出生日期 private Date birthday; // 建立時間 private Date created; // 更新時間 private Date updated; //TODO 須要手動添加getter,setter }
4. 建立 controller,service,config (dao是測試hystrix時建立的,feign中支持熔斷因此不用建立)
package com.consumer.controller; import com.consumer.pojo.User; import com.consumer.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import java.util.List; @RestController @RequestMapping("consume") public class ConsumerController { @Autowired private UserService userService; @GetMapping public List<User> consume(@RequestParam("ids")List<Long> ids){ return this.userService.queryUserByIds(ids); } } package com.consumer.service; import com.consumer.config.UserFeignClient; import com.consumer.config.impl.UserFeignClientImpl; import com.consumer.dao.UserDao; import com.consumer.pojo.User; //import com.netflix.discovery.DiscoveryClient; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.discovery.DiscoveryClient; import org.springframework.stereotype.Service; import org.springframework.web.client.RestTemplate; import java.util.ArrayList; import java.util.List; @Service public class UserService { /** * 根據服務名稱,獲取服務實例 * */ @Autowired private UserFeignClient userFeignClient; public List<User> queryUserByIds(List<Long> ids) { List<User> users = new ArrayList<>(); ids.forEach(id ->{ users.add(userFeignClient.queryById(id)); /* try { Thread.sleep(500); 線程睡眠用於測試能夠刪除 } catch (InterruptedException e) { e.printStackTrace(); }*/ }); return users; } } package com.consumer.config; import com.consumer.config.impl.FeignConfig; import com.consumer.config.impl.UserFeignClientImpl; import com.consumer.pojo.User; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; @FeignClient(value = "userservice",fallback = UserFeignClientImpl.class,configuration = FeignConfig.class) public interface UserFeignClient { @GetMapping("/user/{id}") public User queryById(@PathVariable("id") Long id); } package com.consumer.config.impl; import com.consumer.config.UserFeignClient; import com.consumer.pojo.User; import org.springframework.stereotype.Component; @Component public class UserFeignClientImpl implements UserFeignClient { @Override public User queryById(Long id) { User user = new User(); user.setId(id); user.setName("請求超時,請稍後重試--feign"); return user; } } package com.consumer.config.impl; import feign.Logger; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * 編寫配置類定義feign的日誌級別 feign支持四種級別 * - NONE:不記錄任何日誌信息,這是默認值。 * - BASIC:僅記錄請求的方法,URL以及響應狀態碼和執行時間 * - HEADERS:在BASIC的基礎上,額外記錄了請求和響應的頭信息 * - FULL:記錄全部請求和響應的明細,包括頭信息、請求體、元數據 */ @Configuration public class FeignConfig { @Bean Logger.Level feignLoggerLevel() { return Logger.Level.FULL; } }
4. 建立zuul網關
1.pom.xml中的依賴
<dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-zuul</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> </dependencies>
2. application.yml
server: port: 10010 spring: application: name: gateway zuul: routes: userservice: userservice/** #簡便方式 prefix: /api #添加路由前綴 # path: /userservice/** #這是映射路徑 # serviceId: userservice #指定服務名稱 # url: http://127.0.0.1:8081 映射路徑對應的實際url地址 eureka: client: registry-fetch-interval-seconds: 5 #循環獲取服務列表 service-url: defaultZone: http://127.0.0.1:10086/eureka instance: prefer-ip-address: true ip-address: 127:0.0.1
3. 建立啓動器
package com.zuul; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.netflix.zuul.EnableZuulProxy; @SpringBootApplication @EnableDiscoveryClient @EnableZuulProxy //開啓網關功能 public class Zuul { public static void main(String[] args) { SpringApplication.run(Zuul.class); } }
測試成功的頁面: