feign简单使用
在调用服务的时候,我们常用是RestTemplate,但是这种方式调用时需要凭借url,如果服务的地址或者端口号有变化,我们需要跟着做变动,给开发工作带来不必要的麻烦,
这里引入Feign调用服务接口,这是微服务之间经常使用的调用关联方服务的一种,和Dubbo类似,后期调用就类似于本地方法调用同样的道理
需要的依赖
<!--引入feign依赖--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>
<!--客户端--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency>
列出我使用的springboot版本和springcloud版本
<dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Hoxton.SR3</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-dependencies</artifactId> <version>2.1.0.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.2.1.RELEASE</version> <relativePath/> </parent>
启动类中需要的注解
@SpringBootApplication //开启定时任务支持 @EnableAsync() //设置redis共享 @EnableRedisHttpSession //开启事务支持 @EnableTransactionManagement //开启服务发现 @EnableDiscoveryClient // 开启Feign @EnableFeignClients
方法声明
package com.java.api;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
/**
* @author yourheart
* @Description
* @create 2022-09-07 23:33
*/
@FeignClient(name="ip-service")
public interface QueryIpClient {
@RequestMapping("/queryIpCity/{ip}")
@ResponseBody
public String queryIpCity(@PathVariable String ip);
}
如何使用
package com.java.service.impl;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.java.api.QueryIpClient;
import com.java.bean.Paramter;
import com.java.service.ParamterService;
import com.java.service.QueryIp;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.ui.Model;
import org.springframework.web.client.RestTemplate;
import javax.servlet.http.HttpServletRequest;
/**
* @author yourheart
* @Description
* @create 2021-06-07 0:05
*/
@Service
public class QueryIpServiceImpl implements QueryIp {
private static final Logger logger= LoggerFactory.getLogger(QueryIpServiceImpl.class);
@Autowired
private ParamterService paramterService;
@Autowired
private QueryIpClient queryIpClient;
/**
* 判断ip
*
* @param model
* @param remoteHost
* @param localAddr
*/
@Override
public void judgeIp(Model model, String remoteHost, String localAddr) {
logger.info("remoteHost:{}",remoteHost);
Paramter paramter=new Paramter();
paramter.setParamterType("IpAddress");
paramter.setParamterCode(remoteHost);
String queryByCode = paramterService.queryByCode(paramter);
model.addAttribute("icp", queryByCode);
}
/**
* 查询ip地址详细信息
* @param ip
* @return
*/
@Override
public String queryCityByIp(String ip) {
logger.info("【Feign方式调用】【查询ip地址详细信息】入参:{}",ip);
String forObject = null;
try {
forObject =queryIpClient.queryIpCity(ip);
logger.info("【Feign方式调用】【查询ip地址详细信息】返回参数:{}",forObject);
} catch (Exception e) {
logger.error("【Feign方式调用】【调用获取ip信息接口异常】");
return "中国上海上海市";
}
JSONObject jsonObject = JSON.parseObject(forObject);
String city=jsonObject.getString("address");
logger.info("【Feign方式调用】【查询ip地址详细信息】返回参数:{}",city);
return city;
}
}
application.properties文件配置
spring.application.name=pingan-service #注册到eureka注册中心,如果是注册到集群就用逗号连接多个,单实例写上一个就好 eureka.client.service-url.defaultZone=http://127.0.0.1:8761/eureka
当然你要确保调用的服务是使用了springcloud的形式,或者包装了springcloud的形式
下面给出我调用的服务中配置情况
<?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>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.5.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.ip</groupId>
<artifactId>ip-service</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<java.version>1.8</java.version>
<skipTests>true</skipTests>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Hoxton.SR3</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2.1.0.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!--客户端-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!--tomcat容器-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--添加fastjson依赖-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.7</version>
</dependency>
<!--lombok依赖-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.16</version>
</dependency>
<!--mysql驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
</dependency>
<!--springboot整合mybatis-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.2</version>
</dependency>
<!-- 热部署模块 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional> <!-- 这个需要为 true 热部署才有效 -->
</dependency>
<!--java爬虫需要的jar包-->
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.12.2</version>
</dependency>
<!--判断空的用法 -->
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>3.10.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.lionsoul</groupId>
<artifactId>ip2region</artifactId>
<version>1.7.2</version>
</dependency>
<!--RateLimiter的底层是基于令牌桶算法来实现的,来自谷歌的Guava包中-->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>28.0-jre</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.6</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<!--编译插件定义编译细节-->
<!-- <plugin>-->
<!-- <groupId>org.apache.maven.plugins</groupId>-->
<!-- <artifactId>maven-compiler-plugin</artifactId>-->
<!-- <version>3.1</version>-->
<!-- <configuration>-->
<!-- <source>1.8</source>-->
<!-- <target>1.8</target>-->
<!-- <encoding>utf-8</encoding>-->
<!-- <!–告诉编译器,编译的时候记录下形参的真实名称–>-->
<!-- <compilerArgs>-->
<!-- <arg>-parameters</arg>-->
<!-- </compilerArgs>-->
<!-- </configuration>-->
<!-- </plugin>-->
</plugins>
<finalName>server0825</finalName>
</build>
</project>
package com.ip;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
/**
* @author yourheart
* @Description
* @create 2021-06-06 10:34
*/
@SpringBootApplication
@EnableDiscoveryClient
public class CloudPingAnApplication {
public static void main(String[] args) {
SpringApplication.run(CloudPingAnApplication.class,args);
}
}
package com.ip.controller.front;
import com.alibaba.fastjson.JSONObject;
import com.ip.service.QueryIpService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
/**
* @author yourheart
* @Description
* @create 2021-06-06 10:59
*/
@Controller
@RequestMapping("/queryIp")
@Slf4j
public class QueryIpController {
@Autowired
private QueryIpService queryIpService;
@RequestMapping("/queryIpCity/{ip}")
@ResponseBody
public String queryIpCity(@PathVariable String ip){
long a = System.currentTimeMillis();
JSONObject ipCityByIp = queryIpService.getIpCityByIp(ip);
String jsonString = ipCityByIp.toJSONString();
long b = System.currentTimeMillis();
log.info("接口调用耗时:{}",(b-a)+"ms");
return jsonString;
}
}
其中
queryIpService.getIpCityByIp(ip);可以自己写实现
同时对于调用方式给出使用测试类方式测试
结果报错
feign.RetryableException: iZuf627hz8vloz1wtzgxzdZ executing GET http://ip-service/queryIpCity/116.230.165.108 at feign.FeignException.errorExecuting(FeignException.java:249) at feign.SynchronousMethodHandler.executeAndDecode(SynchronousMethodHandler.java:120) at feign.SynchronousMethodHandler.invoke(SynchronousMethodHandler.java:80) at feign.ReflectiveFeign$FeignInvocationHandler.invoke(ReflectiveFeign.java:100) at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344) at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:198) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) at org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor.invoke(MethodBeforeAdviceInterceptor.java:56) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:175) at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:93) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212) at com.java.ApiTest.test(ApiTest.java:27) at org.springframework.test.context.junit4.statements.RunBeforeTestExecutionCallbacks.evaluate(RunBeforeTestExecutionCallbacks.java:74) at org.springframework.test.context.junit4.statements.RunAfterTestExecutionCallbacks.evaluate(RunAfterTestExecutionCallbacks.java:84) at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75) at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86) at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:251) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:97) at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61) at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:190) Caused by: java.net.UnknownHostException: iZuf627hz8vloz1wtzgxzdZ at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:184) at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:172) at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392) at java.net.Socket.connect(Socket.java:589) at java.net.HttpURLConnection.getResponseCode(HttpURLConnection.java:480) at feign.Client$Default.convertResponse(Client.java:78) at feign.Client$Default.execute(Client.java:74) at org.springframework.cloud.openfeign.ribbon.FeignLoadBalancer.execute(FeignLoadBalancer.java:93) at org.springframework.cloud.openfeign.ribbon.FeignLoadBalancer.execute(FeignLoadBalancer.java:56) at com.netflix.client.AbstractLoadBalancerAwareClient$1.call(AbstractLoadBalancerAwareClient.java:104) at com.netflix.loadbalancer.reactive.LoadBalancerCommand$3$1.call(LoadBalancerCommand.java:303) at com.netflix.loadbalancer.reactive.LoadBalancerCommand$3$1.call(LoadBalancerCommand.java:287) at rx.internal.util.ScalarSynchronousObservable$3.call(ScalarSynchronousObservable.java:231) at rx.internal.util.ScalarSynchronousObservable$3.call(ScalarSynchronousObservable.java:228) at rx.Observable.unsafeSubscribe(Observable.java:10327) at rx.internal.operators.OnSubscribeConcatMap$ConcatMapSubscriber.drain(OnSubscribeConcatMap.java:286) at rx.internal.operators.OnSubscribeConcatMap$ConcatMapSubscriber.onNext(OnSubscribeConcatMap.java:144) at com.netflix.loadbalancer.reactive.LoadBalancerCommand$1.call(LoadBalancerCommand.java:185) at com.netflix.loadbalancer.reactive.LoadBalancerCommand$1.call(LoadBalancerCommand.java:180) at rx.Observable.unsafeSubscribe(Observable.java:10327) at rx.internal.operators.OnSubscribeConcatMap.call(OnSubscribeConcatMap.java:94) at rx.internal.operators.OnSubscribeConcatMap.call(OnSubscribeConcatMap.java:42) at rx.Observable.unsafeSubscribe(Observable.java:10327) at rx.internal.operators.OperatorRetryWithPredicate$SourceSubscriber$1.call(OperatorRetryWithPredicate.java:127) at rx.internal.schedulers.TrampolineScheduler$InnerCurrentThreadScheduler.enqueue(TrampolineScheduler.java:73) at rx.internal.schedulers.TrampolineScheduler$InnerCurrentThreadScheduler.schedule(TrampolineScheduler.java:52) at rx.internal.operators.OperatorRetryWithPredicate$SourceSubscriber.onNext(OperatorRetryWithPredicate.java:79) at rx.internal.operators.OperatorRetryWithPredicate$SourceSubscriber.onNext(OperatorRetryWithPredicate.java:45) at rx.internal.util.ScalarSynchronousObservable$WeakSingleProducer.request(ScalarSynchronousObservable.java:276) at rx.Subscriber.setProducer(Subscriber.java:209) at rx.internal.util.ScalarSynchronousObservable$JustOnSubscribe.call(ScalarSynchronousObservable.java:138) at rx.internal.util.ScalarSynchronousObservable$JustOnSubscribe.call(ScalarSynchronousObservable.java:129) at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48) at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30) at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48) at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30) at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48) at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30) at rx.Observable.subscribe(Observable.java:10423) at rx.Observable.subscribe(Observable.java:10390) at rx.observables.BlockingObservable.blockForSingle(BlockingObservable.java:443) at rx.observables.BlockingObservable.single(BlockingObservable.java:340) at com.netflix.client.AbstractLoadBalancerAwareClient.executeWithLoadBalancer(AbstractLoadBalancerAwareClient.java:112) at org.springframework.cloud.openfeign.ribbon.LoadBalancerFeignClient.execute(LoadBalancerFeignClient.java:83) at feign.SynchronousMethodHandler.executeAndDecode(SynchronousMethodHandler.java:110) ... 21 more
下面给出解决方案,见后续补充地址,其实这里使用Feign调用并没有成功,拿到的事服务器的实例名,并不是服务的信息
下面给Feign添加日志打印
package com.java.config;
import com.java.log.MyFeignLogger;
import feign.Logger;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @Description:
* @Author: Yourheart
* @Create: 2022/9/16 13:30
*/
@Configuration
public class FeignConfig {
/**
* NONE【性能最佳,适用于生产】:不记录任何日志(默认值)
* BASIC【适用于生产环境追踪问题】:仅记录请求方法、URL、响应状态代码以及执行时间
* HEADERS:记录BASIC级别的基础上,记录请求和响应的header。
* FULL【比较适用于开发及测试环境定位问题】:记录请求和响应的header、body和元数 据
* @return
*/
@Bean
public Logger.Level feignLogLevel(){
return Logger.Level.FULL;
}
}
#设置Feign的日志级别 logging.level.com.java.config.FeignConfig = DEBUG
报错显示如下

调整服务提供者的配置文件为
eureka.instance.prefer-ip-address=true
eureka.instance.hostname=127.0.0.1
eureka.instance.instance-id=${eureka.instance.hostname}:${server.port}
然后记录调用的时候,路径要写完整
@FeignClient(value="ip-service-query")
@RequestMapping("/queryIp")
public interface QueryIpClient {
@RequestMapping("/queryIpCity/{ip}")
@ResponseBody
public String queryIpCity(@PathVariable String ip);
}

浙公网安备 33010602011771号