mirror of
https://gitee.com/nutz/nutzboot.git
synced 2024-12-04 04:38:30 +08:00
change: 各位基友强烈要求把nutzcloud的代码分开放
This commit is contained in:
parent
fa6f163851
commit
df91caa94e
@ -10,10 +10,6 @@
|
|||||||
* add: 添加单元测试的支持
|
* add: 添加单元测试的支持
|
||||||
* add: shiro主动搜索ioc容器内的SessionListener并添加到SessionManager
|
* add: shiro主动搜索ioc容器内的SessionListener并添加到SessionManager
|
||||||
* add: jetty添加staticPathLocal属性,解决idea用户开发期js/css文件不更新的问题
|
* add: jetty添加staticPathLocal属性,解决idea用户开发期js/css文件不更新的问题
|
||||||
* add: loach-server NC的'泥鳅'服务端,服务注册与发现
|
|
||||||
* add: loach-client NC的'泥鳅'客户端,服务注册与发现
|
|
||||||
* add: literpc NC的简洁高效的RPC服务
|
|
||||||
* add: gateway-server NC的网关服务
|
|
||||||
|
|
||||||
# 2.1.4 "平凡之路"
|
# 2.1.4 "平凡之路"
|
||||||
|
|
||||||
|
@ -159,7 +159,7 @@ public class MainLauncher {
|
|||||||
- [x] starter-config-client NB Config Client 配置中心的客户端
|
- [x] starter-config-client NB Config Client 配置中心的客户端
|
||||||
- [x] starter-[apollo-client](https://github.com/ctripcorp/apollo) 携程框架部门研发的分布式配置中心的客户端
|
- [x] starter-[apollo-client](https://github.com/ctripcorp/apollo) 携程框架部门研发的分布式配置中心的客户端
|
||||||
- API网关
|
- API网关
|
||||||
- [x] gateway-server NB API网关服务器
|
- [x] gateway-server NC API网关服务器
|
||||||
- [ ] zuul
|
- [ ] zuul
|
||||||
- 数据库类相关
|
- 数据库类相关
|
||||||
- 关系型数据库
|
- 关系型数据库
|
||||||
|
@ -1,23 +0,0 @@
|
|||||||
# NutzCloud
|
|
||||||
|
|
||||||
## 模块划分
|
|
||||||
|
|
||||||
- [x] gateway-server API网关
|
|
||||||
- [x] loach-server 服务注册与服务发现的服务端
|
|
||||||
- [x] loach-client 服务注册与服务发现的客户端
|
|
||||||
- [x] literpc 简洁高效的RPC服务
|
|
||||||
- [x] cloud-demo 演示组件间的协作
|
|
||||||
|
|
||||||
## 编译说明
|
|
||||||
|
|
||||||
### 独立使用的组件
|
|
||||||
|
|
||||||
对应`mvn -Pstandalone`
|
|
||||||
- gateway-server
|
|
||||||
- loach-server
|
|
||||||
|
|
||||||
他们均自带Launcher, 可直接启动
|
|
||||||
|
|
||||||
### demo
|
|
||||||
|
|
||||||
对应`mvn -Pdemo`
|
|
@ -1,21 +0,0 @@
|
|||||||
<?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>
|
|
||||||
<groupId>io.nutz.cloud.demo</groupId>
|
|
||||||
<artifactId>cloud-demo</artifactId>
|
|
||||||
<version>2.2-SNAPSHOT</version>
|
|
||||||
</parent>
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
|
||||||
<artifactId>cloud-demo-common</artifactId>
|
|
||||||
<properties>
|
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
|
||||||
</properties>
|
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.nutz.cloud</groupId>
|
|
||||||
<artifactId>literpc</artifactId>
|
|
||||||
<version>2.2-SNAPSHOT</version>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
</project>
|
|
@ -1,46 +0,0 @@
|
|||||||
package io.nutz.cloud.demo.bean;
|
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
|
|
||||||
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 implements Serializable {
|
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
@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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,18 +0,0 @@
|
|||||||
package io.nutz.cloud.demo.service;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.nutz.boot.starter.literpc.api.RpcService;
|
|
||||||
|
|
||||||
import io.nutz.cloud.demo.bean.User;
|
|
||||||
|
|
||||||
public interface UserService extends RpcService {
|
|
||||||
|
|
||||||
List<User> list();
|
|
||||||
|
|
||||||
User fetch(int id);
|
|
||||||
|
|
||||||
User add(String name, int age);
|
|
||||||
|
|
||||||
void delete(int id);
|
|
||||||
}
|
|
@ -1,78 +0,0 @@
|
|||||||
<?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>
|
|
||||||
<groupId>io.nutz.cloud.demo</groupId>
|
|
||||||
<artifactId>cloud-demo</artifactId>
|
|
||||||
<version>2.2-SNAPSHOT</version>
|
|
||||||
</parent>
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
|
||||||
<artifactId>cloud-demo-service</artifactId>
|
|
||||||
<properties>
|
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
|
||||||
</properties>
|
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.nutz</groupId>
|
|
||||||
<artifactId>nutzboot-starter-jetty</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.slf4j</groupId>
|
|
||||||
<artifactId>slf4j-log4j12</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.nutz</groupId>
|
|
||||||
<artifactId>nutzboot-starter-nutz-dao</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.nutz</groupId>
|
|
||||||
<artifactId>nutzboot-starter-jdbc</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>mysql</groupId>
|
|
||||||
<artifactId>mysql-connector-java</artifactId>
|
|
||||||
<version>5.1.44</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>io.nutz.cloud.demo</groupId>
|
|
||||||
<artifactId>cloud-demo-common</artifactId>
|
|
||||||
<version>2.2-SNAPSHOT</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.nutz.cloud</groupId>
|
|
||||||
<artifactId>loach-client</artifactId>
|
|
||||||
<version>2.2-SNAPSHOT</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>
|
|
@ -1,33 +0,0 @@
|
|||||||
package io.nutz.cloud.demo;
|
|
||||||
|
|
||||||
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 org.nutz.lang.util.NutMap;
|
|
||||||
import org.nutz.mvc.annotation.At;
|
|
||||||
import org.nutz.mvc.annotation.Ok;
|
|
||||||
|
|
||||||
import io.nutz.cloud.demo.bean.User;
|
|
||||||
|
|
||||||
@IocBean(create = "init")
|
|
||||||
public class CloudServiceLauncher {
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
protected Dao dao;
|
|
||||||
|
|
||||||
@Ok("raw")
|
|
||||||
@At("/Status")
|
|
||||||
public NutMap status() {
|
|
||||||
return new NutMap();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void init() {
|
|
||||||
dao.create(User.class, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void main(String[] args) throws Exception {
|
|
||||||
new NbApp().setPrintProcDoc(true).run();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,39 +0,0 @@
|
|||||||
package io.nutz.cloud.demo.service.impl;
|
|
||||||
|
|
||||||
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.annotation.Param;
|
|
||||||
|
|
||||||
import io.nutz.cloud.demo.bean.User;
|
|
||||||
import io.nutz.cloud.demo.service.UserService;
|
|
||||||
|
|
||||||
@IocBean
|
|
||||||
public class UserServiceImpl implements UserService {
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
protected Dao dao;
|
|
||||||
|
|
||||||
public List<User> list() {
|
|
||||||
return dao.query(User.class, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public User fetch(@Param("id")int id) {
|
|
||||||
return dao.fetch(User.class, id);
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void delete(@Param("id")int id) {
|
|
||||||
dao.clear(User.class, Cnd.where("id", "=", id));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,5 +0,0 @@
|
|||||||
nutz.application.name=user-service
|
|
||||||
server.port=0
|
|
||||||
jdbc.url=jdbc:mysql://127.0.0.1:3306/nbdemo
|
|
||||||
jdbc.username=root
|
|
||||||
jdbc.password=root
|
|
@ -1,7 +0,0 @@
|
|||||||
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
|
|
@ -1,17 +0,0 @@
|
|||||||
<!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>
|
|
@ -1,73 +0,0 @@
|
|||||||
<?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>
|
|
||||||
<groupId>io.nutz.cloud.demo</groupId>
|
|
||||||
<artifactId>cloud-demo</artifactId>
|
|
||||||
<version>2.2-SNAPSHOT</version>
|
|
||||||
</parent>
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
|
||||||
<artifactId>cloud-demo-web</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-jetty</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.slf4j</groupId>
|
|
||||||
<artifactId>slf4j-log4j12</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>io.github.openfeign</groupId>
|
|
||||||
<artifactId>feign-ribbon</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.nutz.cloud</groupId>
|
|
||||||
<artifactId>loach-client</artifactId>
|
|
||||||
<version>2.2-SNAPSHOT</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>io.nutz.cloud.demo</groupId>
|
|
||||||
<artifactId>cloud-demo-common</artifactId>
|
|
||||||
<version>2.2-SNAPSHOT</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>
|
|
@ -1,14 +0,0 @@
|
|||||||
package io.nutz.cloud.demo;
|
|
||||||
|
|
||||||
import org.nutz.boot.NbApp;
|
|
||||||
import org.nutz.ioc.loader.annotation.IocBean;
|
|
||||||
|
|
||||||
@IocBean
|
|
||||||
public class CloudWebLauncher {
|
|
||||||
|
|
||||||
// 端口是8082, 请先启动 loach-server
|
|
||||||
public static void main(String[] args) throws Exception {
|
|
||||||
new NbApp().setPrintProcDoc(true).run();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,74 +0,0 @@
|
|||||||
package io.nutz.cloud.demo.module;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.nutz.boot.starter.literpc.annotation.RpcInject;
|
|
||||||
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.cloud.demo.bean.User;
|
|
||||||
import io.nutz.cloud.demo.service.UserService;
|
|
||||||
|
|
||||||
@IocBean
|
|
||||||
@At("/user")
|
|
||||||
@Ok("json:full")
|
|
||||||
@AdaptBy(type=JsonAdaptor.class)
|
|
||||||
public class UserModule {
|
|
||||||
|
|
||||||
private static final Log log = Logs.get();
|
|
||||||
|
|
||||||
@RpcInject
|
|
||||||
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";
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setUserService(UserService userService) {
|
|
||||||
this.userService = userService;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,3 +0,0 @@
|
|||||||
nutz.application.name=web
|
|
||||||
server.port=8082
|
|
||||||
server.host=0.0.0.0
|
|
@ -1,10 +0,0 @@
|
|||||||
log4j.rootLogger=debug,Console
|
|
||||||
|
|
||||||
log4j.logger.org.eclipse.jetty=info
|
|
||||||
log4j.logger.org.apache.http=info
|
|
||||||
log4j.logger.com.netflix.discovery=info
|
|
||||||
log4j.logger.com.netflix.loadbalancer=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
|
|
@ -1,17 +0,0 @@
|
|||||||
<!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>
|
|
@ -1,12 +0,0 @@
|
|||||||
<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-cloud</artifactId>
|
|
||||||
<version>2.2-SNAPSHOT</version>
|
|
||||||
</parent>
|
|
||||||
<groupId>io.nutz.cloud.demo</groupId>
|
|
||||||
<artifactId>cloud-demo</artifactId>
|
|
||||||
<packaging>pom</packaging>
|
|
||||||
</project>
|
|
@ -1,31 +0,0 @@
|
|||||||
<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-starter</artifactId>
|
|
||||||
<version>2.2-SNAPSHOT</version>
|
|
||||||
</parent>
|
|
||||||
<artifactId>gateway-server</artifactId>
|
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.eclipse.jetty</groupId>
|
|
||||||
<artifactId>jetty-proxy</artifactId>
|
|
||||||
<version>${jetty.version}</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.nutz.cloud</groupId>
|
|
||||||
<artifactId>loach-client</artifactId>
|
|
||||||
<version>2.2-SNAPSHOT</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.slf4j</groupId>
|
|
||||||
<artifactId>slf4j-log4j12</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.nutz</groupId>
|
|
||||||
<artifactId>nutzboot-starter-jetty</artifactId>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
<groupId>org.nutz.cloud</groupId>
|
|
||||||
</project>
|
|
@ -1,81 +0,0 @@
|
|||||||
package org.nutz.boot.starter.gateway.server;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.Iterator;
|
|
||||||
|
|
||||||
import javax.servlet.Servlet;
|
|
||||||
import javax.servlet.ServletException;
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
|
||||||
|
|
||||||
import org.eclipse.jetty.proxy.AsyncMiddleManServlet;
|
|
||||||
import org.nutz.boot.starter.WebServletFace;
|
|
||||||
import org.nutz.ioc.loader.annotation.Inject;
|
|
||||||
import org.nutz.ioc.loader.annotation.IocBean;
|
|
||||||
|
|
||||||
@IocBean
|
|
||||||
@SuppressWarnings("serial")
|
|
||||||
public class ApiGateWayServlet extends AsyncMiddleManServlet implements WebServletFace {
|
|
||||||
|
|
||||||
public static final String NAME_ROUTE_CONCEXT = "gateway.route_context";
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
protected RouteConfig routeConfig;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void service(HttpServletRequest clientRequest, HttpServletResponse proxyResponse) throws ServletException, IOException {
|
|
||||||
RouteContext ctx = new RouteContext();
|
|
||||||
ctx.setup(clientRequest, proxyResponse);
|
|
||||||
clientRequest.setAttribute(NAME_ROUTE_CONCEXT, ctx);
|
|
||||||
Iterator<RouteFilter> it = routeConfig.getRouteFilters();
|
|
||||||
while (it.hasNext()) {
|
|
||||||
if (!it.next().preRoute(ctx)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (ctx.targetHost == null && ctx.rewritedTarget == null) {
|
|
||||||
proxyResponse.sendError(404);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
super.service(clientRequest, proxyResponse);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected String rewriteTarget(HttpServletRequest clientRequest) {
|
|
||||||
RouteContext ctx = ((RouteContext)clientRequest.getAttribute(NAME_ROUTE_CONCEXT));
|
|
||||||
if (ctx.rewritedTarget != null)
|
|
||||||
return ctx.rewritedTarget;
|
|
||||||
String url = ctx.targetHost;
|
|
||||||
if (url.startsWith("http://") || url.startsWith("https://")) {
|
|
||||||
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
url = "http://" + url;
|
|
||||||
}
|
|
||||||
if (ctx.targetPort > 0) {
|
|
||||||
url += ":" + ctx.targetPort;
|
|
||||||
}
|
|
||||||
if (ctx.targetUri == null) {
|
|
||||||
url += ctx.uri;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
url += ctx.targetUri;
|
|
||||||
}
|
|
||||||
if (ctx.queryString != null) {
|
|
||||||
url += "?" + ctx.queryString;
|
|
||||||
}
|
|
||||||
return url;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getName() {
|
|
||||||
return "gateway";
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getPathSpec() {
|
|
||||||
return "/*";
|
|
||||||
}
|
|
||||||
|
|
||||||
public Servlet getServlet() {
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
package org.nutz.boot.starter.gateway.server;
|
|
||||||
|
|
||||||
import org.nutz.boot.NbApp;
|
|
||||||
|
|
||||||
public class GatewayServerLauncher {
|
|
||||||
|
|
||||||
public static void main(String[] args) {
|
|
||||||
new NbApp().run();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,44 +0,0 @@
|
|||||||
package org.nutz.boot.starter.gateway.server;
|
|
||||||
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.nutz.boot.starter.gateway.server.impl.SimpleRouteFilter;
|
|
||||||
import org.nutz.ioc.Ioc;
|
|
||||||
import org.nutz.ioc.impl.PropertiesProxy;
|
|
||||||
import org.nutz.ioc.loader.annotation.Inject;
|
|
||||||
import org.nutz.ioc.loader.annotation.IocBean;
|
|
||||||
import org.nutz.log.Log;
|
|
||||||
import org.nutz.log.Logs;
|
|
||||||
|
|
||||||
@IocBean(create="init")
|
|
||||||
public class RouteConfig {
|
|
||||||
|
|
||||||
private static final Log log = Logs.get();
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
protected PropertiesProxy conf;
|
|
||||||
|
|
||||||
@Inject("refer:$ioc")
|
|
||||||
protected Ioc ioc;
|
|
||||||
|
|
||||||
protected List<RouteFilter> routes = new LinkedList<>();
|
|
||||||
|
|
||||||
public Iterator<RouteFilter> getRouteFilters() {
|
|
||||||
return routes.iterator();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void init() {
|
|
||||||
for (String key : conf.getKeys()) {
|
|
||||||
if (key.startsWith("gw.") && key.endsWith(".filters")) {
|
|
||||||
String name = key.substring("gw.".length(), key.length() - ".filters".length());
|
|
||||||
log.debug("add config for name=" + name);
|
|
||||||
// 当前仅支持simple,直接new就行了
|
|
||||||
SimpleRouteFilter simple = new SimpleRouteFilter();
|
|
||||||
simple.setPropertiesProxy(ioc, conf, key.substring(0, key.length() - ".filters".length()));
|
|
||||||
routes.add(simple);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,43 +0,0 @@
|
|||||||
package org.nutz.boot.starter.gateway.server;
|
|
||||||
|
|
||||||
import java.util.Enumeration;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
|
||||||
|
|
||||||
public class RouteContext {
|
|
||||||
|
|
||||||
public String method;
|
|
||||||
public String uri;
|
|
||||||
public String host;
|
|
||||||
public Map<String, String> headers;
|
|
||||||
public String queryString;
|
|
||||||
|
|
||||||
public String targetHost;
|
|
||||||
public String targetUri;
|
|
||||||
public int targetPort;
|
|
||||||
|
|
||||||
public String rewritedTarget;
|
|
||||||
|
|
||||||
public int connectTimeOut, sendTimeOut, readTimeOut;
|
|
||||||
|
|
||||||
public HttpServletResponse resp;
|
|
||||||
public HttpServletRequest req;
|
|
||||||
|
|
||||||
public void setup(HttpServletRequest req, HttpServletResponse resp) {
|
|
||||||
method = req.getMethod().toUpperCase();
|
|
||||||
uri = req.getRequestURI();
|
|
||||||
host = req.getHeader("Host");
|
|
||||||
headers = new HashMap<>();
|
|
||||||
Enumeration<String> headerNames = req.getHeaderNames();
|
|
||||||
while (headerNames.hasMoreElements()) {
|
|
||||||
String headerName = headerNames.nextElement();
|
|
||||||
headers.put(headerName, req.getHeader(headerName));
|
|
||||||
}
|
|
||||||
queryString = req.getQueryString();
|
|
||||||
this.req = req;
|
|
||||||
this.resp = resp;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,19 +0,0 @@
|
|||||||
package org.nutz.boot.starter.gateway.server;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import org.nutz.ioc.Ioc;
|
|
||||||
import org.nutz.ioc.impl.PropertiesProxy;
|
|
||||||
|
|
||||||
public interface RouteFilter {
|
|
||||||
|
|
||||||
default boolean preRoute(RouteContext ctx) throws IOException {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
default void postRoute(RouteContext ctx) throws IOException {}
|
|
||||||
|
|
||||||
default void setPropertiesProxy(Ioc ioc, PropertiesProxy conf, String prefix) {}
|
|
||||||
|
|
||||||
String nickname();
|
|
||||||
}
|
|
@ -1,159 +0,0 @@
|
|||||||
package org.nutz.boot.starter.gateway.server.impl;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
import org.nutz.boot.starter.gateway.server.RouteContext;
|
|
||||||
import org.nutz.boot.starter.gateway.server.RouteFilter;
|
|
||||||
import org.nutz.boot.starter.loach.client.LoachClient;
|
|
||||||
import org.nutz.ioc.Ioc;
|
|
||||||
import org.nutz.ioc.impl.PropertiesProxy;
|
|
||||||
import org.nutz.lang.Strings;
|
|
||||||
import org.nutz.lang.random.R;
|
|
||||||
import org.nutz.lang.util.NutMap;
|
|
||||||
import org.nutz.log.Log;
|
|
||||||
import org.nutz.log.Logs;
|
|
||||||
|
|
||||||
public class SimpleRouteFilter implements RouteFilter {
|
|
||||||
|
|
||||||
private static final Log log = Logs.get();
|
|
||||||
|
|
||||||
protected String prefix;
|
|
||||||
|
|
||||||
protected String[] hostnames;
|
|
||||||
|
|
||||||
protected String serviceName;
|
|
||||||
|
|
||||||
protected String[] servers;
|
|
||||||
|
|
||||||
protected String[] uriPrefixs;
|
|
||||||
|
|
||||||
protected boolean removePrefix;
|
|
||||||
|
|
||||||
protected Pattern uriPattern;
|
|
||||||
|
|
||||||
protected int connectTimeOut, sendTimeOut, readTimeOut;
|
|
||||||
|
|
||||||
protected boolean corsEnable;
|
|
||||||
|
|
||||||
protected LoachClient loachClient;
|
|
||||||
|
|
||||||
public void setPropertiesProxy(Ioc ioc, PropertiesProxy conf, String prefix) {
|
|
||||||
// 需要匹配的域名
|
|
||||||
String hostnames = conf.get(prefix + ".hostnames");
|
|
||||||
if (!Strings.isBlank(hostnames)) {
|
|
||||||
this.hostnames = Strings.splitIgnoreBlank(hostnames, "(;|,)");
|
|
||||||
}
|
|
||||||
// 固定转发的服务器vip
|
|
||||||
String servers = conf.get(prefix + ".servers");
|
|
||||||
if (!Strings.isBlank(servers)) {
|
|
||||||
this.servers = Strings.splitIgnoreBlank(servers, "(;|,)");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// 服务名
|
|
||||||
serviceName = conf.get(prefix + ".serviceName");
|
|
||||||
if (!Strings.isBlank(serviceName)) {
|
|
||||||
loachClient = ioc.get(LoachClient.class);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
String uriPrefixs = conf.get(prefix + ".uri.prefixs");
|
|
||||||
if (!Strings.isBlank(uriPrefixs)) {
|
|
||||||
this.uriPrefixs = Strings.splitIgnoreBlank(uriPrefixs, "(;|,)");
|
|
||||||
}
|
|
||||||
removePrefix = conf.getBoolean(prefix + ".uri.prefix.remove", false);
|
|
||||||
String uripattern = conf.get(prefix + ".uri.match");
|
|
||||||
if (!Strings.isBlank(uripattern)) {
|
|
||||||
uriPattern = Pattern.compile(uripattern);
|
|
||||||
}
|
|
||||||
connectTimeOut = conf.getInt(prefix + ".time.connect", 2000);
|
|
||||||
sendTimeOut = conf.getInt(prefix + ".time.send", 3000);
|
|
||||||
readTimeOut = conf.getInt(prefix + ".time.read", 3000);
|
|
||||||
corsEnable = conf.getBoolean(prefix + ".cors.enable");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean preRoute(RouteContext ctx) throws IOException {
|
|
||||||
// 校验Host
|
|
||||||
if (!checkHost(ctx))
|
|
||||||
return true;
|
|
||||||
// 校验uri前缀
|
|
||||||
if (!checkUriPrefix(ctx))
|
|
||||||
return true;
|
|
||||||
// 校验uri正则表达式
|
|
||||||
if (!checkUriPattern(ctx))
|
|
||||||
return true;
|
|
||||||
// 设置一些必要的超时设置
|
|
||||||
ctx.connectTimeOut = connectTimeOut;
|
|
||||||
ctx.sendTimeOut = sendTimeOut;
|
|
||||||
ctx.readTimeOut = readTimeOut;
|
|
||||||
// TODO 处理跨域
|
|
||||||
|
|
||||||
if (servers != null) {
|
|
||||||
ctx.targetHost = servers[R.random(0, servers.length)];
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
List<NutMap> services = loachClient.getService(serviceName);
|
|
||||||
if (services.isEmpty()) {
|
|
||||||
log.debugf("emtry server list for [%s]", serviceName);
|
|
||||||
ctx.resp.sendError(500);
|
|
||||||
return false; // 终止匹配
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
NutMap service = services.get(R.random(0, services.size() - 1));
|
|
||||||
ctx.targetHost = service.getString("vip");
|
|
||||||
ctx.targetPort = service.getInt("port");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return RouteFilter.super.preRoute(ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean checkHost(RouteContext ctx) {
|
|
||||||
if (hostnames == null)
|
|
||||||
return true;
|
|
||||||
boolean pass = false;
|
|
||||||
for (String hostname : hostnames) {
|
|
||||||
if (hostname.equals(ctx.host)) {
|
|
||||||
pass = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return pass;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean checkUriPrefix(RouteContext ctx) {
|
|
||||||
if (uriPrefixs == null)
|
|
||||||
return true;
|
|
||||||
boolean pass = false;
|
|
||||||
// 校验URL前缀
|
|
||||||
if (uriPrefixs != null) {
|
|
||||||
for (String prefix : uriPrefixs) {
|
|
||||||
if (ctx.uri.startsWith(prefix)) {
|
|
||||||
pass = true;
|
|
||||||
if (removePrefix) {
|
|
||||||
if (ctx.uri.length() == prefix.length()) {
|
|
||||||
ctx.targetUri = "/";
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
ctx.targetUri = ctx.uri.substring(prefix.length());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return pass;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean checkUriPattern(RouteContext ctx) {
|
|
||||||
if (uriPattern == null)
|
|
||||||
return true;
|
|
||||||
return uriPattern.matcher(ctx.uri).find();
|
|
||||||
}
|
|
||||||
|
|
||||||
public String nickname() {
|
|
||||||
return "simple";
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,8 +0,0 @@
|
|||||||
server.port=8620
|
|
||||||
server.host=0.0.0.0
|
|
||||||
|
|
||||||
nutz.application.name=gateway
|
|
||||||
|
|
||||||
gw.demo.filters=simple
|
|
||||||
gw.demo.serviceName=demo
|
|
||||||
gw.demo.url.prefixs=/
|
|
@ -1,7 +0,0 @@
|
|||||||
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
|
|
@ -1,18 +0,0 @@
|
|||||||
<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-cloud</artifactId>
|
|
||||||
<version>2.2-SNAPSHOT</version>
|
|
||||||
</parent>
|
|
||||||
<groupId>org.nutz.cloud</groupId>
|
|
||||||
<artifactId>literpc</artifactId>
|
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.nutz.cloud</groupId>
|
|
||||||
<artifactId>loach-client</artifactId>
|
|
||||||
<version>2.2-SNAPSHOT</version>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
</project>
|
|
@ -1,123 +0,0 @@
|
|||||||
package org.nutz.boot.starter.literpc;
|
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
|
|
||||||
import org.nutz.boot.starter.literpc.api.RpcSerializer;
|
|
||||||
import org.nutz.boot.starter.literpc.impl.RpcInvoker;
|
|
||||||
import org.nutz.boot.starter.literpc.impl.endpoint.RpcEndpoint;
|
|
||||||
import org.nutz.boot.starter.loach.client.LoachClient;
|
|
||||||
import org.nutz.ioc.Ioc;
|
|
||||||
import org.nutz.ioc.loader.annotation.Inject;
|
|
||||||
import org.nutz.ioc.loader.annotation.IocBean;
|
|
||||||
import org.nutz.lang.Lang;
|
|
||||||
import org.nutz.lang.util.NutMap;
|
|
||||||
import org.nutz.log.Log;
|
|
||||||
import org.nutz.log.Logs;
|
|
||||||
|
|
||||||
@IocBean(create="init")
|
|
||||||
public class LiteRpc implements LoachClient.UpdateListener {
|
|
||||||
|
|
||||||
private static final Log log = Logs.get();
|
|
||||||
|
|
||||||
protected static String RPC_REG_KEY = "literpc.v1";
|
|
||||||
|
|
||||||
@Inject("refer:$ioc")
|
|
||||||
protected Ioc ioc;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 持有所有的执行器
|
|
||||||
*/
|
|
||||||
protected Map<String, RpcInvoker> invokers = new ConcurrentHashMap<>();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 方法签名对应的可用服务器列表
|
|
||||||
*/
|
|
||||||
protected Map<String, List<NutMap>> services = new HashMap<>();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 受支持的序列化器
|
|
||||||
*/
|
|
||||||
protected Map<String, RpcSerializer> serializers = new HashMap<>();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 受支持的通信方式
|
|
||||||
*/
|
|
||||||
protected Map<String, RpcEndpoint> endpoints = new HashMap<>();
|
|
||||||
|
|
||||||
public void init() {
|
|
||||||
// 获取所有RpcSerializer实例,并注册
|
|
||||||
for(String name : ioc.getNamesByType(RpcSerializer.class)) {
|
|
||||||
registerSerializer(ioc.get(RpcSerializer.class, name));
|
|
||||||
}
|
|
||||||
// 获取所有RpcEndpoint实例,并注册
|
|
||||||
for(String name : ioc.getNamesByType(RpcEndpoint.class)) {
|
|
||||||
registerEndpoint(ioc.get(RpcEndpoint.class, name));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public RpcInvoker getInvoker(String methodSign) {
|
|
||||||
return invokers.get(methodSign);
|
|
||||||
}
|
|
||||||
|
|
||||||
public RpcInvoker registerInovker(String methodSign, RpcInvoker invoker) {
|
|
||||||
return invokers.put(methodSign, invoker);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getMethodSign(Method method) {
|
|
||||||
return Lang.sha1(method.toGenericString());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void updateLoachRegInfo() {
|
|
||||||
LoachClient.EXT_REG_DATA.put(RPC_REG_KEY, new ArrayList<>(invokers.keySet()));
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<NutMap> getServers(String methodSign) {
|
|
||||||
return this.services.get(methodSign);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onUpdate(Map<String, List<NutMap>> services) {
|
|
||||||
if (services == null || services.isEmpty()) {
|
|
||||||
return; // fuck
|
|
||||||
}
|
|
||||||
Map<String, List<NutMap>> rpcMap = new HashMap<>();
|
|
||||||
for (List<NutMap> _se : services.values()) {
|
|
||||||
for (NutMap server : _se) {
|
|
||||||
List<String> rpcKeys = server.getList(RPC_REG_KEY, String.class);
|
|
||||||
if (rpcKeys == null || rpcKeys.isEmpty())
|
|
||||||
continue;
|
|
||||||
for (String rpcKey : rpcKeys) {
|
|
||||||
List<NutMap> servers = rpcMap.get(rpcKey);
|
|
||||||
if (servers == null) {
|
|
||||||
servers = new ArrayList<>();
|
|
||||||
rpcMap.put(rpcKey, servers);
|
|
||||||
}
|
|
||||||
servers.add(server);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.services = rpcMap;
|
|
||||||
}
|
|
||||||
|
|
||||||
public RpcSerializer getSerializer(String name) {
|
|
||||||
return serializers.get(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void registerSerializer(RpcSerializer serializer) {
|
|
||||||
log.debug("add RpcSerializer name=" + serializer.getName());
|
|
||||||
this.serializers.put(serializer.getName(), serializer);
|
|
||||||
}
|
|
||||||
|
|
||||||
public RpcEndpoint getEndpoint(String name) {
|
|
||||||
return endpoints.get(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void registerEndpoint(RpcEndpoint endpoint) {
|
|
||||||
log.debug("add RpcEndpoint name=" + endpoint.getName());
|
|
||||||
this.endpoints.put(endpoint.getName(), endpoint);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,25 +0,0 @@
|
|||||||
package org.nutz.boot.starter.literpc;
|
|
||||||
|
|
||||||
@SuppressWarnings("serial")
|
|
||||||
public class RpcException extends RuntimeException {
|
|
||||||
|
|
||||||
public RpcException() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public RpcException(String message) {
|
|
||||||
super(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
public RpcException(Throwable cause) {
|
|
||||||
super(cause);
|
|
||||||
}
|
|
||||||
|
|
||||||
public RpcException(String message, Throwable cause) {
|
|
||||||
super(message, cause);
|
|
||||||
}
|
|
||||||
|
|
||||||
public RpcException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
|
|
||||||
super(message, cause, enableSuppression, writableStackTrace);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,25 +0,0 @@
|
|||||||
package org.nutz.boot.starter.literpc.annotation;
|
|
||||||
|
|
||||||
import java.lang.annotation.Documented;
|
|
||||||
import java.lang.annotation.ElementType;
|
|
||||||
import java.lang.annotation.Retention;
|
|
||||||
import java.lang.annotation.RetentionPolicy;
|
|
||||||
import java.lang.annotation.Target;
|
|
||||||
|
|
||||||
import org.nutz.boot.starter.literpc.impl.proxy.DefaultRpcInjectProxy;
|
|
||||||
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
|
||||||
@Target({ElementType.FIELD})
|
|
||||||
@Documented
|
|
||||||
public @interface RpcInject {
|
|
||||||
|
|
||||||
Class<? extends DefaultRpcInjectProxy> by() default DefaultRpcInjectProxy.class;
|
|
||||||
|
|
||||||
int connectTimeout() default -1;
|
|
||||||
|
|
||||||
int timeout() default -1;
|
|
||||||
|
|
||||||
String endpointType() default "";
|
|
||||||
|
|
||||||
String serializer() default "";
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
package org.nutz.boot.starter.literpc.api;
|
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
|
|
||||||
public class RpcReq {
|
|
||||||
public Object object;
|
|
||||||
public Method method;
|
|
||||||
public String methodSign;
|
|
||||||
public Object[] args;
|
|
||||||
public int timeout, connectTimeout;
|
|
||||||
}
|
|
@ -1,22 +0,0 @@
|
|||||||
package org.nutz.boot.starter.literpc.api;
|
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
|
|
||||||
public class RpcResp implements Serializable {
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
public Throwable err;
|
|
||||||
public Object returnValue;
|
|
||||||
|
|
||||||
public RpcResp() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public RpcResp(Object returnValue) {
|
|
||||||
this.returnValue = returnValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
public RpcResp(Throwable err) {
|
|
||||||
this.err = err;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,13 +0,0 @@
|
|||||||
package org.nutz.boot.starter.literpc.api;
|
|
||||||
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
|
|
||||||
public interface RpcSerializer {
|
|
||||||
|
|
||||||
void write(Object obj, OutputStream out) throws Exception;
|
|
||||||
|
|
||||||
Object read(InputStream ins) throws Exception;
|
|
||||||
|
|
||||||
String getName();
|
|
||||||
}
|
|
@ -1,4 +0,0 @@
|
|||||||
package org.nutz.boot.starter.literpc.api;
|
|
||||||
|
|
||||||
public interface RpcService {
|
|
||||||
}
|
|
@ -1,68 +0,0 @@
|
|||||||
package org.nutz.boot.starter.literpc.impl;
|
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
|
||||||
import java.lang.reflect.Proxy;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import org.nutz.boot.starter.literpc.LiteRpc;
|
|
||||||
import org.nutz.boot.starter.literpc.annotation.RpcInject;
|
|
||||||
import org.nutz.boot.starter.literpc.impl.proxy.AbstractRpcRefProxy;
|
|
||||||
import org.nutz.ioc.Ioc;
|
|
||||||
import org.nutz.ioc.IocEventListener;
|
|
||||||
import org.nutz.ioc.loader.annotation.Inject;
|
|
||||||
import org.nutz.ioc.loader.annotation.IocBean;
|
|
||||||
import org.nutz.lang.Mirror;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 当一个ioc对象生成的时候,看看有无@RpcInject注解,如果有,注入代理对象
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
@IocBean(depose="depose")
|
|
||||||
public class LiteRpcInjectFactory implements IocEventListener {
|
|
||||||
|
|
||||||
@Inject("refer:$ioc")
|
|
||||||
protected Ioc ioc;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
protected LiteRpc liteRpc;
|
|
||||||
|
|
||||||
protected Map<String, AbstractRpcRefProxy> rpcProxys = new HashMap<>();
|
|
||||||
|
|
||||||
protected ClassLoader classLoader = getClass().getClassLoader();
|
|
||||||
|
|
||||||
public Object afterBorn(Object obj, String beanName) {
|
|
||||||
Mirror<Object> mirror = Mirror.me(obj);
|
|
||||||
Field[] fields = Mirror.me(obj).getFields();
|
|
||||||
for (Field field : fields) {
|
|
||||||
RpcInject rpcInject = field.getAnnotation(RpcInject.class);
|
|
||||||
if (rpcInject == null)
|
|
||||||
continue;
|
|
||||||
AbstractRpcRefProxy proxy = Mirror.me(rpcInject.by()).born();
|
|
||||||
proxy.setField(field);
|
|
||||||
proxy.setIoc(ioc);
|
|
||||||
proxy.setRpcInject(rpcInject);
|
|
||||||
proxy.setObject(obj);
|
|
||||||
proxy.setLiteRpc(liteRpc);
|
|
||||||
Object t = Proxy.newProxyInstance(classLoader, new Class[] {field.getType()}, proxy);
|
|
||||||
mirror.setValue(obj, field.getName(), t);
|
|
||||||
proxy.afterInject();
|
|
||||||
rpcProxys.put(field.toGenericString(), proxy);
|
|
||||||
}
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object afterCreate(Object obj, String beanName) {
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getOrder() {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void depose() {
|
|
||||||
for (AbstractRpcRefProxy proxy : rpcProxys.values()) {
|
|
||||||
proxy.beforeDepose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,32 +0,0 @@
|
|||||||
package org.nutz.boot.starter.literpc.impl;
|
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
|
|
||||||
import org.nutz.lang.reflect.FastClassFactory;
|
|
||||||
import org.nutz.lang.reflect.FastMethod;
|
|
||||||
|
|
||||||
public class RpcInvoker {
|
|
||||||
|
|
||||||
protected Object obj;
|
|
||||||
|
|
||||||
protected FastMethod fastMethod;
|
|
||||||
|
|
||||||
protected Method method;
|
|
||||||
|
|
||||||
public void setObj(Object obj) {
|
|
||||||
this.obj = obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setFastMethod(FastMethod fastMethod) {
|
|
||||||
this.fastMethod = fastMethod;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setMethod(Method method) {
|
|
||||||
this.method = method;
|
|
||||||
setFastMethod(FastClassFactory.get(method));
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object invoke(Object...args) throws Throwable {
|
|
||||||
return fastMethod.invoke(obj, args);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,41 +0,0 @@
|
|||||||
package org.nutz.boot.starter.literpc.impl;
|
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
|
|
||||||
import org.nutz.boot.starter.literpc.LiteRpc;
|
|
||||||
import org.nutz.boot.starter.literpc.api.RpcService;
|
|
||||||
import org.nutz.ioc.Ioc;
|
|
||||||
import org.nutz.ioc.loader.annotation.Inject;
|
|
||||||
import org.nutz.ioc.loader.annotation.IocBean;
|
|
||||||
import org.nutz.lang.Strings;
|
|
||||||
|
|
||||||
@IocBean(create="init")
|
|
||||||
public class RpcServiceScaner {
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
protected LiteRpc liteRpc;
|
|
||||||
|
|
||||||
@Inject("refer:$ioc")
|
|
||||||
protected Ioc ioc;
|
|
||||||
|
|
||||||
public void init() {
|
|
||||||
for (String beanName : ioc.getNamesByType(RpcService.class)) {
|
|
||||||
if (Strings.isBlank(beanName))
|
|
||||||
continue;
|
|
||||||
Object obj = ioc.get(null, beanName);
|
|
||||||
for (Class<?> klass : obj.getClass().getInterfaces()) {
|
|
||||||
if (klass == RpcService.class)
|
|
||||||
continue;
|
|
||||||
if (RpcService.class.isAssignableFrom(klass)) {
|
|
||||||
for (Method method : klass.getMethods()) {
|
|
||||||
RpcInvoker invoker = new RpcInvoker();
|
|
||||||
invoker.setObj(obj);
|
|
||||||
invoker.setMethod(method);
|
|
||||||
liteRpc.registerInovker(LiteRpc.getMethodSign(method), invoker);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
liteRpc.updateLoachRegInfo();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,67 +0,0 @@
|
|||||||
package org.nutz.boot.starter.literpc.impl.endpoint;
|
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
|
|
||||||
import org.nutz.boot.starter.literpc.RpcException;
|
|
||||||
import org.nutz.boot.starter.literpc.api.RpcReq;
|
|
||||||
import org.nutz.boot.starter.literpc.api.RpcResp;
|
|
||||||
import org.nutz.boot.starter.literpc.api.RpcSerializer;
|
|
||||||
import org.nutz.http.Header;
|
|
||||||
import org.nutz.http.Request;
|
|
||||||
import org.nutz.http.Response;
|
|
||||||
import org.nutz.http.Sender;
|
|
||||||
import org.nutz.ioc.loader.annotation.IocBean;
|
|
||||||
import org.nutz.lang.util.NutMap;
|
|
||||||
|
|
||||||
@IocBean
|
|
||||||
public class HttpRpcEndpoint implements RpcEndpoint {
|
|
||||||
|
|
||||||
public static String METHOD_HEADER_NAME = "LiteRpc-Method";
|
|
||||||
public static String SC_HEADER_NAME = "LiteRpc-Serializer";
|
|
||||||
public static String ENDPOINT_URI = "/literpc/endpoint";
|
|
||||||
|
|
||||||
public RpcResp send(RpcReq rpcReq, NutMap server, RpcSerializer serializer) {
|
|
||||||
String vip = server.getString("vip");
|
|
||||||
int port = server.getInt("port");
|
|
||||||
String url = "http://" + vip + ":" + port + ENDPOINT_URI;
|
|
||||||
Request req = Request.post(url);
|
|
||||||
Header header = req.getHeader();
|
|
||||||
header.clear();
|
|
||||||
header.set("Content-Type", "LiteRpcBody");
|
|
||||||
header.set(METHOD_HEADER_NAME, rpcReq.methodSign);
|
|
||||||
header.set(SC_HEADER_NAME, "jdk"); // 先固定为jdk,以后再扩展吧
|
|
||||||
|
|
||||||
ByteArrayOutputStream tmp = new ByteArrayOutputStream();
|
|
||||||
try {
|
|
||||||
serializer.write(rpcReq.args, tmp);
|
|
||||||
}
|
|
||||||
catch (Exception e1) {
|
|
||||||
return new RpcResp(e1);
|
|
||||||
}
|
|
||||||
req.setData(tmp.toByteArray());
|
|
||||||
|
|
||||||
Sender sender = Sender.create(req);
|
|
||||||
sender.setConnTimeout(rpcReq.connectTimeout);
|
|
||||||
sender.setTimeout(rpcReq.timeout);
|
|
||||||
Response resp;
|
|
||||||
try {
|
|
||||||
resp = sender.send();
|
|
||||||
if (!resp.isOK()) {
|
|
||||||
throw new RpcException("endpoint resp code=" + resp.getStatus());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception e) {
|
|
||||||
return new RpcResp(e);
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
return (RpcResp) serializer.read(resp.getStream());
|
|
||||||
}
|
|
||||||
catch (Exception e) {
|
|
||||||
return new RpcResp(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getName() {
|
|
||||||
return "http";
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,156 +0,0 @@
|
|||||||
package org.nutz.boot.starter.literpc.impl.endpoint;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.EnumSet;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import javax.servlet.DispatcherType;
|
|
||||||
import javax.servlet.Filter;
|
|
||||||
import javax.servlet.FilterChain;
|
|
||||||
import javax.servlet.FilterConfig;
|
|
||||||
import javax.servlet.ServletException;
|
|
||||||
import javax.servlet.ServletRequest;
|
|
||||||
import javax.servlet.ServletResponse;
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
|
||||||
|
|
||||||
import org.nutz.boot.starter.WebFilterFace;
|
|
||||||
import org.nutz.boot.starter.literpc.LiteRpc;
|
|
||||||
import org.nutz.boot.starter.literpc.api.RpcResp;
|
|
||||||
import org.nutz.boot.starter.literpc.api.RpcSerializer;
|
|
||||||
import org.nutz.boot.starter.literpc.impl.RpcInvoker;
|
|
||||||
import org.nutz.ioc.Ioc;
|
|
||||||
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;
|
|
||||||
|
|
||||||
@IocBean(create="_init")
|
|
||||||
public class HttpServletRpcEndpoint implements WebFilterFace, Filter {
|
|
||||||
|
|
||||||
private static final Log log = Logs.get();
|
|
||||||
|
|
||||||
@Inject("refer:$ioc")
|
|
||||||
protected Ioc ioc;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
protected PropertiesProxy conf;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
protected LiteRpc liteRpc;
|
|
||||||
|
|
||||||
protected boolean debug;
|
|
||||||
|
|
||||||
public void _init() {
|
|
||||||
debug = conf.getBoolean("literpc.endpoint.http.debug", false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
|
|
||||||
HttpServletRequest req = (HttpServletRequest)request;
|
|
||||||
HttpServletResponse resp = (HttpServletResponse)response;
|
|
||||||
// 首先,检查是否有LiteRpc特有的header
|
|
||||||
String methodSign = req.getHeader(HttpRpcEndpoint.METHOD_HEADER_NAME);
|
|
||||||
if (Strings.isBlank(methodSign)) {
|
|
||||||
if (debug)
|
|
||||||
log.debug("miss http header " + HttpRpcEndpoint.METHOD_HEADER_NAME);
|
|
||||||
resp.sendError(400);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
String scName = req.getHeader(HttpRpcEndpoint.SC_HEADER_NAME);
|
|
||||||
if (Strings.isBlank(scName)) {
|
|
||||||
if (debug)
|
|
||||||
log.debug("miss http header " + HttpRpcEndpoint.SC_HEADER_NAME);
|
|
||||||
resp.sendError(400);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
RpcSerializer serializer = liteRpc.getSerializer(scName);
|
|
||||||
if (serializer == null) {
|
|
||||||
if (debug)
|
|
||||||
log.debug("not support serializer=" + scName);
|
|
||||||
resp.sendError(400);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// 本服务器是否支持这个method
|
|
||||||
RpcInvoker invoker = liteRpc.getInvoker(methodSign);
|
|
||||||
if (invoker == null) {
|
|
||||||
resp.setHeader("LiteRpc-Msg", "No such Method at this service methodSign="+methodSign);
|
|
||||||
if (debug)
|
|
||||||
log.debug("no such method methodSign=" + methodSign);
|
|
||||||
resp.sendError(404);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// 反序列化方法参数
|
|
||||||
Object[] args;
|
|
||||||
try {
|
|
||||||
args = (Object[]) serializer.read(req.getInputStream());
|
|
||||||
}
|
|
||||||
catch (Throwable e) {
|
|
||||||
resp.setHeader("LiteRpc-Msg", "Serializer Exception when reading");
|
|
||||||
if (debug)
|
|
||||||
log.debug("Serializer Exception when reading", e);
|
|
||||||
resp.sendError(404);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// 执行之
|
|
||||||
RpcResp rpcResp = new RpcResp();
|
|
||||||
try {
|
|
||||||
rpcResp.returnValue = invoker.invoke(args);
|
|
||||||
}
|
|
||||||
catch (Throwable e) {
|
|
||||||
rpcResp.err = e;
|
|
||||||
}
|
|
||||||
// 将结果序列化
|
|
||||||
try {
|
|
||||||
serializer.write(rpcResp, resp.getOutputStream());
|
|
||||||
}
|
|
||||||
catch (Throwable e) {
|
|
||||||
if (debug)
|
|
||||||
log.debug("Serializer Exception when writing", e);
|
|
||||||
if (resp.isCommitted()) {
|
|
||||||
// nothing we can do
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
resp.reset();
|
|
||||||
resp.setHeader("LiteRpc-Msg", "Serializer Exception when write");
|
|
||||||
resp.sendError(404);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
public String getName() {
|
|
||||||
return "literpc";
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getPathSpec() {
|
|
||||||
return HttpRpcEndpoint.ENDPOINT_URI;
|
|
||||||
}
|
|
||||||
|
|
||||||
public EnumSet<DispatcherType> getDispatches() {
|
|
||||||
return EnumSet.of(DispatcherType.REQUEST);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Filter getFilter() {
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map<String, String> getInitParameters() {
|
|
||||||
return new HashMap<>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getOrder() {
|
|
||||||
return WebFilterFace.FilterOrder.NutFilter - 5;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void init(FilterConfig filterConfig) throws ServletException {
|
|
||||||
}
|
|
||||||
|
|
||||||
public void destroy() {
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,13 +0,0 @@
|
|||||||
package org.nutz.boot.starter.literpc.impl.endpoint;
|
|
||||||
|
|
||||||
import org.nutz.boot.starter.literpc.api.RpcReq;
|
|
||||||
import org.nutz.boot.starter.literpc.api.RpcResp;
|
|
||||||
import org.nutz.boot.starter.literpc.api.RpcSerializer;
|
|
||||||
import org.nutz.lang.util.NutMap;
|
|
||||||
|
|
||||||
public interface RpcEndpoint {
|
|
||||||
|
|
||||||
RpcResp send(RpcReq req, NutMap server, RpcSerializer serializer);
|
|
||||||
|
|
||||||
String getName();
|
|
||||||
}
|
|
@ -1,52 +0,0 @@
|
|||||||
package org.nutz.boot.starter.literpc.impl.proxy;
|
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
|
||||||
import java.lang.reflect.InvocationHandler;
|
|
||||||
|
|
||||||
import org.nutz.boot.starter.literpc.LiteRpc;
|
|
||||||
import org.nutz.boot.starter.literpc.annotation.RpcInject;
|
|
||||||
import org.nutz.boot.starter.literpc.api.RpcSerializer;
|
|
||||||
import org.nutz.boot.starter.literpc.impl.endpoint.RpcEndpoint;
|
|
||||||
import org.nutz.ioc.Ioc;
|
|
||||||
import org.nutz.lang.Strings;
|
|
||||||
|
|
||||||
public abstract class AbstractRpcRefProxy implements InvocationHandler {
|
|
||||||
|
|
||||||
protected Field field;
|
|
||||||
protected RpcInject rpcInect;
|
|
||||||
protected Ioc ioc;
|
|
||||||
protected Object object;
|
|
||||||
protected LiteRpc liteRpc;
|
|
||||||
|
|
||||||
protected RpcEndpoint endpoint;
|
|
||||||
|
|
||||||
protected RpcSerializer serializer;
|
|
||||||
|
|
||||||
public void setField(Field field) {
|
|
||||||
this.field = field;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setRpcInject(RpcInject rpcInect) {
|
|
||||||
this.rpcInect = rpcInect;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setIoc(Ioc ioc) {
|
|
||||||
this.ioc = ioc;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setObject(Object object) {
|
|
||||||
this.object = object;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setLiteRpc(LiteRpc liteRpc) {
|
|
||||||
this.liteRpc = liteRpc;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void afterInject() {
|
|
||||||
endpoint = liteRpc.getEndpoint(Strings.sBlank(rpcInect.endpointType(), "http"));
|
|
||||||
serializer = liteRpc.getSerializer(Strings.sBlank(rpcInect.serializer(), "jdk"));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void beforeDepose() {
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,39 +0,0 @@
|
|||||||
package org.nutz.boot.starter.literpc.impl.proxy;
|
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.concurrent.atomic.AtomicLong;
|
|
||||||
|
|
||||||
import org.nutz.boot.starter.literpc.LiteRpc;
|
|
||||||
import org.nutz.boot.starter.literpc.RpcException;
|
|
||||||
import org.nutz.boot.starter.literpc.api.RpcReq;
|
|
||||||
import org.nutz.boot.starter.literpc.api.RpcResp;
|
|
||||||
import org.nutz.lang.util.NutMap;
|
|
||||||
|
|
||||||
public class DefaultRpcInjectProxy extends AbstractRpcRefProxy {
|
|
||||||
|
|
||||||
protected AtomicLong AL = new AtomicLong();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
|
|
||||||
// 构建RpcReq
|
|
||||||
RpcReq req = new RpcReq();
|
|
||||||
req.args = args;
|
|
||||||
req.object = proxy;
|
|
||||||
req.connectTimeout = rpcInect.connectTimeout() == -1 ? 1000 : rpcInect.connectTimeout();
|
|
||||||
req.timeout = rpcInect.timeout() == -1 ? 1000 : rpcInect.timeout();
|
|
||||||
req.method = method;
|
|
||||||
req.methodSign = LiteRpc.getMethodSign(method);
|
|
||||||
// 获取支持该方法的服务器信息
|
|
||||||
List<NutMap> servers = liteRpc.getServers(req.methodSign);
|
|
||||||
if (servers == null || servers.isEmpty()) {
|
|
||||||
throw new RpcException("No server support -> [" + method + "]");
|
|
||||||
}
|
|
||||||
// 选一个,执行之
|
|
||||||
NutMap server = servers.get((int)(AL.incrementAndGet() % servers.size()));
|
|
||||||
RpcResp resp = endpoint.send(req, server, serializer);
|
|
||||||
if (resp.err == null)
|
|
||||||
return resp.returnValue;
|
|
||||||
throw resp.err;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,34 +0,0 @@
|
|||||||
package org.nutz.boot.starter.literpc.impl.serializer;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.ObjectInputStream;
|
|
||||||
import java.io.ObjectOutputStream;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
|
|
||||||
import org.nutz.boot.starter.literpc.api.RpcSerializer;
|
|
||||||
import org.nutz.ioc.loader.annotation.IocBean;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* JDK原生序列化, 最基本的,同时也是兼容性最好的序列化器
|
|
||||||
* @author wendal
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
@IocBean
|
|
||||||
public class JdkRpcSerializer implements RpcSerializer {
|
|
||||||
|
|
||||||
public void write(Object obj, OutputStream out) throws Exception {
|
|
||||||
ObjectOutputStream oos = new ObjectOutputStream(out);
|
|
||||||
oos.writeObject(obj);
|
|
||||||
oos.flush();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object read(InputStream ins) throws IOException, ClassNotFoundException {
|
|
||||||
ObjectInputStream ois = new ObjectInputStream(ins);
|
|
||||||
return ois.readObject();
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getName() {
|
|
||||||
return "jdk";
|
|
||||||
}
|
|
||||||
}
|
|
@ -1 +0,0 @@
|
|||||||
org.nutz.boot.starter.literpc.impl.RpcServiceScaner
|
|
@ -1,11 +0,0 @@
|
|||||||
<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-cloud</artifactId>
|
|
||||||
<version>2.2-SNAPSHOT</version>
|
|
||||||
</parent>
|
|
||||||
<artifactId>loach-client</artifactId>
|
|
||||||
<groupId>org.nutz.cloud</groupId>
|
|
||||||
</project>
|
|
@ -1,277 +0,0 @@
|
|||||||
package org.nutz.boot.starter.loach.client;
|
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.concurrent.ExecutorService;
|
|
||||||
import java.util.concurrent.Executors;
|
|
||||||
|
|
||||||
import org.nutz.boot.AppContext;
|
|
||||||
import org.nutz.boot.NbApp;
|
|
||||||
import org.nutz.http.Request;
|
|
||||||
import org.nutz.http.Request.METHOD;
|
|
||||||
import org.nutz.http.Response;
|
|
||||||
import org.nutz.http.Sender;
|
|
||||||
import org.nutz.ioc.Ioc;
|
|
||||||
import org.nutz.ioc.impl.PropertiesProxy;
|
|
||||||
import org.nutz.ioc.loader.annotation.Inject;
|
|
||||||
import org.nutz.ioc.loader.annotation.IocBean;
|
|
||||||
import org.nutz.json.Json;
|
|
||||||
import org.nutz.json.JsonFormat;
|
|
||||||
import org.nutz.lang.Strings;
|
|
||||||
import org.nutz.lang.hardware.NetworkType;
|
|
||||||
import org.nutz.lang.hardware.Networks;
|
|
||||||
import org.nutz.lang.random.R;
|
|
||||||
import org.nutz.lang.util.NutMap;
|
|
||||||
import org.nutz.log.Log;
|
|
||||||
import org.nutz.log.Logs;
|
|
||||||
import org.nutz.runner.NutRunner;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* '泥鳅'客户端
|
|
||||||
*
|
|
||||||
* @author wendal
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
@IocBean(create = "init", depose = "depose")
|
|
||||||
public class LoachClient extends NutRunner {
|
|
||||||
|
|
||||||
public LoachClient() {
|
|
||||||
super("loach.client");
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final Log log = Logs.get();
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
protected PropertiesProxy conf;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
protected AppContext appContext;
|
|
||||||
|
|
||||||
@Inject("refer:$ioc")
|
|
||||||
protected Ioc ioc;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
protected NbApp nbApp;
|
|
||||||
|
|
||||||
protected String id;
|
|
||||||
|
|
||||||
protected int startUpDelay;
|
|
||||||
|
|
||||||
protected ExecutorService es;
|
|
||||||
|
|
||||||
protected NutRunner updater;
|
|
||||||
|
|
||||||
protected List<UpdateListener> listeners = new LinkedList<>();
|
|
||||||
|
|
||||||
public static interface UpdateListener {
|
|
||||||
void onUpdate(Map<String, List<NutMap>> services);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void depose() {
|
|
||||||
getLock().stop();
|
|
||||||
if (updater != null)
|
|
||||||
updater.getLock().stop();
|
|
||||||
es.shutdown();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void init() {
|
|
||||||
startUpDelay = conf.getInt("loach.client.startUpDelay", -1);
|
|
||||||
es = Executors.newCachedThreadPool();
|
|
||||||
id = R.UU32();
|
|
||||||
url = conf.get("loach.client.url", "http://127.0.0.1:8610/loach/v1");
|
|
||||||
for (String name : ioc.getNamesByType(UpdateListener.class)) {
|
|
||||||
addListener(ioc.get(UpdateListener.class, name));
|
|
||||||
}
|
|
||||||
|
|
||||||
setDebug(conf.getBoolean("loach.client.debug", false));
|
|
||||||
if (conf.getBoolean("loach.client.enable", true)) {
|
|
||||||
if (Strings.isBlank(conf.get("nutz.application.name"))) {
|
|
||||||
throw new RuntimeException("need nutz.application.name");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (conf.getBoolean("loach.client.enable", true)) {
|
|
||||||
es.submit(this);
|
|
||||||
}
|
|
||||||
if (conf.getBoolean("loach.updater.enable", true)) {
|
|
||||||
updater = new NutRunner("loach.updater." + url) {
|
|
||||||
public long exec() throws Exception {
|
|
||||||
LoachClient.this.updateServiceList();
|
|
||||||
return conf.getInt("loach.client.updater.interval", 3000);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
updater.setDebug(isDebug());
|
|
||||||
es.submit(updater);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map<String, List<NutMap>> getServiceList() {
|
|
||||||
return Collections.unmodifiableMap(serviceList);
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<NutMap> getService(String name) {
|
|
||||||
if (serviceList == null)
|
|
||||||
return null;
|
|
||||||
return serviceList.get(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected String getUrls() {
|
|
||||||
return conf.get("loach.client.url", "http://127.0.0.1:8610/loach/v1");
|
|
||||||
}
|
|
||||||
|
|
||||||
protected String getServiceName() {
|
|
||||||
return conf.get("nutz.application.name", "demo");
|
|
||||||
}
|
|
||||||
|
|
||||||
protected long getPingInterval() {
|
|
||||||
return conf.getLong("loach.client.ping.interval", 3000);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected int pingRetryCount;
|
|
||||||
|
|
||||||
public String url;
|
|
||||||
|
|
||||||
protected String lastPingETag = "ABC";
|
|
||||||
|
|
||||||
protected String lastListETag = "ABC";
|
|
||||||
|
|
||||||
protected boolean regOk;
|
|
||||||
|
|
||||||
protected boolean _reg(String regData) {
|
|
||||||
try {
|
|
||||||
String regURL = url + "/reg";
|
|
||||||
if (isDebug()) {
|
|
||||||
log.debug("Reg URL :" + regURL);
|
|
||||||
log.debug("Reg Data:" + regData);
|
|
||||||
}
|
|
||||||
Request req = Request.create(regURL, METHOD.POST);
|
|
||||||
req.setData(regData);
|
|
||||||
req.getHeader().clear();
|
|
||||||
req.getHeader().asJsonContentType();
|
|
||||||
Response resp = Sender.create(req).setTimeout(3000).send();
|
|
||||||
if (resp.isOK()) {
|
|
||||||
NutMap re = Json.fromJson(NutMap.class, resp.getReader());
|
|
||||||
if (re != null && re.getBoolean("ok", false)) {
|
|
||||||
log.infof("Reg Done id=%s url=%s", id, url);
|
|
||||||
regOk = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Throwable e) {
|
|
||||||
log.debugf("bad url? %s %s", url, e.getMessage());
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected boolean _ping() {
|
|
||||||
try {
|
|
||||||
String pingURL = url + "/ping/" + getServiceName() + "/" + id;
|
|
||||||
if (isDebug())
|
|
||||||
log.debug("Ping URL=" + pingURL);
|
|
||||||
Request req = Request.create(pingURL, METHOD.GET);
|
|
||||||
req.getHeader().clear();
|
|
||||||
req.getHeader().set("If-Not-Match", lastPingETag);
|
|
||||||
Response resp = Sender.create(req, conf.getInt("loach.client.ping.timeout", 1000)).setConnTimeout(1000).send();
|
|
||||||
String cnt = resp.getContent();
|
|
||||||
if (isDebug())
|
|
||||||
log.debug("Ping result : " + cnt);
|
|
||||||
if (resp.isOK()) {
|
|
||||||
lastPingETag = Strings.sBlank(resp.getHeader().get("ETag"), "ABC");
|
|
||||||
NutMap re = Json.fromJson(NutMap.class, cnt);
|
|
||||||
if (re != null && re.getBoolean("ok", false))
|
|
||||||
return true;
|
|
||||||
} else if (resp.getStatus() == 304) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Throwable e) {
|
|
||||||
log.debugf("bad url? %s %s", url, e.getMessage());
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 主逻辑
|
|
||||||
*/
|
|
||||||
public long exec() throws Exception {
|
|
||||||
// 启动延时
|
|
||||||
if (startUpDelay > 0) {
|
|
||||||
log.debug("start up delay " + startUpDelay + "ms");
|
|
||||||
int delay = startUpDelay;
|
|
||||||
startUpDelay = 0;
|
|
||||||
return delay;
|
|
||||||
} else if (startUpDelay == -1) {
|
|
||||||
if (!nbApp.isStarted())
|
|
||||||
return 100;
|
|
||||||
}
|
|
||||||
// 心跳
|
|
||||||
if (regOk) {
|
|
||||||
// 尝试心跳,成功就是返回
|
|
||||||
if (_ping()) {
|
|
||||||
if (pingRetryCount > 0 && isDebug())
|
|
||||||
log.debug("loach client ping OK");
|
|
||||||
pingRetryCount = 0;
|
|
||||||
return getPingInterval();
|
|
||||||
} else {
|
|
||||||
if (pingRetryCount < 5) {
|
|
||||||
pingRetryCount++;
|
|
||||||
log.info("loach client ping FAIL count=" + pingRetryCount);
|
|
||||||
return getInterval();
|
|
||||||
} else {
|
|
||||||
regOk = false;
|
|
||||||
log.info("loach client ping FAIL too many time, redo reg!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
NutMap regInfo = new NutMap();
|
|
||||||
regInfo.put("id", id);
|
|
||||||
regInfo.put("name", getServiceName());
|
|
||||||
regInfo.put("vip", conf.get("server.vip", "127.0.0.1"));
|
|
||||||
regInfo.put("port", appContext.getServerPort(null));
|
|
||||||
regInfo.put("eth.mac", Networks.mac(NetworkType.LAN));
|
|
||||||
regInfo.put("eth.ipv4", Networks.ipv4(NetworkType.LAN));
|
|
||||||
regInfo.putAll(EXT_REG_DATA);
|
|
||||||
String regData = Json.toJson(regInfo, JsonFormat.compact());
|
|
||||||
_reg(regData);
|
|
||||||
return getInterval();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map<String, List<NutMap>> serviceList = new HashMap<>();
|
|
||||||
protected long lastChecked;
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public void updateServiceList() {
|
|
||||||
try {
|
|
||||||
String listURL = url + "/list";
|
|
||||||
Request req = Request.create(listURL, METHOD.GET);
|
|
||||||
req.getHeader().clear();
|
|
||||||
req.getHeader().set("If-Not-Match", lastListETag);
|
|
||||||
Response resp = Sender.create(req).setConnTimeout(1000).setTimeout(3000).send();
|
|
||||||
if (resp.isOK()) {
|
|
||||||
serviceList = (Map<String, List<NutMap>>) Json.fromJson(NutMap.class, resp.getReader()).get("data");
|
|
||||||
for (UpdateListener listener : listeners) {
|
|
||||||
listener.onUpdate(serviceList);
|
|
||||||
}
|
|
||||||
lastChecked = System.currentTimeMillis();
|
|
||||||
lastListETag = Strings.sBlank(resp.getHeader().get("ETag", "ABC"));
|
|
||||||
} else if (resp.getStatus() == 304) {
|
|
||||||
// ok
|
|
||||||
lastChecked = System.currentTimeMillis();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Throwable e) {
|
|
||||||
log.debugf("bad url? %s %s", url, e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addListener(UpdateListener listener) {
|
|
||||||
if (this.listeners.contains(listener))
|
|
||||||
return;
|
|
||||||
listeners.add(listener);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static NutMap EXT_REG_DATA = new NutMap();
|
|
||||||
}
|
|
@ -1,40 +0,0 @@
|
|||||||
package org.nutz.boot.starter.loach.client;
|
|
||||||
|
|
||||||
import org.nutz.boot.annotation.PropDoc;
|
|
||||||
import org.nutz.boot.starter.ServerFace;
|
|
||||||
import org.nutz.ioc.Ioc;
|
|
||||||
import org.nutz.ioc.loader.annotation.Inject;
|
|
||||||
import org.nutz.ioc.loader.annotation.IocBean;
|
|
||||||
|
|
||||||
@IocBean
|
|
||||||
public class LoachClientStarter implements ServerFace {
|
|
||||||
|
|
||||||
@PropDoc(value = "是否启用'泥鳅'客户端", defaultValue = "true")
|
|
||||||
public static final String PROP_CLIENT_ENABLE = "loach.client.enable";
|
|
||||||
|
|
||||||
@PropDoc(value = "是否启用'泥鳅'服务器列表更新", defaultValue = "true")
|
|
||||||
public static final String PROP_UPDATER_ENABLE = "loach.updater.enable";
|
|
||||||
|
|
||||||
@PropDoc(value = "对外服务的虚拟ip或者域名", defaultValue="127.0.0.1")
|
|
||||||
public static final String PROP_HOST = "server.vip";
|
|
||||||
|
|
||||||
@PropDoc(value = "心跳频率,单位毫秒", defaultValue = "3000", type = "int")
|
|
||||||
public static final String PROP_PING_INTERVAL = "loach.client.ping.interval";
|
|
||||||
|
|
||||||
@PropDoc(value = "启动延时,单位毫秒", defaultValue = "-1", type = "int")
|
|
||||||
public static final String PROP_STARTUP_DELAY = "loach.client.startUpDelay";
|
|
||||||
|
|
||||||
@PropDoc(value = "'泥鳅'服务器的URL,可以多个,用分号隔开即可", defaultValue = "http://127.0.0.1:8610/loach/v1")
|
|
||||||
public static final String PROP_URLS = "loach.client.urls";
|
|
||||||
|
|
||||||
@PropDoc(value = "调试模式", defaultValue = "false")
|
|
||||||
public static final String PROP_DEBUG = "loach.client.debug";
|
|
||||||
|
|
||||||
|
|
||||||
@Inject("refer:$ioc")
|
|
||||||
protected Ioc ioc;
|
|
||||||
|
|
||||||
public void start() throws Exception {
|
|
||||||
ioc.get(LoachClient.class);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1 +0,0 @@
|
|||||||
org.nutz.boot.starter.loach.client.LoachClientStarter
|
|
@ -1,33 +0,0 @@
|
|||||||
<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-cloud</artifactId>
|
|
||||||
<version>2.2-SNAPSHOT</version>
|
|
||||||
</parent>
|
|
||||||
<groupId>org.nutz.cloud</groupId>
|
|
||||||
<artifactId>loach-server</artifactId>
|
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.nutz</groupId>
|
|
||||||
<artifactId>nutzboot-starter-jetty</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.nutz</groupId>
|
|
||||||
<artifactId>nutzboot-starter-nutz-mvc</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.nutz</groupId>
|
|
||||||
<artifactId>nutzboot-starter-redis</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.nutz</groupId>
|
|
||||||
<artifactId>nutzboot-starter-swagger</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.slf4j</groupId>
|
|
||||||
<artifactId>slf4j-log4j12</artifactId>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
</project>
|
|
@ -1,46 +0,0 @@
|
|||||||
package org.nutz.cloud.loach.server;
|
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
|
||||||
|
|
||||||
import org.nutz.ioc.Ioc;
|
|
||||||
import org.nutz.ioc.loader.annotation.IocBean;
|
|
||||||
import org.nutz.json.Json;
|
|
||||||
import org.nutz.json.JsonFormat;
|
|
||||||
import org.nutz.lang.Lang;
|
|
||||||
import org.nutz.mvc.View;
|
|
||||||
import org.nutz.mvc.ViewMaker;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 为了减少 客户端与服务器端之间的流量, 做点黑魔法. <p/>
|
|
||||||
* 如果客户端发送了ETag,与服务器端的计算结果一样,那就是没变更啦,304!
|
|
||||||
* @author wendal
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
@IocBean(name="$views_json304")
|
|
||||||
public class Json304ViewMaker implements ViewMaker, View {
|
|
||||||
|
|
||||||
private static JsonFormat jf = JsonFormat.compact();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public View make(Ioc ioc, String type, String value) {
|
|
||||||
if ("json304".equals(type))
|
|
||||||
return this;
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void render(HttpServletRequest req, HttpServletResponse resp, Object obj) throws Throwable {
|
|
||||||
String data = obj instanceof String ? obj.toString() : Json.toJson(obj, jf);
|
|
||||||
String sha1 = Lang.sha1(data);
|
|
||||||
byte[] re = data.getBytes();
|
|
||||||
if (sha1.equalsIgnoreCase(req.getHeader("If-None-Match"))) {
|
|
||||||
resp.setStatus(304);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
resp.setContentLength(re.length);
|
|
||||||
resp.setHeader("ETag", sha1);
|
|
||||||
resp.getOutputStream().write(re);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,12 +0,0 @@
|
|||||||
package org.nutz.cloud.loach.server;
|
|
||||||
|
|
||||||
import org.nutz.boot.NbApp;
|
|
||||||
|
|
||||||
public class LoachServerLauncher {
|
|
||||||
|
|
||||||
// 访问地址是 http://127.0.0.1:8610
|
|
||||||
public static void main(String[] args) {
|
|
||||||
new NbApp().setArgs(args).setPrintProcDoc(true).run();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,190 +0,0 @@
|
|||||||
package org.nutz.cloud.loach.server.module;
|
|
||||||
|
|
||||||
import static org.nutz.integration.jedis.RedisInterceptor.jedis;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import org.nutz.ioc.aop.Aop;
|
|
||||||
import org.nutz.ioc.impl.PropertiesProxy;
|
|
||||||
import org.nutz.ioc.loader.annotation.Inject;
|
|
||||||
import org.nutz.ioc.loader.annotation.IocBean;
|
|
||||||
import org.nutz.json.Json;
|
|
||||||
import org.nutz.json.JsonFormat;
|
|
||||||
import org.nutz.lang.Strings;
|
|
||||||
import org.nutz.lang.random.R;
|
|
||||||
import org.nutz.lang.util.NutMap;
|
|
||||||
import org.nutz.lang.util.Regex;
|
|
||||||
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.GET;
|
|
||||||
import org.nutz.mvc.annotation.Ok;
|
|
||||||
import org.nutz.mvc.annotation.POST;
|
|
||||||
|
|
||||||
@IocBean
|
|
||||||
@At("/loach/v1")
|
|
||||||
@Ok("json304")
|
|
||||||
public class LoachV1Module {
|
|
||||||
|
|
||||||
protected JsonFormat jsonFormat = JsonFormat.compact();
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
protected PropertiesProxy conf;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 供客户端心跳入口
|
|
||||||
*/
|
|
||||||
@At({"/ping", "/ping/?/?"})
|
|
||||||
@Aop("redis")
|
|
||||||
@GET
|
|
||||||
public String ping(String serviceName, String id) {
|
|
||||||
if (id != null && id.length() < 30) {
|
|
||||||
long re = jedis().expire("loach:service:" + serviceName + ":" + id, getPingTimeout() / 1000);
|
|
||||||
if (re == 0) {
|
|
||||||
return "{ok:false}";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return "{ok:true}";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 注册一个服务,必须带service.vip和service.name,其他属性可任选.
|
|
||||||
*/
|
|
||||||
@AdaptBy(type = JsonAdaptor.class)
|
|
||||||
@POST
|
|
||||||
@At
|
|
||||||
@Aop("redis")
|
|
||||||
public NutMap reg(NutMap params) {
|
|
||||||
NutMap map = new NutMap();
|
|
||||||
// 检查基本的信息
|
|
||||||
if (Strings.isBlank(params.getString("vip"))) {
|
|
||||||
map.put("err", "miss vip");
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
String serviceName = (String) params.remove("name");
|
|
||||||
if (Strings.isBlank(serviceName)) {
|
|
||||||
map.put("err", "miss name");
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
if (!Regex.match("^[a-zA-Z0-9_-]{3,16}$", serviceName)) {
|
|
||||||
map.put("err", "name is invaild");
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
String regJson = Json.toJson(params, jsonFormat);
|
|
||||||
if (regJson.length() > getRegMaxSize()) {
|
|
||||||
map.put("err", "reg info is too big");
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
String id = params.getString("id");
|
|
||||||
if (id == null)
|
|
||||||
id = R.UU32();
|
|
||||||
jedis().setex("loach:service:" + serviceName + ":" + id, getPingTimeout() / 1000, regJson);
|
|
||||||
map.setv("ok", true).setv("id", id);
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
|
|
||||||
@At
|
|
||||||
@DELETE
|
|
||||||
@Ok("void")
|
|
||||||
public void unreg(String serviceName, String id) {
|
|
||||||
if (isAllowUnreg())
|
|
||||||
jedis().del("loach:service:" + serviceName + ":" + id);
|
|
||||||
}
|
|
||||||
|
|
||||||
@At("/list/?")
|
|
||||||
@Aop("redis")
|
|
||||||
public NutMap list(String serviceName) {
|
|
||||||
List<String> keys = new ArrayList<>(jedis().keys("loach:service:" + serviceName + ":*"));
|
|
||||||
Collections.sort(keys);
|
|
||||||
|
|
||||||
NutMap re = new NutMap();
|
|
||||||
re.put("ok", true);
|
|
||||||
List<NutMap> services = new LinkedList<>();
|
|
||||||
for (String key : keys) {
|
|
||||||
String cnt = jedis().get(key);
|
|
||||||
if (cnt == null)
|
|
||||||
continue;
|
|
||||||
NutMap serviceInfo = Json.fromJson(NutMap.class, cnt);
|
|
||||||
services.add(serviceInfo);
|
|
||||||
}
|
|
||||||
re.put("data", new NutMap(serviceName, services));
|
|
||||||
return re;
|
|
||||||
}
|
|
||||||
|
|
||||||
@At("/list")
|
|
||||||
public NutMap listAll() {
|
|
||||||
NutMap re = new NutMap();
|
|
||||||
re.put("ok", true);
|
|
||||||
re.put("data", getAllServices());
|
|
||||||
return re;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Ok("raw")
|
|
||||||
@At("/list/forlook")
|
|
||||||
public String listAllForLook(boolean verbose) {
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
Map<String, List<NutMap>> services = getAllServices();
|
|
||||||
String NL = "\r\n";
|
|
||||||
sb.append("Service Count : ").append(services.size()).append(NL);
|
|
||||||
if (services.size() > 0) {
|
|
||||||
sb.append("Services :").append(NL);
|
|
||||||
for (String serviceName : services.keySet()) {
|
|
||||||
sb.append(" - ").append(serviceName).append(" :").append(NL);
|
|
||||||
for (NutMap service : services.get(serviceName)) {
|
|
||||||
sb.append(" - ").append(service.get("id"));
|
|
||||||
if (verbose) {
|
|
||||||
sb.append(":").append(NL);
|
|
||||||
for (Map.Entry<String, Object> en2 : service.entrySet()) {
|
|
||||||
sb.append(" - ").append(en2.getKey()).append(" : ").append(en2.getValue()).append(NL);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
sb.append(" : ").append(service.get("vip")).append(":").append(service.getInt("port")).append(NL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return sb.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Aop("redis")
|
|
||||||
protected Map<String, List<NutMap>> getAllServices() {
|
|
||||||
List<String> keys = new ArrayList<>(jedis().keys("loach:service:*"));
|
|
||||||
Collections.sort(keys);
|
|
||||||
Map<String, List<NutMap>> services = new HashMap<>();
|
|
||||||
for (String key : keys) {
|
|
||||||
String[] tmp = key.split("\\:");
|
|
||||||
if (tmp.length != 4)
|
|
||||||
continue;
|
|
||||||
String cnt = jedis().get(key);
|
|
||||||
if (cnt == null)
|
|
||||||
continue;
|
|
||||||
NutMap serviceInfo = Json.fromJson(NutMap.class, cnt);
|
|
||||||
List<NutMap> infos = services.get(tmp[2]);
|
|
||||||
if (infos == null) {
|
|
||||||
infos = new LinkedList<>();
|
|
||||||
services.put(tmp[2], infos);
|
|
||||||
}
|
|
||||||
serviceInfo.put("id", tmp[3]);
|
|
||||||
infos.add(serviceInfo);
|
|
||||||
}
|
|
||||||
return services;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getPingTimeout() {
|
|
||||||
return conf.getInt("loach.server.ping.timeout", 15000);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getRegMaxSize() {
|
|
||||||
return conf.getInt("loach.server.reg.maxSize", 8192);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isAllowUnreg() {
|
|
||||||
return conf.getBoolean("loach.server.unreg.enable", false);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,3 +0,0 @@
|
|||||||
nutz.application.name=loach-server
|
|
||||||
server.port=8610
|
|
||||||
server.ip=0.0.0.0
|
|
@ -1,12 +0,0 @@
|
|||||||
log4j.rootLogger=debug,Console
|
|
||||||
|
|
||||||
log4j.logger.org.eclipse.jetty=info
|
|
||||||
log4j.logger.org.apache.jasper=info
|
|
||||||
log4j.logger.org.nutz.ioc=warn
|
|
||||||
log4j.logger.org.nutz.mvc=info
|
|
||||||
log4j.logger.org.nutz.resource=info
|
|
||||||
log4j.logger.io.swagger=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
|
|
@ -1,17 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>'泥鳅'服务器</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div>
|
|
||||||
<h2>这里提供服务注册/服务发现</h2>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<h2>
|
|
||||||
<a href="loach/v1/list/forlook">查看已注册的服务</a>
|
|
||||||
</h2>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
@ -1,36 +0,0 @@
|
|||||||
<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-parent</artifactId>
|
|
||||||
<version>2.2-SNAPSHOT</version>
|
|
||||||
</parent>
|
|
||||||
<artifactId>nutzboot-cloud</artifactId>
|
|
||||||
<packaging>pom</packaging>
|
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.nutz</groupId>
|
|
||||||
<artifactId>nutzboot-core</artifactId>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
<modules>
|
|
||||||
<module>loach-client</module>
|
|
||||||
<module>literpc</module>
|
|
||||||
</modules>
|
|
||||||
<profiles>
|
|
||||||
<profile>
|
|
||||||
<id>demo</id>
|
|
||||||
<modules>
|
|
||||||
<module>cloud-demo</module>
|
|
||||||
</modules>
|
|
||||||
</profile>
|
|
||||||
<profile>
|
|
||||||
<id>standalone</id>
|
|
||||||
<modules>
|
|
||||||
<module>loach-server</module>
|
|
||||||
<module>gateway-server</module>
|
|
||||||
</modules>
|
|
||||||
</profile>
|
|
||||||
</profiles>
|
|
||||||
</project>
|
|
Loading…
Reference in New Issue
Block a user