10分钟零基础带你入门Ribbon小项目-啥?小白都能看懂?
文章目錄
- 一、前置說明及其框架搭建
- 1、思路詳解
- 2、框架搭建
- 二、代碼編寫
- 1、編寫五個pom文件
- 1.1、父pom文件
- 1.2、子模塊pom
- 2、編寫啟動類
- 3、application.yml文件編寫
- 4、config文件配置
- 5、編寫controller層
- 6、entity層
- 7、service層
- 三、測試
一、前置說明及其框架搭建
1、思路詳解
由于設備限制,使用五個端口模擬五個服務(兩個注冊中心、兩個服務提供者、一個服務消費者)其中兩個注冊中心用來演示Eureka集群的高可用,兩個服務提供者用來演示Ribbon的負載均衡,一個服務消費者用來進行遠程調用)
#當然官網中是以三個注冊中心來演示Eureka集群高可用的,我用兩個當然也可以。
如果你了解過zookeeper、consul或者nacos作為注冊中心,這個對于你來說就比較簡單了。
2、框架搭建
通過聚合工程來創建一個父工程和五個子模塊
二、代碼編寫
1、編寫五個pom文件
1.1、父pom文件
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.hao</groupId><artifactId>cloud-eureka-demo</artifactId><packaging>pom</packaging><version>1.0-SNAPSHOT</version><modules><module>cloud-eureka-server</module><module>cloud-eureka-server02</module><module>service-provider</module><module>service-consumer</module><module>service-provider02</module></modules><parent><artifactId>spring-boot-starter-parent</artifactId><groupId>org.springframework.boot</groupId><version>2.4.3</version></parent><properties><spring-cloud.version>2020.0.2</spring-cloud.version></properties><dependencyManagement><dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><version>${spring-cloud.version}</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement></project>父工程主要就一個cloud依賴和五個子模塊以及繼承的父依賴。
1.2、子模塊pom
1、cloud-eureka-server、cloud-eureka-server02
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>cloud-eureka-demo</artifactId><groupId>com.hao</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>cloud-eureka-server</artifactId><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-server</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></dependency></dependencies> </project>這兩個eureka注冊模塊pom不被我們熟知的依賴是spring-cloud-starter-netflix-eureka-server,這個依賴繼承了eureka相關的所有包(包括Ribbon);導入spring-boot-starter-security的原因是對我們的注冊中心客戶端需要登錄認證
2、service-consumer
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>cloud-eureka-demo</artifactId><groupId>com.hao</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>service-consumer</artifactId><dependencies><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-web</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency></dependencies> </project>這個spring-cloud-starter-netflix-eureka-client和上面的spring-cloud-starter-netflix-eureka-server是兩種服務,從字面意思也應該都明白。
3、service-provider和service-provider02
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>cloud-eureka-demo</artifactId><groupId>com.hao</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>service-provider</artifactId><dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency></dependencies> </project>2、編寫啟動類
1、eureka-server子模塊的啟動類
@SpringBootApplication @EnableEurekaServer public class EurekaServerApplication {public static void main(String[] args) {SpringApplication.run(EurekaServerApplication.class);} }@EnableEurekaServer:該注解是自動識別為注冊服務中心
2、eureka-server02子模塊的啟動類
@SpringBootApplication @EnableEurekaServer public class EurekaServerApplication02 {public static void main(String[] args) {SpringApplication.run(EurekaServerApplication02.class);} }3、service-consumer子模塊啟動類
@SpringBootApplication @EnableEurekaClient public class ConsumerApplication {public static void main(String[] args) {SpringApplication.run(ConsumerApplication.class);} }@EnableEurekaClient注解在最新版已經可以省略
4、service-provider子模塊啟動類
@SpringBootApplication public class ProviderApplication {public static void main(String[] args) {SpringApplication.run(ProviderApplication.class);} }5、service-provider02子模塊啟動類
@SpringBootApplication @EnableEurekaClient public class Provider02Application {public static void main(String[] args) {SpringApplication.run(Provider02Application.class);} }3、application.yml文件編寫
1、eureka-server子模塊yml
server:port: 8080spring:application:name: cloud-eureka-serversecurity:user:name: rootpassword: root eureka:instance:hostname: eureka01prefer-ip-address: trueinstance-id: ${spring.cloud.client.ip-address}:${server.port}client:service-url:defaultZone: http://root:root@127.0.0.1:${server.port}/eureka/ #注冊中心對外暴露的注冊地址2、eureka-server02子模塊yml
server:port: 8081spring:application:name: cloud-eureka-server02security:user:name: rootpassword: root eureka:instance:hostname: eureka02prefer-ip-address: trueinstance-id: ${spring.cloud.client.ip-address}:${server.port}client:service-url:defaultZone: http://root:root@127.0.0.1:8080/eureka/3、eureka-consumer子模塊yml
server:port: 9090 spring:application:name: service-consumereureka:instance:hostname: consumerprefer-ip-address: trueinstance-id: http://${spring.cloud.client.ip-address}:${server.port}client: # fetch-registry: false # register-with-eureka: falseservice-url:defaultZone: http://root:root@127.0.0.1:8080/eureka/,http://root:root@127.0.0.1:8081/eureka/4、service-provider子模塊yml
server:port: 7070 spring:application:name: service-providereureka:instance:hostname: providerprefer-ip-address: trueinstance-id: http://${spring.cloud.client.ip-address}:${server.port}client:service-url:defaultZone: http://root:root@127.0.0.1:8080/eureka/,http://root:root@127.0.0.1:8081/eureka/5、service-provider02子模塊pom
server:port: 7071 spring:application:name: service-provider #集群下的名字是相同的eureka:instance:hostname: provider02prefer-ip-address: true #是否使用ip形式顯示instance-id: http://${spring.cloud.client.ip-address}:${server.port}client:service-url:defaultZone: http://root:root@127.0.0.1:8080/eureka/,http://root:root@127.0.0.1:8081/eureka/4、config文件配置
cloud-eureka-server 、cloud-eureka-server02
@EnableWebSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter {@Overrideprotected void configure(HttpSecurity http) throws Exception {//關閉某個path下的csrf,否者provider無法注冊進去super.configure(http);http.csrf().ignoringAntMatchers("/eureka/**");} }service-consumer
@Configuration public class ConsumerConfig {@Bean // @LoadBalancedpublic RestTemplate getRestTemplate() {return new RestTemplate();} }5、編寫controller層
service-consumer
@RestController public class OrderController {@Resourceprivate OrderService orderService;@GetMapping(value ="/order/{id}")public Order getOrderById(@PathVariable("id") Integer id) {return orderService.selectOrderById(id);} }service-provider 、service-provider02
@RestController @RequestMapping(value = "/product") public class ProductController {@Resourceprivate ProductService productService;@GetMapping(value = "/list")public List<Product> getProductList() {return productService.selectProductList();} }6、entity層
service-consumer
@Data @AllArgsConstructor @NoArgsConstructor public class Order {private Integer id;private String orderNo;private String orderAddress;private Double totalPrice;private List<Product> productList;}service-provider 、service-provider02
@Data @AllArgsConstructor @NoArgsConstructor public class Product {private Integer id;private String productName;private Integer productNum;private Double productPrice; } @Data @AllArgsConstructor @NoArgsConstructor public class Product {private Integer id;private String productName;private Integer productNum;private Double productPrice; }7、service層
service-consumer
public interface OrderService {Order selectOrderById(Integer id); } @Service public class OrderServiceImpl implements OrderService {@Autowiredprivate RestTemplate restTemplate;@Autowiredprivate DiscoveryClient discoveryClient;@Autowiredprivate LoadBalancerClient loadBalancerClient;@Overridepublic Order selectOrderById(Integer id) {return new Order(id, "order-1", "china", 1024D ,getProductListByLoadBalancerClient());}public List<Product> getProductListByDiscoveryClient() {StringBuffer sb = null;List<String> services = discoveryClient.getServices();if (CollectionUtils.isEmpty(services)) {return null;}//獲取name為service-provider的服務實例List<ServiceInstance> instances = discoveryClient.getInstances("service-provider");if (CollectionUtils.isEmpty(instances)) {return null;}ServiceInstance serviceInstance = instances.get(0);sb = new StringBuffer();//拼接地址sb.append("http://"+serviceInstance.getHost()+":"+serviceInstance.getPort()+"/product/list");ResponseEntity<List<Product>> exchange = restTemplate.exchange(sb.toString(), HttpMethod.GET, null, new ParameterizedTypeReference<List<Product>>() {});return exchange.getBody();}public List<Product> getProductListByLoadBalancerClient() {StringBuffer sb = null;ServiceInstance instance = loadBalancerClient.choose("service-provider");if (instance == null) {return null;}sb = new StringBuffer();sb.append("http://"+instance.getHost()+":"+instance.getPort()+"/product/list");System.out.println(instance.getHost()+":"+instance.getPort());ResponseEntity<List<Product>> exchange = restTemplate.exchange(sb.toString(), HttpMethod.GET, null, new ParameterizedTypeReference<List<Product>>() {});return exchange.getBody();}public List<Product> getProductListByAnnotation() {ResponseEntity<List<Product>> exchange = restTemplate.exchange("http://service-provider/product/list", HttpMethod.GET, null, new ParameterizedTypeReference<List<Product>>() {});System.out.println(exchange);return exchange.getBody();} }這是演示的三種方式實現
service-provider 、service-provider02
public interface ProductService {List<Product> selectProductList(); } @Service public class ProductServiceImpl implements ProductService {@Overridepublic List<Product> selectProductList() {return Arrays.asList(new Product(1, "HuaWei nova3", 100, 2999.0),new Product(2, "xiaomi", 99, 1999.0),new Product(3, "vivo", 102, 2999.0));} }#使用Arrays.asList模擬返回數據
三、測試
訪問http://localhost:8080/(賬號和密碼是在配置文件中配置的)
Eureka的高可用集群也搭建成功了
訪問http://localhost:9090/order/1
服務間調用也成功!
下面多次刷新該頁面,查看控制臺打印結果
負載均衡!
總結
以上是生活随笔為你收集整理的10分钟零基础带你入门Ribbon小项目-啥?小白都能看懂?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Eureka出现No instances
- 下一篇: 玩转Eureka+Ribbon系列之Ri