This commit is contained in:
@@ -133,7 +133,7 @@
|
||||
-->
|
||||
<rest base="org.redkale.net.http.DefaultRestServlet" mustsign="false" autoload="true" includes="" excludes="">
|
||||
<!--
|
||||
value: Service类名,列出的表示必须被加载的Service对象, 且对象的Resource资源名称只能是""。
|
||||
value: Service类名,列出的表示必须被加载的Service对象
|
||||
ignore: 是否忽略,设置为true则不会加载该Service对象,默认值为false
|
||||
-->
|
||||
<service value="com.xxx.XXXXService"/>
|
||||
|
||||
@@ -172,7 +172,6 @@ public class NodeHttpServer extends NodeServer {
|
||||
final ClassFilter restFilter = ClassFilter.create(restConf.getValue("includes", ""), restConf.getValue("excludes", ""), includeValues, excludeValues);
|
||||
|
||||
super.interceptorServiceWrappers.forEach((wrapper) -> {
|
||||
if (!wrapper.getName().isEmpty()) return; //只加载resourceName为空的service
|
||||
final Class stype = wrapper.getType();
|
||||
RestService rs = (RestService) stype.getAnnotation(RestService.class);
|
||||
if (rs != null && rs.ignore()) return;
|
||||
@@ -183,17 +182,8 @@ public class NodeHttpServer extends NodeServer {
|
||||
if (!autoload && !includeValues.contains(stypename)) return;
|
||||
if (!restFilter.accept(stypename)) return;
|
||||
|
||||
RestHttpServlet servlet = Rest.createRestServlet(baseServletClass, wrapper.getName(), stype, sncp);
|
||||
if (servlet == null) return;
|
||||
RestHttpServlet servlet = httpServer.addRestServlet(stype, wrapper.getName(), wrapper.getService(), baseServletClass, prefix, (AnyValue) null);
|
||||
if (finest) logger.finest("Create RestServlet = " + servlet);
|
||||
try {
|
||||
Field serviceField = servlet.getClass().getDeclaredField("_service");
|
||||
serviceField.setAccessible(true);
|
||||
serviceField.set(servlet, wrapper.getService());
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(wrapper.getType() + " generate rest servlet error", e);
|
||||
}
|
||||
httpServer.addHttpServlet(servlet, prefix, (AnyValue) null);
|
||||
if (ss != null) {
|
||||
String[] mappings = servlet.getClass().getAnnotation(WebServlet.class).value();
|
||||
for (int i = 0; i < mappings.length; i++) {
|
||||
|
||||
@@ -107,7 +107,7 @@ public final class HttpPrepareServlet extends PrepareServlet<String, HttpContext
|
||||
}
|
||||
synchronized (allMapStrings) {
|
||||
for (String mapping : mappings) {
|
||||
if(mapping == null) continue;
|
||||
if (mapping == null) continue;
|
||||
if (!prefix.toString().isEmpty()) mapping = prefix + mapping;
|
||||
if (this.allMapStrings.containsKey(mapping)) {
|
||||
Class old = this.allMapStrings.get(mapping);
|
||||
@@ -158,6 +158,10 @@ public final class HttpPrepareServlet extends PrepareServlet<String, HttpContext
|
||||
return this.resourceHttpServlet;
|
||||
}
|
||||
|
||||
Set<HttpServlet> getServlets() {
|
||||
return this.servlets;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy(HttpContext context, AnyValue config) {
|
||||
this.resourceHttpServlet.destroy(context, config);
|
||||
|
||||
@@ -5,11 +5,13 @@
|
||||
*/
|
||||
package org.redkale.net.http;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.net.HttpCookie;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import org.redkale.net.*;
|
||||
import org.redkale.service.Service;
|
||||
import org.redkale.util.*;
|
||||
import org.redkale.watch.WatchFactory;
|
||||
|
||||
@@ -39,6 +41,48 @@ public final class HttpServer extends Server<String, HttpContext, HttpRequest, H
|
||||
this.prepare.addServlet(servlet, prefix, conf, mappings);
|
||||
}
|
||||
|
||||
public <S extends Service, T extends RestHttpServlet> RestHttpServlet addRestServlet(Class<S> serviceType,
|
||||
final String name, final S service, final Class<T> baseServletClass, final String prefix, AnyValue conf) {
|
||||
RestHttpServlet servlet = null;
|
||||
for (final HttpServlet item : ((HttpPrepareServlet) this.prepare).getServlets()) {
|
||||
if (!(item instanceof RestHttpServlet)) continue;
|
||||
try {
|
||||
Field field = item.getClass().getDeclaredField(Rest.REST_SERVICE_FIELD_NAME);
|
||||
if (serviceType.equals(field.getType())) {
|
||||
servlet = (RestHttpServlet) item;
|
||||
break;
|
||||
}
|
||||
} catch (NoSuchFieldException | SecurityException e) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (servlet == null) servlet = Rest.createRestServlet(baseServletClass, serviceType, false);
|
||||
try { //若提供动态变更Service服务功能,则改Rest服务无法做出相应更新
|
||||
Field field = servlet.getClass().getDeclaredField(Rest.REST_SERVICE_FIELD_NAME);
|
||||
field.setAccessible(true);
|
||||
|
||||
Field mapfield = servlet.getClass().getDeclaredField(Rest.REST_SERVICEMAP_FIELD_NAME);
|
||||
mapfield.setAccessible(true);
|
||||
|
||||
Service firstService = (Service) field.get(servlet);
|
||||
if (name.isEmpty()) {
|
||||
field.set(servlet, service);
|
||||
firstService = service;
|
||||
}
|
||||
Map map = (Map) mapfield.get(servlet);
|
||||
if (map == null && !name.isEmpty()) map = new HashMap();
|
||||
if (map != null) {
|
||||
map.put(name, service);
|
||||
if (firstService != null) map.put("", firstService);
|
||||
}
|
||||
mapfield.set(servlet, map);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(serviceType + " generate rest servlet error", e);
|
||||
}
|
||||
this.prepare.addServlet(servlet, prefix, conf);
|
||||
return servlet;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
protected HttpContext createContext() {
|
||||
|
||||
@@ -27,6 +27,12 @@ import org.redkale.source.Flipper;
|
||||
*/
|
||||
public final class Rest {
|
||||
|
||||
public static final String REST_HEADER_RESOURCE_NAME = "rest-resource-name";
|
||||
|
||||
static final String REST_SERVICE_FIELD_NAME = "_service";
|
||||
|
||||
static final String REST_SERVICEMAP_FIELD_NAME = "_servicemap"; //如果只有name=""的Service资源,则实例中_servicemap必须为null
|
||||
|
||||
private static final Set<String> EXCLUDERMETHODS = new HashSet<>();
|
||||
|
||||
static {
|
||||
@@ -38,14 +44,14 @@ public final class Rest {
|
||||
private Rest() {
|
||||
}
|
||||
|
||||
public static String getWebModuleName(Class<? extends Service> serviceType) {
|
||||
static String getWebModuleName(Class<? extends Service> serviceType) {
|
||||
final RestService controller = serviceType.getAnnotation(RestService.class);
|
||||
if (controller == null) return serviceType.getSimpleName().replaceAll("Service.*$", "").toLowerCase();
|
||||
if (controller.ignore()) return null;
|
||||
return (!controller.value().isEmpty()) ? controller.value() : serviceType.getSimpleName().replaceAll("Service.*$", "").toLowerCase();
|
||||
}
|
||||
|
||||
public static <T extends RestHttpServlet> T createRestServlet(final Class<T> baseServletClass, final String serviceName, final Class<? extends Service> serviceType, final boolean sncp) {
|
||||
static <T extends RestHttpServlet> T createRestServlet(final Class<T> baseServletClass, final Class<? extends Service> serviceType, final boolean sncp) {
|
||||
if (baseServletClass == null || serviceType == null) return null;
|
||||
if (!RestHttpServlet.class.isAssignableFrom(baseServletClass)) return null;
|
||||
int mod = baseServletClass.getModifiers();
|
||||
@@ -66,13 +72,6 @@ public final class Rest {
|
||||
if (controller != null && controller.ignore()) return null; //标记为ignore=true不创建Servlet
|
||||
ClassLoader loader = Sncp.class.getClassLoader();
|
||||
String newDynName = serviceTypeString.substring(0, serviceTypeString.lastIndexOf('/') + 1) + "_Dyn" + serviceType.getSimpleName().replaceAll("Service.*$", "") + "RestServlet";
|
||||
if (!serviceName.isEmpty()) {
|
||||
boolean normal = true;
|
||||
for (char ch : serviceName.toCharArray()) {//含特殊字符的使用hash值
|
||||
if (!((ch >= '0' && ch <= '9') || ch == '_' || (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'))) normal = false;
|
||||
}
|
||||
newDynName += "_" + (normal ? serviceName : Sncp.hash(serviceName));
|
||||
}
|
||||
try {
|
||||
return ((Class<T>) Class.forName(newDynName.replace('/', '.'))).newInstance();
|
||||
} catch (Exception ex) {
|
||||
@@ -113,18 +112,21 @@ public final class Rest {
|
||||
av0.visitEnd();
|
||||
classMap.put("type", serviceType.getName());
|
||||
classMap.put("url", urlpath);
|
||||
if (!serviceName.isEmpty()) classMap.put("resource", serviceName);
|
||||
classMap.put("moduleid", moduleid);
|
||||
classMap.put("repair", repair);
|
||||
}
|
||||
|
||||
{ //注入 @Resource private XXXService _service;
|
||||
fv = cw.visitField(ACC_PRIVATE, "_service", serviceDesc, null, null);
|
||||
fv = cw.visitField(ACC_PRIVATE, REST_SERVICE_FIELD_NAME, serviceDesc, null, null);
|
||||
av0 = fv.visitAnnotation("Ljavax/annotation/Resource;", true);
|
||||
av0.visit("name", serviceName);
|
||||
av0.visit("name", "");
|
||||
av0.visitEnd();
|
||||
fv.visitEnd();
|
||||
}
|
||||
{ //_servicemap字段 Map<String, XXXService>
|
||||
fv = cw.visitField(ACC_PRIVATE, REST_SERVICEMAP_FIELD_NAME, "Ljava/util/Map;", "Ljava/util/Map<Ljava/lang/String;" + serviceDesc + ">;", null);
|
||||
fv.visitEnd();
|
||||
}
|
||||
{ //构造函数
|
||||
mv = new AsmMethodVisitor(cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null));
|
||||
//mv.setDebug(true);
|
||||
@@ -182,9 +184,34 @@ public final class Rest {
|
||||
av0 = mv.visitAnnotation(authDesc, true);
|
||||
av0.visitEnd();
|
||||
}
|
||||
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitFieldInsn(GETFIELD, newDynName, REST_SERVICEMAP_FIELD_NAME, "Ljava/util/Map;");
|
||||
Label lmapif = new Label();
|
||||
mv.visitJumpInsn(IFNONNULL, lmapif);
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitFieldInsn(GETFIELD, newDynName, REST_SERVICE_FIELD_NAME, serviceDesc);
|
||||
Label lserif = new Label();
|
||||
mv.visitJumpInsn(GOTO, lserif);
|
||||
mv.visitLabel(lmapif);
|
||||
|
||||
mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
|
||||
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitFieldInsn(GETFIELD, newDynName, REST_SERVICEMAP_FIELD_NAME, "Ljava/util/Map;");
|
||||
mv.visitVarInsn(ALOAD, 1);
|
||||
mv.visitLdcInsn(REST_HEADER_RESOURCE_NAME);
|
||||
mv.visitLdcInsn("");
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, "org/redkale/net/http/HttpRequest", "getHeader", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;", false);
|
||||
mv.visitMethodInsn(INVOKEINTERFACE, "java/util/Map", "get", "(Ljava/lang/Object;)Ljava/lang/Object;", true);
|
||||
mv.visitTypeInsn(CHECKCAST, serviceTypeString);
|
||||
mv.visitLabel(lserif);
|
||||
mv.visitFrame(Opcodes.F_SAME1, 0, null, 1, new Object[]{serviceTypeString});
|
||||
mv.visitVarInsn(ASTORE, 3);
|
||||
|
||||
final int maxStack = 3 + params.length;
|
||||
List<int[]> varInsns = new ArrayList<>();
|
||||
int maxLocals = 3;
|
||||
int maxLocals = 4;
|
||||
boolean hasVisitWebAction = false;
|
||||
final String jsvar = entry.jsvar.isEmpty() ? null : entry.jsvar;
|
||||
int argIndex = 0;
|
||||
@@ -495,8 +522,9 @@ public final class Rest {
|
||||
actionMap.put("methods", entry.methods);
|
||||
}
|
||||
|
||||
mv.visitVarInsn(ALOAD, 0); //调用this
|
||||
mv.visitFieldInsn(GETFIELD, newDynName, "_service", serviceDesc);
|
||||
//mv.visitVarInsn(ALOAD, 0); //调用this
|
||||
//mv.visitFieldInsn(GETFIELD, newDynName, REST_SERVICE_FIELD_NAME, serviceDesc);
|
||||
mv.visitVarInsn(ALOAD, 3);
|
||||
for (int[] ins : varInsns) {
|
||||
mv.visitVarInsn(ins[0], ins[1]);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user