四、springcloud之feign
如果想要调用各个微服务之间的方法,可以使用spring提供的RestTemplete,或者使用客户端的服务分发组件eureka,但是这些的便捷性和优雅性都不如feign,下面介绍feign的简单操作以及坑位。
项目列表
-- consumer-order-feign
--provider-user
consumer-order-feign,基本功能与consumer-order类似,springboot版本1.5.9,springcloud版本为Edgware.SR2。
App启动类 package cn.huangwei.app;
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.feign.EnableFeignClients; import org.springframework.context.annotation.Bean; import org.springframework.web.client.RestTemplate;
@SpringBootApplication(scanBasePackages = "cn.huangwei") @EnableFeignClients(basePackages = "cn.huangwei.controller") public class ConsumerOrder { @Bean//相当于xml中的bean标签,主要用于调用当前方法获取指定对象 public RestTemplate getTemplate() { return new RestTemplate(); }
public static void main(String[] args) { SpringApplication.run(ConsumerOrder.class, args); } } 可能由于版本的问题,此时的SpringBootApplication注解上,必须手动添加scanPackage的扫描包,如果不添加,将不会扫描相关注解;同时EnableFeignClients,也要添加basePackages的路径,否则接下来的FeignTest的bean实例将不会产生,提示FeignTest对象not found。 OrderController类 package cn.huangwei.controller;
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 cn.huangwei.entity.User;
@RestController public class OrderController { @Autowired private FeignTest feignTest;
@GetMapping("/order/{id}") public User getOrder(@PathVariable long id) { User user = feignTest.getUser(id); return user; } } 该controller的作用就是通过访问order/id,实质上通过feign去调用provider-user的相关服务 FeignTest类 package cn.huangwei.controller;
import org.springframework.cloud.netflix.feign.FeignClient; import org.springframework.stereotype.Component; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable;
import cn.huangwei.entity.User;
@FeignClient(name = "provider-user", url = "http://localhost:7903") public interface FeignTest { @GetMapping(value = "/user/{id}") public User getUser(@PathVariable Long id); } Pom文件 Application.yml server: port: 8900 spring: application: name: consumer-order-feign |
provider-user项目,简单的提供user的服务
启动类app package cn.huangwei.app;
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication(scanBasePackages = "cn.huangwei") public class ProviderUser { public static void main(String[] args) { SpringApplication.run(ProviderUser.class, args); } } Controller类 package cn.huangwei.controller;
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 com.netflix.appinfo.InstanceInfo; import com.netflix.discovery.EurekaClient;
import cn.huangwei.entity.User;
@RestController public class UserController { @Autowired private EurekaClient discoveryClient;
@GetMapping("/user/{id}") public User getUser(@PathVariable long id) { return new User(id); } } Pom文件 Application.yml server: port: 7903 spring: application: name: provider-user-swagger |
运行项目;
先启动provider-user项目,正常启动
然后启动consumer-order-feign
提示:
原因出在这里:
如果使用了getMapping等Restful风格的注解,那么@PathVariable也需要使用restful风格,变为@PathVariable(“id”);
feign坑位
1.@RequestMapping(value = "/user/{id}", method = RequestMethod.GET)
@GetMapping("/user/{id}")
这两个注解的效果是等价的,但是在Feign使用中,只能用上面的那种方式,不能直接用@GetMapping,下面我们将前面的那个示例中,改成@GetMapping注解看下效果,我们发现,修改注解后重新启动服务的时候,抛了如下异常:
Caused by: java.lang.IllegalStateException: Method findById not annotated with HTTP method type (ex. GET, POST)
由于存在版本问题,这个情况可能会出现,也可能不出现
2.多参数问题
@RequestMapping(value="/user/name", method=RequestMethod.GET) User findByUsername(final String userName, final String address); 启动服务后,提示 Caused by: java.lang.IllegalStateException: Method has too many Body parameters 当使用feign时,如果发送的时get请求,那么需要在请求参数前加上@RequestParam,表示该请求参数时get请求的参数,如果不标注,可能会提示Request method 'POST' not supported 因为我们使用的是get请求,如果userName没有被@RequestParam注解修饰,会自动当成requestbody来处理。只要有body,feign认为是post请求,例如参数是一个复杂对象User,那么也会当成post请求,从而报错 |