Transport 改版

This commit is contained in:
wentch
2016-01-12 15:12:40 +08:00
parent f0cc76a1d6
commit 585d5866e6
24 changed files with 491 additions and 411 deletions

View File

@@ -26,16 +26,25 @@
<application port="6560" lib="">
<!-- 所有服务所需的资源 -->
<resources>
<!--
<resources>
<!--
transport节点只能有一个用于配置所有Transport的池参数没配置该节点将自动创建一个。
threads 线程总数, 默认: <group>节点数*CPU核数*8
bufferCapacity: ByteBuffer的初始化大小 默认: 8K;
bufferPoolSize ByteBuffer池的大小默认: <group>节点数*CPU核数*8
-->
<transport capacity="8192" bufferPoolSize="32" threads="32"/>
<!--
一个组包含多个NODE 同一Service服务可以由多个进程提供这些进程称为一个GROUP且同一GROUP内的进程必须在同一机房或局域网内
name: 服务组ID长度不能超过11个字节. 默认为空字符串
一个group节点对应一个 Transport 对象
name: 服务组ID长度不能超过11个字节. 默认为空字符串。 注意: name不能包含$符号。
protocol值只能是UDP TCP 默认TCP
注意: 一个node只能所属一个group。只要存在protocol=SNCP的Server节点信息 就必须有group节点信息。
-->
<group name="" protocol="TCP">
<!--
需要将本地node的addr与port列在此处。
同一个<node>节点值只能存在一个<group>节点内即同一个addr+port只能属于一个group。
addr: required IP地址
port: required 端口
clients: 连接池数, 默认: CPU核数*4
@@ -73,7 +82,7 @@
backlog: 默认10K
threads 线程总数, 默认: CPU核数*16
maxbody: request.body最大值 默认: 64K
capacity: ByteBuffer的初始化大小 默认: 8K; 如果是HTTP协议则默认: 16K + 8B (兼容HTTP 2.0)
bufferCapacity: ByteBuffer的初始化大小 默认: 8K; 如果是HTTP协议则默认: 16K + 8B (兼容HTTP 2.0)
bufferPoolSize ByteBuffer池的大小默认: CPU核数*512
responsePoolSize Response池的大小默认: CPU核数*256
readTimeoutSecond: 读操作超时秒数, 默认0 表示永久不超时
@@ -98,7 +107,7 @@
<!-- 显著加载指定的Service的接口类 -->
<service value="com.xxx.XXX1Service"/>
<!--
name: 显式指定name覆盖默认的空字符串值。
name: 显式指定name覆盖默认的空字符串值。 注意: name不能包含$符号。
groups: 显式指定groups覆盖<services>节点的groups默认值。
-->
<service value="com.xxx.XXX2Service" name="" groups="xxx;yyy"/>
@@ -113,7 +122,7 @@
当Server为HTTP协议时, request节点才有效。
remoteaddr 节点: 替换请求方节点的IP地址 通常请求方是由nginx等web静态服务器转发过的则需要配置该节点。
且value值只能是以request.headers.开头表示从request.headers中获取对应的header值。
例如下面例子获取request.getRemoteAddr()值如果header存在X-RemoteAddress值则返回X-RemoteAddress值不存在返回request.getRemoteAddress()。
例如下面例子获取request.getRemoteAddr()值如果header存在X-RemoteAddress值则返回X-RemoteAddress值不存在返回getRemoteAddress()。
-->
<request>
<remoteaddr value="request.headers.X-RemoteAddress"/>

View File

