This commit is contained in:
@@ -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。
|
||||
*
|
||||
* <p>
|
||||
* <p>
|
||||
* 详情见: http://redkale.org
|
||||
*
|
||||
@@ -30,8 +29,14 @@ import org.redkale.util.AutoLoad;
|
||||
@SuppressWarnings("unchecked")
|
||||
public final class ClassFilter<T> {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(ClassFilter.class.getName());
|
||||
|
||||
private static final boolean finer = logger.isLoggable(Level.FINER);
|
||||
|
||||
private final Set<FilterEntry<T>> entrys = new HashSet<>();
|
||||
|
||||
private final Set<FilterEntry<T>> expectEntrys = new HashSet<>();
|
||||
|
||||
private boolean refused;
|
||||
|
||||
private Class superClass;
|
||||
@@ -79,10 +84,31 @@ public final class ClassFilter<T> {
|
||||
return entrys;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取预留的class集合
|
||||
*
|
||||
* @return Set<FilterEntry<T>>
|
||||
*/
|
||||
public final Set<FilterEntry<T>> getFilterExpectEntrys() {
|
||||
return expectEntrys;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有的class集合
|
||||
*
|
||||
* @return Set<FilterEntry<T>>
|
||||
*/
|
||||
public final Set<FilterEntry<T>> getAllFilterEntrys() {
|
||||
HashSet<FilterEntry<T>> 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<T> {
|
||||
/**
|
||||
* 过滤指定的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<T> {
|
||||
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<T> {
|
||||
/**
|
||||
* 判断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<T> {
|
||||
* 判断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<T> {
|
||||
|
||||
private final boolean autoload;
|
||||
|
||||
private final boolean expect;
|
||||
|
||||
public FilterEntry(Class<T> type, AnyValue property) {
|
||||
this(type, false, property);
|
||||
this(type, false, false, property);
|
||||
}
|
||||
|
||||
public FilterEntry(Class<T> type, final boolean autoload, AnyValue property) {
|
||||
public FilterEntry(Class<T> 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<T> {
|
||||
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<T> {
|
||||
return autoload;
|
||||
}
|
||||
|
||||
public boolean isExpect() {
|
||||
return expect;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -342,6 +379,7 @@ public final class ClassFilter<T> {
|
||||
*
|
||||
* @param exclude 不需要扫描的文件夹, 可以为null
|
||||
* @param filters 过滤器
|
||||
*
|
||||
* @throws IOException 异常
|
||||
*/
|
||||
public static void load(final File exclude, final ClassFilter... filters) throws IOException {
|
||||
|
||||
@@ -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<FilterEntry<Service>> entrys = serviceFilter.getFilterEntrys();
|
||||
final Set<FilterEntry<Service>> entrys = serviceFilter.getAllFilterEntrys();
|
||||
ResourceFactory regFactory = isSNCP() ? application.getResourceFactory() : resourceFactory;
|
||||
|
||||
for (FilterEntry<Service> entry : entrys) { //service实现类
|
||||
final Class<? extends Service> 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("<name> value cannot contains '$' in " + entry.getProperty());
|
||||
if (resourceFactory.find(entry.getName(), type) != null) continue; //Server加载Service时需要判断是否已经加载过了。
|
||||
final HashSet<String> groups = entry.getGroups(); //groups.isEmpty()表示<services>没有配置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<ServiceWrapper> swlist = new ArrayList<>(localServiceWrappers);
|
||||
Collections.sort(swlist);
|
||||
|
||||
@@ -66,6 +66,11 @@ public final class ServiceWrapper<T extends Service> implements Comparable<Servi
|
||||
maxClassNameLength = Math.max(maxClassNameLength, s.length() + 1);
|
||||
}
|
||||
|
||||
public static Class[] parseTypes(final Class<? extends Service> 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 ");
|
||||
|
||||
@@ -11,7 +11,7 @@ import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* 自动加载。 使用场景:
|
||||
* 1、被标记为@AutoLoad(false)的Service类不会被自动加载
|
||||
* 1、被标记为@AutoLoad(false)的Service类不会被自动加载, 当被依赖时才会被加载
|
||||
* 2、被标记为@AutoLoad(false)的Servlet类不会被自动加载
|
||||
*
|
||||
* <p> 详情见: http://redkale.org
|
||||
|
||||
@@ -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<Type, ResourceLoader> 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<T> {
|
||||
|
||||
Reference in New Issue
Block a user