change: 重写feign的demo,并修改默认encoder/decoder为空

change: 移除jackson的强制依赖
add: feign添加nutzjson的encoder/decoder实现
add: feign的encoder/decoder支持gson/jaxb/jaxrs
add: feign客户端支持/okhttp/httpclient/ribbon
This commit is contained in:
Wendal Chen 2017-12-31 00:11:29 +08:00
parent d36620ddcf
commit bc716bf7cc
28 changed files with 567 additions and 91 deletions

View File

@ -4,6 +4,7 @@
变更:
* add: [caffeine](https://github.com/ben-manes/caffeine) by [幸福的旁边](https://github.com/happyday517)
* change: feign默认不设置encoder/decoder,上一个版本默认jackson,并添加更多配置项.
## 2.0.1 "刚好遇见你"

View File

@ -0,0 +1,63 @@
<?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">
<parent>
<artifactId>nutzboot-demo-feign</artifactId>
<groupId>org.nutz</groupId>
<version>2.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>nutzboot-demo-feign-client-json</artifactId>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.nutz</groupId>
<artifactId>nutzboot-starter-nutz-mvc</artifactId>
</dependency>
<dependency>
<groupId>org.nutz</groupId>
<artifactId>nutzboot-starter-feign</artifactId>
</dependency>
<dependency>
<groupId>org.nutz</groupId>
<artifactId>nutzboot-starter-jetty</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer
implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer" />
<transformer
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>META-INF/nutz/org.nutz.boot.starter.NbStarter</resource>
</transformer>
<transformer
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>io.nutz.demo.simple.MainLauncher</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,14 @@
package io.nutz.demo.feign;
import org.nutz.boot.NbApp;
import org.nutz.ioc.loader.annotation.IocBean;
@IocBean
public class MainLauncher {
// 端口是8082
public static void main(String[] args) throws Exception {
new NbApp().setPrintProcDoc(true).run();
}
}

View File

@ -0,0 +1,70 @@
package io.nutz.demo.feign.module;
import java.util.List;
import org.nutz.boot.starter.feign.annotation.FeignInject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.json.Json;
import org.nutz.log.Log;
import org.nutz.log.Logs;
import org.nutz.mvc.adaptor.JsonAdaptor;
import org.nutz.mvc.annotation.AdaptBy;
import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.DELETE;
import org.nutz.mvc.annotation.Ok;
import org.nutz.mvc.annotation.POST;
import org.nutz.mvc.annotation.Param;
import io.nutz.demo.feign.bean.User;
import io.nutz.demo.feign.service.UserService;
@IocBean
@At("/user")
@Ok("json:full")
@AdaptBy(type=JsonAdaptor.class)
public class UserModule {
private static final Log log = Logs.get();
@FeignInject
protected UserService userService;
@At
public List<User> list() {
return userService.list();
}
@At
public User fetch(@Param("id")int id) {
return userService.fetch(id);
}
@POST
public User add(@Param("name")String name, @Param("age")int age) {
return userService.add(name, age);
}
@DELETE
public void delete(@Param("id")int id) {
userService.delete(id);
}
/**
* 这是演示api调用的入口,会顺序调用一堆请求,请关注日志
*/
@Ok("raw")
@At
public String apitest() {
List<User> users = userService.list();
log.info("users=" + Json.toJson(users));
User haoqoo = userService.add("haoqoo", 19);
User wendal = userService.add("wendal", 28);
users = userService.list();
log.info("users=" + Json.toJson(users));
userService.delete(haoqoo.getId());
userService.delete(wendal.getId());
users = userService.list();
log.info("users=" + Json.toJson(users));
return "done";
}
}

View File

@ -0,0 +1,7 @@
jetty.port=8082
jetty.host=0.0.0.0
feign.encoder=nutzjson
feign.decoder=nutzjson
feign.logLevel=headers
feign.url=http://127.0.0.1:8080/feign/json

View File

@ -0,0 +1,17 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Hello, So NB!</title>
</head>
<body>
<div>
<h2>这是Feign客户端,没有dao相关的依赖及代码</h2>
</div>
<div>
<h2>
<a href="user/apitest">调用apitest,请看日志的输出</a>
</h2>
</div>
</body>
</html>

View File

@ -2,12 +2,12 @@
<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">
<parent>
<artifactId>nutzboot-demo-simple</artifactId>
<artifactId>nutzboot-demo-feign</artifactId>
<groupId>org.nutz</groupId>
<version>2.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>nutzboot-demo-simple-feign</artifactId>
<artifactId>nutzboot-demo-feign-service</artifactId>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
@ -16,10 +16,6 @@
<groupId>org.nutz</groupId>
<artifactId>nutzboot-starter-nutz-mvc</artifactId>
</dependency>
<dependency>
<groupId>org.nutz</groupId>
<artifactId>nutzboot-starter-feign</artifactId>
</dependency>
<dependency>
<groupId>org.nutz</groupId>
<artifactId>nutzboot-starter-jetty</artifactId>

View File

@ -0,0 +1,24 @@
package io.nutz.demo.feign;
import org.nutz.boot.NbApp;
import org.nutz.dao.Dao;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import io.nutz.demo.feign.bean.User;
@IocBean(create = "init")
public class MainLauncher {
@Inject
protected Dao dao;
public void init() {
dao.create(User.class, true);
}
public static void main(String[] args) throws Exception {
new NbApp().setPrintProcDoc(true).run();
}
}

View File

@ -0,0 +1,42 @@
package io.nutz.demo.feign.bean;
import org.nutz.dao.entity.annotation.Id;
import org.nutz.dao.entity.annotation.Name;
import org.nutz.dao.entity.annotation.Table;
@Table("t_user")
public class User {
@Id
private int id;
@Name
private String name;
private int age;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}

View File

@ -0,0 +1,55 @@
package io.nutz.demo.feign.module;
import java.util.List;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.mvc.adaptor.JsonAdaptor;
import org.nutz.mvc.annotation.AdaptBy;
import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.DELETE;
import org.nutz.mvc.annotation.Ok;
import org.nutz.mvc.annotation.POST;
import org.nutz.mvc.annotation.Param;
import io.nutz.demo.feign.bean.User;
/**
* 这个给nutzboot-demo-feign-client-json调用的模块
*
*/
@IocBean
@At("/feign/json/user")
@Ok("json:full")
@AdaptBy(type=JsonAdaptor.class)
public class UserJsonModule {
@Inject
protected Dao dao;
@At
public List<User> list() {
return dao.query(User.class, null);
}
@At
public User fetch(@Param("id")int id) {
return dao.fetch(User.class, id);
}
@POST
public User add(@Param("name")String name, @Param("age")int age) {
User user = new User();
user.setName(name);
user.setAge(age);
return dao.insert(user);
}
@DELETE
public void delete(@Param("id")int id) {
dao.clear(User.class, Cnd.where("id", "=", id));
}
}

View File

@ -15,13 +15,12 @@ import org.nutz.mvc.annotation.POST;
import org.nutz.mvc.annotation.Param;
import io.nutz.demo.feign.bean.User;
import io.nutz.demo.feign.service.UserService;
@IocBean
@At("/user")
@At("/feign/json/user")
@Ok("json:full")
@AdaptBy(type=JsonAdaptor.class)
public class UserModule implements UserService {
public class UserWsModule {
@Inject
protected Dao dao;

View File

@ -0,0 +1,4 @@
jetty.port=8080
jetty.host=0.0.0.0
jdbc.url=jdbc:h2:mem:~

View File

@ -0,0 +1,7 @@
log4j.rootLogger=debug,Console
log4j.logger.org.eclipse.jetty=info
log4j.appender.Console=org.apache.log4j.ConsoleAppender
log4j.appender.Console.layout=org.apache.log4j.PatternLayout
log4j.appender.Console.layout.ConversionPattern=[%-5p] %d{HH:mm:ss.SSS} %l - %m%n

View File

@ -0,0 +1,17 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Hello, So NB!</title>
</head>
<body>
<div>
<h2>这是服务端,不带任何feign依赖及代码. </h2>
</div>
<div>
<h2>
请启动并访问客户端 <a href="http://127.0.0.1:8082">http://127.0.0.1:8082</a>
</h2>
</div>
</body>
</html>

View File

@ -0,0 +1,24 @@
<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.nutz</groupId>
<artifactId>nutzboot-demo</artifactId>
<version>2.1-SNAPSHOT</version>
</parent>
<artifactId>nutzboot-demo-feign</artifactId>
<packaging>pom</packaging>
<modules>
<module>nutzboot-demo-feign-service</module>
<module>nutzboot-demo-feign-client-json</module>
</modules>
<properties>
</properties>
<dependencies>
<dependency>
<groupId>org.nutz</groupId>
<artifactId>nutzboot-starter</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -1,61 +0,0 @@
package io.nutz.demo.feign;
import java.util.List;
import org.nutz.boot.AppContext;
import org.nutz.boot.NbApp;
import org.nutz.boot.starter.feign.annotation.FeignInject;
import org.nutz.dao.Dao;
import org.nutz.ioc.Ioc;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.json.Json;
import org.nutz.log.Log;
import org.nutz.log.Logs;
import io.nutz.demo.feign.bean.User;
import io.nutz.demo.feign.service.UserService;
@IocBean(create = "init")
public class MainLauncher {
private static final Log log = Logs.get();
@Inject
protected Dao dao;
public void init() {
dao.create(User.class, true);
}
//-------------------------------------------------------
// 下面这段代码应该是另外一个项目中的,放在一起只是为了演示方便
@FeignInject
protected UserService userService;
public void mock_client_call() {
List<User> users = userService.list();
log.info("users=" + Json.toJson(users));
User haoqoo = userService.add("haoqoo", 19);
User wendal = userService.add("wendal", 28);
users = userService.list();
log.info("users=" + Json.toJson(users));
userService.delete(haoqoo.getId());
userService.delete(wendal.getId());
users = userService.list();
log.info("users=" + Json.toJson(users));
}
//--------------------------------------------------------
public static void main(String[] args) throws Exception {
// new NbApp().setPrintProcDoc(true).run();
NbApp app = new NbApp().setPrintProcDoc(true);
app.start();
Thread.sleep(5000); // 一般都能启动完成了吧?
Ioc ioc = AppContext.getDefault().getIoc();
MainLauncher launcher = ioc.get(MainLauncher.class);
launcher.mock_client_call();
app.shutdown();
}
}

View File

@ -1,6 +0,0 @@
jetty.port=8082
jetty.host=0.0.0.0
jdbc.url=jdbc:h2:mem:~
feign.logLevel=headers
feign.url=http://127.0.0.1:8082

View File

@ -29,7 +29,7 @@
<module>nutzboot-demo-simple-zkclient</module>
<module>nutzboot-demo-simple-velocity</module>
<module>nutzboot-demo-simple-jetty</module>
<module>nutzboot-demo-simple-feign</module>
<module>nutzboot-demo-simple-caffeine</module>
</modules>

View File

@ -14,6 +14,8 @@
<module>nutzboot-demo-zbus</module>
<module>nutzboot-demo-dubbo</module>
<module>nutzboot-demo-cxf</module>
<module>nutzboot-demo-feign</module>
</modules>
<properties>
</properties>

View File

@ -14,22 +14,54 @@
<dependency>
<groupId>org.nutz</groupId>
<artifactId>nutzboot-starter</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-core</artifactId>
<version>9.5.1</version>
</dependency>
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-jackson</artifactId>
<version>9.5.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-slf4j</artifactId>
<version>9.5.1</version>
</dependency>
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-gson</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-httpclient</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-hystrix</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-jaxb</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-jaxrs</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-okhttp</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-ribbon</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>

View File

@ -13,19 +13,42 @@ import org.nutz.lang.Strings;
import feign.Feign;
import feign.Logger.Level;
import feign.gson.GsonDecoder;
import feign.gson.GsonEncoder;
import feign.httpclient.ApacheHttpClient;
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;
@IocBean
public class FeignStarter implements IocEventListener {
protected static String PRE = "feign.";
@PropDoc(value = "日志级别", defaultValue = "basic", possible= {"none", "basic", "headers", "full"})
@PropDoc(value = "日志级别", defaultValue = "basic", possible = {"none", "basic", "headers", "full"})
public static final String PROP_LOGLEVEL = PRE + "logLevel";
@PropDoc(value = "Api Base URL", defaultValue = "http://127.0.0.1:8080")
public static final String PROP_URL = PRE + "url";
@PropDoc(value = "客户端实现类", defaultValue = "jdk", possible = {"jdk", "httpclient", "okhttp", "ribbon"})
public static final String PROP_CLIENT = PRE + "client";
@PropDoc(value = "WebService的schema地址")
public static final String PROP_SCHEMA = PRE + "schema";
@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"})
public static final String PROP_DECODER = PRE + "decoder";
@Inject("refer:$ioc")
protected Ioc ioc;
@ -39,17 +62,67 @@ public class FeignStarter implements IocEventListener {
if (fc == null)
continue;
Feign.Builder builder = Feign.builder();
switch (fc.encoder()) {
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 (fc.decoder()) {
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;
}

View File

@ -0,0 +1,19 @@
package org.nutz.boot.starter.feign;
import java.io.IOException;
import java.lang.reflect.Type;
import org.nutz.json.Json;
import feign.FeignException;
import feign.Response;
import feign.codec.DecodeException;
import feign.codec.Decoder;
public class NutzJsonDecoder implements Decoder {
public Object decode(Response response, Type type) throws IOException, DecodeException, FeignException {
return Json.fromJson(type, response.body().asReader());
}
}

View File

@ -0,0 +1,18 @@
package org.nutz.boot.starter.feign;
import java.lang.reflect.Type;
import org.nutz.json.Json;
import org.nutz.json.JsonFormat;
import feign.RequestTemplate;
import feign.codec.EncodeException;
import feign.codec.Encoder;
public class NutzJsonEncoder implements Encoder {
public void encode(Object object, Type bodyType, RequestTemplate template) throws EncodeException {
template.body(Json.toJson(object, JsonFormat.full()));
}
}

View File

@ -16,7 +16,14 @@ public @interface FeignInject {
String apiBaseUrl() default "";
String encoder() default "jackson";
String encoder() default "";
String decoder() default "jackson";
String decoder() default "";
/**
* JAXB作为编码/解码器的时候必须填写
*/
String schema() default "";
String client() default "";
}

52
pom.xml
View File

@ -24,6 +24,7 @@
<velocity.version>1.7</velocity.version>
<caffeine.version>2.6.1</caffeine.version>
<nutzboot.version>2.1-SNAPSHOT</nutzboot.version>
<feign.version>9.5.1</feign.version>
</properties>
<description>NutzBoot, micoservice base on Nutz</description>
@ -629,6 +630,57 @@
<artifactId>caffeine</artifactId>
<version>${caffeine.version}</version>
</dependency>
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-core</artifactId>
<version>${feign.version}</version>
</dependency>
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-jackson</artifactId>
<version>${feign.version}</version>
</dependency>
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-gson</artifactId>
<version>${feign.version}</version>
</dependency>
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-httpclient</artifactId>
<version>${feign.version}</version>
</dependency>
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-hystrix</artifactId>
<version>${feign.version}</version>
</dependency>
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-jaxb</artifactId>
<version>${feign.version}</version>
</dependency>
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-jaxrs</artifactId>
<version>${feign.version}</version>
</dependency>
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-okhttp</artifactId>
<version>${feign.version}</version>
</dependency>
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-slf4j</artifactId>
<version>${feign.version}</version>
</dependency>
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-ribbon</artifactId>
<version>${feign.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<repositories>