OpenFeign入门
跟着yang哥的视频学,来简单做一下入门笔记,新手使用Markdown,如果有写的不对的地方请多多指教_
-
什么是openFeign
-
openFeign是一个微服务调用框架,主要作用在消费者端,即调用服务。
-
是个声明式的web服务客户端,让编写web服务客户端变得更加容易,只需创建一个接口并在接口上添加注解即可–>@FeignClient,即只需要提供一个与provider服务一模一样的接口,并加上@GetMapping/@PostMapping,Feign就会帮我们调用这个ProVider的方法
-
SpringCloud对Feign进行了封装,指出Spring mvc标准注解以及HttpMessageConverters。
-
-
OpenFeign的入门案例
-
入门案例所需环境IDEA+eureka(做服务注册与发现,现已停更可以改用zookeeper/consul)+OpenFeign+SpringCloud H+mybatis
-
一、provider服务
- maven的依赖
<dependencies> <!-- 包含了sleuth zipkin 数据链路追踪--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-zipkin</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!--监控--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> </dependency> <!--eureka client--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <!--如果没写版本,从父层面找,找到了就直接用,全局统一--> </dependency> <!--mysql-connector-java--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <!--jdbc--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <!--热部署--> <!-- 上了生产环境的时候一定要关--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>com.psf</groupId> <artifactId>cloud-api-commons</artifactId> <version>${project.version}</version> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> </dependencies>
-
配置yml
server: port: 8001 #配置名字 spring: application: name: cloud-payment-service datasource: # 当前数据源操作类型 type: com.alibaba.druid.pool.DruidDataSource # mysql驱动类 driver-class-name: com.mysql.jdbc.Driver username: root password: 123 url: jdbc:mysql://localhost:3306/db2019?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8 mybatis: //在resources下创建一个Mapper目录管理mybatis的xml mapper-locations: classpath*:mapper/*.xml type-aliases-package: com.psf.springcloud.entities eureka: client: register-with-eureka: true fetch-registry: true service-url: # 单击版 # defaultZone: http://localhost:7001/eureka # 集群版 defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka #集群版 #配置访问7001端口的时候显示的信息 instance: instance-id: payment8001 #显示ip地址 prefer-ip-address: true lease-renewal-interval-in-seconds: 1 lease-expiration-duration-in-seconds: 2
-
编写主启动类
@SpringBootApplication //使注解生效 @EnableEurekaClient @EnableDiscoveryClient public class PaymentMain8001 { public static void main(String[] args) { SpringApplication.run(PaymentMain8001.class,args); } }
-
编写dao
@Mapper public interface PaymentDao { public int create(Payment payment); public Payment getPaymentById(@Param("id") Long id); }
-
编写service(这里还要编写一个实现类,就不写出)
public interface PaymentService { public int create(Payment payment); public Payment getPaymentById(@Param("id") Long id); }
-
编写controller
@RestController @Slf4j public class PaymentController { @Autowired private PaymentService paymentService; @Value("${server.port}") private String serverPort; /**CommonResult是个实体类,如果没看过yang哥的视频的同学可以参考下面属性去创建,主要属性有 private Integer code; private String message; private T data; */ @GetMapping("/payment/get/{id}") public CommonResult getPaymentById(@PathVariable("id") Long id){ Payment payment = paymentService.getPaymentById(id); log.info("*****查询结果"+payment); if (payment !=null){ return new CommonResult(200,"查询成功,端口号:"+serverPort,payment); }else { return new CommonResult(444,"没有对应记录,查询id"+id,null); } } }
-
controller写完
-
二、customer服务
-
由于customer是调用provider端的,所以可以不用dao层,service层也有一点变化
-
pom其实就是多了个OpenFeign的starter
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>
-
配置yml
server: port: 80 eureka: client: register-with-eureka: false service-url: #这里配置的是集群 defaultZone: http://eureka7001.com:7001/eureka, http://eureka7002.com:7002/eureka
-
主启动类
@SpringBootApplication @EnableFeignClients public class OrderFeignMain80 { public static void main(String[] args) { SpringApplication.run(OrderFeignMain80.class); } }
-
编写service
//要添加component注解 @Component //这里要添加一个新的注解 @FeignClient(value = "cloud-payment-service") public interface PaymentFeignService { @GetMapping("/payment/get/{id}") public CommonResult<Payment> getPaymentById(@PathVariable("id") Long id); }
-
编写controlelr
@RestController @Slf4j public class OrderFeignController { @Resource private PaymentFeignService paymentFeignService; @GetMapping("/customer/payment/get/{id}") public CommonResult<Payment> getPaymentById(@PathVariable("id") Long id){ //这里也是只需要调用service的方法就行 return paymentFeignService.getPaymentById(id); } }
-
到这里customer服务也写完了
-
-
三、discovery and regist(注册与发现)服务
-
pom
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency>
-
yml
server: port: 7001 ##搭建集群的话:相互守望,相互注册 eureka: #初始化主机名字 instance: hostname: eureka7001.com #eureka服务端的实例名字 client: fetch-registry: false #不注册自己 register-with-eureka: false #注册的ur,开启集群模式,需要指向对方 service-url: defaultZone: http://eureka7002.com:7002/eureka/ # defaultZone: http://eureka7001.com:7001/eureka/ #关闭自我保护机制 server: enable-self-preservation: false eviction-interval-timer-in-ms: 2000
-
配置主启动类
@SpringBootApplication //这里要引入一个注解,才能使eureka生效 @EnableEurekaServer public class EurekaMain7001 { public static void main(String[] args) { SpringApplication.run(EurekaMain7001.class); } }
-
到这里就完全结束啦
-
先把注册服务启动,再把消费者与provider服务启动
-
访问localhost:/customer/payment/get/1 就能看到信息
-
-
-
openFeign超时控制
-
意思就是在provider端,需要处理3秒钟,但是customer端只能等1秒钟,这样就会报错
-
status 404 reading PaymentFeignService#paymentFeignTimeout()
-
案例演示:
-
provider的controller添加如下方法
//模拟超时控制 @GetMapping("/payment/feign/timeout") public String paymentFeignTimeout(){ try { //模拟处理三秒钟 TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); } return serverPort; }
-
customer的service添加上面方法的一个接口
-
customer的controller添加接口的方法
@GetMapping("/customer/payment/feign/timeout") public String paymentFeignTimeout(){ //openFeign底层是ribbon,客户端默认等待1秒钟,但是支付端要处理三秒钟 return paymentFeignService.paymentFeignTimeout(); }
-
那我们需要解决这种问题,feign的超时控制是由ribbon控制的,所以我们可以在yml中配置一下超时控制。解决某些请求确实要超过默认时间,把默认等待时间和默认处理时间调整一致
-
在customer的yml添加
#与server同级 ribbon: ReadTimeout: 5000 ConnectTimeout: 5000
-
-
openFeign日志打印功能
-
对feign接口的调用情况进行监控和输出
-
配置yml
logging: level: com.atguigu.springcloud.service.PaymentFeignService: debug
-
配置config类
@Configuration public class FeignConfig { /** *feign的日志打印有5中 FULL:除了HEAD,全部打印 BASE:仅记录请求方法,URL,响应装代码 HEAD:除BASE,打印 NONE:不打印 */ @Bean Logger.Level feignLoggerLevel(){ return Logger.Level.FULL; } }
-