diff --git a/src/main/java/org/redkale/annotation/ResourceChanged.java b/src/main/java/org/redkale/annotation/ResourceChanged.java
index 9fdcd34b3..82636bf2c 100644
--- a/src/main/java/org/redkale/annotation/ResourceChanged.java
+++ b/src/main/java/org/redkale/annotation/ResourceChanged.java
@@ -5,11 +5,10 @@
*/
package org.redkale.annotation;
+import java.lang.annotation.*;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
-import java.lang.annotation.*;
-
/**
* @Resource资源被更新时的监听事件, 本注解只能标记在方法参数为ResourceEvent[]上
* 注意: 一个类只能存在一个@ResourceChanged的方法, 多余的会被忽略
@@ -29,7 +28,8 @@ import java.lang.annotation.*;
* @ResourceChanged
* private void changeResource(ResourceEvent[] events) {
* for(ResourceEvent event : events) {
- * System.out .println("@Resource = " + event.name() + " 资源变更: newVal = " + event.newValue() + ", oldVal = " + event.oldValue());
+ * System.out .println("@Resource = " + event.name()
+ * + " 资源变更: newVal = " + event.newValue() + ", oldVal = " + event.oldValue());
* }
* }
*
@@ -56,8 +56,9 @@ import java.lang.annotation.*;
public @interface ResourceChanged {
/**
- * 新旧值是否不同时才回调方法
- * true: 新值与旧值不同时才回调ResourceChanged方法 false: 只要执行了ResourceFactory.register 就回调ResourceChanged方法
+ * 新旧值是否不相同的情况下才回调方法
+ * true: 新值与旧值不相同才回调ResourceChanged方法
+ * false: 只要执行了ResourceFactory.register 就回调ResourceChanged方法
*
* @since 2.7.0
* @return boolean
diff --git a/src/main/java/org/redkale/annotation/ResourceInjected.java b/src/main/java/org/redkale/annotation/ResourceInjected.java
index 9c865ad8c..3f7398e91 100644
--- a/src/main/java/org/redkale/annotation/ResourceInjected.java
+++ b/src/main/java/org/redkale/annotation/ResourceInjected.java
@@ -5,11 +5,10 @@
*/
package org.redkale.annotation;
+import java.lang.annotation.*;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
-import java.lang.annotation.*;
-
/**
* @Resource资源被依赖注入时的监听事件。
* 本注解只能标记在空参数或者(String、Object、java.lang.reflect.Field)三个参数类型的任意组合方法上
@@ -27,8 +26,8 @@ import java.lang.annotation.*;
* private String name;
*
* @ResourceInjected
- * private void onInjected(Object src, String fieldName) {
- * System.out .println("资源被注入到对象(" + src + ")的字段(" + fieldName + ")上");
+ * private void onInjected(Object dest, String fieldName) {
+ * System.out .println("资源被注入到对象(" + dest + ")的字段(" + fieldName + ")上");
* }
* }
*
diff --git a/src/main/java/org/redkale/boot/Application.java b/src/main/java/org/redkale/boot/Application.java
index 54893f982..cf469edac 100644
--- a/src/main/java/org/redkale/boot/Application.java
+++ b/src/main/java/org/redkale/boot/Application.java
@@ -33,6 +33,7 @@ import org.redkale.convert.Convert;
import org.redkale.convert.bson.BsonFactory;
import org.redkale.convert.json.*;
import org.redkale.convert.proto.ProtobufFactory;
+import org.redkale.inject.Configuration;
import org.redkale.inject.ResourceEvent;
import org.redkale.inject.ResourceFactory;
import org.redkale.inject.ResourceTypeLoader;
@@ -370,8 +371,8 @@ public final class Application {
}
public void init() throws Exception {
- // 注册ResourceType
- this.initResourceTypeLoader();
+ // 注册Resource加载器
+ this.initInjectResource();
// 读取远程配置,并合并app.config
this.propertiesModule.initRemoteProperties();
// 解析配置
@@ -388,7 +389,7 @@ public final class Application {
this.onAppPostInit();
}
- private void initResourceTypeLoader() {
+ private void initInjectResource() {
final Application application = this;
// 只有WatchService才能加载Application、WatchFactory
this.resourceFactory.register(new ResourceTypeLoader() {
@@ -700,6 +701,13 @@ public final class Application {
return HttpRpcClient.class;
}
});
+ // 加载Configuration
+ ClassFilter filter = new ClassFilter(this.getClassLoader(), Configuration.class);
+ try {
+ loadClassByFilters(filter);
+ } catch (IOException e) {
+ throw new RedkaleException(e);
+ }
}
private void registerResourceEnvs(boolean first, Properties... envs) {
@@ -731,7 +739,11 @@ public final class Application {
AutoLoad auto = en.getType().getAnnotation(AutoLoad.class);
if (auto == null || auto.value()) {
int c = RetCodes.load(en.getType());
- sb.append("Load RetCodes (type=").append(en.getType().getName() + ") " + c + " records\r\n");
+ sb.append("Load RetCodes (type=")
+ .append(en.getType().getName())
+ .append(") ")
+ .append(c)
+ .append(" records\r\n");
}
}
});
@@ -1435,9 +1447,7 @@ public final class Application {
this.onAppPreShutdown();
stopServers();
this.propertiesModule.destroy();
- if (this.workExecutor != null) {
- this.workExecutor.shutdownNow();
- }
+ this.workExecutor.shutdownNow();
if (this.clientAsyncGroup != null) {
long s = System.currentTimeMillis();
this.clientAsyncGroup.dispose();
diff --git a/src/main/java/org/redkale/boot/NodeWebSocketNodeLoader.java b/src/main/java/org/redkale/boot/NodeWebSocketNodeLoader.java
index bb2425e9a..b761d0bc9 100644
--- a/src/main/java/org/redkale/boot/NodeWebSocketNodeLoader.java
+++ b/src/main/java/org/redkale/boot/NodeWebSocketNodeLoader.java
@@ -131,7 +131,7 @@ class NodeWebSocketNodeLoader implements ResourceTypeLoader {
continue;
}
sncpResFactory = ns.resourceFactory;
- loader = sncpResFactory.findTypeLoader(WebSocketNode.class, field);
+ loader = sncpResFactory.findResourceTypeLoader(WebSocketNode.class, field);
if (loader != null) {
break;
}
diff --git a/src/main/java/org/redkale/inject/Configuration.java b/src/main/java/org/redkale/inject/Configuration.java
new file mode 100644
index 000000000..c3af0941e
--- /dev/null
+++ b/src/main/java/org/redkale/inject/Configuration.java
@@ -0,0 +1,15 @@
+/*
+
+*/
+
+package org.redkale.inject;
+
+/**
+ * 启动服务时的初始化配置,需要结合{@link org.redkale.annotation.Resource}使用
+ *
+ * 详情见: https://redkale.org
+ *
+ * @author zhangjx
+ * @since 2.8.0
+ */
+public interface Configuration {}
diff --git a/src/main/java/org/redkale/inject/ResourceFactory.java b/src/main/java/org/redkale/inject/ResourceFactory.java
index 11e41e29c..bbe9b2fc6 100644
--- a/src/main/java/org/redkale/inject/ResourceFactory.java
+++ b/src/main/java/org/redkale/inject/ResourceFactory.java
@@ -18,6 +18,7 @@ import java.util.logging.*;
import org.redkale.annotation.*;
import org.redkale.convert.*;
import org.redkale.convert.json.JsonConvert;
+import org.redkale.util.Creator;
import org.redkale.util.RedkaleClassLoader;
import org.redkale.util.RedkaleException;
import org.redkale.util.TypeToken;
@@ -54,12 +55,16 @@ public final class ResourceFactory {
private final List> chidren = new CopyOnWriteArrayList<>();
+ private final ConcurrentHashMap resTypeLoaderMap = new ConcurrentHashMap();
+
private final ConcurrentHashMap, ResourceAnnotationLoader> resAnnotationLoaderMap =
new ConcurrentHashMap();
- private final ConcurrentHashMap resTypeLoaderMap = new ConcurrentHashMap();
+ private final ConcurrentHashMap> resConfigureSupplierMap =
+ new ConcurrentHashMap();
- private final ConcurrentHashMap> store = new ConcurrentHashMap();
+ private final ConcurrentHashMap> entryStore =
+ new ConcurrentHashMap();
private ResourceFactory(ResourceFactory parent) {
this.parent = parent;
@@ -101,9 +106,9 @@ public final class ResourceFactory {
return result;
}
- /** 清空当前ResourceFactory注入资源 */
+ /** 清空当前已注入资源的缓存 */
public void release() {
- this.store.clear();
+ this.entryStore.clear();
}
/** inject时的锁 */
@@ -155,6 +160,80 @@ public final class ResourceFactory {
return rt2 == null ? clazz : rt2.value();
}
+ /**
+ * 替换资源名中含${xxx}或{system.property.xxx}的配置项
+ *
+ * @param name 资源名
+ * @return 不包含配置项的资源名
+ */
+ public static String getResourceName(String name) {
+ return getResourceName(null, name);
+ }
+
+ /**
+ * 替换资源名中含${xxx}或{system.property.xxx}的配置项
+ *
+ * @param parent 父资源名
+ * @param name 资源名
+ * @return 不包含配置项的资源名
+ */
+ public static String getResourceName(String parent, String name) {
+ if (name == null) {
+ return null;
+ }
+ if (name.startsWith("${")) {
+ String subName = name.substring(2);
+ int pos = subName.lastIndexOf('}');
+ if (pos > 0) {
+ subName = subName.substring(0, pos);
+ pos = subName.indexOf(':');
+ if (pos > 0) {
+ subName = subName.substring(0, pos);
+ }
+ name = subName;
+ }
+ }
+ int pos = name.indexOf("{system.property.");
+ if (pos < 0) {
+ return (name.contains(Resource.PARENT_NAME) && parent != null)
+ ? name.replace(Resource.PARENT_NAME, parent)
+ : name;
+ }
+ String prefix = name.substring(0, pos);
+ String subName = name.substring(pos + "{system.property.".length());
+ pos = subName.lastIndexOf('}');
+ if (pos < 0) {
+ return (name.contains(Resource.PARENT_NAME) && parent != null)
+ ? name.replace(Resource.PARENT_NAME, parent)
+ : name;
+ }
+ String postfix = subName.substring(pos + 1);
+ String property = subName.substring(0, pos);
+ return getResourceName(parent, prefix + System.getProperty(property, "") + postfix);
+ }
+
+ /**
+ * 替换资源名中的配置项, 没有配置项返回null
+ * @param parent 父资源名
+ * @param name 可能包含配置项的资源名
+ * @return 替换资源名中的配置项后的资源名
+ */
+ private static String getResourceDefaultValue(String parent, String name) {
+ if (name.startsWith("${")) {
+ String subName = name.substring(2);
+ int pos = subName.lastIndexOf('}');
+ if (pos > 0) {
+ subName = subName.substring(0, pos);
+ pos = subName.indexOf(':');
+ if (pos > 0) {
+ String val = subName.substring(pos + 1);
+ return "null".equals(val) ? null : val;
+ }
+ }
+ }
+ return null;
+ }
+
/**
* 将对象指定类型且name=""注入到资源池中,并同步已被注入的资源
*
@@ -520,6 +599,84 @@ public final class ResourceFactory {
}
}
+ /**
+ * 注册 ResourceAnnotationLoader
+ *
+ * @param 注解泛型
+ * @param loader ResourceAnnotationLoader
+ */
+ public void register(final ResourceAnnotationLoader loader) {
+ Objects.requireNonNull(loader);
+ parentRoot().resAnnotationLoaderMap.put(loader.annotationType(), loader);
+ }
+
+ /**
+ * 注册 ResourceTypeLoader
+ *
+ * @param loader ResourceTypeLoader
+ */
+ public void register(final ResourceTypeLoader loader) {
+ resTypeLoaderMap.put(loader.resourceType(), loader);
+ }
+
+ /**
+ * 注册 Configuration子类
+ *
+ * @param 泛型
+ * @param configuareClass Configuration的实现类
+ *
+ */
+ public void register(final Class configuareClass) {
+ Configuration instance = Creator.create(configuareClass).create();
+ for (Method method : configuareClass.getDeclaredMethods()) {
+ Resource res = method.getAnnotation(Resource.class);
+ if (res == null) {
+ continue;
+ }
+ Parameter[] params = method.getParameters();
+ Supplier[] paramSuppliers = new Supplier[params.length];
+ for (int i = 0; i < params.length; i++) {
+ Resource pres = params[i].getAnnotation(Resource.class);
+ String presName = pres == null ? "" : getResourceName(pres.name());
+ Type presType0 = params[i].getParameterizedType();
+ if (presType0 == null) {
+ presType0 = params[i].getType();
+ }
+ Type presType = presType0;
+ paramSuppliers[i] = () -> load(presName, presType);
+ }
+ String resName = getResourceName(res.name());
+ Type resType = method.getGenericReturnType();
+ method.setAccessible(true);
+ Supplier resSupplier = () -> {
+ Object[] args = new Object[paramSuppliers.length];
+ for (int i = 0; i < paramSuppliers.length; i++) {
+ args[i] = paramSuppliers[i].get();
+ }
+ try {
+ return method.invoke(instance, args);
+ } catch (Exception e) {
+ throw new RedkaleException(method + " invoke error", e);
+ }
+ };
+ RedkaleClassLoader.putReflectionMethod(configuareClass.getName(), method);
+ resConfigureSupplierMap
+ .computeIfAbsent(resType, k -> new ConcurrentHashMap<>())
+ .put(resName, resSupplier);
+ }
+ }
+
+ /**
+ * 将对象以指定资源名和类型注入到资源池中
+ *
+ * @param 泛型
+ * @param autoSync 是否同步已被注入的资源
+ * @param name 资源名
+ * @param clazz 资源类型
+ * @param val 资源对象
+ * @param wrappers 资源对象的缓存集合
+ * @return 旧资源对象
+ */
private A register(
final boolean autoSync,
final String name,
@@ -593,7 +750,8 @@ public final class ResourceFactory {
}
} while ((c = c.getSuperclass()) != Object.class);
}
- ConcurrentHashMap map = this.store.computeIfAbsent(clazz, k -> new ConcurrentHashMap());
+ ConcurrentHashMap map =
+ this.entryStore.computeIfAbsent(clazz, k -> new ConcurrentHashMap());
ResourceEntry re = map.get(name);
if (re == null) {
map.put(name, new ResourceEntry(name, val));
@@ -613,7 +771,7 @@ public final class ResourceFactory {
* @return 是否存在
*/
public boolean contains(boolean recursive, String name, Class extends A> clazz) {
- Map map = this.store.get(clazz);
+ Map map = this.entryStore.get(clazz);
if (map != null) {
return map.containsKey(name);
}
@@ -628,7 +786,7 @@ public final class ResourceFactory {
* @return ResourceFactory
*/
public ResourceFactory findResourceFactory(String name, Type clazz) {
- Map map = this.store.get(clazz);
+ Map map = this.entryStore.get(clazz);
if (map != null && map.containsKey(name)) {
return this;
}
@@ -638,6 +796,78 @@ public final class ResourceFactory {
return null;
}
+ /**
+ * 获取类型对应的ResourceTypeLoader
+ *
+ * @param clazz 类型
+ * @return ResourceTypeLoader
+ */
+ public ResourceTypeLoader findResourceTypeLoader(Type clazz) {
+ ResourceTypeLoader it = this.resTypeLoaderMap.get(clazz);
+ if (it != null) {
+ return it;
+ }
+ return parent == null ? null : parent.findResourceTypeLoader(clazz);
+ }
+
+ /**
+ * 获取类型对应的ResourceTypeLoader
+ * 优先匹配Type, 再匹配Class,再匹配父类
+ * @param ft 类型
+ * @param field 字段
+ * @return ResourceTypeLoader
+ */
+ public ResourceTypeLoader findResourceTypeLoader(Type ft, @Nullable Field field) {
+ ResourceTypeLoader it = this.findClassTypeLoader(ft, field);
+ if (it == null && field == null && !(ft instanceof Class)) {
+ return findClassTypeLoader(TypeToken.typeToClass(ft), field);
+ }
+ return it == null ? findSuperTypeLoader(ft, field) : it;
+ }
+
+ /**
+ * 获取类型对应的ResourceTypeLoader
+ * 优先匹配Type, 再匹配Class
+ * @param ft 类型
+ * @param field 字段
+ * @return ResourceTypeLoader
+ */
+ private ResourceTypeLoader findClassTypeLoader(Type ft, @Nullable Field field) {
+ ResourceTypeLoader it = this.resTypeLoaderMap.get(ft);
+ if (it == null && field != null) {
+ it = this.resTypeLoaderMap.get(field.getType());
+ }
+ if (it != null) {
+ return it;
+ }
+ return parent == null ? null : parent.findClassTypeLoader(ft, field);
+ }
+
+ /**
+ * 获取类型对应的ResourceTypeLoader
+ * 优先匹配Type,再匹配父类
+ *
+ * @param ft
+ * @param field
+ * @return
+ */
+ private ResourceTypeLoader findSuperTypeLoader(Type ft, @Nullable Field field) {
+ if (field == null) {
+ return null;
+ }
+ Class c = field.getType();
+ for (Map.Entry en : this.resTypeLoaderMap.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.findSuperTypeLoader(ft, field);
+ }
+
public A find(Class extends A> clazz) {
return find("", clazz);
}
@@ -657,7 +887,7 @@ public final class ResourceFactory {
if (rs != null) {
return rs;
}
- for (Map.Entry> en : this.store.entrySet()) {
+ for (Map.Entry> en : this.entryStore.entrySet()) {
if (!(en.getKey() instanceof Class)) {
continue;
}
@@ -672,8 +902,8 @@ public final class ResourceFactory {
return null;
}
- private ResourceEntry findEntry(String name, Type clazz) {
- Map map = this.store.get(clazz);
+ private ResourceEntry findEntry(String name, Type clazz) {
+ Map map = this.entryStore.get(clazz);
if (map != null) {
ResourceEntry re = map.get(name);
if (re != null) {
@@ -686,27 +916,44 @@ public final class ResourceFactory {
return null;
}
- public A load(Class extends A> clazz) {
+ /**
+ * 加载资源对象, 没有返回null
+ *
+ * @param 泛型
+ * @param clazz 资源类型
+ * @return 资源对象
+ *
+ * @since 2.8.0
+ */
+ public A load(Type clazz) {
return load("", clazz);
}
+ /**
+ * 加载资源对象, 没有返回null
+ *
+ * @param 泛型
+ * @param name 资源名
+ * @param clazz 资源类型
+ * @return 资源对象
+ *
+ * @since 2.8.0
+ */
public A load(String name, Type clazz) {
A val = find(name, clazz);
if (val == null) {
- ResourceTypeLoader loader = findResourceTypeLoader(clazz);
- if (loader != null) {
- val = (A) loader.load(this, null, null, name, null, null);
- }
- }
- return val;
- }
-
- public A load(String name, Class extends A> clazz) {
- A val = find(name, clazz);
- if (val == null) {
- ResourceTypeLoader loader = findResourceTypeLoader(clazz);
- if (loader != null) {
- val = (A) loader.load(this, null, null, name, null, null);
+ Map supplierMap = this.resConfigureSupplierMap.get(clazz);
+ Supplier supplier = supplierMap == null ? null : supplierMap.get(name);
+ if (supplier != null) {
+ val = (A) supplier.get();
+ if (val != null) {
+ inject(name, val);
+ }
+ } else {
+ ResourceTypeLoader loader = findResourceTypeLoader(clazz, (Field) null);
+ if (loader != null) {
+ val = (A) loader.load(this, null, null, name, null, null);
+ }
}
}
return val;
@@ -721,7 +968,7 @@ public final class ResourceFactory {
}
private List query(final List list, Type clazz) {
- Map map = this.store.get(clazz);
+ Map map = this.entryStore.get(clazz);
if (map != null) {
for (ResourceEntry re : map.values()) {
if (re.value != null) {
@@ -743,7 +990,7 @@ public final class ResourceFactory {
if (predicate == null) {
return list;
}
- for (ConcurrentHashMap map : this.store.values()) {
+ for (ConcurrentHashMap map : this.entryStore.values()) {
for (Map.Entry en : map.entrySet()) {
if (predicate.test(en.getKey(), en.getValue().value)) {
list.add((A) en.getValue().value);
@@ -756,48 +1003,98 @@ public final class ResourceFactory {
return list;
}
- private ResourceEntry findEntry(String name, Class extends A> clazz) {
- Map map = this.store.get(clazz);
- if (map != null) {
- ResourceEntry rs = map.get(name);
- if (rs != null) {
- return rs;
- }
- }
- if (parent != null) {
- return parent.findEntry(name, clazz);
- }
- return null;
- }
-
+ /**
+ * 注入资源对象
+ *
+ * @param srcObj 资源依附对象
+ * @return 是否成功注入
+ */
public boolean inject(final Object srcObj) {
return inject(srcObj, null);
}
+ /**
+ * 注入资源对象
+ *
+ * @param 泛型
+ * @param srcObj 资源依附对象
+ * @param attachment 附加对象
+ * @return 是否成功注入
+ */
public boolean inject(final Object srcObj, final T attachment) {
return inject(srcObj, attachment, null);
}
+ /**
+ * 注入资源对象
+ *
+ * @param srcObj 资源依附对象
+ * @param consumer 字段处理函数
+ * @return 是否成功注入
+ */
public boolean inject(final Object srcObj, final BiConsumer