mirror of
https://gitee.com/nutz/nutzboot.git
synced 2024-12-02 03:38:08 +08:00
change: 各位基友强烈要求把nutzcloud的代码分开放
This commit is contained in:
parent
fa6f163851
commit
df91caa94e
@ -10,10 +10,6 @@
|
||||
* add: 添加单元测试的支持
|
||||
* add: shiro主动搜索ioc容器内的SessionListener并添加到SessionManager
|
||||
* 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 "平凡之路"
|
||||
|
||||
|
@ -159,7 +159,7 @@ public class MainLauncher {
|
||||
- [x] starter-config-client NB Config Client 配置中心的客户端
|
||||
- [x] starter-[apollo-client](https://github.com/ctripcorp/apollo) 携程框架部门研发的分布式配置中心的客户端
|
||||
- API网关
|
||||
- [x] gateway-server NB API网关服务器
|
||||
- [x] gateway-server NC API网关服务器
|
||||
- [ ] 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