diff --git a/src/org/redkale/boot/ClassFilter.java b/src/org/redkale/boot/ClassFilter.java index 53c5aefd5..085be5466 100644 --- a/src/org/redkale/boot/ClassFilter.java +++ b/src/org/redkale/boot/ClassFilter.java @@ -14,13 +14,12 @@ import java.util.concurrent.*; import java.util.jar.*; import java.util.logging.*; import java.util.regex.*; -import org.redkale.util.AnyValue; +import org.redkale.util.*; import org.redkale.util.AnyValue.DefaultAnyValue; -import org.redkale.util.AutoLoad; /** * class过滤器, 符合条件的class会保留下来存入FilterEntry。 - * + *

*

* 详情见: http://redkale.org * @@ -30,8 +29,14 @@ import org.redkale.util.AutoLoad; @SuppressWarnings("unchecked") public final class ClassFilter { + private static final Logger logger = Logger.getLogger(ClassFilter.class.getName()); + + private static final boolean finer = logger.isLoggable(Level.FINER); + private final Set> entrys = new HashSet<>(); + private final Set> expectEntrys = new HashSet<>(); + private boolean refused; private Class superClass; @@ -79,10 +84,31 @@ public final class ClassFilter { return entrys; } + /** + * 获取预留的class集合 + * + * @return Set<FilterEntry<T>> + */ + public final Set> getFilterExpectEntrys() { + return expectEntrys; + } + + /** + * 获取所有的class集合 + * + * @return Set<FilterEntry<T>> + */ + public final Set> getAllFilterEntrys() { + HashSet> rs = new HashSet<>(); + rs.addAll(entrys); + rs.addAll(expectEntrys); + return rs; + } + /** * 自动扫描地过滤指定的class * - * @param property AnyValue + * @param property AnyValue * @param clazzname String */ @SuppressWarnings("unchecked") @@ -93,9 +119,9 @@ public final class ClassFilter { /** * 过滤指定的class * - * @param property application.xml中对应class节点下的property属性项 + * @param property application.xml中对应class节点下的property属性项 * @param clazzname class名称 - * @param autoscan 为true表示自动扫描的, false表示显著调用filter, AutoLoad的注解将被忽略 + * @param autoscan 为true表示自动扫描的, false表示显著调用filter, AutoLoad的注解将被忽略 */ public final void filter(AnyValue property, String clazzname, boolean autoscan) { boolean r = accept0(property, clazzname); @@ -129,8 +155,15 @@ public final class ClassFilter { property = dav; } } - entrys.add(new FilterEntry(clazz, autoscan, property)); + + AutoLoad auto = (AutoLoad) clazz.getAnnotation(AutoLoad.class); + if (autoscan && auto != null && !auto.value()) { //自动扫描且被标记为@AutoLoad(false)的 + expectEntrys.add(new FilterEntry(clazz, autoscan, true, property)); + } else { + entrys.add(new FilterEntry(clazz, autoscan, false, property)); + } } catch (Throwable cfe) { + if (finer) logger.log(Level.FINER, ClassFilter.class.getSimpleName() + " filter error", cfe); } } @@ -152,8 +185,9 @@ public final class ClassFilter { /** * 判断class是否有效 * - * @param property AnyValue + * @param property AnyValue * @param classname String + * * @return boolean */ public boolean accept(AnyValue property, String classname) { @@ -191,17 +225,14 @@ public final class ClassFilter { * 判断class是否有效 * * @param property AnyValue - * @param clazz Class + * @param clazz Class * @param autoscan boolean + * * @return boolean */ @SuppressWarnings("unchecked") public boolean accept(AnyValue property, Class clazz, boolean autoscan) { if (this.refused || !Modifier.isPublic(clazz.getModifiers())) return false; - if (autoscan) { - AutoLoad auto = (AutoLoad) clazz.getAnnotation(AutoLoad.class); - if (auto != null && !auto.value()) return false; - } if (annotationClass != null && clazz.getAnnotation(annotationClass) == null) return false; return superClass == null || (clazz != superClass && superClass.isAssignableFrom(clazz)); } @@ -263,11 +294,13 @@ public final class ClassFilter { private final boolean autoload; + private final boolean expect; + public FilterEntry(Class type, AnyValue property) { - this(type, false, property); + this(type, false, false, property); } - public FilterEntry(Class type, final boolean autoload, AnyValue property) { + public FilterEntry(Class type, final boolean autoload, boolean expect, AnyValue property) { this.type = type; String str = property == null ? null : property.getValue("groups"); if (str != null) { @@ -277,6 +310,7 @@ public final class ClassFilter { if (str != null) groups.addAll(Arrays.asList(str.split(";"))); this.property = property; this.autoload = autoload; + this.expect = expect; this.name = property == null ? "" : property.getValue("name", ""); } @@ -322,6 +356,9 @@ public final class ClassFilter { return autoload; } + public boolean isExpect() { + return expect; + } } /** @@ -342,6 +379,7 @@ public final class ClassFilter { * * @param exclude 不需要扫描的文件夹, 可以为null * @param filters 过滤器 + * * @throws IOException 异常 */ public static void load(final File exclude, final ClassFilter... filters) throws IOException { diff --git a/src/org/redkale/boot/NodeServer.java b/src/org/redkale/boot/NodeServer.java index 28996edfb..5fc7a690b 100644 --- a/src/org/redkale/boot/NodeServer.java +++ b/src/org/redkale/boot/NodeServer.java @@ -21,6 +21,7 @@ import javax.persistence.Transient; import static org.redkale.boot.Application.*; import org.redkale.boot.ClassFilter.FilterEntry; import org.redkale.net.*; +import org.redkale.net.http.WebSocketNode; import org.redkale.net.sncp.*; import org.redkale.service.*; import org.redkale.source.*; @@ -249,13 +250,21 @@ public abstract class NodeServer { protected void loadService(ClassFilter serviceFilter) throws Exception { if (serviceFilter == null) return; final String threadName = "[" + Thread.currentThread().getName() + "] "; - final Set> entrys = serviceFilter.getFilterEntrys(); + final Set> entrys = serviceFilter.getAllFilterEntrys(); ResourceFactory regFactory = isSNCP() ? application.getResourceFactory() : resourceFactory; for (FilterEntry entry : entrys) { //service实现类 final Class type = entry.getType(); if (Modifier.isFinal(type.getModifiers())) continue; //修饰final的类跳过 if (!Modifier.isPublic(type.getModifiers())) continue; + if (entry.isExpect()) { + if (Modifier.isAbstract(type.getModifiers())) continue; //修饰abstract的类跳过 + if (DataSource.class.isAssignableFrom(type)) continue; + if (CacheSource.class.isAssignableFrom(type)) continue; + if (DataSQLListener.class.isAssignableFrom(type)) continue; + if (DataCacheListener.class.isAssignableFrom(type)) continue; + if (WebSocketNode.class.isAssignableFrom(type)) continue; + } if (entry.getName().contains("$")) throw new RuntimeException(" value cannot contains '$' in " + entry.getProperty()); if (resourceFactory.find(entry.getName(), type) != null) continue; //Server加载Service时需要判断是否已经加载过了。 final HashSet groups = entry.getGroups(); //groups.isEmpty()表示没有配置groups属性。 @@ -266,29 +275,52 @@ public abstract class NodeServer { || (this.sncpGroup == null && entry.isEmptyGroups()) //空的SNCP配置 || type.getAnnotation(LocalService.class) != null;//本地模式 if (localed && (type.isInterface() || Modifier.isAbstract(type.getModifiers()))) continue; //本地模式不能实例化接口和抽象类的Service类 - - Service service; - if (localed) { //本地模式 - service = Sncp.createLocalService(entry.getName(), getExecutor(), application.getResourceFactory(), type, this.sncpAddress, loadTransport(this.sncpGroup), loadTransports(groups)); - } else { - service = Sncp.createRemoteService(entry.getName(), getExecutor(), type, this.sncpAddress, loadTransport(groups)); - } - if (SncpClient.parseMethod(type).isEmpty()) continue; //class没有可用的方法, 通常为BaseService - final ServiceWrapper wrapper = new ServiceWrapper(type, service, entry.getName(), localed ? this.sncpGroup : null, groups, entry.getProperty()); - for (final Class restype : wrapper.getTypes()) { - if (resourceFactory.find(wrapper.getName(), restype) == null) { - regFactory.register(wrapper.getName(), restype, wrapper.getService()); - } else if (isSNCP() && !entry.isAutoload()) { - throw new RuntimeException(ServiceWrapper.class.getSimpleName() + "(class:" + type.getName() + ", name:" + entry.getName() + ", group:" + groups + ") is repeat."); + final Runnable runner = new Runnable() { + @Override + public void run() { + try { + Service service; + if (localed) { //本地模式 + service = Sncp.createLocalService(entry.getName(), getExecutor(), application.getResourceFactory(), type, + NodeServer.this.sncpAddress, loadTransport(NodeServer.this.sncpGroup), loadTransports(groups)); + } else { + service = Sncp.createRemoteService(entry.getName(), getExecutor(), type, NodeServer.this.sncpAddress, loadTransport(groups)); + } + if (SncpClient.parseMethod(type).isEmpty()) return; //class没有可用的方法, 通常为BaseService + final ServiceWrapper wrapper = new ServiceWrapper(type, service, entry.getName(), localed ? NodeServer.this.sncpGroup : null, groups, entry.getProperty()); + for (final Class restype : wrapper.getTypes()) { + if (resourceFactory.find(wrapper.getName(), restype) == null) { + regFactory.register(wrapper.getName(), restype, wrapper.getService()); + } else if (isSNCP() && !entry.isAutoload()) { + throw new RuntimeException(ServiceWrapper.class.getSimpleName() + "(class:" + type.getName() + ", name:" + entry.getName() + ", group:" + groups + ") is repeat."); + } + } + if (wrapper.isRemote()) { + remoteServiceWrappers.add(wrapper); + } else { + localServiceWrappers.add(wrapper); + if (consumer != null) consumer.accept(wrapper); + } + } catch (RuntimeException ex) { + throw ex; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + }; + if (entry.isExpect()) { + ResourceFactory.ResourceLoader resourceLoader = (ResourceFactory rf, final Object src, final String resourceName, Field field, final Object attachment) -> { + runner.run(); + }; + for (final Class restype : ServiceWrapper.parseTypes(entry.getType())) { + resourceFactory.register(resourceLoader, restype); } - } - if (wrapper.isRemote()) { - remoteServiceWrappers.add(wrapper); } else { - localServiceWrappers.add(wrapper); - if (consumer != null) consumer.accept(wrapper); + runner.run(); } + } + application.servicecdl.countDown(); application.servicecdl.await(); @@ -297,12 +329,14 @@ public abstract class NodeServer { new ArrayList<>(localServiceWrappers).forEach(y -> { resourceFactory.inject(y.getService(), NodeServer.this); }); - remoteServiceWrappers.forEach(y -> { + new ArrayList<>(remoteServiceWrappers).forEach(y -> { resourceFactory.inject(y.getService(), NodeServer.this); - if (sb != null) { - sb.append(threadName).append(y.toSimpleString()).append(" loaded and injected").append(LINE_SEPARATOR); - } }); + if (sb != null) { + remoteServiceWrappers.forEach(y -> { + sb.append(threadName).append(y.toSimpleString()).append(" loaded and injected").append(LINE_SEPARATOR); + }); + } //----------------- init ----------------- List swlist = new ArrayList<>(localServiceWrappers); Collections.sort(swlist); diff --git a/src/org/redkale/net/sncp/ServiceWrapper.java b/src/org/redkale/net/sncp/ServiceWrapper.java index 744b02ccb..651640fd7 100644 --- a/src/org/redkale/net/sncp/ServiceWrapper.java +++ b/src/org/redkale/net/sncp/ServiceWrapper.java @@ -66,6 +66,11 @@ public final class ServiceWrapper implements Comparable servicetype) { + ResourceType rty = servicetype.getAnnotation(ResourceType.class); + return rty == null ? new Class[]{servicetype} : rty.value(); + } + public String toSimpleString() { StringBuilder sb = new StringBuilder(); sb.append(remote ? "RemoteService" : "LocalService "); diff --git a/src/org/redkale/util/AutoLoad.java b/src/org/redkale/util/AutoLoad.java index 65294f907..ff8298e8a 100644 --- a/src/org/redkale/util/AutoLoad.java +++ b/src/org/redkale/util/AutoLoad.java @@ -11,7 +11,7 @@ import java.lang.annotation.*; /** * 自动加载。 使用场景: - * 1、被标记为@AutoLoad(false)的Service类不会被自动加载 + * 1、被标记为@AutoLoad(false)的Service类不会被自动加载, 当被依赖时才会被加载 * 2、被标记为@AutoLoad(false)的Servlet类不会被自动加载 * *

详情见: http://redkale.org diff --git a/src/org/redkale/util/ResourceFactory.java b/src/org/redkale/util/ResourceFactory.java index 93560e974..7a9ea0d09 100644 --- a/src/org/redkale/util/ResourceFactory.java +++ b/src/org/redkale/util/ResourceFactory.java @@ -373,16 +373,26 @@ public final class ResourceFactory { } } - private ResourceLoader findLoader(Type ft, Field field) { + private ResourceLoader findMatchLoader(Type ft, Field field) { ResourceLoader it = this.loadermap.get(ft); + if (it == null) it = this.loadermap.get(field.getType()); if (it != null) return it; + return parent == null ? null : parent.findMatchLoader(ft, field); + } + + private ResourceLoader findRegxLoader(Type ft, Field field) { Class c = field.getType(); for (Map.Entry en : this.loadermap.entrySet()) { Type t = en.getKey(); if (t == ft) return en.getValue(); if (t instanceof Class && (((Class) t)).isAssignableFrom(c)) return en.getValue(); } - return parent == null ? null : parent.findLoader(ft, field); + return parent == null ? null : parent.findRegxLoader(ft, field); + } + + private ResourceLoader findLoader(Type ft, Field field) { + ResourceLoader it = this.findMatchLoader(ft, field); + return it == null ? findRegxLoader(ft, field) : it; } private static class ResourceEntry {