Spring Cloud在一个服务中使用Feign远程调用另一个服务 超、凢脫俗 2022-03-10 16:00 306阅读 0赞 首先是搭建服务注册中心Eureka Server 参考: [https://blog.csdn.net/weixin\_42465125/article/details/88233722][https_blog.csdn.net_weixin_42465125_article_details_88233722] [https://blog.csdn.net/weixin\_42465125/article/details/88337698][https_blog.csdn.net_weixin_42465125_article_details_88337698] 两个客户端工程结构如下: ![20190311154942951.png][] 采用的是Maven的聚合工程,聚合工程的创建参考:[https://blog.csdn.net/weixin\_42465125/article/details/87906095][https_blog.csdn.net_weixin_42465125_article_details_87906095] cuit-product-center和cuit-user-center作为父工程,cuit-product-center-\*和cuit-user-center-\*为聚合的子模块 ### cuit-product-center父工程: ### 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>cn.cuit.product</groupId> <artifactId>cuit-product-center</artifactId> <version>1.0.0</version> <packaging>pom</packaging> <modules> <module>cuit-product-center-api</module> <module>cuit-product-center-service</module> </modules> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.3.RELEASE</version> <relativePath /> <!-- lookup parent from repository --> </parent> <properties> <java.version>1.8</java.version> <spring-cloud.version>Greenwich.RELEASE</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> <!-- 因为cuit-product-center-api工程没main class,加这个会报错 --> <!-- <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> --> <repositories> <repository> <id>spring-milestones</id> <name>Spring Milestones</name> <url>https://repo.spring.io/milestone</url> </repository> </repositories> </project> ### cuit-product-center-api子模块: ### 该模块下面放的是domain类和service接口 pom文件: <?xml version="1.0"?> <project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>cn.cuit.product</groupId> <artifactId>cuit-product-center</artifactId> <version>1.0.0</version> </parent> <artifactId>cuit-product-center-api</artifactId> <name>cuit-product-center-api</name> <url>http://maven.apache.org</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <dependencies> </dependencies> </project> Product类: package cn.cuit.product.center.api.domian; import java.io.Serializable; public class Product implements Serializable { private static final long serialVersionUID = 3895325943679327522L; private String id; private String name; private Integer price; public Product() { } public Product(String name, Integer price) { this.name = name; this.price = price; } public Product(String id, String name, Integer price) { this.id = id; this.name = name; this.price = price; } public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getPrice() { return price; } public void setPrice(Integer price) { this.price = price; } } ProductService接口: package cn.cuit.product.center.api.service; import cn.cuit.product.center.api.domian.Product; public interface ProductService { Product getProductById(String id); } ### cuit-product-center-service子模块: ### 该模块主要放Controller类和Service实现及Feign接口和启动类 pom文件: <?xml version="1.0"?> <project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>cn.cuit.product</groupId> <artifactId>cuit-product-center</artifactId> <version>1.0.0</version> </parent> <artifactId>cuit-product-center-service</artifactId> <name>cuit-product-center-service</name> <url>http://maven.apache.org</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <dependencies> <dependency> <groupId>cn.cuit.product</groupId> <artifactId>cuit-product-center-api</artifactId> <version>1.0.0</version> </dependency> <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-client</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-feign</artifactId> <version>1.4.6.RELEASE</version> </dependency> </dependencies> </project> properties配置文件: spring.aop.auto = true spring.aop.proxy-target-class = true # logback日志配置,日志环境类型,服务名,级别 log.env.profile = dev log.env.module = cuit-product-center-service log.env.logger.level = info #服务提供者的名字 spring.application.name = cuit-product-center-service #服务提供者的端口号 server.port=8088 #服务上下文配置,springboot2.X server.servlet.context-path=/cuit-product-center-service #服务注册中心的地址 #无需验证的方式: #eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka/ #有用户名密码的验证方式,Eureka服务端依赖SpringSecurity eureka.client.serviceUrl.defaultZone=http://user:pwd@localhost:8761/eureka/ 日志文件: <?xml version="1.0" encoding="UTF-8"?> <configuration> <include resource="org/springframework/boot/logging/logback/base.xml"/> <property resource="application.properties"/> <appender name="ROLLING" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>logs/${log.env.module}.log</file> <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"> <fileNamePattern>logs/${log.env.module}-%d{yyyy-MM-dd}.%i.log </fileNamePattern> <maxFileSize>5MB</maxFileSize> <maxHistory>30</maxHistory> <totalSizeCap>20GB</totalSizeCap> </rollingPolicy> <encoder> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level [%.15thread] %logger{36}:%X{sysUser} - %.-4096msg%n</pattern> <charset>UTF-8</charset> </encoder> </appender> <root level="${log.env.logger.level}"> <appender-ref ref="ROLLING"/> </root> </configuration> 启动类: package cn.cuit.product.center.service; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.openfeign.EnableFeignClients; @SpringBootApplication // 将自己作为一个可以被Eureka Server发现注册的Client @EnableDiscoveryClient // 将自己作为一个可以被其他服务通过Feign调用的Client @EnableFeignClients public class App { public static void main(String[] args) { SpringApplication.run(App.class, args); } } Controller: package cn.cuit.product.center.service.controller; import org.slf4j.Logger; import org.slf4j.LoggerFactory; 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.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import cn.cuit.product.center.api.domian.Product; import cn.cuit.product.center.api.service.ProductService; @RestController @RequestMapping("/api/products") public class ProductController { private final Logger logger = LoggerFactory.getLogger(this.getClass()); @Autowired private ProductService productService; // 远程访问的经验,先保证自己访问能访问通,再去整另外一个服务来调这个服务,否则坑是填不完的 // http://localhost:8088/cuit-product-center-service/api/products/testFeign?a=10&b=20 @GetMapping("/testFeign") public String testFeign(@RequestParam Integer a, @RequestParam Integer b) { logger.info(">>>>>>>>>>>>>>>>通过Feign远程调用成功 a = {}, b = {}", a, b); return "通过Feign远程调用成功 a + b = " + (a + b); } // http://localhost:8088/cuit-product-center-service/api/products/getProductById/10 @GetMapping("/getProductById/{id}") public Product getProductById(@PathVariable("id") String id) { logger.info(">>>>>>>>>>>>>>>>通过Feign远程调用成功 "); return productService.getProductById(id); } } Service实现: package cn.cuit.product.center.service.impl; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; import cn.cuit.product.center.api.domian.Product; import cn.cuit.product.center.api.service.ProductService; @Service public class ProductServiceImpl implements ProductService { private static final Logger LOG = LoggerFactory.getLogger(ProductServiceImpl.class); @Override public Product getProductById(String id) { LOG.info(">>>>>>>>>>>>>id = {}", id); return new Product(id, "cuit", 998); } } 测试本地调用是否好使: 访问: [http://localhost:8088/cuit-product-center-service/api/products/testFeign?a=10&b=20][http_localhost_8088_cuit-product-center-service_api_products_testFeign_a_10_b_20] ![20190311160000195.png][] [http://localhost:8088/cuit-product-center-service/api/products/getProductById/10][http_localhost_8088_cuit-product-center-service_api_products_getProductById_10] ![20190311160008719.png][] 然后搭建另一个user服务:大体与上面一致 主要实现: Controller: package cn.cuit.user.center.service.controller; import org.slf4j.Logger; import org.slf4j.LoggerFactory; 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.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import cn.cuit.product.center.api.domian.Product; import cn.cuit.user.center.service.feign.UserCenterProductFeign; @RestController @RequestMapping("/api/users") public class UserController { private final Logger LOG = LoggerFactory.getLogger(this.getClass()); @Autowired private UserCenterProductFeign userCenterProductFeign; // http://localhost:8081/cuit-user-center-service/api/users/testFeign?a=10&b=20 @GetMapping(value = "/testFeign") public String testCallUserServiceWithFeign(@RequestParam Integer a, @RequestParam Integer b) { LOG.info("in cuit-user-center-service a = {}, b = {}", a, b); String msg = userCenterProductFeign.sum(a, b); return msg; } // http://localhost:8081/cuit-user-center-service/api/products/getProductById/10 @GetMapping(value = "/getProductById/{id}") public Product getProductById(@PathVariable("id") String id) { LOG.info(".................in cuit-user-center-service id = {}", id); Product product = userCenterProductFeign.getProductById(id); return product; } } UserCenterProductFeign: package cn.cuit.user.center.service.feign; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import cn.cuit.product.center.api.domian.Product; /** * Feign Client */ // @FeignClient注解配置 要调用的那个服务 // 如果配置错误会报: /** * java.lang.RuntimeException: com.netflix.client.ClientException: Load balancer * does not have available server for client: XXX-Service */ @FeignClient("cuit-product-center-service") public interface UserCenterProductFeign { // 远程服务请求的url, // 注意这里的神坑,虽然不是问题,但是真的很坑,就是不要忘了Controller类上面的@RequestMapping路径和properties里面的context-path路径 // 如果没配对本服务报500,Feign报404【404表示找不到资源,一般大多数是请求路径不对,或者参数没对】, // SynchronousMethodHandler#executeAndDecode#97行发起调用,到LoadBalancerFeignClient类的57行,就可以看到请求的url @RequestMapping(value = "/product-service/api/products/testFeign", method = RequestMethod.GET) public String sum(@RequestParam Integer a, @RequestParam Integer b); // 旧版Feign不能使用@GetMapping会报错 @GetMapping("/product-service/api/products/getProductById/{id}") public Product getProductById(@PathVariable("id") String id); } 发起远程调用: 访问: [http://localhost:8081/cuit-user-center-service/api/users/testFeign?a=10&b=20][http_localhost_8081_cuit-user-center-service_api_users_testFeign_a_10_b_20] ![20190311160240898.png][] [http://localhost:8081/cuit-user-center-service/api/users/getProductById/23][http_localhost_8081_cuit-user-center-service_api_users_getProductById_23] ![20190311160251285.png][] 完整代码GitHub地址: [https://github.com/CUITLLB/eureka-feign-remote-call-demo][https_github.com_CUITLLB_eureka-feign-remote-call-demo] \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* 不积跬步无以至千里,不积小流无以成江海 \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* [https_blog.csdn.net_weixin_42465125_article_details_88233722]: https://blog.csdn.net/weixin_42465125/article/details/88233722 [https_blog.csdn.net_weixin_42465125_article_details_88337698]: https://blog.csdn.net/weixin_42465125/article/details/88337698 [20190311154942951.png]: /images/20220310/022e0c1449a64f7fb9ff12f29cf7c520.png [https_blog.csdn.net_weixin_42465125_article_details_87906095]: https://blog.csdn.net/weixin_42465125/article/details/87906095 [http_localhost_8088_cuit-product-center-service_api_products_testFeign_a_10_b_20]: http://localhost:8088/cuit-product-center-service/api/products/testFeign?a=10&b=20 [20190311160000195.png]: /images/20220310/171c61f8a59644c88bd86832c8255248.png [http_localhost_8088_cuit-product-center-service_api_products_getProductById_10]: http://localhost:8088/cuit-product-center-service/api/products/getProductById/10 [20190311160008719.png]: /images/20220310/06d3f55d85984d768134b339058c4816.png [http_localhost_8081_cuit-user-center-service_api_users_testFeign_a_10_b_20]: http://localhost:8081/cuit-user-center-service/api/users/testFeign?a=10&b=20 [20190311160240898.png]: /images/20220310/97fa04b2fbea46e0abe506f02e3209b4.png [http_localhost_8081_cuit-user-center-service_api_users_getProductById_23]: http://localhost:8081/cuit-user-center-service/api/users/getProductById/23 [20190311160251285.png]: /images/20220310/08474914c2ba4f4c96e444de7dac8a40.png [https_github.com_CUITLLB_eureka-feign-remote-call-demo]: https://github.com/CUITLLB/eureka-feign-remote-call-demo
还没有评论,来说两句吧...