Spring Cloud Openfeign

pom.xml

	<dependencies>
		<dependency>
    		<groupId>org.springframework.cloud</groupId>
    		<artifactId>spring-cloud-starter-openfeign</artifactId>
    		<version>2.1.3.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>com.fasterxml.jackson.core</groupId>
			<artifactId>jackson-databind</artifactId>
		</dependency>
		<dependency>
			<groupId>com.fasterxml.jackson.core</groupId>
			<artifactId>jackson-annotations</artifactId>
		</dependency>
		<dependency>
    		<groupId>io.github.openfeign</groupId>
    		<artifactId>feign-httpclient</artifactId>
    		<version>10.2.3</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-log4j2</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-validation</artifactId>
			<exclusions>
				<exclusion>
					<groupId>org.springframework.boot</groupId>
					<artifactId>spring-boot-starter-logging</artifactId>
				</exclusion>
			</exclusions>
		</dependency>	

		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>io.github.openfeign</groupId>
			<artifactId>feign-mock</artifactId>
			<version>10.2.3</version>
			<scope>test</scope>
		</dependency>				
	</dependencies>

application.properties

feign.compression.response.enabled=true
feign.compression.request.enabled=true

#feign.client.config.default.connectTimeout=2000
feign.client.config.default.readTimeout=20000
feign.client.config.default.loggerLevel=full

feign.client.config.clientA.url=xxx.xxx.xxx.xxx:80
feign.client.config.clientB.url=xxx.xxx.xxx.xxx:8080/rest

conf (in sacn)

@Configuration
public class FeignConf {

	@Bean
	public Retryer retryer() {//after try 8 ~ every call 30s			
		return new Retryer.Default(5000,30000,20);
	}

	@Bean
	public ErrorDecoder errorDecoder() {
		return new MyErrorDecoder();
	}
	
	@Log4j2
	private static class MyErrorDecoder extends ErrorDecoder.Default{

		@Override
		public Exception decode(String methodKey, Response response) {
			FeignException e =(FeignException)super.decode(methodKey, response);
			if(e instanceof RetryableException) {
				return  e;
			}else {
				log.warn("Retry now");
				return new RetryableException(e.status(),e.getMessage(),response.request().httpMethod(),null);				
			}
		}
		
	}
}

feign clent conf (out scan)

@Configuration
public class ClientAConf {

	@Bean
	public RequestInterceptor requestInterceptorsA(Environment env) {
		
		return new AuthHeaderOfA(env);
	}
	
}

//below out scan directory

public class AuthHeaderOfA implements RequestInterceptor {
		
	private Environment env;	
	
	public AuthHeaderOfA(Environment env){
		this.env=env;
	}
	
	@Override
	public void apply(RequestTemplate template) {		
		if(!template.headers().containsKey("Authorization"))
			template.header("Authorization","xxxxxxx");
	}

}

Junit

calss

import feign.Feign;
import feign.mock.MockTarget;

public class FeignInterFaceBuilder {

	private Feign.Builder builder;
	
	public FeignInterFaceBuilder(Feign.Builder builder) {
		this.builder=builder;
	}
	
	 public <T> T target( Class<T> target) {
		 return builder.build().newInstance(new MockTarget<T>(target));
	 }
}

@Configuration
@ConditionalOnClass({FeignInterFaceBuilder.class,MockClient.class})
@Import({ JacksonAutoConfiguration.class, HttpMessageConvertersAutoConfiguration.class,
		FeignClientsConfiguration.class })
@ConditionalOnProperty(prefix = "mock.feign.test", name = "enabled" ,matchIfMissing=true)
public class FeignTestAutoConfiguration {

	
	@Bean
	@ConditionalOnMissingBean
	public MockClient feignMockClient() {
		return new MockClient();
	}
	
	@Bean
	@ConditionalOnMissingBean
	public FeignInterFaceBuilder feignInterFaceBuilder(Feign.Builder builder, Decoder decoder, Encoder encoder, MockClient client,
			Contract contract) {
		builder.client(client).contract(contract).decoder(decoder).encoder(encoder);
		return new FeignInterFaceBuilder(builder);
	}
}

help function

	private RequestKey genKey(RequestObj req,String url) throws JsonProcessingException {
		String data=json.writeValueAsString(Arrays.asList(req));
		RequestHeaders h=RequestHeaders.builder()
				.add("Accept", MediaType.APPLICATION_JSON_UTF8_VALUE)
				.add("Content-Type", MediaType.APPLICATION_JSON_VALUE)	
				.add("Content-Length", ""+(data.getBytes().length))
				.build();
		RequestKey k=RequestKey.builder(HttpMethod.POST, url)
				.headers(h)
				.charset(Charset.forName("utf-8"))				
				.body(data)
				.build();
		return k;
	}
	
	private Response.Builder genResponseBody(Object obj) throws JsonProcessingException{
		Map<String,Collection<String>> rh=new HashMap<>();		
		rh.put("Content-Type", Stream.of(MediaType.APPLICATION_JSON_VALUE).collect(Collectors.toList()));
		Response.Builder r=Response.builder()
				.status(200).headers(rh)
				.body(json.writeValueAsString(obj),Charset.forName("utf-8"));
		return r;
	}