update: 让feign支持hystrix

This commit is contained in:
Wendal Chen 2017-12-31 22:47:53 +08:00
parent bc716bf7cc
commit 9319a15f6a
2 changed files with 102 additions and 73 deletions

View File

@ -11,17 +11,22 @@ import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.Strings;
import feign.Client;
import feign.Feign;
import feign.Logger;
import feign.Logger.Level;
import feign.codec.Decoder;
import feign.codec.Encoder;
import feign.gson.GsonDecoder;
import feign.gson.GsonEncoder;
import feign.httpclient.ApacheHttpClient;
import feign.hystrix.FallbackFactory;
import feign.hystrix.HystrixFeign;
import feign.jackson.JacksonDecoder;
import feign.jackson.JacksonEncoder;
import feign.jaxb.JAXBContextFactory;
import feign.jaxb.JAXBDecoder;
import feign.jaxb.JAXBEncoder;
import feign.jaxrs.JAXRSContract;
import feign.okhttp.OkHttpClient;
import feign.ribbon.RibbonClient;
import feign.slf4j.Slf4jLogger;
@ -43,92 +48,53 @@ public class FeignStarter implements IocEventListener {
@PropDoc(value = "WebService的schema地址")
public static final String PROP_SCHEMA = PRE + "schema";
@PropDoc(value = "默认编码器", possible= {"raw", "nutzjson", "jackson", "gson", "jaxb", "jaxrs"})
@PropDoc(value = "默认编码器", possible = {"raw", "nutzjson", "jackson", "gson", "jaxb", "jaxrs"})
public static final String PROP_ENCODER = PRE + "encoder";
@PropDoc(value = "默认解码器", possible= {"raw", "nutzjson", "jackson", "gson", "jaxb", "jaxrs"})
@PropDoc(value = "默认解码器", possible = {"raw", "nutzjson", "jackson", "gson", "jaxb", "jaxrs"})
public static final String PROP_DECODER = PRE + "decoder";
@PropDoc(value = "是否使用Hystrix", defaultValue = "false", possible = {"true", "false"})
public static final String PROP_USE_HYSTRIX = PRE + "useHystrix";
@Inject("refer:$ioc")
protected Ioc ioc;
@Inject
protected PropertiesProxy conf;
@SuppressWarnings({"unchecked", "rawtypes"})
public Object afterBorn(Object obj, String beanName) {
try {
for (Field field : obj.getClass().getDeclaredFields()) {
FeignInject fc = field.getAnnotation(FeignInject.class);
if (fc == null)
continue;
Feign.Builder builder = Feign.builder();
switch (Strings.sBlank(fc.encoder(), conf.get(PROP_ENCODER, ""))) {
case "":
case "raw":
break;
case "nutzjson":
builder.encoder(new NutzJsonEncoder());
break;
case "jackson":
builder.encoder(new JacksonEncoder());
break;
case "gson":
builder.encoder(new GsonEncoder());
break;
case "jaxb":
JAXBContextFactory jaxbFactory = new JAXBContextFactory.Builder().withMarshallerJAXBEncoding("UTF-8").withMarshallerSchemaLocation(fc.schema()).build();
builder.encoder(new JAXBEncoder(jaxbFactory));
break;
case "jaxrs":
builder.contract(new JAXRSContract());
break;
default:
break;
}
switch (Strings.sBlank(fc.decoder(), conf.get(PROP_DECODER, ""))) {
case "":
case "raw":
break;
case "nutzjson":
builder.decoder(new NutzJsonDecoder());
break;
case "jackson":
builder.decoder(new JacksonDecoder());
break;
case "gson":
builder.decoder(new GsonDecoder());
break;
case "jaxb":
JAXBContextFactory jaxbFactory = new JAXBContextFactory.Builder().withMarshallerJAXBEncoding("UTF-8")
.withMarshallerSchemaLocation(Strings.sBlank(fc.schema(), conf.get(PROP_SCHEMA)))
.build();
builder.decoder(new JAXBDecoder(jaxbFactory));
break;
case "jaxrs":
builder.contract(new JAXRSContract());
break;
default:
break;
}
switch (Strings.sBlank(fc.client(), conf.get(PROP_CLIENT, "jdk"))) {
case "jdk":
// nop
break;
case "okhttp":
builder.client(new OkHttpClient());
break;
case "httpclient":
builder.client(new ApacheHttpClient());
break;
case "ribbon":
builder.client(RibbonClient.create());
break;
default:
break;
}
builder.logger(new Slf4jLogger());
builder.logLevel(Level.valueOf(conf.get(PROP_LOGLEVEL, "BASIC").toUpperCase()));
Object t = builder.target(field.getType(), Strings.sBlank(conf.get(PROP_URL), "http://127.0.0.1:8080"));
Encoder encoder = getEncoder(fc, field);
Decoder decoder = getDecoder(fc, field);
Client client = getClient(fc, field);
Logger.Level level = Level.valueOf(conf.get(PROP_LOGLEVEL, "BASIC").toUpperCase());
String url = Strings.sBlank(conf.get(PROP_URL), "http://127.0.0.1:8080");
Class<?> apiType = field.getType();
Logger logger = new Slf4jLogger(apiType);
boolean useHystrix = "true".equals(Strings.sBlank(fc.useHystrix(), conf.get(PROP_USE_HYSTRIX)));
Feign.Builder builder = useHystrix ? HystrixFeign.builder() : Feign.builder();
if (encoder != null)
builder.encoder(encoder);
if (decoder != null)
builder.decoder(decoder);
if (client != null)
builder.client(client);
builder.logger(logger);
builder.logLevel(level);
Object t = useHystrix ? ((HystrixFeign.Builder) builder).target(apiType, url, new FallbackFactory() {
public Object create(Throwable cause) {
if (Strings.isBlank(fc.fallback()))
return ioc.getByType(apiType);
return ioc.get(apiType, fc.fallback());
}
}) : builder.target(apiType, url);
field.setAccessible(true);
field.set(obj, t);
}
@ -147,4 +113,63 @@ public class FeignStarter implements IocEventListener {
return 0;
}
protected Decoder getDecoder(FeignInject fc, Field field) {
switch (Strings.sBlank(fc.decoder(), conf.get(PROP_DECODER, ""))) {
case "":
case "raw":
break;
case "nutzjson":
return new NutzJsonDecoder();
case "jackson":
return new JacksonDecoder();
case "gson":
return new GsonDecoder();
case "jaxb":
JAXBContextFactory jaxbFactory = new JAXBContextFactory.Builder().withMarshallerJAXBEncoding("UTF-8")
.withMarshallerSchemaLocation(Strings.sBlank(fc.schema(), conf.get(PROP_SCHEMA)))
.build();
return new JAXBDecoder(jaxbFactory);
default:
break;
}
return null;
}
protected Encoder getEncoder(FeignInject fc, Field field) {
switch (Strings.sBlank(fc.encoder(), conf.get(PROP_ENCODER, ""))) {
case "":
case "raw":
break;
case "nutzjson":
return new NutzJsonEncoder();
case "jackson":
return new JacksonEncoder();
case "gson":
return new GsonEncoder();
case "jaxb":
JAXBContextFactory jaxbFactory = new JAXBContextFactory.Builder().withMarshallerJAXBEncoding("UTF-8").withMarshallerSchemaLocation(fc.schema()).build();
return new JAXBEncoder(jaxbFactory);
default:
break;
}
return null;
}
protected Client getClient(FeignInject fc, Field field) {
switch (Strings.sBlank(fc.client(), conf.get(PROP_CLIENT, "jdk"))) {
case "jdk":
// nop
break;
case "okhttp":
return new OkHttpClient();
case "httpclient":
return new ApacheHttpClient();
case "ribbon":
return RibbonClient.create();
default:
break;
}
return null;
}
}

View File

@ -19,11 +19,15 @@ public @interface FeignInject {
String encoder() default "";
String decoder() default "";
/**
* JAXB作为编码/解码器的时候必须填写
*/
String schema() default "";
String client() default "";
String useHystrix() default "";
String fallback() default "";
}