增加Configuration功能
This commit is contained in:
@@ -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[]上 <br>
|
||||
* 注意: 一个类只能存在一个@ResourceChanged的方法, 多余的会被忽略 <br>
|
||||
@@ -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 {
|
||||
|
||||
/**
|
||||
* 新旧值是否不同时才回调方法 <br>
|
||||
* true: 新值与旧值不同时才回调ResourceChanged方法 false: 只要执行了ResourceFactory.register 就回调ResourceChanged方法
|
||||
* 新旧值是否不相同的情况下才回调方法 <br>
|
||||
* true: 新值与旧值不相同才回调ResourceChanged方法 <br>
|
||||
* false: 只要执行了ResourceFactory.register 就回调ResourceChanged方法
|
||||
*
|
||||
* @since 2.7.0
|
||||
* @return boolean
|
||||
|
||||
@@ -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资源被依赖注入时的监听事件。<br>
|
||||
* 本注解只能标记在空参数或者(String、Object、java.lang.reflect.Field)三个参数类型的任意组合方法上 <br>
|
||||
@@ -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 + ")上");
|
||||
* }
|
||||
* }
|
||||
*
|
||||
|
||||
@@ -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<Configuration> 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();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
15
src/main/java/org/redkale/inject/Configuration.java
Normal file
15
src/main/java/org/redkale/inject/Configuration.java
Normal file
@@ -0,0 +1,15 @@
|
||||
/*
|
||||
|
||||
*/
|
||||
|
||||
package org.redkale.inject;
|
||||
|
||||
/**
|
||||
* 启动服务时的初始化配置,需要结合{@link org.redkale.annotation.Resource}使用
|
||||
* <p>
|
||||
* 详情见: https://redkale.org
|
||||
*
|
||||
* @author zhangjx
|
||||
* @since 2.8.0
|
||||
*/
|
||||
public interface Configuration {}
|
||||
@@ -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<WeakReference<ResourceFactory>> chidren = new CopyOnWriteArrayList<>();
|
||||
|
||||
private final ConcurrentHashMap<Type, ResourceTypeLoader> resTypeLoaderMap = new ConcurrentHashMap();
|
||||
|
||||
private final ConcurrentHashMap<Class<? extends Annotation>, ResourceAnnotationLoader> resAnnotationLoaderMap =
|
||||
new ConcurrentHashMap();
|
||||
|
||||
private final ConcurrentHashMap<Type, ResourceTypeLoader> resTypeLoaderMap = new ConcurrentHashMap();
|
||||
private final ConcurrentHashMap<Type, ConcurrentHashMap<String, Supplier>> resConfigureSupplierMap =
|
||||
new ConcurrentHashMap();
|
||||
|
||||
private final ConcurrentHashMap<Type, ConcurrentHashMap<String, ResourceEntry>> store = new ConcurrentHashMap();
|
||||
private final ConcurrentHashMap<Type, ConcurrentHashMap<String, ResourceEntry>> 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 <T> 注解泛型
|
||||
* @param loader ResourceAnnotationLoader
|
||||
*/
|
||||
public <T extends Annotation> void register(final ResourceAnnotationLoader<T> 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 <T> 泛型
|
||||
* @param configuareClass Configuration的实现类
|
||||
*
|
||||
*/
|
||||
public <T extends Configuration> void register(final Class<T> 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 <A> 泛型
|
||||
* @param autoSync 是否同步已被注入的资源
|
||||
* @param name 资源名
|
||||
* @param clazz 资源类型
|
||||
* @param val 资源对象
|
||||
* @param wrappers 资源对象的缓存集合
|
||||
* @return 旧资源对象
|
||||
*/
|
||||
private <A> A register(
|
||||
final boolean autoSync,
|
||||
final String name,
|
||||
@@ -593,7 +750,8 @@ public final class ResourceFactory {
|
||||
}
|
||||
} while ((c = c.getSuperclass()) != Object.class);
|
||||
}
|
||||
ConcurrentHashMap<String, ResourceEntry> map = this.store.computeIfAbsent(clazz, k -> new ConcurrentHashMap());
|
||||
ConcurrentHashMap<String, ResourceEntry> 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 <A> boolean contains(boolean recursive, String name, Class<? extends A> clazz) {
|
||||
Map<String, ResourceEntry> map = this.store.get(clazz);
|
||||
Map<String, ResourceEntry> 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<String, ResourceEntry> map = this.store.get(clazz);
|
||||
Map<String, ResourceEntry> map = this.entryStore.get(clazz);
|
||||
if (map != null && map.containsKey(name)) {
|
||||
return this;
|
||||
}
|
||||
@@ -638,6 +796,78 @@ public final class ResourceFactory {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取类型对应的ResourceTypeLoader <br>
|
||||
*
|
||||
* @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 <br>
|
||||
* 优先匹配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 <br>
|
||||
* 优先匹配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 <br>
|
||||
* 优先匹配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<Type, ResourceTypeLoader> 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> 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<Type, ConcurrentHashMap<String, ResourceEntry>> en : this.store.entrySet()) {
|
||||
for (Map.Entry<Type, ConcurrentHashMap<String, ResourceEntry>> 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<String, ResourceEntry> map = this.store.get(clazz);
|
||||
private <A> ResourceEntry<A> findEntry(String name, Type clazz) {
|
||||
Map<String, ResourceEntry> 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> A load(Class<? extends A> clazz) {
|
||||
/**
|
||||
* 加载资源对象, 没有返回null
|
||||
*
|
||||
* @param <A> 泛型
|
||||
* @param clazz 资源类型
|
||||
* @return 资源对象
|
||||
*
|
||||
* @since 2.8.0
|
||||
*/
|
||||
public <A> A load(Type clazz) {
|
||||
return load("", clazz);
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载资源对象, 没有返回null
|
||||
*
|
||||
* @param <A> 泛型
|
||||
* @param name 资源名
|
||||
* @param clazz 资源类型
|
||||
* @return 资源对象
|
||||
*
|
||||
* @since 2.8.0
|
||||
*/
|
||||
public <A> 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> 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<String, Supplier> 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 <A> List<A> query(final List<A> list, Type clazz) {
|
||||
Map<String, ResourceEntry> map = this.store.get(clazz);
|
||||
Map<String, ResourceEntry> 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<String, ResourceEntry> map : this.store.values()) {
|
||||
for (ConcurrentHashMap<String, ResourceEntry> map : this.entryStore.values()) {
|
||||
for (Map.Entry<String, ResourceEntry> 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 <A> ResourceEntry<A> findEntry(String name, Class<? extends A> clazz) {
|
||||
Map<String, ResourceEntry> 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 <T> 泛型
|
||||
* @param srcObj 资源依附对象
|
||||
* @param attachment 附加对象
|
||||
* @return 是否成功注入
|
||||
*/
|
||||
public <T> 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<Object, Field> consumer) {
|
||||
return inject(srcObj, null, consumer);
|
||||
}
|
||||
|
||||
/**
|
||||
* 注入资源对象
|
||||
*
|
||||
* @param <T> 泛型
|
||||
* @param srcObj 资源依附对象
|
||||
* @param attachment 附加对象
|
||||
* @param consumer 字段处理函数
|
||||
* @return 是否成功注入
|
||||
*/
|
||||
public <T> boolean inject(final Object srcObj, final T attachment, final BiConsumer<Object, Field> consumer) {
|
||||
return inject(null, srcObj, attachment, consumer, new ArrayList());
|
||||
}
|
||||
|
||||
/**
|
||||
* 注入资源对象
|
||||
*
|
||||
* @param srcResourceName 资源名
|
||||
* @param srcObj 资源依附对象
|
||||
* @return 是否成功注入
|
||||
*/
|
||||
public boolean inject(final String srcResourceName, final Object srcObj) {
|
||||
return inject(srcResourceName, srcObj, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 注入资源对象
|
||||
*
|
||||
* @param <T> 泛型
|
||||
* @param srcResourceName 资源名
|
||||
* @param srcObj 资源依附对象
|
||||
* @param attachment 附加对象
|
||||
* @return 是否成功注入
|
||||
*/
|
||||
public <T> boolean inject(final String srcResourceName, final Object srcObj, final T attachment) {
|
||||
return inject(srcResourceName, srcObj, attachment, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 注入资源对象
|
||||
*
|
||||
* @param srcResourceName 资源名
|
||||
* @param srcObj 资源依附对象
|
||||
* @param consumer 字段处理函数
|
||||
* @return 是否成功注入
|
||||
*/
|
||||
public boolean inject(final String srcResourceName, final Object srcObj, final BiConsumer<Object, Field> consumer) {
|
||||
return inject(srcResourceName, srcObj, null, consumer);
|
||||
}
|
||||
|
||||
/**
|
||||
* 注入资源对象
|
||||
*
|
||||
* @param <T> 泛型
|
||||
* @param srcResourceName 资源名
|
||||
* @param srcObj 资源依附对象
|
||||
* @param attachment 附加对象
|
||||
* @param consumer 字段处理函数
|
||||
* @return 是否成功注入
|
||||
*/
|
||||
public <T> boolean inject(
|
||||
final String srcResourceName,
|
||||
final Object srcObj,
|
||||
@@ -806,61 +1103,17 @@ public final class ResourceFactory {
|
||||
return inject(srcResourceName, srcObj, attachment, consumer, new ArrayList());
|
||||
}
|
||||
|
||||
public static String getResourceName(String name) {
|
||||
return getResourceName(null, name);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 注入资源对象
|
||||
*
|
||||
* @param <T> 泛型
|
||||
* @param srcResourceName 资源名
|
||||
* @param srcObj 资源依附对象
|
||||
* @param attachment 附加对象
|
||||
* @param consumer 字段处理函数
|
||||
* @param list 层级对象集合
|
||||
* @return 是否成功注入
|
||||
*/
|
||||
private <T> boolean inject(
|
||||
String srcResourceName,
|
||||
Object srcObj,
|
||||
@@ -1017,17 +1270,19 @@ public final class ResourceFactory {
|
||||
&& rcname.startsWith("property.")) { // 兼容2.8.0之前版本自动追加property.开头的配置项
|
||||
re = findEntry(rcname.substring("property.".length()), String.class);
|
||||
} else {
|
||||
re = findEntry(rcname, classType);
|
||||
rs = findEntry(rcname, classType);
|
||||
}
|
||||
}
|
||||
if (re == null) {
|
||||
ResourceTypeLoader it = findTypeLoader(gencType, field);
|
||||
ResourceTypeLoader it = findResourceTypeLoader(gencType, field);
|
||||
if (it != null) {
|
||||
rs = it.load(this, srcResourceName, srcObj, rcname, field, attachment);
|
||||
autoRegNull = it.autoNone();
|
||||
if (rs == null) {
|
||||
re = findEntry(rcname, gencType);
|
||||
}
|
||||
} else {
|
||||
rs = load(rcname, gencType);
|
||||
}
|
||||
}
|
||||
if (rs == null && re == null && gencType != classType) {
|
||||
@@ -1049,17 +1304,19 @@ public final class ResourceFactory {
|
||||
}
|
||||
}
|
||||
if (re == null) {
|
||||
ResourceTypeLoader it = findTypeLoader(classType, field);
|
||||
ResourceTypeLoader it = findResourceTypeLoader(classType, field);
|
||||
if (it != null) {
|
||||
rs = it.load(this, srcResourceName, srcObj, rcname, field, attachment);
|
||||
autoRegNull = it.autoNone();
|
||||
if (rs == null) {
|
||||
re = findEntry(rcname, classType);
|
||||
}
|
||||
} else {
|
||||
re = load(rcname, gencType);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (rs == null && re == null && autoRegNull && rcname.indexOf(Resource.PARENT_NAME) < 0) {
|
||||
if (rs == null && re == null && autoRegNull && !rcname.contains(Resource.PARENT_NAME)) {
|
||||
if (rcname.startsWith("${")) {
|
||||
String sub = rcname.substring(rcname.lastIndexOf("${") + 2, rcname.lastIndexOf('}'));
|
||||
register(sub, gencType, null); // 自动注入null的值
|
||||
@@ -1106,28 +1363,11 @@ public final class ResourceFactory {
|
||||
}
|
||||
}
|
||||
|
||||
public <T extends Annotation> void register(final ResourceAnnotationLoader<T> loader) {
|
||||
Objects.requireNonNull(loader);
|
||||
parentRoot().resAnnotationLoaderMap.put(loader.annotationType(), loader);
|
||||
}
|
||||
|
||||
public void register(final ResourceTypeLoader rs) {
|
||||
resTypeLoaderMap.put(rs.resourceType(), rs);
|
||||
}
|
||||
|
||||
public ResourceTypeLoader findResourceTypeLoader(Type clazz) {
|
||||
ResourceTypeLoader it = this.resTypeLoaderMap.get(clazz);
|
||||
if (it != null) {
|
||||
return it;
|
||||
}
|
||||
return parent == null ? null : parent.findResourceTypeLoader(clazz);
|
||||
}
|
||||
|
||||
public ResourceTypeLoader findTypeLoader(Type ft, @Nullable Field field) {
|
||||
ResourceTypeLoader it = this.findMatchTypeLoader(ft, field);
|
||||
return it == null ? findRegexTypeLoader(ft, field) : it;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取最底层ResourceFactory
|
||||
*
|
||||
* @return ResourceFactory
|
||||
*/
|
||||
private ResourceFactory parentRoot() {
|
||||
if (parent == null) {
|
||||
return this;
|
||||
@@ -1135,35 +1375,14 @@ public final class ResourceFactory {
|
||||
return parent.parentRoot();
|
||||
}
|
||||
|
||||
private ResourceTypeLoader findMatchTypeLoader(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.findMatchTypeLoader(ft, field);
|
||||
}
|
||||
|
||||
private ResourceTypeLoader findRegexTypeLoader(Type ft, @Nullable Field field) {
|
||||
if (field == null) {
|
||||
return null;
|
||||
}
|
||||
Class c = field.getType();
|
||||
for (Map.Entry<Type, ResourceTypeLoader> 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.findRegexTypeLoader(ft, field);
|
||||
}
|
||||
|
||||
private void onResourceInjected(Object src, Field field, Object res) {
|
||||
/**
|
||||
* 调用标记ResourceInjected的监听方法
|
||||
*
|
||||
* @param dest 资源的依附对象
|
||||
* @param field 资源的依附对象的字段
|
||||
* @param res 资源对象
|
||||
*/
|
||||
private void onResourceInjected(Object dest, Field field, Object res) {
|
||||
if (res == null
|
||||
|| res.getClass().isPrimitive()
|
||||
|| res.getClass().getName().startsWith("java.")
|
||||
@@ -1179,7 +1398,7 @@ public final class ResourceFactory {
|
||||
Object[] params = new Object[paramTypes.length];
|
||||
for (int i = 0; i < params.length; i++) {
|
||||
if (paramTypes[i] == Object.class) {
|
||||
params[i] = src;
|
||||
params[i] = dest;
|
||||
} else if (paramTypes[i] == String.class) {
|
||||
params[i] = field.getName();
|
||||
} else if (paramTypes[i] == Field.class) {
|
||||
@@ -1200,6 +1419,11 @@ public final class ResourceFactory {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 资源依附信息的缓存对象
|
||||
*
|
||||
* @param <T> 泛型
|
||||
*/
|
||||
private static class ResourceEntry<T> {
|
||||
|
||||
public final String name;
|
||||
@@ -1267,6 +1491,11 @@ public final class ResourceFactory {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 资源字段和变更监听方法信息的缓存对象
|
||||
*
|
||||
* @param <T> 泛型
|
||||
*/
|
||||
private static class ResourceElement<T> {
|
||||
|
||||
private static final ReentrantLock syncLock = new ReentrantLock();
|
||||
|
||||
78
src/test/java/org/redkale/test/inject/ConfigurationTest.java
Normal file
78
src/test/java/org/redkale/test/inject/ConfigurationTest.java
Normal file
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
|
||||
*/
|
||||
package org.redkale.test.inject;
|
||||
|
||||
import org.junit.jupiter.api.*;
|
||||
import org.redkale.annotation.Resource;
|
||||
import org.redkale.convert.json.JsonFactory;
|
||||
import org.redkale.inject.Configuration;
|
||||
import org.redkale.inject.ResourceFactory;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author zhangjx
|
||||
*/
|
||||
public class ConfigurationTest {
|
||||
|
||||
public static void main(String[] args) throws Throwable {
|
||||
ConfigurationTest test = new ConfigurationTest();
|
||||
test.run();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void run() throws Exception {
|
||||
ResourceFactory factory = ResourceFactory.create();
|
||||
factory.register("a.id", 1234);
|
||||
factory.register("a.name", "my a name");
|
||||
factory.register("b.id", 4321);
|
||||
factory.register("b.name", "my b name");
|
||||
factory.register(DiyConfiguration.class);
|
||||
|
||||
BeanB pb = new BeanB();
|
||||
factory.inject(pb);
|
||||
Assertions.assertEquals(new BeanA(1234, "my a name", "auto").toString(), pb.bean.toString());
|
||||
System.out.println(pb.bean);
|
||||
}
|
||||
|
||||
public static class DiyConfiguration implements Configuration {
|
||||
|
||||
@Resource(name = "a")
|
||||
BeanA createBeanA() {
|
||||
System.out.println("创建一个Bean");
|
||||
BeanA bean = new BeanA();
|
||||
bean.desc = "auto";
|
||||
return bean;
|
||||
}
|
||||
}
|
||||
|
||||
public static class BeanB {
|
||||
|
||||
@Resource(name = "a")
|
||||
public BeanA bean;
|
||||
}
|
||||
|
||||
public static class BeanA {
|
||||
|
||||
@Resource(name = "@.id")
|
||||
public int id;
|
||||
|
||||
@Resource(name = "@.name")
|
||||
public String name;
|
||||
|
||||
public String desc;
|
||||
|
||||
public BeanA() {}
|
||||
|
||||
public BeanA(int id, String name, String desc) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.desc = desc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return JsonFactory.root().getConvert().convertTo(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user