@@ -63,19 +63,18 @@ public final class Application {
public static final String RESNAME_APP_NODES = "APP_NODES";
//当前Service的IP地址+端口 类型: SocketAddress、InetSocketAddress、String
public static final String RESNAME_SERVER_ADDR = "SERVER_ADDR"; // SERVER_ADDR
public static final String RESNAME_SERVER_ADDR = "SERVER_ADDR";
//当前SNCP Server所属的组 类型: String
public static final String RESNAME_SERVER_GROUP = "SERVER_GROUP";
//当前Service所属的组 类型: Set<String>、String[]
public static final String RESNAME_SNCP_GROUPS = Sncp.RESNAME_SNCP_GROUPS; // SNCP_GROUPS
final Map<InetSocketAddress, String> globalNodes = new HashMap<>();
final Map<String, Set<InetSocketAddress>> globalGroups = new HashMap<>();
final List<Transport> transports = new ArrayList<>();
final Map<String, String> globalGroupProtocols = new HashMap<>();
final Map<String, Transport> transports = new HashMap<>();
final InetAddress localAddress;
@@ -87,12 +86,18 @@ public final class Application {
CountDownLatch servicecdl; //会出现两次赋值
final ObjectPool<ByteBuffer> transportBufferPool;
final ExecutorService transportExecutor;
final AsynchronousChannelGroup transportChannelGroup;
//--------------------------------------------------------------------------------------------
private final ResourceFactory factory = ResourceFactory.root();
private final WatchFactory watch = WatchFactory.root();
private File home;
private final File home;
private final Logger logger;
@@ -185,6 +190,47 @@ public final class Application {
}
this.logger = Logger.getLogger(this.getClass().getSimpleName());
this.serversLatch = new CountDownLatch(config.getAnyValues("server").length + 1);
//------------------配置 <transport> 节点 ------------------
ObjectPool<ByteBuffer> transportPool = null;
ExecutorService transportExec = null;
AsynchronousChannelGroup transportGroup = null;
final AnyValue resources = config.getAnyValue("resources");
if (resources != null) {
AnyValue transportConf = resources.getAnyValue("transport");
int groupsize = resources.getAnyValues("group").length;
if (groupsize > 0 && transportConf == null) transportConf = new DefaultAnyValue();
if (transportConf != null) {
//--------------transportBufferPool-----------
AtomicLong createBufferCounter = watch == null ? new AtomicLong() : watch.createWatchNumber(Transport.class.getSimpleName() + ".Buffer.creatCounter");
AtomicLong cycleBufferCounter = watch == null ? new AtomicLong() : watch.createWatchNumber(Transport.class.getSimpleName() + ".Buffer.cycleCounter");
final int bufferCapacity = transportConf.getIntValue("bufferCapacity", 8 * 1024);
final int bufferPoolSize = transportConf.getIntValue("bufferPoolSize", groupsize * Runtime.getRuntime().availableProcessors() * 8);
final int threads = transportConf.getIntValue("threads", groupsize * Runtime.getRuntime().availableProcessors() * 8);
transportPool = new ObjectPool<>(createBufferCounter, cycleBufferCounter, bufferPoolSize,
(Object... params) -> ByteBuffer.allocateDirect(bufferCapacity), null, (e) -> {
if (e == null || e.isReadOnly() || e.capacity() != bufferCapacity) return false;
e.clear();
return true;
});
//-----------transportChannelGroup--------------
try {
final AtomicInteger counter = new AtomicInteger();
transportExec = Executors.newFixedThreadPool(threads, (Runnable r) -> {
Thread t = new Thread(r);
t.setDaemon(true);
t.setName("Transport-Thread-" + counter.incrementAndGet());
return t;
});
transportGroup = AsynchronousChannelGroup.withCachedThreadPool(transportExec, 1);
} catch (Exception e) {
throw new RuntimeException(e);
}
logger.log(Level.INFO, Transport.class.getSimpleName() + " configure bufferCapacity = " + bufferCapacity + "; bufferPoolSize = " + bufferPoolSize + "; threads = " + threads + ";");
}
}
this.transportBufferPool = transportPool;
this.transportExecutor = transportExec;
this.transportChannelGroup = transportGroup;
}
public ResourceFactory getResourceFactory() {
@@ -279,13 +325,14 @@ public final class Application {
for (AnyValue conf : resources.getAnyValues("group")) {
final String group = conf.getValue("name", "");
String protocol = conf.getValue("protocol", Transport.DEFAULT_PROTOCOL).toUpperCase();
final String protocol = conf.getValue("protocol", Transport.DEFAULT_PROTOCOL).toUpperCase();
if (!"TCP".equalsIgnoreCase(protocol) && !"UDP".equalsIgnoreCase(protocol)) {
throw new RuntimeException("Not supported Transport Protocol " + conf.getValue("protocol"));
}
Set<InetSocketAddress> addrs = globalGroups.get(group);
if (addrs == null) {
addrs = new LinkedHashSet<>();
globalGroupProtocols.put(group, protocol);
globalGroups.put(group, addrs);
}
for (AnyValue node : conf.getAnyValues("node")) {
@@ -479,8 +526,8 @@ public final class Application {
public static <T extends Service> T singleton(Class<T> serviceClass, boolean remote) throws Exception {
final Application application = Application.create();
Consumer<Runnable> executor = (x) -> Executors.newFixedThreadPool(8).submit(x);
T service = remote ? Sncp.createRemoteService("", executor, serviceClass, null, new LinkedHashSet<>(), null)
: Sncp.createLocalService("", executor, serviceClass, null, new LinkedHashSet<>(), null, null);
T service = remote ? Sncp.createRemoteService("", executor, serviceClass, null, null)
: Sncp.createLocalService("", executor, serviceClass, null, null, null);
application.init();
application.factory.register(service);
application.servicecdl = new CountDownLatch(1);
@@ -515,6 +562,11 @@ public final class Application {
System.exit(0);
}
String findGroupProtocol(String group) {
if (group == null) return null;
return globalGroupProtocols.get(group);
}
Set<InetSocketAddress> findGlobalGroup(String group) {
if (group == null) return null;
Set<InetSocketAddress> set = globalGroups.get(group);
@@ -546,6 +598,13 @@ public final class Application {
logger.log(Level.FINER, "close CacheSource erroneous", e);
}
}
if (this.transportChannelGroup != null) {
try {
this.transportChannelGroup.shutdownNow();
} catch (Exception e) {
logger.log(Level.FINER, "close transportChannelGroup erroneous", e);
}
}
}
private static AnyValue load(final InputStream in0) {

View File

@@ -269,6 +269,10 @@ public final class ClassFilter<T> {
public FilterEntry(Class<T> type, final boolean autoload, AnyValue property) {
this.type = type;
String str = property == null ? null : property.getValue("groups");
if (str != null) {
str = str.trim();
if (str.endsWith(";")) str = str.substring(0, str.length() - 1);
}
if (str != null) groups.addAll(Arrays.asList(str.split(";")));
this.property = property;
this.autoload = autoload;

View File

@@ -25,7 +25,9 @@ import org.redkale.util.*;
/**
* HTTP Server节点的配置Server
*
* <p> 详情见: http://www.redkale.org
* <p>
* 详情见: http://www.redkale.org
*
* @author zhangjx
*/
@NodeProtocol({"HTTP"})
@@ -34,7 +36,7 @@ public final class NodeHttpServer extends NodeServer {
private final HttpServer httpServer;
public NodeHttpServer(Application application, AnyValue serconf) {
super(application, application.getResourceFactory().createChild(), createServer(application, serconf));
super(application, createServer(application, serconf));
this.httpServer = (HttpServer) server;
}
@@ -54,7 +56,7 @@ public final class NodeHttpServer extends NodeServer {
@Override
protected void loadServlet(ClassFilter<? extends Servlet> servletFilter) throws Exception {
if (httpServer != null) loadHttpServlet(this.nodeConf.getAnyValue("servlets"), servletFilter);
if (httpServer != null) loadHttpServlet(this.serverConf.getAnyValue("servlets"), servletFilter);
}
@Override
@@ -66,28 +68,17 @@ public final class NodeHttpServer extends NodeServer {
private void initWebSocketService() {
final NodeServer self = this;
final ResourceFactory regFactory = application.getResourceFactory();
factory.add(WebSocketNode.class, (ResourceFactory rf, final Object src, final String resourceName, Field field, Object attachment) -> {
factory.add(WebSocketNode.class, (ResourceFactory rf, final Object src, final String resourceName, Field field, Object attachment) -> { //主要用于单点的服务
try {
if (field.getAnnotation(Resource.class) == null) return;
if (!(src instanceof WebSocketServlet)) return;
synchronized (regFactory) {
Service nodeService = (Service) rf.find(resourceName, WebSocketNode.class);
if (nodeService == null) {
nodeService = Sncp.createLocalService(resourceName, getExecutor(), (Class<? extends Service>) WebSocketNodeService.class,
getSncpAddress(), sncpDefaultGroups, sncpSameGroupTransports, sncpDiffGroupTransports);
nodeService = Sncp.createLocalService(resourceName, getExecutor(), WebSocketNodeService.class, (InetSocketAddress) null, (Transport) null, (Collection<Transport>) null);
regFactory.register(resourceName, WebSocketNode.class, nodeService);
factory.inject(nodeService, self);
logger.fine("[" + Thread.currentThread().getName() + "] Load Service " + nodeService);
if (getSncpAddress() != null) {
NodeSncpServer sncpServer = null;
for (NodeServer node : application.servers) {
if (node.isSNCP() && getSncpAddress().equals(node.getSncpAddress())) {
sncpServer = (NodeSncpServer) node;
}
}
ServiceWrapper wrapper = new ServiceWrapper(WebSocketNodeService.class, nodeService, resourceName, getSncpGroup(), sncpDefaultGroups, null);
sncpServer.getSncpServer().addService(wrapper);
}
}
field.set(src, nodeService);
}

View File

@@ -23,7 +23,6 @@ import java.util.logging.*;
import javax.annotation.*;
import javax.persistence.*;
import org.redkale.net.*;
import org.redkale.net.http.*;
import org.redkale.service.*;
import org.redkale.source.*;
import org.redkale.util.*;
@@ -57,27 +56,19 @@ public abstract class NodeServer {
private String sncpGroup = null; //当前Server的SNCP协议的组
private String nodeProtocol = Transport.DEFAULT_PROTOCOL;
private InetSocketAddress sncpAddress; //HttpServer中的sncpAddress 为所属group对应的SncpServer, 为null表示只是单节点没有分布式结构
protected Consumer<ServiceWrapper> consumer;
protected AnyValue nodeConf;
protected final HashSet<String> sncpDefaultGroups = new LinkedHashSet<>();
protected final List<Transport> sncpSameGroupTransports = new ArrayList<>();
protected final List<Transport> sncpDiffGroupTransports = new ArrayList<>();
protected AnyValue serverConf;
protected final Set<ServiceWrapper> localServiceWrappers = new LinkedHashSet<>();
protected final Set<ServiceWrapper> remoteServiceWrappers = new LinkedHashSet<>();
public NodeServer(Application application, ResourceFactory factory, Server server) {
public NodeServer(Application application, Server server) {
this.application = application;
this.factory = factory;
this.factory = application.getResourceFactory().createChild();
this.server = server;
this.logger = Logger.getLogger(this.getClass().getSimpleName());
this.fine = logger.isLoggable(Level.FINE);
@@ -115,16 +106,15 @@ public abstract class NodeServer {
}
public void init(AnyValue config) throws Exception {
this.nodeConf = config == null ? AnyValue.create() : config;
this.serverConf = config == null ? AnyValue.create() : config;
if (isSNCP()) { // SNCP协议
String host = this.nodeConf.getValue("host", "0.0.0.0").replace("0.0.0.0", "");
this.sncpAddress = new InetSocketAddress(host.isEmpty() ? application.localAddress.getHostAddress() : host, this.nodeConf.getIntValue("port"));
String host = this.serverConf.getValue("host", "0.0.0.0").replace("0.0.0.0", "");
this.sncpAddress = new InetSocketAddress(host.isEmpty() ? application.localAddress.getHostAddress() : host, this.serverConf.getIntValue("port"));
this.sncpGroup = application.globalNodes.get(this.sncpAddress);
if (this.sncpGroup == null) throw new RuntimeException("Server (" + String.valueOf(config).replaceAll("\\s+", " ") + ") not found <group> info");
if (server != null) this.nodeProtocol = server.getProtocol();
}
initGroup();
if (this.sncpAddress != null) this.factory.register(RESNAME_SERVER_ADDR, this.sncpAddress);
if (this.sncpAddress != null) this.factory.register(RESNAME_SERVER_ADDR, this.sncpAddress); //单点服务不会有 sncpAddress、sncpGroup
if (this.sncpGroup != null) this.factory.register(RESNAME_SERVER_GROUP, this.sncpGroup);
{
//设置root文件夹
@@ -137,8 +127,9 @@ public abstract class NodeServer {
Server.loadLib(logger, config.getValue("lib", "") + ";" + homepath + "/lib/*;" + homepath + "/classes");
if (server != null) server.init(config);
}
initResource();
//prepare();
initResource(); //给 DataSource、CacheSource 注册依赖注入时的监听回调事件。
ClassFilter<Servlet> servletFilter = createServletClassFilter();
ClassFilter<Service> serviceFilter = createServiceClassFilter();
long s = System.currentTimeMillis();
@@ -166,25 +157,23 @@ public abstract class NodeServer {
DataSource source = new DataDefaultSource(resourceName);
application.dataSources.add(source);
regFactory.register(resourceName, DataSource.class, source);
List<Transport> sameGroupTransports = sncpSameGroupTransports;
List<Transport> diffGroupTransports = sncpDiffGroupTransports;
Transport sameGroupTransport = null;
List<Transport> diffGroupTransports = null;
try {
Field ts = src.getClass().getDeclaredField("_sameGroupTransports");
Field ts = src.getClass().getDeclaredField("_sameGroupTransport");
ts.setAccessible(true);
Transport[] lts = (Transport[]) ts.get(src);
sameGroupTransports = Arrays.asList(lts);
sameGroupTransport = (Transport) ts.get(src);
ts = src.getClass().getDeclaredField("_diffGroupTransports");
ts.setAccessible(true);
lts = (Transport[]) ts.get(src);
diffGroupTransports = Arrays.asList(lts);
diffGroupTransports = Arrays.asList((Transport[]) ts.get(src));
} catch (Exception e) {
//src 不含 MultiRun 方法
}
if (factory.find(resourceName, DataCacheListener.class) == null) {
Service cacheListenerService = Sncp.createLocalService(resourceName, getExecutor(), DataCacheListenerService.class, this.sncpAddress, sncpDefaultGroups, sameGroupTransports, diffGroupTransports);
Service cacheListenerService = Sncp.createLocalService(resourceName, getExecutor(), DataCacheListenerService.class, this.sncpAddress, sameGroupTransport, diffGroupTransports);
regFactory.register(resourceName, DataCacheListener.class, cacheListenerService);
ServiceWrapper wrapper = new ServiceWrapper(DataCacheListenerService.class, cacheListenerService, resourceName, sncpGroup, sncpDefaultGroups, null);
ServiceWrapper wrapper = new ServiceWrapper(DataCacheListenerService.class, cacheListenerService, resourceName, sncpGroup, null, null);
localServiceWrappers.add(wrapper);
if (consumer != null) consumer.accept(wrapper);
rf.inject(cacheListenerService, self);
@@ -199,22 +188,20 @@ public abstract class NodeServer {
try {
if (field.getAnnotation(Resource.class) == null) return;
if ((src instanceof Service) && Sncp.isRemote((Service) src)) return; //远程模式不得注入 CacheSource
List<Transport> sameGroupTransports = sncpSameGroupTransports;
List<Transport> diffGroupTransports = sncpDiffGroupTransports;
Transport sameGroupTransport = null;
List<Transport> diffGroupTransports = null;
try {
Field ts = src.getClass().getDeclaredField("_sameGroupTransports");
Field ts = src.getClass().getDeclaredField("_sameGroupTransport");
ts.setAccessible(true);
Transport[] lts = (Transport[]) ts.get(src);
sameGroupTransports = Arrays.asList(lts);
sameGroupTransport = (Transport) ts.get(src);
ts = src.getClass().getDeclaredField("_diffGroupTransports");
ts.setAccessible(true);
lts = (Transport[]) ts.get(src);
diffGroupTransports = Arrays.asList(lts);
diffGroupTransports = Arrays.asList((Transport[]) ts.get(src));
} catch (Exception e) {
//src 不含 MultiRun 方法
}
CacheSourceService source = Sncp.createLocalService(resourceName, getExecutor(), CacheSourceService.class, this.sncpAddress, sncpDefaultGroups, sameGroupTransports, diffGroupTransports);
CacheSourceService source = Sncp.createLocalService(resourceName, getExecutor(), CacheSourceService.class, this.sncpAddress, sameGroupTransport, diffGroupTransports);
Type genericType = field.getGenericType();
ParameterizedType pt = (genericType instanceof ParameterizedType) ? (ParameterizedType) genericType : null;
Type valType = pt == null ? null : pt.getActualTypeArguments()[1];
@@ -232,7 +219,7 @@ public abstract class NodeServer {
sncpServer = (NodeSncpServer) node;
}
}
ServiceWrapper wrapper = new ServiceWrapper(CacheSourceService.class, (Service) source, resourceName, getSncpGroup(), sncpDefaultGroups, null);
ServiceWrapper wrapper = new ServiceWrapper(CacheSourceService.class, (Service) source, resourceName, getSncpGroup(), null, null);
sncpServer.getSncpServer().addService(wrapper);
}
logger.fine("[" + Thread.currentThread().getName() + "] Load Source " + source);
@@ -242,120 +229,37 @@ public abstract class NodeServer {
});
}
private void initGroup() {
final AnyValue[] services = this.nodeConf.getAnyValues("services");
final String[] groups = services.length < 1 ? new String[]{""} : services[0].getValue("groups", "").split(";");
this.sncpDefaultGroups.addAll(Arrays.asList(groups));
if (!isSNCP()) {
NodeSncpServer sncpServer = null;
for (NodeServer node : application.servers) {
if (!node.isSNCP()) continue;
if (!this.sncpDefaultGroups.contains(node.sncpGroup)) continue;
sncpServer = (NodeSncpServer) node;
break;
}
if (sncpServer == null && (groups.length == 1 && groups[0].isEmpty())) {
for (NodeServer node : application.servers) {
if (!node.isSNCP()) continue;
sncpServer = (NodeSncpServer) node;
break;
}
}
if (sncpServer != null) {
this.sncpAddress = sncpServer.getSncpAddress();
this.sncpGroup = sncpServer.getSncpGroup();
this.sncpDefaultGroups.clear();
this.sncpDefaultGroups.addAll(sncpServer.sncpDefaultGroups);
this.sncpSameGroupTransports.addAll(sncpServer.sncpSameGroupTransports);
this.sncpDiffGroupTransports.addAll(sncpServer.sncpDiffGroupTransports);
return;
}
}
final Set<InetSocketAddress> sameGroupAddrs = application.findGlobalGroup(this.sncpGroup);
final Map<String, Set<InetSocketAddress>> diffGroupAddrs = new HashMap<>();
for (String groupitem : groups) {
final Set<InetSocketAddress> addrs = application.findGlobalGroup(groupitem);
if (addrs == null || groupitem.equals(this.sncpGroup)) continue;
diffGroupAddrs.put(groupitem, addrs);
}
if (sameGroupAddrs != null) {
sameGroupAddrs.remove(this.sncpAddress);
for (InetSocketAddress iaddr : sameGroupAddrs) {
sncpSameGroupTransports.add(loadTransport(this.sncpGroup, getNodeProtocol(), iaddr));
}
}
diffGroupAddrs.forEach((k, v) -> sncpDiffGroupTransports.add(loadTransport(k, getNodeProtocol(), v)));
}
@SuppressWarnings("unchecked")
protected void loadService(ClassFilter serviceFilter) throws Exception {
if (serviceFilter == null) return;
final String threadName = "[" + Thread.currentThread().getName() + "] ";
final Set<FilterEntry<Service>> entrys = serviceFilter.getFilterEntrys();
ResourceFactory regFactory = isSNCP() ? application.getResourceFactory() : factory;
final Set<InetSocketAddress> sg = application.findGlobalGroup(this.sncpGroup);
for (FilterEntry<Service> entry : entrys) { //service实现类
final Class<? extends Service> type = entry.getType();
if (Modifier.isFinal(type.getModifiers())) continue;
if (Modifier.isFinal(type.getModifiers())) continue; //修饰final的类跳过
if (!Modifier.isPublic(type.getModifiers())) continue;
if (!isSNCP() && factory.find(entry.getName(), type) != null) continue;
final Set<InetSocketAddress> sameGroupAddrs = new LinkedHashSet<>();
final Map<String, Set<InetSocketAddress>> diffGroupAddrs = new HashMap<>();
final HashSet<String> groups = entry.getGroups();
for (String g : groups) {
if (g.isEmpty()) continue;
if (g.equals(this.sncpGroup) && sg != null) sameGroupAddrs.addAll(sg);
Set<InetSocketAddress> set = application.findGlobalGroup(g);
if (set == null) throw new RuntimeException(type.getName() + " has illegal group (" + groups + ")");
if (!g.equals(this.sncpGroup)) {
diffGroupAddrs.put(g, set);
}
}
List<Transport> diffGroupTransports = new ArrayList<>();
diffGroupAddrs.forEach((k, v) -> diffGroupTransports.add(loadTransport(k, server.getProtocol(), v)));
final boolean localed = (sameGroupAddrs.isEmpty() && diffGroupAddrs.isEmpty()) || sameGroupAddrs.contains(this.sncpAddress) || type.getAnnotation(LocalService.class) != null;//本地模式
if (entry.getName().contains("$")) throw new RuntimeException("<name> value cannot contains '$' in " + entry.getProperty());
if (!isSNCP() && factory.find(entry.getName(), type) != null) continue; //非SNCP的Server加载Service时需要判断是否在SNCP的Server已经加载过了。
final HashSet<String> groups = entry.getGroups(); //groups.isEmpty()表示<services>没有配置groups属性。
if (groups.isEmpty() && isSNCP()) groups.add(this.sncpGroup);
final boolean localed = this.sncpAddress == null //非SNCP的Server通常是单点服务
|| groups.contains(this.sncpGroup) //本地IP含在内的
|| type.getAnnotation(LocalService.class) != null;//本地模式
if (localed && (type.isInterface() || Modifier.isAbstract(type.getModifiers()))) continue; //本地模式不能实例化接口和抽象类的Service类
final ServiceResource st = type.getAnnotation(ServiceResource.class);
final Class<? extends Service> resType = st == null ? type : st.value();
if (st != null && (!isSNCP() && factory.find(entry.getName(), resType) != null)) continue;
ServiceWrapper wrapper;
Service service;
if (localed) { //本地模式
sameGroupAddrs.remove(this.sncpAddress);
List<Transport> sameGroupTransports = new ArrayList<>();
for (InetSocketAddress iaddr : sameGroupAddrs) {
Set<InetSocketAddress> tset = new HashSet<>();
tset.add(iaddr);
sameGroupTransports.add(loadTransport(this.sncpGroup, server.getProtocol(), tset));
}
Service service = Sncp.createLocalService(entry.getName(), getExecutor(), type, this.sncpAddress, groups, sameGroupTransports, diffGroupTransports);
wrapper = new ServiceWrapper(resType, service, this.sncpGroup, entry);
if (fine) logger.fine("[" + Thread.currentThread().getName() + "] Load Service " + service);
service = Sncp.createLocalService(entry.getName(), getExecutor(), type, this.sncpAddress, loadTransport(this.sncpGroup), loadTransports(groups));
} else {
sameGroupAddrs.remove(this.sncpAddress);
StringBuilder g = new StringBuilder();
diffGroupAddrs.forEach((k, v) -> {
if (g.length() > 0) g.append(';');
g.append(k);
sameGroupAddrs.addAll(v);
});
if (sameGroupAddrs.isEmpty()) throw new RuntimeException(type.getName() + " has no remote address on group (" + groups + ")");
Service service = Sncp.createRemoteService(entry.getName(), getExecutor(), type, this.sncpAddress, groups, loadTransport(g.toString(), server.getProtocol(), sameGroupAddrs));
wrapper = new ServiceWrapper(resType, service, "", entry);
if (fine) logger.fine("[" + Thread.currentThread().getName() + "] Load Service " + service);
service = Sncp.createRemoteService(entry.getName(), getExecutor(), type, this.sncpAddress, loadTransport(groups));
}
final ServiceWrapper wrapper = new ServiceWrapper(type, service, entry.getName(), localed ? this.sncpGroup : null, groups, entry.getProperty());
if (fine) logger.fine("[" + Thread.currentThread().getName() + "] Load Service " + wrapper.getService());
if (factory.find(wrapper.getName(), wrapper.getType()) == null) {
regFactory.register(wrapper.getName(), wrapper.getType(), wrapper.getService());
if (wrapper.getService() instanceof DataSource) {
regFactory.register(wrapper.getName(), DataSource.class, wrapper.getService());
} else if (wrapper.getService() instanceof CacheSource) {
regFactory.register(wrapper.getName(), CacheSource.class, wrapper.getService());
} else if (wrapper.getService() instanceof DataCacheListener) {
regFactory.register(wrapper.getName(), DataCacheListener.class, wrapper.getService());
} else if (wrapper.getService() instanceof DataSQLListener) {
regFactory.register(wrapper.getName(), DataSQLListener.class, wrapper.getService());
} else if (wrapper.getService() instanceof WebSocketNode) {
regFactory.register(wrapper.getName(), WebSocketNode.class, wrapper.getService());
}
regFactory.register(wrapper.getName(), wrapper.getService());
if (wrapper.isRemote()) {
remoteServiceWrappers.add(wrapper);
} else {
@@ -392,30 +296,69 @@ public abstract class NodeServer {
if (sb != null && sb.length() > 0) logger.log(Level.INFO, sb.toString());
}
protected Transport loadTransport(String group, String protocol, InetSocketAddress addr) {
if (addr == null) return null;
Set<InetSocketAddress> set = new HashSet<>();
set.add(addr);
return loadTransport(group, protocol, set);
protected List<Transport> loadTransports(final HashSet<String> groups) {
if (groups == null) return null;
final List<Transport> transports = new ArrayList<>();
for (String group : groups) {
transports.add(loadTransport(group));
}
return transports;
}
protected Transport loadTransport(String group, String protocol, Set<InetSocketAddress> addrs) {
Transport transport = null;
if (!addrs.isEmpty()) {
synchronized (application.transports) {
for (Transport tran : application.transports) {
if (tran.match(addrs)) {
transport = tran;
break;
}
}
if (transport == null) {
transport = new Transport(group + "_" + application.transports.size(), protocol, application.getWatchFactory(), 32, addrs);
logger.info(transport + " created");
application.transports.add(transport);
}
protected Transport loadTransport(final HashSet<String> groups) {
if (groups == null || groups.isEmpty()) return null;
List<String> tmpgroup = new ArrayList<>(groups);
Collections.sort(tmpgroup); //按字母排列顺序
boolean flag = false;
StringBuilder sb = new StringBuilder();
for (String g : tmpgroup) {
if (flag) sb.append(';');
sb.append(g);
flag = true;
}
final String groupid = sb.toString();
Transport transport = application.transports.get(groupid);
if (transport != null) return transport;
final List<Transport> transports = new ArrayList<>();
for (String group : groups) {
transports.add(loadTransport(group));
}
Set<InetSocketAddress> addrs = new HashSet();
for (Transport t : transports) {
for (InetSocketAddress addr : t.getRemoteAddresses()) {
addrs.add(addr);
}
}
Transport first = transports.get(0);
Transport newTransport = new Transport(groupid, application.findGroupProtocol(first.getName()), application.getWatchFactory(),
application.transportBufferPool, application.transportChannelGroup, this.sncpAddress, addrs);
synchronized (application.transports) {
transport = application.transports.get(groupid);
if (transport == null) {
transport = newTransport;
application.transports.put(groupid, transport);
}
}
return transport;
}
protected Transport loadTransport(final String group) {
if (group == null) return null;
Transport transport;
synchronized (application.transports) {
transport = application.transports.get(group);
if (transport != null) {
if (this.sncpAddress != null && !this.sncpAddress.equals(transport.getClientAddress())) {
throw new RuntimeException(transport + "repeat create on newClientAddress = " + this.sncpAddress + ", oldClientAddress = " + transport.getClientAddress());
}
return transport;
}
Set<InetSocketAddress> addrs = application.findGlobalGroup(group);
if (addrs == null) throw new RuntimeException("Not found <group> = " + group + " on <resources> ");
transport = new Transport(group, application.findGroupProtocol(group), application.getWatchFactory(),
application.transportBufferPool, application.transportChannelGroup, this.sncpAddress, addrs);
application.transports.put(group, transport);
}
return transport;
}
@@ -429,13 +372,17 @@ public abstract class NodeServer {
Class inter, Class<? extends Annotation> ref2, String properties, String property) {
ClassFilter cf = new ClassFilter(ref, inter, null);
if (properties == null && properties == null) return cf;
if (this.nodeConf == null) return cf;
AnyValue[] proplist = this.nodeConf.getAnyValues(properties);
if (this.serverConf == null) return cf;
AnyValue[] proplist = this.serverConf.getAnyValues(properties);
if (proplist == null || proplist.length < 1) return cf;
cf = null;
for (AnyValue list : proplist) {
DefaultAnyValue prop = null;
String sc = list.getValue("groups");
if (sc != null) {
sc = sc.trim();
if (sc.endsWith(";")) sc = sc.substring(0, sc.length() - 1);
}
if (sc == null) sc = localGroup;
if (sc != null) {
prop = new AnyValue.DefaultAnyValue();
@@ -496,10 +443,6 @@ public abstract class NodeServer {
return sncpGroup;
}
public String getNodeProtocol() {
return nodeProtocol;
}
public void start() throws IOException {
server.start();
}

View File

@@ -13,7 +13,9 @@ import org.redkale.util.*;
/**
*
* <p> 详情见: http://www.redkale.org
* <p>
* 详情见: http://www.redkale.org
*
* @author zhangjx
*/
@NodeProtocol({"SNCP"})
@@ -22,7 +24,7 @@ public final class NodeSncpServer extends NodeServer {
private final SncpServer sncpServer;
public NodeSncpServer(Application application, AnyValue serconf) {
super(application, application.getResourceFactory().createChild(), createServer(application, serconf));
super(application, createServer(application, serconf));
this.sncpServer = (SncpServer) this.server;
this.consumer = sncpServer == null ? null : x -> sncpServer.addService(x);
}

View File

@@ -19,7 +19,9 @@ import org.redkale.watch.*;
/**
*
* <p> 详情见: http://www.redkale.org
* <p>
* 详情见: http://www.redkale.org
*
* @author zhangjx
*/
public abstract class Server {
@@ -49,7 +51,7 @@ public abstract class Server {
protected ProtocolServer serverChannel;
protected int capacity;
protected int bufferCapacity;
protected int threads;
@@ -82,8 +84,8 @@ public abstract class Server {
this.backlog = config.getIntValue("backlog", 8 * 1024);
this.readTimeoutSecond = config.getIntValue("readTimeoutSecond", 0);
this.writeTimeoutSecond = config.getIntValue("writeTimeoutSecond", 0);
this.capacity = config.getIntValue("capacity", 8 * 1024);
this.maxbody = config.getIntValue("maxbody", 64 * 1024);
this.bufferCapacity = config.getIntValue("bufferCapacity", 8 * 1024);
this.threads = config.getIntValue("threads", Runtime.getRuntime().availableProcessors() * 16);
this.bufferPoolSize = config.getIntValue("bufferPoolSize", Runtime.getRuntime().availableProcessors() * 512);
this.responsePoolSize = config.getIntValue("responsePoolSize", Runtime.getRuntime().availableProcessors() * 256);
@@ -127,7 +129,7 @@ public abstract class Server {
serverChannel.accept();
final String threadName = "[" + Thread.currentThread().getName() + "] ";
logger.info(threadName + this.getClass().getSimpleName() + "." + protocol + " listen: " + address
+ ", threads: " + threads + ", bufferCapacity: " + capacity + ", bufferPoolSize: " + bufferPoolSize + ", responsePoolSize: " + responsePoolSize
+ ", threads: " + threads + ", bufferCapacity: " + bufferCapacity + ", bufferPoolSize: " + bufferPoolSize + ", responsePoolSize: " + responsePoolSize
+ ", started in " + (System.currentTimeMillis() - context.getServerStartTime()) + " ms");
}

View File

@@ -10,7 +10,6 @@ import java.nio.*;
import java.nio.channels.*;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.*;
import java.util.function.*;
import org.redkale.util.*;
import org.redkale.watch.*;
@@ -42,97 +41,104 @@ public final class Transport {
supportTcpNoDelay = tcpNoDelay;
}
protected final String name;
protected final int bufferPoolSize;
protected final int bufferCapacity;
protected final String name; //即<group>的name属性
protected final boolean tcp;
protected final String protocol;
protected final WatchFactory watch;
protected final AsynchronousChannelGroup group;
protected final InetSocketAddress[] remoteAddres;
protected final InetSocketAddress clientAddress;
protected InetSocketAddress[] remoteAddres = new InetSocketAddress[0];
protected final ObjectPool<ByteBuffer> bufferPool;
protected final ConcurrentHashMap<SocketAddress, BlockingQueue<AsyncConnection>> connPool = new ConcurrentHashMap<>();
public Transport(Transport transport, InetSocketAddress localAddress, Collection<Transport> transports) {
this(transport.name, transport.protocol, null, transport.bufferPoolSize, parse(localAddress, transports));
public Transport(String name, WatchFactory watch, final ObjectPool<ByteBuffer> transportBufferPool,
final AsynchronousChannelGroup transportChannelGroup, final InetSocketAddress clientAddress, final Collection<InetSocketAddress> addresses) {
this(name, DEFAULT_PROTOCOL, watch, transportBufferPool, transportChannelGroup, clientAddress, addresses);
}
public Transport(String name, WatchFactory watch, int bufferPoolSize, Collection<InetSocketAddress> addresses) {
this(name, DEFAULT_PROTOCOL, watch, bufferPoolSize, addresses);
}
public Transport(String name, String protocol, WatchFactory watch, int bufferPoolSize, Collection<InetSocketAddress> addresses) {
public Transport(String name, String protocol, WatchFactory watch, final ObjectPool<ByteBuffer> transportBufferPool,
final AsynchronousChannelGroup transportChannelGroup, final InetSocketAddress clientAddress, final Collection<InetSocketAddress> addresses) {
this.name = name;
this.watch = watch;
this.protocol = protocol;
this.tcp = "TCP".equalsIgnoreCase(protocol);
this.bufferPoolSize = bufferPoolSize;
this.bufferCapacity = 8192;
AsynchronousChannelGroup g = null;
try {
final AtomicInteger counter = new AtomicInteger();
ExecutorService executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * 8, (Runnable r) -> {
Thread t = new Thread(r);
t.setDaemon(true);
t.setName("Transport-" + name + "-Thread-" + counter.incrementAndGet());
return t;
});
g = AsynchronousChannelGroup.withCachedThreadPool(executor, 1);
} catch (Exception e) {
throw new RuntimeException(e);
}
this.group = g;
AtomicLong createBufferCounter = watch == null ? new AtomicLong() : watch.createWatchNumber(Transport.class.getSimpleName() + "-" + name + "-" + protocol + ".Buffer.creatCounter");
AtomicLong cycleBufferCounter = watch == null ? new AtomicLong() : watch.createWatchNumber(Transport.class.getSimpleName() + "-" + name + "-" + protocol + ".Buffer.cycleCounter");
final int rcapacity = bufferCapacity;
this.bufferPool = new ObjectPool<>(createBufferCounter, cycleBufferCounter, bufferPoolSize,
(Object... params) -> ByteBuffer.allocateDirect(rcapacity), null, (e) -> {
if (e == null || e.isReadOnly() || e.capacity() != rcapacity) return false;
e.clear();
return true;
});
this.remoteAddres = addresses.toArray(new InetSocketAddress[addresses.size()]);
this.group = transportChannelGroup;
this.bufferPool = transportBufferPool;
this.clientAddress = clientAddress;
updateRemoteAddresses(addresses);
}
private static Collection<InetSocketAddress> parse(InetSocketAddress addr, Collection<Transport> transports) {
final Set<InetSocketAddress> set = new LinkedHashSet<>();
public Transport(final Collection<Transport> transports) {
Transport first = null;
List<String> tmpgroup = new ArrayList<>();
for (Transport t : transports) {
set.addAll(Arrays.asList(t.remoteAddres));
if (first == null) first = t;
tmpgroup.add(t.name);
}
set.remove(addr);
return set;
Collections.sort(tmpgroup); //按字母排列顺序
boolean flag = false;
StringBuilder sb = new StringBuilder();
for (String g : tmpgroup) {
if (flag) sb.append(';');
sb.append(g);
flag = true;
}
this.name = sb.toString();
this.watch = first.watch;
this.protocol = first.protocol;
this.tcp = "TCP".equalsIgnoreCase(first.protocol);
this.group = first.group;
this.bufferPool = first.bufferPool;
this.clientAddress = first.clientAddress;
Set<InetSocketAddress> addrs = new HashSet();
for (Transport t : transports) {
for (InetSocketAddress addr : t.getRemoteAddresses()) {
addrs.add(addr);
}
}
updateRemoteAddresses(addrs);
}
public final InetSocketAddress[] updateRemoteAddresses(final Collection<InetSocketAddress> addresses) {
InetSocketAddress[] oldAddresses = this.remoteAddres;
List<InetSocketAddress> list = new ArrayList<>();
if (addresses != null) {
for (InetSocketAddress addr : addresses) {
if (clientAddress != null && clientAddress.equals(addr)) continue;
list.add(addr);
}
}
this.remoteAddres = list.toArray(new InetSocketAddress[list.size()]);
return oldAddresses;
}
public String getName() {
return name;
}
public void close() {
connPool.forEach((k, v) -> v.forEach(c -> c.dispose()));
}
public boolean match(Collection<InetSocketAddress> addrs) {
if (addrs == null) return false;
if (addrs.size() != this.remoteAddres.length) return false;
for (InetSocketAddress addr : this.remoteAddres) {
if (!addrs.contains(addr)) return false;
}
return true;
public InetSocketAddress getClientAddress() {
return clientAddress;
}
public InetSocketAddress[] getRemoteAddress() {
public InetSocketAddress[] getRemoteAddresses() {
return remoteAddres;
}
@Override
public String toString() {
return Transport.class.getSimpleName() + "{name=" + name + ",protocol=" + protocol + ",remoteAddres=" + Arrays.toString(remoteAddres) + "}";
}
public int getBufferCapacity() {
return bufferCapacity;
return Transport.class.getSimpleName() + "{name = " + name + ", protocol = " + protocol + ", clientAddress = " + clientAddress + ", remoteAddres = " + Arrays.toString(remoteAddres) + "}";
}
public ByteBuffer pollBuffer() {
@@ -207,7 +213,7 @@ public final class Transport {
}
public void offerConnection(final boolean forceClose, AsyncConnection conn) {
if (!forceClose && conn.isTCP()) { //暂时每次都关闭
if (!forceClose && conn.isTCP()) {
if (conn.isOpen()) {
BlockingQueue<AsyncConnection> queue = connPool.get(conn.getRemoteAddress());
if (queue == null) {

View File

@@ -47,7 +47,7 @@ public final class HttpServer extends Server {
final int port = this.address.getPort();
AtomicLong createBufferCounter = watch == null ? new AtomicLong() : watch.createWatchNumber("HTTP_" + port + ".Buffer.creatCounter");
AtomicLong cycleBufferCounter = watch == null ? new AtomicLong() : watch.createWatchNumber("HTTP_" + port + ".Buffer.cycleCounter");
final int rcapacity = Math.max(this.capacity, 16 * 1024 + 8); //兼容 HTTP 2.0
final int rcapacity = Math.max(this.bufferCapacity, 16 * 1024 + 8); //兼容 HTTP 2.0
ObjectPool<ByteBuffer> bufferPool = new ObjectPool<>(createBufferCounter, cycleBufferCounter, this.bufferPoolSize,
(Object... params) -> ByteBuffer.allocateDirect(rcapacity), null, (e) -> {
if (e == null || e.isReadOnly() || e.capacity() != rcapacity) return false;

View File

@@ -12,6 +12,7 @@ import java.util.*;
import java.util.concurrent.*;
import java.util.logging.*;
import javax.annotation.*;
import org.redkale.boot.*;
import org.redkale.service.*;
import org.redkale.source.*;
import org.redkale.util.*;
@@ -29,7 +30,7 @@ public abstract class WebSocketNode {
protected final boolean finest = logger.isLoggable(Level.FINEST);
@Resource(name = "SERVER_ADDR")
@Resource(name = Application.RESNAME_SERVER_GROUP)
protected InetSocketAddress localSncpAddress; //为SncpServer的服务address
@DynRemote

View File

@@ -8,12 +8,14 @@ package org.redkale.net.sncp;
import org.redkale.service.Service;
import org.redkale.util.AnyValue;
import java.util.*;
import org.redkale.boot.*;
import org.redkale.util.*;
/**
* Service对象的封装类
* Service对象的封装类
*
* <p>
* 详情见: http://www.redkale.org
*
* <p> 详情见: http://www.redkale.org
* @author zhangjx
* @param <T> Service的子类
*/
@@ -25,26 +27,26 @@ public final class ServiceWrapper<T extends Service> {
private final AnyValue conf;
private final String group;
private final String sncpGroup; //自身的组节点名 可能为null
private final Set<String> groups;
private final Set<String> groups; //所有的组节点,包含自身
private final String name;
private final boolean remote;
public ServiceWrapper(Class<T> type, T service, String group, ClassFilter.FilterEntry<Service> entry) {
this(type, service, entry.getName(), group, entry.getGroups(), entry.getProperty());
}
private final Class[] resTypes;
public ServiceWrapper(Class<T> type, T service, String name, String group, Set<String> groups, AnyValue conf) {
public ServiceWrapper(Class<T> type, T service, String name, String sncpGroup, Set<String> groups, AnyValue conf) {
this.type = type == null ? (Class<T>) service.getClass() : type;
this.service = service;
this.conf = conf;
this.group = group;
this.sncpGroup = sncpGroup;
this.groups = groups;
this.name = name;
this.remote = Sncp.isRemote(service);
ResourceType rty = service.getClass().getAnnotation(ResourceType.class);
this.resTypes = rty == null ? new Class[]{this.type} : rty.value();
}
@Override
@@ -53,14 +55,14 @@ public final class ServiceWrapper<T extends Service> {
if (obj == null) return false;
if (!(obj instanceof ServiceWrapper)) return false;
ServiceWrapper other = (ServiceWrapper) obj;
return (this.type.equals(other.type) && this.remote == other.remote && this.name.equals(other.name) && this.group.equals(other.group));
return (this.type.equals(other.type) && this.remote == other.remote && this.name.equals(other.name) && Objects.equals(this.sncpGroup, other.sncpGroup));
}
@Override
public int hashCode() {
int hash = 3;
hash = 67 * hash + Objects.hashCode(this.type);
hash = 67 * hash + Objects.hashCode(this.group);
hash = 67 * hash + Objects.hashCode(this.sncpGroup);
hash = 67 * hash + Objects.hashCode(this.name);
hash = 67 * hash + (this.remote ? 1 : 0);
return hash;
@@ -70,6 +72,10 @@ public final class ServiceWrapper<T extends Service> {
return type;
}
public Class[] getResTypes() {
return resTypes;
}
public Service getService() {
return service;
}

View File

@@ -12,7 +12,6 @@ import java.net.*;
import java.security.*;
import java.util.*;
import java.util.function.*;
import javax.annotation.*;
import jdk.internal.org.objectweb.asm.*;
import static jdk.internal.org.objectweb.asm.ClassWriter.COMPUTE_FRAMES;
import static jdk.internal.org.objectweb.asm.Opcodes.*;
@@ -34,12 +33,6 @@ import org.redkale.service.DynRemote;
*/
public abstract class Sncp {
//当前SNCP Server的IP地址+端口 类型: SocketAddress、InetSocketAddress、String
public static final String RESNAME_SNCP_ADDR = "SNCP_ADDR";
//当前Service所属的组 类型: Set<String>、String[]
public static final String RESNAME_SNCP_GROUPS = "SNCP_GROUPS";
private static final java.lang.reflect.Type GROUPS_TYPE1 = new TypeToken<Set<String>>() {
}.getType();
@@ -128,12 +121,13 @@ public abstract class Sncp {
* <blockquote><pre>
* &#64;Resource(name = "")
* &#64;SncpDyn(remote = false)
* &#64;ResourceType({TestService.class})
* public final class _DynLocalTestService extends TestService{
*
* &#64;Resource
* private BsonConvert _convert;
*
* private Transport[] _sameGroupTransports;
* private Transport _sameGroupTransport;
*
* private Transport[] _diffGroupTransports;
*
@@ -155,8 +149,8 @@ public abstract class Sncp {
* public void _createSomeThing(boolean selfrunnable, boolean samerunnable, boolean diffrunnable, TestBean bean){
* if(selfrunnable) super.createSomeThing(bean);
* if (_client== null) return;
* if (samerunnable) _client.remote(_convert, _sameGroupTransports, 0, true, false, false, bean);
* if (diffrunnable) _client.remote(_convert, _diffGroupTransports, 0, true, true, false, bean);
* if (samerunnable) _client.remoteSameGroup(_convert, _sameGroupTransport, 0, true, false, false, bean);
* if (diffrunnable) _client.remoteDiffGroup(_convert, _diffGroupTransports, 0, true, true, false, bean);
* }
*
* &#64;Override
@@ -168,8 +162,8 @@ public abstract class Sncp {
* public String _updateSomeThing(boolean selfrunnable, boolean samerunnable, boolean diffrunnable, String id){
* String rs = super.updateSomeThing(id);
* if (_client== null) return;
* if (samerunnable) _client.remote(_convert, _sameGroupTransports, 1, true, false, false, id);
* if (diffrunnable) _client.remote(_convert, _diffGroupTransports, 1, true, true, false, id);
* if (samerunnable) _client.remoteSameGroup(_convert, _sameGroupTransport, 1, true, false, false, id);
* if (diffrunnable) _client.remoteDiffGroup(_convert, _diffGroupTransports, 1, true, true, false, id);
* return rs;
* }
* }
@@ -196,6 +190,7 @@ public abstract class Sncp {
final String clientDesc = Type.getDescriptor(SncpClient.class);
final String convertDesc = Type.getDescriptor(BsonConvert.class);
final String sncpDynDesc = Type.getDescriptor(SncpDyn.class);
final String transportDesc = Type.getDescriptor(Transport.class);
final String transportsDesc = Type.getDescriptor(Transport[].class);
ClassLoader loader = Sncp.class.getClassLoader();
String newDynName = supDynName.substring(0, supDynName.lastIndexOf('/') + 1) + LOCALPREFIX + serviceClass.getSimpleName();
@@ -227,6 +222,22 @@ public abstract class Sncp {
av0.visit("remote", Boolean.FALSE);
av0.visitEnd();
}
{
av0 = cw.visitAnnotation(Type.getDescriptor(ResourceType.class), true);
{
AnnotationVisitor av1 = av0.visitArray("value");
ResourceType rty = serviceClass.getAnnotation(ResourceType.class);
if (rty == null) {
av1.visit(null, Type.getType(Type.getDescriptor(serviceClass)));
} else {
for (Class cl : rty.value()) {
av1.visit(null, Type.getType(Type.getDescriptor(cl)));
}
}
av1.visitEnd();
}
av0.visitEnd();
}
if (hasMultiRun) {
{
fv = cw.visitField(ACC_PRIVATE, "_convert", convertDesc, null, null);
@@ -235,7 +246,7 @@ public abstract class Sncp {
fv.visitEnd();
}
{
fv = cw.visitField(ACC_PRIVATE, "_sameGroupTransports", transportsDesc, null, null);
fv = cw.visitField(ACC_PRIVATE, "_sameGroupTransport", transportDesc, null, null);
fv.visitEnd();
}
{
@@ -437,8 +448,8 @@ public abstract class Sncp {
mv.visitFieldInsn(GETFIELD, newDynName, "_client", clientDesc);
mv.visitVarInsn(ALOAD, 0); //传递 _convert
mv.visitFieldInsn(GETFIELD, newDynName, "_convert", convertDesc);
mv.visitVarInsn(ALOAD, 0); //传递 _sameGroupTransports
mv.visitFieldInsn(GETFIELD, newDynName, "_sameGroupTransports", transportsDesc);
mv.visitVarInsn(ALOAD, 0); //传递 _sameGroupTransport
mv.visitFieldInsn(GETFIELD, newDynName, "_sameGroupTransport", transportDesc);
if (index <= 5) { //第几个 SncpAction
mv.visitInsn(ICONST_0 + index);
@@ -498,7 +509,7 @@ public abstract class Sncp {
}
mv.visitInsn(AASTORE);
}
mv.visitMethodInsn(INVOKEVIRTUAL, clientName, mrun.async() ? "asyncRemote" : "remote", "(" + convertDesc + transportsDesc + "I[Ljava/lang/Object;)V", false);
mv.visitMethodInsn(INVOKEVIRTUAL, clientName, mrun.async() ? "asyncRemoteSameGroup" : "remoteSameGroup", "(" + convertDesc + transportDesc + "I[Ljava/lang/Object;)V", false);
mv.visitLabel(sameLabel);
//---------------------------- 调用diffrun ---------------------------------
mv.visitVarInsn(ILOAD, 3); //读取 diffrunnable
@@ -570,7 +581,7 @@ public abstract class Sncp {
}
mv.visitInsn(AASTORE);
}
mv.visitMethodInsn(INVOKEVIRTUAL, clientName, mrun.async() ? "asyncRemote" : "remote", "(" + convertDesc + transportsDesc + "I[Ljava/lang/Object;)V", false);
mv.visitMethodInsn(INVOKEVIRTUAL, clientName, mrun.async() ? "asyncRemoteDiffGroup" : "remoteDiffGroup", "(" + convertDesc + transportsDesc + "I[Ljava/lang/Object;)V", false);
mv.visitLabel(diffLabel);
if (returnType == void.class) {
@@ -669,53 +680,33 @@ public abstract class Sncp {
* @return Service的本地模式实例
*/
@SuppressWarnings("unchecked")
public static <T extends Service> T createLocalService(final String name, final Consumer<Runnable> executor, final Class<T> serviceClass,
final InetSocketAddress clientAddress, HashSet<String> groups, Collection<Transport> sameGroupTransports, Collection<Transport> diffGroupTransports) {
public static <T extends Service> T createLocalService(final String name, final Consumer<Runnable> executor,
final Class<T> serviceClass, final InetSocketAddress clientAddress, final Transport sameGroupTransport, final Collection<Transport> diffGroupTransports) {
try {
final Class newClazz = createLocalServiceClass(name, serviceClass);
T rs = (T) newClazz.newInstance();
//--------------------------------------
if (sameGroupTransports == null) sameGroupTransports = new ArrayList<>();
if (diffGroupTransports == null) diffGroupTransports = new ArrayList<>();
Service remoteService = null;
Transport remoteTransport = null;
{
Class loop = newClazz;
String[] groupArray = null;
do {
for (Field field : loop.getDeclaredFields()) {
int mod = field.getModifiers();
if (Modifier.isFinal(mod) || Modifier.isStatic(mod)) continue;
if (field.getAnnotation(DynRemote.class) != null) {
field.setAccessible(true);
if (remoteTransport == null) {
List<Transport> list = new ArrayList<>();
list.addAll(sameGroupTransports);
list.addAll(diffGroupTransports);
if (!list.isEmpty()) remoteTransport = new Transport(list.get(0), clientAddress, list);
}
if (field.getType().isAssignableFrom(newClazz) && remoteTransport != null) {
field.set(rs, createRemoteService(name, executor, serviceClass, clientAddress, groups, remoteTransport));
}
continue;
}
Resource res = field.getAnnotation(Resource.class);
if (res == null) continue;
if (field.getAnnotation(DynRemote.class) == null) continue;
if (!field.getType().isAssignableFrom(newClazz)) continue;
field.setAccessible(true);
if (res.name().equals(RESNAME_SNCP_GROUPS)) {
if (groups == null) groups = new LinkedHashSet<>();
if (groupArray == null) groupArray = groups.toArray(new String[groups.size()]);
if (field.getGenericType().equals(GROUPS_TYPE1)) {
field.set(rs, groups);
} else if (field.getGenericType().equals(GROUPS_TYPE2)) {
field.set(rs, groupArray);
}
} else if (res.name().endsWith(RESNAME_SNCP_ADDR)) {
if (field.getType() == String.class) {
field.set(rs, clientAddress == null ? null : (clientAddress.getHostString() + ":" + clientAddress.getPort()));
} else {
field.set(rs, clientAddress);
}
if (remoteTransport == null) {
List<Transport> list = new ArrayList<>();
if (sameGroupTransport != null) list.add(sameGroupTransport);
if (diffGroupTransports != null) list.addAll(diffGroupTransports);
if (!list.isEmpty()) remoteTransport = new Transport(list);
}
if (remoteService == null && remoteTransport != null) {
remoteService = createRemoteService(name, executor, serviceClass, clientAddress, remoteTransport);
}
if (remoteService != null) field.set(rs, remoteService);
}
} while ((loop = loop.getSuperclass()) != Object.class);
}
@@ -724,7 +715,7 @@ public abstract class Sncp {
try {
Field e = newClazz.getDeclaredField("_client");
e.setAccessible(true);
client = new SncpClient(name, executor, hash(serviceClass), false, newClazz, clientAddress, groups);
client = new SncpClient(name, executor, hash(serviceClass), false, newClazz, clientAddress);
e.set(rs, client);
} catch (NoSuchFieldException ne) {
}
@@ -735,19 +726,23 @@ public abstract class Sncp {
if (client != null) {
sb.append(", nameid = ").append(client.getNameid()).append(", serviceid = ").append(client.getServiceid());
sb.append(", action.size = ").append(client.getActionCount());
List<String> groups = new ArrayList<>();
if (sameGroupTransport != null) groups.add(sameGroupTransport.getName());
if (diffGroupTransports != null) {
for (Transport t : diffGroupTransports) {
groups.add(t.getName());
}
}
sb.append(", address = ").append(clientAddress).append(", groups = ").append(groups);
List<InetSocketAddress> addrs = new ArrayList<>();
for (Transport t : sameGroupTransports) {
addrs.addAll(Arrays.asList(t.getRemoteAddress()));
}
sb.append(", samegroups = ").append(addrs);
sb.append(", sameaddrs = ").append(sameGroupTransport == null ? null : Arrays.asList(sameGroupTransport.getRemoteAddresses()));
addrs.clear();
for (Transport t : diffGroupTransports) {
addrs.addAll(Arrays.asList(t.getRemoteAddress()));
List<InetSocketAddress> addrs = new ArrayList<>();
if (diffGroupTransports != null) {
for (Transport t : diffGroupTransports) {
addrs.addAll(Arrays.asList(t.getRemoteAddresses()));
}
}
sb.append(", diffgroups = ").append(addrs);
sb.append(", diffaddrs = ").append(addrs);
} else {
sb.append(", ").append(MultiRun.class.getSimpleName().toLowerCase()).append(" = false");
}
@@ -758,11 +753,11 @@ public abstract class Sncp {
}
if (client == null) return rs;
{
Field c = newClazz.getDeclaredField("_sameGroupTransports");
Field c = newClazz.getDeclaredField("_sameGroupTransport");
c.setAccessible(true);
c.set(rs, sameGroupTransports.toArray(new Transport[sameGroupTransports.size()]));
c.set(rs, sameGroupTransport);
}
{
if (diffGroupTransports != null) {
Field t = newClazz.getDeclaredField("_diffGroupTransports");
t.setAccessible(true);
t.set(rs, diffGroupTransports.toArray(new Transport[diffGroupTransports.size()]));
@@ -780,6 +775,7 @@ public abstract class Sncp {
* <blockquote><pre>
* &#64;Resource(name = "")
* &#64;SncpDyn(remote = true)
* &#64;ResourceType({TestService.class})
* public final class _DynRemoteTestService extends TestService{
*
* &#64;Resource
@@ -837,7 +833,7 @@ public abstract class Sncp {
*/
@SuppressWarnings("unchecked")
public static <T extends Service> T createRemoteService(final String name, final Consumer<Runnable> executor, final Class<T> serviceClass,
final InetSocketAddress clientAddress, HashSet<String> groups, final Transport transport) {
final InetSocketAddress clientAddress, final Transport transport) {
if (serviceClass == null) return null;
if (!Service.class.isAssignableFrom(serviceClass)) return null;
int mod = serviceClass.getModifiers();
@@ -852,7 +848,7 @@ public abstract class Sncp {
final String anyValueDesc = Type.getDescriptor(AnyValue.class);
ClassLoader loader = Sncp.class.getClassLoader();
String newDynName = supDynName.substring(0, supDynName.lastIndexOf('/') + 1) + REMOTEPREFIX + serviceClass.getSimpleName();
final SncpClient client = new SncpClient(name, executor, hash(serviceClass), true, realed ? createLocalServiceClass(name, serviceClass) : serviceClass, clientAddress, groups);
final SncpClient client = new SncpClient(name, executor, hash(serviceClass), true, realed ? createLocalServiceClass(name, serviceClass) : serviceClass, clientAddress);
try {
Class newClazz = Class.forName(newDynName.replace('/', '.'));
T rs = (T) newClazz.newInstance();
@@ -867,8 +863,8 @@ public abstract class Sncp {
sb.append(newClazz.getName()).append("{name = ").append(name);
sb.append(", nameid = ").append(client.getNameid()).append(", serviceid = ").append(client.getServiceid());
sb.append(", action.size = ").append(client.getActionCount());
sb.append(", address = ").append(clientAddress).append(", groups = ").append(groups);
sb.append(", remotes = ").append(transport == null ? null : Arrays.asList(transport.getRemoteAddress()));
sb.append(", address = ").append(clientAddress).append(", groups = ").append(transport == null ? null : transport.getName());
sb.append(", remoteaddrs = ").append(transport == null ? null : Arrays.asList(transport.getRemoteAddresses()));
sb.append("}");
Field s = newClazz.getDeclaredField("_selfstring");
s.setAccessible(true);
@@ -889,6 +885,22 @@ public abstract class Sncp {
av0.visit("name", name);
av0.visitEnd();
}
{
av0 = cw.visitAnnotation(Type.getDescriptor(ResourceType.class), true);
{
AnnotationVisitor av1 = av0.visitArray("value");
ResourceType rty = serviceClass.getAnnotation(ResourceType.class);
if (rty == null) {
av1.visit(null, Type.getType(Type.getDescriptor(serviceClass)));
} else {
for (Class cl : rty.value()) {
av1.visit(null, Type.getType(Type.getDescriptor(cl)));
}
}
av1.visitEnd();
}
av0.visitEnd();
}
{
av0 = cw.visitAnnotation(sncpDynDesc, true);
av0.visit("remote", Boolean.TRUE);
@@ -1070,8 +1082,8 @@ public abstract class Sncp {
sb.append(newClazz.getName()).append("{name = ").append(name);
sb.append(", nameid = ").append(client.getNameid()).append(", serviceid = ").append(client.getServiceid());
sb.append(", action.size = ").append(client.getActionCount());
sb.append(", address = ").append(clientAddress).append(", groups = ").append(groups);
sb.append(", remotes = ").append(transport == null ? null : Arrays.asList(transport.getRemoteAddress()));
sb.append(", address = ").append(clientAddress).append(", groups = ").append(transport == null ? null : transport.getName());
sb.append(", remotes = ").append(transport == null ? null : Arrays.asList(transport.getRemoteAddresses()));
sb.append("}");
Field s = newClazz.getDeclaredField("_selfstring");
s.setAccessible(true);

View File

@@ -129,8 +129,6 @@ public final class SncpClient {
protected final InetSocketAddress address;
protected final HashSet<String> groups;
private final byte[] addrBytes;
private final int addrPort;
@@ -144,12 +142,11 @@ public final class SncpClient {
protected final Consumer<Runnable> executor;
public SncpClient(final String serviceName, final Consumer<Runnable> executor, final DLong serviceid, boolean remote, final Class serviceClass,
final InetSocketAddress clientAddress, final HashSet<String> groups) {
final InetSocketAddress clientAddress) {
this.remote = remote;
this.executor = executor;
this.serviceClass = serviceClass;
this.address = clientAddress;
this.groups = groups;
//if (subLocalClass != null && !serviceClass.isAssignableFrom(subLocalClass)) throw new RuntimeException(subLocalClass + " is not " + serviceClass + " sub class ");
this.name = serviceName;
this.nameid = Sncp.hash(serviceName);
@@ -187,7 +184,7 @@ public final class SncpClient {
if (remote) service = service.replace(Sncp.LOCALPREFIX, Sncp.REMOTEPREFIX);
return this.getClass().getSimpleName() + "(service = " + service + ", serviceid = " + serviceid + ", nameid = " + nameid
+ ", name = '" + name + "', address = " + (address == null ? "" : (address.getHostString() + ":" + address.getPort()))
+ ", groups = " + groups + ", actions.size = " + actions.length + ")";
+ ", actions.size = " + actions.length + ")";
}
public static List<Method> parseMethod(final Class serviceClass) {
@@ -230,11 +227,50 @@ public final class SncpClient {
return multis;
}
public void remoteSameGroup(final BsonConvert convert, Transport transport, final int index, final Object... params) {
final SncpAction action = actions[index];
if (action.handlerFuncParamIndex >= 0) params[action.handlerFuncParamIndex] = null; //不能让远程调用handler因为之前本地方法已经调用过了
for (InetSocketAddress addr : transport.getRemoteAddresses()) {
remote0(null, convert, transport, addr, action, params);
}
}
public void asyncRemoteSameGroup(final BsonConvert convert, Transport transport, final int index, final Object... params) {
if (executor != null) {
executor.accept(() -> {
remoteSameGroup(convert, transport, index, params);
});
} else {
remoteSameGroup(convert, transport, index, params);
}
}
public void remoteDiffGroup(final BsonConvert convert, Transport[] transports, final int index, final Object... params) {
if (transports == null || transports.length < 1) return;
final SncpAction action = actions[index];
if (action.handlerFuncParamIndex >= 0) params[action.handlerFuncParamIndex] = null; //不能让远程调用handler因为之前本地方法已经调用过了
for (Transport transport : transports) {
remote0(null, convert, transport, null, action, params);
}
}
public void asyncRemoteDiffGroup(final BsonConvert convert, Transport[] transports, final int index, final Object... params) {
if (transports == null || transports.length < 1) return;
if (executor != null) {
executor.accept(() -> {
remoteDiffGroup(convert, transports, index, params);
});
} else {
remoteDiffGroup(convert, transports, index, params);
}
}
//只给远程模式调用的
public <T> T remote(final BsonConvert convert, Transport transport, final int index, final Object... params) {
final SncpAction action = actions[index];
final CompletionHandler handlerFunc = action.handlerFuncParamIndex >= 0 ? (CompletionHandler) params[action.handlerFuncParamIndex] : null;
if (action.handlerFuncParamIndex >= 0) params[action.handlerFuncParamIndex] = null;
Future<byte[]> future = remote0(handlerFunc, convert, transport, action, params);
Future<byte[]> future = remote0(handlerFunc, convert, transport, null, action, params);
if (handlerFunc != null) return null;
final BsonReader reader = convert.pollBsonReader();
try {
@@ -257,22 +293,11 @@ public final class SncpClient {
if (transports == null || transports.length < 1) return;
remote(convert, transports[0], index, params);
for (int i = 1; i < transports.length; i++) {
remote0(null, convert, transports[i], actions[index], params);
remote0(null, convert, transports[i], null, actions[index], params);
}
}
public <T> void asyncRemote(final BsonConvert convert, Transport[] transports, final int index, final Object... params) {
if (transports == null || transports.length < 1) return;
if (executor != null) {
executor.accept(() -> {
remote(convert, transports, index, params);
});
} else {
remote(convert, transports, index, params);
}
}
private Future<byte[]> remote0(final CompletionHandler handler, final BsonConvert convert, final Transport transport, final SncpAction action, final Object... params) {
private Future<byte[]> remote0(final CompletionHandler handler, final BsonConvert convert, final Transport transport, final SocketAddress addr0, final SncpAction action, final Object... params) {
Type[] myparamtypes = action.paramTypes;
if (action.addressSourceParamIndex >= 0) params[action.addressSourceParamIndex] = this.address;
final BsonWriter writer = convert.pollBsonWriter(transport.getBufferSupplier()); // 将head写入
@@ -283,7 +308,7 @@ public final class SncpClient {
final int reqBodyLength = writer.count() - HEADER_SIZE; //body总长度
final long seqid = System.nanoTime();
final DLong actionid = action.actionid;
final SocketAddress addr = action.addressTargetParamIndex >= 0 ? (SocketAddress) params[action.addressTargetParamIndex] : null;
final SocketAddress addr = addr0 == null ? (action.addressTargetParamIndex >= 0 ? (SocketAddress) params[action.addressTargetParamIndex] : null) : addr0;
final AsyncConnection conn = transport.pollConnection(addr);
if (conn == null || !conn.isOpen()) {
logger.log(Level.SEVERE, action.method + " sncp (params: " + jsonConvert.convertTo(params) + ") cannot connect " + (conn == null ? addr : conn.getRemoteAddress()));

View File

@@ -154,9 +154,9 @@ public final class SncpDynServlet extends SncpServlet {
*
* &#64;Override
* public void action(final BsonReader in, final BsonWriter out) throws Throwable {
* TestBean arg1 = convert.convertFrom(in, paramTypes[1]);
* String arg2 = convert.convertFrom(in, paramTypes[2]);
* int arg3 = convert.convertFrom(in, paramTypes[3]);
* TestBean arg1 = convert.convertFrom(paramTypes[1], in);
* String arg2 = convert.convertFrom(paramTypes[2], in);
* int arg3 = convert.convertFrom(paramTypes[3], in);
* Object rs = service.change(arg1, arg2, arg3);
* callParameter(out, arg1, arg2, arg3);
* convert.convertTo(out, paramTypes[0], rs);
@@ -210,9 +210,9 @@ public final class SncpDynServlet extends SncpServlet {
mv.visitMaxs(1, 1);
mv.visitEnd();
}
String convertFromDesc = "(" + convertReaderDesc + "Ljava/lang/reflect/Type;)Ljava/lang/Object;";
String convertFromDesc = "(Ljava/lang/reflect/Type;" + convertReaderDesc + ")Ljava/lang/Object;";
try {
convertFromDesc = Type.getMethodDescriptor(BsonConvert.class.getMethod("convertFrom", BsonReader.class, java.lang.reflect.Type.class));
convertFromDesc = Type.getMethodDescriptor(BsonConvert.class.getMethod("convertFrom", java.lang.reflect.Type.class, BsonReader.class));
} catch (Exception ex) {
throw new RuntimeException(ex); //不可能会发生
}
@@ -227,7 +227,6 @@ public final class SncpDynServlet extends SncpServlet {
for (int i = 0; i < paramClasses.length; i++) { //参数
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, newDynName, "convert", Type.getDescriptor(BsonConvert.class));
mv.visitVarInsn(ALOAD, 1);
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, newDynName, "paramTypes", "[Ljava/lang/reflect/Type;");
if (iconst > ICONST_5) {
@@ -236,6 +235,7 @@ public final class SncpDynServlet extends SncpServlet {
mv.visitInsn(iconst); //
}
mv.visitInsn(AALOAD);
mv.visitVarInsn(ALOAD, 1);
mv.visitMethodInsn(INVOKEVIRTUAL, convertName, "convertFrom", convertFromDesc, false);
int load = ALOAD;

View File

@@ -48,7 +48,7 @@ public final class SncpServer extends Server {
final int port = this.address.getPort();
AtomicLong createBufferCounter = watch == null ? new AtomicLong() : watch.createWatchNumber("SNCP_" + port + ".Buffer.creatCounter");
AtomicLong cycleBufferCounter = watch == null ? new AtomicLong() : watch.createWatchNumber("SNCP_" + port + ".Buffer.cycleCounter");
final int rcapacity = Math.max(this.capacity, 4 * 1024);
final int rcapacity = Math.max(this.bufferCapacity, 4 * 1024);
ObjectPool<ByteBuffer> bufferPool = new ObjectPool<>(createBufferCounter, cycleBufferCounter, this.bufferPoolSize,
(Object... params) -> ByteBuffer.allocateDirect(rcapacity), null, (e) -> {
if (e == null || e.isReadOnly() || e.capacity() != rcapacity) return false;

View File

@@ -29,6 +29,7 @@ import org.redkale.util.*;
* @author zhangjx
*/
@AutoLoad(false)
@ResourceType({CacheSourceService.class, CacheSource.class})
public class CacheSourceService<K extends Serializable, V extends Object> implements CacheSource<K, V>, Service, AutoCloseable {
@Resource(name = "APP_HOME")

View File

@@ -12,10 +12,13 @@ import org.redkale.util.*;
/**
*
* <p> 详情见: http://www.redkale.org
* <p>
* 详情见: http://www.redkale.org
*
* @author zhangjx
*/
@AutoLoad(false)
@ResourceType({DataCacheListenerService.class, DataCacheListener.class})
public class DataCacheListenerService implements DataCacheListener, Service {
@Resource(name = "$")

View File

@@ -15,6 +15,7 @@ import java.util.*;
import java.util.concurrent.*;
import java.util.logging.*;
import javax.annotation.Resource;
import org.redkale.util.*;
/**
* 暂时不实现
@@ -25,6 +26,7 @@ import javax.annotation.Resource;
* @author zhangjx
*/
@AutoLoad(false)
@ResourceType({DataSQLListenerService.class, DataSQLListener.class})
public class DataSQLListenerService implements DataSQLListener, Service {
private static final String format = "%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS.%tL";

View File

@@ -15,10 +15,13 @@ import org.redkale.util.*;
/**
* DataSource对应的Service类 该类主要特点是将所有含FilterBean参数的方法重载成FilterNode对应的方法。
*
* <p> 详情见: http://www.redkale.org
* <p>
* 详情见: http://www.redkale.org
*
* @author zhangjx
*/
@AutoLoad(false)
@ResourceType({DataSourceService.class, DataSource.class})
public class DataSourceService implements DataSource, Service, AutoCloseable {
@Resource(name = "$")

View File

@@ -8,9 +8,16 @@ package org.redkale.service;
import org.redkale.util.*;
/**
* 所有Service的实现类不得声明为final 允许远程模式的public方法和public String name()方法都不能声明为final。
* 所有Service的实现类不得声明为final 允许远程模式的public方法都不能声明为final。
* 注意: "$"是一个很特殊的Service.name值 。 被标记为@Resource(name = "$") 的Service的资源名与所属父Service的资源名一致。
*
* <p>
* <blockquote><pre>
* Service的资源类型
* 业务逻辑的Service通常有两种编写方式
* 1、只写一个Service实现类。
* 2、先定义业务的Service接口或抽象类再编写具体实现类。
* 第二种方式需要在具体实现类上使用&#64;ResourceType指明资源注入的类型。
* </pre></blockquote>
* <p>
* &#64;Resource(name = ".*")
* private HashMap&lt;String, XXXService&gt; nodemap;

View File

@@ -1,33 +0,0 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.service;
import java.lang.annotation.*;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* <blockquote><pre>
* Service的资源类型
* 业务逻辑的Service通常有两种编写方式
* 1、只写一个Service实现类。
* 2、先定义业务的Service接口或抽象类再编写具体实现类。
* &#64;ServiceResource用于第二种方式 在具体实现类上需要使用&#64;ServiceResource指明资源注入的类型。
* </pre></blockquote>
* <p>
* 详情见: http://www.redkale.org
*
* @author zhangjx
*/
@Inherited
@Documented
@Target({TYPE})
@Retention(RUNTIME)
public @interface ServiceResource {
Class<? extends Service> value();
}

View File

@@ -14,10 +14,13 @@ import org.redkale.util.*;
/**
*
* <p> 详情见: http://www.redkale.org
* <p>
* 详情见: http://www.redkale.org
*
* @author zhangjx
*/
@AutoLoad(false)
@ResourceType({WebSocketNodeService.class, WebSocketNode.class})
public class WebSocketNodeService extends WebSocketNode implements Service {
@Override

View File

@@ -67,7 +67,15 @@ public final class ResourceFactory {
}
public void register(final String name, final Object rs) {
register(name, rs.getClass(), rs);
final Class claz = rs.getClass();
ResourceType rtype = (ResourceType) claz.getAnnotation(ResourceType.class);
if (rtype == null) {
register(name, claz, rs);
} else {
for (Class cl : rtype.value()) {
register(name, cl, rs);
}
}
}
public <A> void register(final String name, final Class<? extends A> clazz, final A rs) {

View File

@@ -0,0 +1,26 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.util;
import java.lang.annotation.*;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* 显式的指明资源类型
* <p>
* 详情见: http://www.redkale.org
*
* @author zhangjx
*/
@Inherited
@Documented
@Target({TYPE})
@Retention(RUNTIME)
public @interface ResourceType {
Class[] value();
}