目录
3.Ribbon本地负载均衡客户端与Nginx服务器端负载均衡的区别
6..Feign客户端工具超时时间设置
1.客户端本地负载均衡原理
Ribbon本地负载均衡,默认使用的是轮循的策略,根据总请求数对服务器台数取模,得到实际下标服务器位置。
2.手写代码实现类似于Ribbon本地负载均衡效果
3.Ribbon本地负载均衡客户端与Nginx服务器端负载均衡的区别
4.声明式Feign客户端调用方式
SpringCloud中支持两种客户端调用工具:
1)RestTemplate 这种方式基本上实际开发中不用
2)Feign客户端工具,实际开发中使用此种方式
Feign是一个声明式的Http客户端调用工具,采用接口+注解方式实现,易读性比较强。
我们基于之前的springcloud-eureka-server,springcloud-member,springcloud-order 项目上进行演示:
基本上是在调用者 springcloud-order 项目上修改:
1.在pom文件上添加feign依赖
<!-- SpringBoot整合feign客户端 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>
2.新建接口 MemberApiFeign
package com.itmayiedu.feign; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.RequestMapping; @FeignClient("app-itmayiedu-member") public interface MemberApiFeign { // Feign 书写方式 以springmvc接口形式书写 // @FeignClient 调用接口的服务名称 @RequestMapping("/getMember") public String getMember(); }
1)@FeignClient :值为调用接口(会员服务)的服务名称
2)接口里的方法,是重写member项目中的方法:
3.新建FeignController,调用Feign接口
package com.itmayiedu.controller; import com.itmayiedu.feign.MemberApiFeign; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class FeignController { @Autowired private MemberApiFeign memberApiFeign; @RequestMapping("/feignMember") public String getMember(){ return memberApiFeign.getMember(); } }
4.在启动类中添加 @EnableFeignClients 注解
package com.itmayiedu;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
@EnableEurekaClient
@SpringBootApplication
@EnableFeignClients
public class SpringcloudOrderApplication {
public static void main(String[] args) {
SpringApplication.run(SpringcloudOrderApplication.class, args);
}
// 解决restTemplate找不到问题:将restTemplate注入到springboot容器中
@Bean
@LoadBalanced
RestTemplate restTemplate() {
return new RestTemplate();
}
}
5.启动eureka,member,order项目,浏览器访问:
5.基于Feign客户端进行项目重构
发现:我们发现,上述案例在member项目中写getMember实现时,在order项目调用此方法时,也需要写一个getMember的接口,这样如果有很多实现方法时,我们要写很多接口,就很不方便了,所以我们要进行项目重构。
项目重构结构:
springcloud-parent 父工程,pom类型,存放共同的依赖信息
—— springcloud-api-service 接口模块,pom类型,只有接口没有实现
———— springcloud-api-member-service 会员接口模块
———— springcloud-api-order-service 订单接口模块
—— springcloud-member-service-impl 会员接口实现模块
—— springcloud-order-service-impl 订单接口实现模块
5.1.springcloud-parent
1) 项目结构
2)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.itmayiedu</groupId> <artifactId>springcloud-parent</artifactId> <version>1.0-SNAPSHOT</version> <packaging>pom</packaging> <modules> <module>springcloud-api-service</module> <module>springcloud-order-service-impl</module> <module>springcloud-member-service-impl</module> </modules> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.1.RELEASE</version> </parent> <!-- 管理依赖 --> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Finchley.M7</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <!-- SpringBoot整合Web组件 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- SpringBoot整合eureka客户端 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <!-- SpringBoot整合feign客户端 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> </dependencies> <!-- 注意: 这里必须要添加, 否者各种依赖有问题 --> <repositories> <repository> <id>spring-milestones</id> <name>Spring Milestones</name> <url>https://repo.spring.io/libs-milestone</url> <snapshots> <enabled>false</enabled> </snapshots> </repository> </repositories> </project>
5.2.springcloud-api-service
1)项目结构
2)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"> <parent> <artifactId>springcloud-parent</artifactId> <groupId>com.itmayiedu</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>springcloud-api-service</artifactId> <packaging>pom</packaging> <modules> <module>springcloud-api-member-service</module> <module>springcloud-api-order-service</module> </modules> </project>
5.3.springcloud-api-member-service
1)项目结构
注:实体类可以放到接口项目里
2)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"> <parent> <artifactId>springcloud-api-service</artifactId> <groupId>com.itmayiedu</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>springcloud-api-member-service</artifactId> <packaging>jar</packaging> </project>
3)会员接口 IMemberService
package com.itmayiedu.api.service; import com.itmayiedu.api.entity.UserEntity; import org.springframework.web.bind.annotation.RequestMapping; public interface IMemberService { @RequestMapping("/getMember") public UserEntity getMember(); }
4)实体类 UserEntity
package com.itmayiedu.api.entity; import lombok.Data; @Data public class UserEntity { private String name; private Integer age; }
5.4.springcloud-api-order-service
1)项目结构
2)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"> <parent> <artifactId>springcloud-api-service</artifactId> <groupId>com.itmayiedu</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>springcloud-api-order-service</artifactId> <packaging>jar</packaging> </project>
3)订单项目调用会员项目接口 IOrderService
package com.itmayiedu.api.service; import org.springframework.web.bind.annotation.RequestMapping; public interface IOrderService { @RequestMapping("/getOrederToMember") public String getOrederToMember(); }
5.5.springcloud-member-service-impl
1)项目结构
2)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"> <parent> <artifactId>springcloud-parent</artifactId> <groupId>com.itmayiedu</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>springcloud-member-service-impl</artifactId> <packaging>jar</packaging> <dependencies> <!--在member实现类项目中 引入依赖member接口项目 --> <dependency> <groupId>com.itmayiedu</groupId> <artifactId>springcloud-api-member-service</artifactId> <version>1.0-SNAPSHOT</version> </dependency> </dependencies> </project>
3)会员接口实现类 MemberServiceImpl
package com.itamyiedu.api.service.impl; import com.itmayiedu.api.entity.UserEntity; import com.itmayiedu.api.service.IMemberService; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class MemberServiceImpl implements IMemberService { @RequestMapping("/getMember") public UserEntity getMember(){ UserEntity userEntity = new UserEntity(); userEntity.setName("张飞"); userEntity.setAge(50); return userEntity; } }
4)启动类
package com.itamyiedu.api.service; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; import org.springframework.cloud.openfeign.EnableFeignClients; @SpringBootApplication @EnableEurekaClient @EnableFeignClients public class AppMember { public static void main(String[] args) { SpringApplication.run(AppMember.class, args); } }
5)application.yml文件:端口号8080
###服务启动端口号 server: port: 8000 ###服务名称(服务注册到eureka名称) spring: application: name: app-itmayiedu-member ###服务注册到eureka地址 eureka: client: service-url: defaultZone: http://localhost:8100/eureka ###因为该应用为注册中心,不会注册自己 register-with-eureka: true ###是否需要从eureka上获取注册信息 fetch-registry: true
5.6.springcloud-order-service-impl
1)项目结构
2)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"> <parent> <artifactId>springcloud-parent</artifactId> <groupId>com.itmayiedu</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>springcloud-order-service-impl</artifactId> <packaging>jar</packaging> <dependencies> <!--在order实现类项目中 引入依赖member接口项目 --> <dependency> <groupId>com.itmayiedu</groupId> <artifactId>springcloud-api-member-service</artifactId> <version>1.0-SNAPSHOT</version> </dependency> <!--在order实现类项目中 引入依赖order接口项目 --> <dependency> <groupId>com.itmayiedu</groupId> <artifactId>springcloud-api-order-service</artifactId> <version>1.0-SNAPSHOT</version> </dependency> </dependencies> </project>
3)会员接口 Feign客户端
package com.itmayiedu.api.fegin; import com.itmayiedu.api.service.IMemberService; import org.springframework.cloud.openfeign.FeignClient; @FeignClient(name = "app-itmayiedu-member") public interface MemberApiFegin extends IMemberService { }
注:此代码不能写在会员项目中,要写在订单项目中,因为是订单项目调用会员项目,之后会做一些服务降级,服务熔断等操作,不同的调用方项目做的服务降级等操作级别不同,所以应该写在调用方,而不能写在被调用发。
4)订单项目调用会员项目接口实现类 IOrderServiceImpl
package com.itmayiedu.api.service.impl; import com.itmayiedu.api.entity.UserEntity; import com.itmayiedu.api.service.IOrderService; import com.itmayiedu.api.fegin.MemberApiFegin; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class IOrderServiceImpl implements IOrderService { @Autowired private MemberApiFegin memberApiFegin; @RequestMapping("/getOrederToMember") public String getOrederToMember() { UserEntity user = memberApiFegin.getMember(); return user.toString(); } }
注:直接引入会员项目的feign客户端类调用即可
5)启动类
package com.itmayiedu.api; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; import org.springframework.cloud.openfeign.EnableFeignClients; @SpringBootApplication @EnableEurekaClient @EnableFeignClients public class AppOrder { public static void main(String[] args) { SpringApplication.run(AppOrder.class, args); } }
5.6.启动项目
1)依次启动eureka注册中心,会员项目启动类,订单项目启动类。
2)直接访问会员项目
3)访问订单项目,内部调用会员项目
6.Feign客户端工具超时时间设置
1)在member接口中新增方法
2)在order接口中新增方法,调用member接口
3.浏览器访问order项目,报错!
报错,读取超时;order项目调用member项目的接口时,休眠了1.5s,而feign客户端默认时间为1s,所以需要设置feign客户端超时时间。
在order项目application.yml文件中添加配置:
###springcloud 默认支持ribbon ###设置feign客户端超时时间 ribbon: ###指的是建立连接所用的时间,适用于网络状况正常的情况下,两端连接所用的时间。 ReadTimeout: 5000 ###指的是建立连接后从服务器读取到可用资源所用的时间。 ConnectTimeout: 5000
4.再次浏览器访问order项目,成功!
注:springcloud默认支持ribbon本地负载均衡,所以无论使用rest还是feign都支持本地负载均衡。
后文:代码已上传到码云 https://gitee.com/xuruanshun/springcloud.git