Merge pull request #77 from nutzam/better_feign_inject

add: 改造feign的实现
This commit is contained in:
haoqoo 2017-12-25 21:58:17 +08:00 committed by GitHub
commit 5d69e97e3a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 340 additions and 243 deletions

View File

@ -1,5 +1,10 @@
# NB进化史
## dev
* 变更
* add: [feign](https://github.com/OpenFeign/feign) by [haoqoo](https://github.com/haoqoo) and [wendal](https://github.com/wendal)
## 2.0 "Merry Christmas"
大家昨晚都很累吧 ^_^

View File

@ -128,6 +128,7 @@ public class MainLauncher {
- Rpc类启动器
- [x] [Dubbo](http://dubbo.io/) 阿里出品的高性能RPC平台
- [x] [zbus](http://zbus.io) 国产知名RPC平台
- [x] [feign](https://github.com/OpenFeign/feign) by [haoqoo](https://github.com/haoqoo) and [wendal](https://github.com/wendal)
- [ ] [motan](https://github.com/weibocom/motan)
- 其他
- [x] Ngrok 内网穿透,轻松获取外网地址

View File

@ -1,67 +1,81 @@
<?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-simple</artifactId>
<groupId>org.nutz</groupId>
<version>2.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>nutzboot-demo-simple-feign</artifactId>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.nutz</groupId>
<artifactId>nutzboot-starter-nutz-mvc</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.nutz</groupId>
<artifactId>nutzboot-starter-feign</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.nutz</groupId>
<artifactId>nutzboot-starter-jetty</artifactId>
<version>${project.version}</version>
</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 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>
<groupId>org.nutz</groupId>
<version>2.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>nutzboot-demo-simple-feign</artifactId>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.nutz</groupId>
<artifactId>nutzboot-starter-nutz-mvc</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.nutz</groupId>
<artifactId>nutzboot-starter-feign</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.nutz</groupId>
<artifactId>nutzboot-starter-jetty</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</dependency>
<dependency>
<groupId>org.nutz</groupId>
<artifactId>nutzboot-starter-nutz-dao</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.4.193</version>
</dependency>
<dependency>
<groupId>org.nutz</groupId>
<artifactId>nutzboot-starter-jdbc</artifactId>
<version>${project.version}</version>
</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,61 @@
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

@ -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,52 @@
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;
import io.nutz.demo.feign.service.UserService;
@IocBean
@At("/user")
@Ok("json:full")
@AdaptBy(type=JsonAdaptor.class)
public class UserModule implements UserService {
@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

@ -0,0 +1,22 @@
package io.nutz.demo.feign.service;
import java.util.List;
import feign.Param;
import feign.RequestLine;
import io.nutz.demo.feign.bean.User;
public interface UserService {
@RequestLine("GET /user/list")
List<User> list();
@RequestLine("GET /user/fetch")
User fetch(@Param("id") int id);
@RequestLine("POST /user/add")
User add(@Param("name") String name, @Param("age") int age);
@RequestLine("DELETE /user/delete")
void delete(@Param("id") int id);
}

View File

@ -1,43 +0,0 @@
package org.nutz.boot.starter;
import org.nutz.boot.NbApp;
import org.nutz.boot.starter.feignclient.UserFeignClient;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.util.NutMap;
import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok;
import java.util.Map;
@IocBean
public class MainLauncher {
@Inject("java:$feignRegister.get('UserFeignClient')")
private UserFeignClient userFeignClient;
@At({"/", "/index"})
@Ok("json")
public NutMap index() {
NutMap obj = new NutMap();
obj.setv("name", "牛牪犇").setv("age", 18);
return obj;
}
@At({"/test"})
@Ok("json")
public Map test() {
Map u = userFeignClient.index();
return userFeignClient.index();
}
public static void main(String[] args) throws Exception {
new NbApp().setPrintProcDoc(true).run();
System.out.println(1234);
}
}

View File

@ -1,23 +0,0 @@
package org.nutz.boot.starter.feignclient;
import feign.Param;
import feign.RequestLine;
import org.nutz.boot.starter.feign.annotation.FeignClient;
import org.nutz.ioc.loader.annotation.IocBean;
import java.util.List;
import java.util.Map;
/**
*
*/
@IocBean
@FeignClient
public interface UserFeignClient {
@RequestLine("GET /")
Map index();
@RequestLine("POST /user/list")
List<Map> list(@Param("id") String id);
}

View File

@ -1,7 +1,6 @@
jetty.port=8080
jetty.port=8082
jetty.host=0.0.0.0
feign.pkgs= org.nutz.boot.starter.feignclient
jdbc.url=jdbc:h2:mem:~
feign.logLevel=headers
feign.url=http://127.0.0.1:8082

View File

@ -26,6 +26,11 @@
<artifactId>feign-jackson</artifactId>
<version>9.5.1</version>
</dependency>
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-slf4j</artifactId>
<version>9.5.1</version>
</dependency>
</dependencies>
</project>

View File

@ -1,24 +0,0 @@
package org.nutz.boot.starter.feign;
import org.nutz.ioc.loader.annotation.IocBean;
import java.util.HashMap;
import java.util.Map;
/**
*
*/
@IocBean(name = "feignRegister")
public class FeignRegister {
private static Map<String,Object> register = new HashMap<String,Object>();
public <T> void add(String key,T t){
register.put(key,t);
}
public <T> T get(String key){
return (T) register.get(key);
}
}

View File

@ -1,34 +0,0 @@
package org.nutz.boot.starter.feign;
import org.nutz.ioc.IocMaking;
import org.nutz.ioc.ValueProxy;
import org.nutz.ioc.ValueProxyMaker;
import org.nutz.ioc.meta.IocValue;
import org.nutz.lang.Lang;
/**
*
*/
public class FeignScanValueProxyMaker implements ValueProxyMaker {
@Override
public String[] supportedTypes() {
return new String[]{"feign"};
}
@Override
public ValueProxy make(IocMaking ing, IocValue iv) {
if ("feign".equals(iv.getType())) {
final String zclassName = iv.getValue().toString();
return new ValueProxy() {
public Object get(IocMaking ing) {
// 根据 address 创建一个对象
return null;
}
};
}
return null;
}
}

View File

@ -1,64 +1,77 @@
package org.nutz.boot.starter.feign;
import feign.Feign;
import feign.jackson.JacksonDecoder;
import feign.jackson.JacksonEncoder;
import org.nutz.boot.starter.feign.annotation.FeignClient;
import org.nutz.ioc.impl.NutIoc;
import java.lang.reflect.Field;
import org.nutz.boot.annotation.PropDoc;
import org.nutz.boot.starter.feign.annotation.FeignInject;
import org.nutz.ioc.Ioc;
import org.nutz.ioc.IocEventListener;
import org.nutz.ioc.impl.PropertiesProxy;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.Strings;
import org.nutz.log.Log;
import org.nutz.log.Logs;
import org.nutz.resource.Scans;
/**
*
*/
@IocBean(create = "init")
public class FeignStarter {
import feign.Feign;
import feign.Logger.Level;
import feign.jackson.JacksonDecoder;
import feign.jackson.JacksonEncoder;
import feign.slf4j.Slf4jLogger;
private static final Log log = Logs.get();
@IocBean
public class FeignStarter implements IocEventListener {
protected static String PRE = "feign.";
@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";
@Inject("refer:$ioc")
protected Ioc ioc;
@Inject
protected PropertiesProxy conf;
@Inject
protected FeignRegister feignRegister;
public void init() {
String prefix = "feign.";
for (String key : conf.getKeys()) {
if (key.length() < prefix.length() + 1 || !key.startsWith(prefix))
continue;
String name = key.substring(prefix.length());
if ("pkgs".equals(name)) {
log.debug("found feign packages = " + conf.get(key));
for (String pkg : Strings.splitIgnoreBlank(conf.get(key), ",")) {
addPackage(pkg);
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 (fc.encoder()) {
case "jackson":
builder.encoder(new JacksonEncoder());
break;
default:
break;
}
continue;
switch (fc.decoder()) {
case "jackson":
builder.decoder(new JacksonDecoder());
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"));
field.setAccessible(true);
field.set(obj, t);
}
}
}
public <T> void addPackage(String pkg) {
for (Class<?> klass : Scans.me().scanPackage(pkg)) {
FeignClient feignClient = klass.getAnnotation(FeignClient.class);
String key = klass.getSimpleName();
if (feignClient != null) {
T o = (T) Feign.builder()
.encoder(new JacksonEncoder())
.decoder(new JacksonDecoder())
.target(klass, "http://localhost:8080");
//iocContext.save("app",klass.getSimpleName(),objectProxy.setObj(o));
feignRegister.add(key,o);
log.debug("feignRegister cache "+key);
}
catch (Throwable e) {
throw new RuntimeException(e);
}
return obj;
}
public Object afterCreate(Object obj, String beanName) {
return obj;
}
public int getOrder() {
return 0;
}
}

View File

@ -1,5 +1,6 @@
package org.nutz.boot.starter.feign.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@ -8,8 +9,14 @@ import java.lang.annotation.Target;
/**
*
*/
@Target(ElementType.TYPE)
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface FeignClient {
String apiBaseUrl="";
@Documented
public @interface FeignInject {
String apiBaseUrl() default "";
String encoder() default "jackson";
String decoder() default "jackson";
}