list = new ArrayList<>();
- list.add(this.envProperties);
- list.addAll(Arrays.asList(envs));
- for (Properties prop : list) {
- if (prop.containsKey(key)) {
- newVal = getPropertyValue(prop.getProperty(key), envs);
- break;
- }
- }
- if (newVal == null) {
- newVal = this.resourceFactory.find(key, String.class);
- }
- }
- if (newVal == null) {
- throw new RedkaleException("Not found '" + key + "' value");
- }
- return getPropertyValue(val.substring(0, pos1) + newVal + val.substring(pos2 + 1), envs);
- } else if ((pos1 >= 0 && pos2 < 0) || (pos1 < 0 && pos2 >= 0)) {
- throw new RedkaleException(value + " is illegal naming");
- }
- return val;
- }
-
private static String generateHelp() {
return ""
+ "Usage: redkale [command] [arguments]\r\n"
@@ -1616,11 +1350,7 @@ public final class Application {
long f = System.currentTimeMillis();
this.onAppPreShutdown();
stopServers();
- if (this.propertiesAgent != null) {
- long s = System.currentTimeMillis();
- this.propertiesAgent.destroy(config.getAnyValue("properties"));
- logger.info(this.propertiesAgent.getClass().getSimpleName() + " destroy in " + (System.currentTimeMillis() - s) + " ms");
- }
+ this.propertiesModule.destroy();
if (this.workExecutor != null) {
this.workExecutor.shutdownNow();
}
@@ -1699,8 +1429,8 @@ public final class Application {
return home;
}
- public URI getConfPath() {
- return confPath;
+ public URI getConfDir() {
+ return confDir;
}
public long getStartTime() {
diff --git a/src/main/java/org/redkale/boot/ApplicationListener.java b/src/main/java/org/redkale/boot/ApplicationListener.java
index 8148f5495..c31a09c8c 100644
--- a/src/main/java/org/redkale/boot/ApplicationListener.java
+++ b/src/main/java/org/redkale/boot/ApplicationListener.java
@@ -28,42 +28,58 @@ public interface ApplicationListener {
}
/**
- * Application 在运行start前调用
+ * Application在运行start前调用
*
* @param application Application
*/
- default void preStart(Application application) {
+ default void onPreStart(Application application) {
}
/**
- * Application 在运行start后调用
+ * 服务全部停掉前被调用
*
* @param application Application
*/
- default void postStart(Application application) {
+ default void onServersPreStop(Application application) {
}
/**
- * Application 在运行Compile前调用
+ * 服务全部停掉后被调用
*
* @param application Application
*/
- default void preCompile(Application application) {
+ default void onServersPostStop(Application application) {
}
/**
- * Application 在运行Compile后调用
+ * Application在运行start后调用
*
* @param application Application
*/
- default void postCompile(Application application) {
+ default void onPostStart(Application application) {
}
/**
- * Application 在运行shutdown前调用
+ * Application在运行Compile前调用
*
* @param application Application
*/
- default void preShutdown(Application application) {
+ default void onPreCompile(Application application) {
+ }
+
+ /**
+ * Application在运行Compile后调用
+ *
+ * @param application Application
+ */
+ default void onPostCompile(Application application) {
+ }
+
+ /**
+ * Application在运行shutdown前调用
+ *
+ * @param application Application
+ */
+ default void onPreShutdown(Application application) {
}
}
diff --git a/src/main/java/org/redkale/boot/LoggingModule.java b/src/main/java/org/redkale/boot/LoggingModule.java
new file mode 100644
index 000000000..cd2b09497
--- /dev/null
+++ b/src/main/java/org/redkale/boot/LoggingModule.java
@@ -0,0 +1,180 @@
+/*
+ *
+ */
+package org.redkale.boot;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import java.util.logging.Handler;
+import java.util.logging.LogManager;
+import java.util.logging.SimpleFormatter;
+import org.redkale.net.sncp.SncpClient;
+import org.redkale.util.Environment;
+import org.redkale.util.ResourceEvent;
+
+/**
+ *
+ * 日志模块组件
+ *
+ *
+ * 详情见: https://redkale.org
+ *
+ * @author zhangjx
+ *
+ * @since 2.8.0
+ */
+class LoggingModule {
+
+ private final Application application;
+
+ //日志配置资源
+ private final Properties loggingProperties = new Properties();
+
+ LoggingModule(Application application) {
+ this.application = application;
+ }
+
+ /**
+ * 配置变更
+ *
+ * @param events 变更项
+ */
+ public void onEnvironmentUpdated(List events) {
+ Set loggingRemovedKeys = new HashSet<>();
+ Properties loggingChangedProps = new Properties();
+ for (ResourceEvent event : events) {
+ if (event.newValue() == null) {
+ if (loggingProperties.containsKey(event.name())) {
+ loggingRemovedKeys.add(event.name());
+ }
+ } else {
+ loggingChangedProps.put(event.name(), event.newValue());
+ }
+ }
+ if (!loggingRemovedKeys.isEmpty() || !loggingChangedProps.isEmpty()) {
+ Properties newProps = new Properties(this.loggingProperties);
+ loggingRemovedKeys.forEach(newProps::remove);
+ newProps.putAll(loggingChangedProps);
+ reconfigLogging(false, newProps);
+ }
+ }
+
+ /**
+ * 设置日志策略
+ *
+ * @param first 是否首次设置
+ * @param allProps 配置项全量
+ */
+ public void reconfigLogging(boolean first, Properties allProps) {
+ String searchRawHandler = "java.util.logging.SearchHandler";
+ String searchReadHandler = LoggingSearchHandler.class.getName();
+ Properties onlyLogProps = new Properties();
+ Environment environment = application.getEnvironment();
+ allProps.entrySet().forEach(x -> {
+ String key = x.getKey().toString();
+ if (key.startsWith("java.util.logging.") || key.contains(".level") || key.equals("handlers")) {
+ String val = environment.getPropertyValue(x.getValue().toString()
+ .replace("%m", "%tY%tm").replace("%d", "%tY%tm%td") //兼容旧时间格式
+ .replace(searchRawHandler, searchReadHandler));
+ onlyLogProps.put(key.replace(searchRawHandler, searchReadHandler), val);
+ }
+ });
+ if (onlyLogProps.getProperty("java.util.logging.FileHandler.formatter") == null) {
+ if (application.isCompileMode()) {
+ onlyLogProps.setProperty("java.util.logging.FileHandler.formatter", SimpleFormatter.class.getName());
+ if (onlyLogProps.getProperty("java.util.logging.SimpleFormatter.format") == null) {
+ onlyLogProps.setProperty("java.util.logging.SimpleFormatter.format", LoggingFileHandler.FORMATTER_FORMAT.replaceAll("\r\n", "%n"));
+ }
+ } else {
+ onlyLogProps.setProperty("java.util.logging.FileHandler.formatter", LoggingFileHandler.LoggingFormater.class.getName());
+ }
+ }
+ if (onlyLogProps.getProperty("java.util.logging.ConsoleHandler.formatter") == null) {
+ if (application.isCompileMode()) {
+ onlyLogProps.setProperty("java.util.logging.ConsoleHandler.formatter", SimpleFormatter.class.getName());
+ if (onlyLogProps.getProperty("java.util.logging.SimpleFormatter.format") == null) {
+ onlyLogProps.setProperty("java.util.logging.SimpleFormatter.format", LoggingFileHandler.FORMATTER_FORMAT.replaceAll("\r\n", "%n"));
+ }
+ } else {
+ onlyLogProps.setProperty("java.util.logging.ConsoleHandler.formatter", LoggingFileHandler.LoggingFormater.class.getName());
+ }
+ }
+ if (!application.isCompileMode()) { //ConsoleHandler替换成LoggingConsoleHandler
+ final String handlers = onlyLogProps.getProperty("handlers");
+ if (handlers != null && handlers.contains("java.util.logging.ConsoleHandler")) {
+ final String consoleHandlerClass = LoggingFileHandler.LoggingConsoleHandler.class.getName();
+ onlyLogProps.setProperty("handlers", handlers.replace("java.util.logging.ConsoleHandler", consoleHandlerClass));
+ Properties prop = new Properties();
+ String prefix = consoleHandlerClass + ".";
+ onlyLogProps.entrySet().forEach(x -> {
+ if (x.getKey().toString().startsWith("java.util.logging.ConsoleHandler.")) {
+ prop.put(x.getKey().toString().replace("java.util.logging.ConsoleHandler.", prefix), x.getValue());
+ }
+ });
+ prop.entrySet().forEach(x -> {
+ onlyLogProps.put(x.getKey(), x.getValue());
+ });
+ }
+ }
+ String fileHandlerPattern = onlyLogProps.getProperty("java.util.logging.FileHandler.pattern");
+ if (fileHandlerPattern != null && fileHandlerPattern.contains("%")) { //带日期格式
+ final String fileHandlerClass = LoggingFileHandler.class.getName();
+ Properties prop = new Properties();
+ final String handlers = onlyLogProps.getProperty("handlers");
+ if (handlers != null && handlers.contains("java.util.logging.FileHandler")) {
+ //singletonrun模式下不输出文件日志
+ prop.setProperty("handlers", handlers.replace("java.util.logging.FileHandler",
+ application.isSingletonMode() || application.isCompileMode() ? "" : fileHandlerClass));
+ }
+ if (!prop.isEmpty()) {
+ String prefix = fileHandlerClass + ".";
+ onlyLogProps.entrySet().forEach(x -> {
+ if (x.getKey().toString().startsWith("java.util.logging.FileHandler.")) {
+ prop.put(x.getKey().toString().replace("java.util.logging.FileHandler.", prefix), x.getValue());
+ }
+ });
+ prop.entrySet().forEach(x -> onlyLogProps.put(x.getKey(), x.getValue()));
+ }
+ if (!application.isCompileMode()) {
+ onlyLogProps.put(SncpClient.class.getSimpleName() + ".handlers", LoggingFileHandler.LoggingSncpFileHandler.class.getName());
+ }
+ }
+ if (application.isCompileMode()) {
+ onlyLogProps.put("handlers", "java.util.logging.ConsoleHandler");
+ Map newprop = new HashMap(onlyLogProps);
+ newprop.forEach((k, v) -> {
+ if (k.toString().startsWith("java.util.logging.FileHandler.")) {
+ onlyLogProps.remove(k);
+ }
+ });
+ }
+
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ final PrintStream ps = new PrintStream(out);
+ onlyLogProps.forEach((x, y) -> ps.println(x + "=" + y));
+ try {
+ LogManager manager = LogManager.getLogManager();
+ manager.readConfiguration(new ByteArrayInputStream(out.toByteArray()));
+ this.loggingProperties.clear();
+ this.loggingProperties.putAll(onlyLogProps);
+ Enumeration en = manager.getLoggerNames();
+ while (en.hasMoreElements()) {
+ for (Handler handler : manager.getLogger(en.nextElement()).getHandlers()) {
+ if (handler instanceof LoggingSearchHandler) {
+ ((LoggingSearchHandler) handler).application = application;
+ }
+ }
+ }
+ } catch (IOException e) { //不会发生
+ }
+ }
+}
diff --git a/src/main/java/org/redkale/boot/LoggingSearchHandler.java b/src/main/java/org/redkale/boot/LoggingSearchHandler.java
index ec72f0898..91ca4ee3f 100644
--- a/src/main/java/org/redkale/boot/LoggingSearchHandler.java
+++ b/src/main/java/org/redkale/boot/LoggingSearchHandler.java
@@ -10,6 +10,7 @@ import java.util.logging.*;
import java.util.logging.Formatter;
import java.util.regex.Pattern;
import static org.redkale.boot.Application.RESNAME_APP_NAME;
+import static org.redkale.boot.Application.SYSNAME_APP_NAME;
import org.redkale.convert.*;
import org.redkale.convert.json.JsonConvert;
import org.redkale.persistence.*;
@@ -160,7 +161,7 @@ public class LoggingSearchHandler extends LoggingBaseHandler {
if (!checkTagName(tagStr.replaceAll("\\$\\{.+\\}", ""))) {
throw new RedkaleException("found illegal logging.property " + cname + ".tag = " + tagStr);
}
- this.tag = tagStr.replace("${" + RESNAME_APP_NAME + "}", System.getProperty("redkale.application.name", ""));
+ this.tag = tagStr.replace("${" + RESNAME_APP_NAME + "}", System.getProperty(SYSNAME_APP_NAME, ""));
if (this.tag.contains("%")) {
this.tagDateFormat = this.tag;
Times.formatTime(this.tagDateFormat, -1, System.currentTimeMillis()); //测试时间格式是否正确
diff --git a/src/main/java/org/redkale/boot/ModuleEngine.java b/src/main/java/org/redkale/boot/ModuleEngine.java
index 324889eb9..4399aa81c 100644
--- a/src/main/java/org/redkale/boot/ModuleEngine.java
+++ b/src/main/java/org/redkale/boot/ModuleEngine.java
@@ -7,6 +7,7 @@ import java.util.List;
import java.util.Properties;
import java.util.logging.Logger;
import org.redkale.service.Service;
+import org.redkale.util.AnyValue;
import org.redkale.util.Environment;
import org.redkale.util.ResourceEvent;
import org.redkale.util.ResourceFactory;
@@ -38,6 +39,20 @@ public abstract class ModuleEngine {
this.environment = application.getEnvironment();
}
+ /**
+ * 判断模块的配置项合并策略, 返回null表示模块不识别此配置项
+ *
+ * @param path 配置项路径
+ * @param key 配置项名称
+ * @param val1 配置项原值
+ * @param val2 配置项新值
+ *
+ * @return MergeEnum
+ */
+ public AnyValue.MergeEnum mergeAppConfigStrategy(String path, String key, AnyValue val1, AnyValue val2) {
+ return null;
+ }
+
/**
* 进入Application.init方法时被调用
* 此时状态:
@@ -88,6 +103,22 @@ public abstract class ModuleEngine {
//do nothing
}
+ /**
+ * Application 在运行Compile前调用
+ *
+ */
+ public void onPreCompile() {
+ //do nothing
+ }
+
+ /**
+ * Application 在运行Compile后调用
+ *
+ */
+ public void onPostCompile() {
+ //do nothing
+ }
+
/**
* 服务全部启动前被调用
*/
diff --git a/src/main/java/org/redkale/boot/NodeServer.java b/src/main/java/org/redkale/boot/NodeServer.java
index e18319a37..7dea90d69 100644
--- a/src/main/java/org/redkale/boot/NodeServer.java
+++ b/src/main/java/org/redkale/boot/NodeServer.java
@@ -174,7 +174,7 @@ public abstract class NodeServer {
this.sncpAddress, new ClientAddress(this.sncpAddress), server.getNetprotocol(), Utility.cpus(), 1000);
}
- initResource(); //给DataSource、CacheSource注册依赖注入时的监听回调事件。
+ registerResTypeLoader(); //给DataSource、CacheSource注册依赖注入时的监听回调事件。
String interceptorClass = this.serverConf.getValue("interceptor", "");
if (!interceptorClass.isEmpty()) {
Class clazz = serverClassLoader.loadClass(interceptorClass);
@@ -238,155 +238,12 @@ public abstract class NodeServer {
protected abstract void loadServlet(ClassFilter extends Servlet> servletFilter) throws Exception;
- private void initResource() {
+ private void registerResTypeLoader() {
+ //--------------------- 注册 Local AutoLoad(false) Service ---------------------
+ resourceFactory.register(this::loadService, Service.class);
+ //----------------------------- 注册 WebSocketNode -----------------------------
final NodeServer self = this;
- //---------------------------------------------------------------------------------------------
final ResourceFactory appResFactory = application.getResourceFactory();
- //------------------------------------- 注册 Resource --------------------------------------------------------
-// resourceFactory.register((ResourceFactory rf, String srcResourceName, final Object srcObj, String resourceName, Field field, final Object attachment) -> {
-// try {
-// String resName = null;
-// Resource res = field.getAnnotation(Resource.class);
-// if (res != null) {
-// resName = res.name();
-// } else {
-// javax.annotation.Resource res2 = field.getAnnotation(javax.annotation.Resource.class);
-// if (res2 != null) {
-// resName = res2.name();
-// }
-// }
-// if (resName == null || !resName.startsWith("properties.")) {
-// return null;
-// }
-// if ((srcObj instanceof Service) && Sncp.isRemote((Service) srcObj)) {
-// return null; //远程模式不得注入 DataSource
-// }
-// Class type = field.getType();
-// if (type != AnyValue.class && type != AnyValue[].class) {
-// return null;
-// }
-// Object resource = null;
-// final AnyValue properties = application.getAppConfig().getAnyValue("properties");
-// if (properties != null && type == AnyValue.class) {
-// resource = properties.getAnyValue(resName.substring("properties.".length()));
-// appResFactory.register(resourceName, AnyValue.class, resource);
-// } else if (properties != null && type == AnyValue[].class) {
-// resource = properties.getAnyValues(resName.substring("properties.".length()));
-// appResFactory.register(resourceName, AnyValue[].class, resource);
-// }
-// field.set(srcObj, resource);
-// return resource;
-// } catch (Exception e) {
-// logger.log(Level.SEVERE, "Resource inject error", e);
-// return null;
-// }
-// }, AnyValue.class, AnyValue[].class);
-
- //------------------------------------- 注册 Local AutoLoad(false) Service --------------------------------------------------------
- resourceFactory.register((ResourceFactory rf, String srcResourceName, final Object srcObj, String resourceName, Field field, final Object attachment) -> {
- Class resServiceType = Service.class;
- try {
- if (field.getAnnotation(Resource.class) == null && field.getAnnotation(javax.annotation.Resource.class) == null) {
- return null;
- }
- if ((srcObj instanceof Service) && Sncp.isRemote((Service) srcObj)) {
- return null; //远程模式不得注入 AutoLoad Service
- }
- if (!Service.class.isAssignableFrom(field.getType())) {
- return null;
- }
- resServiceType = (Class) field.getType();
- if (resServiceType.getAnnotation(Local.class) == null) {
- return null;
- }
- boolean auto = true;
- AutoLoad al = resServiceType.getAnnotation(AutoLoad.class);
- if (al != null) {
- auto = al.value();
- }
- org.redkale.util.AutoLoad al2 = resServiceType.getAnnotation(org.redkale.util.AutoLoad.class);
- if (al2 != null) {
- auto = al2.value();
- }
- if (auto) {
- return null;
- }
-
- //ResourceFactory resfactory = (isSNCP() ? appResFactory : resourceFactory);
- Service service = Modifier.isFinal(resServiceType.getModifiers()) || Sncp.isComponent(resServiceType)
- ? (Service) resServiceType.getConstructor().newInstance()
- : Sncp.createLocalService(serverClassLoader, resourceName, resServiceType,
- appResFactory, application.getSncpRpcGroups(), sncpClient, null, null, null);
- appResFactory.register(resourceName, resServiceType, service);
-
- field.set(srcObj, service);
- rf.inject(resourceName, service, self); // 给其可能包含@Resource的字段赋值;
- if (!application.isCompileMode()) {
- service.init(null);
- }
- logger.info("Load Service(@Local @AutoLoad service = " + resServiceType.getSimpleName() + ", resourceName = '" + resourceName + "')");
- return service;
- } catch (Exception e) {
- logger.log(Level.SEVERE, "Load @Local @AutoLoad(false) Service inject " + resServiceType + " to " + srcObj + " error", e);
- return null;
- }
- }, Service.class);
-//
-// //------------------------------------- 注册 DataSource --------------------------------------------------------
-// resourceFactory.register((ResourceFactory rf, String srcResourceName, final Object srcObj, String resourceName, Field field, final Object attachment) -> {
-// try {
-// if (field.getAnnotation(Resource.class) == null && field.getAnnotation(javax.annotation.Resource.class) == null) {
-// return null;
-// }
-// if ((srcObj instanceof Service) && Sncp.isRemote((Service) srcObj)) {
-// return null; //远程模式不得注入 DataSource
-// }
-// DataSource source = application.loadDataSource(resourceName, false);
-// field.set(srcObj, source);
-// return source;
-// } catch (Exception e) {
-// logger.log(Level.SEVERE, "DataSource inject to " + srcObj + " error", e);
-// return null;
-// }
-// }, DataSource.class);
-//
-// //------------------------------------- 注册 CacheSource --------------------------------------------------------
-// resourceFactory.register(new ResourceTypeLoader() {
-// @Override
-// public Object load(ResourceFactory rf, String srcResourceName, final Object srcObj, final String resourceName, Field field, final Object attachment) {
-// try {
-// if (field.getAnnotation(Resource.class) == null && field.getAnnotation(javax.annotation.Resource.class) == null) {
-// return null;
-// }
-// if ((srcObj instanceof Service) && Sncp.isRemote((Service) srcObj)) {
-// return null; //远程模式不需要注入 CacheSource
-// }
-// if (srcObj instanceof Servlet) {
-// throw new RedkaleException("CacheSource cannot inject in Servlet " + srcObj);
-// }
-// final boolean ws = (srcObj instanceof org.redkale.net.http.WebSocketNodeService);
-// CacheSource source = application.loadCacheSource(resourceName, ws);
-// field.set(srcObj, source);
-// Resource res = field.getAnnotation(Resource.class);
-// if (res != null && res.required() && source == null) {
-// throw new RedkaleException("CacheSource (resourceName = '" + resourceName + "') not found");
-// } else {
-// logger.info("Load CacheSource (type = " + (source == null ? null : source.getClass().getSimpleName()) + ", resourceName = '" + resourceName + "')");
-// }
-// return source;
-// } catch (Exception e) {
-// logger.log(Level.SEVERE, "DataSource inject error", e);
-// return null;
-// }
-// }
-//
-// @Override
-// public boolean autoNone() {
-// return false;
-// }
-// }, CacheSource.class);
-
- //------------------------------------- 注册 WebSocketNode --------------------------------------------------------
resourceFactory.register(new ResourceTypeLoader() {
@Override
public Object load(ResourceFactory rf, String srcResourceName, final Object srcObj, final String resourceName, Field field, final Object attachment) {
@@ -433,6 +290,57 @@ public abstract class NodeServer {
}, WebSocketNode.class);
}
+ private Object loadService(ResourceFactory rf, String srcResourceName, Object srcObj, String resourceName, Field field, Object attachment) {
+ final NodeServer self = this;
+ final ResourceFactory appResFactory = application.getResourceFactory();
+ Class resServiceType = Service.class;
+ try {
+ if (field.getAnnotation(Resource.class) == null && field.getAnnotation(javax.annotation.Resource.class) == null) {
+ return null;
+ }
+ if ((srcObj instanceof Service) && Sncp.isRemote((Service) srcObj)) {
+ return null; //远程模式不得注入 AutoLoad Service
+ }
+ if (!Service.class.isAssignableFrom(field.getType())) {
+ return null;
+ }
+ resServiceType = (Class) field.getType();
+ if (resServiceType.getAnnotation(Local.class) == null) {
+ return null;
+ }
+ boolean auto = true;
+ AutoLoad al = resServiceType.getAnnotation(AutoLoad.class);
+ if (al != null) {
+ auto = al.value();
+ }
+ org.redkale.util.AutoLoad al2 = resServiceType.getAnnotation(org.redkale.util.AutoLoad.class);
+ if (al2 != null) {
+ auto = al2.value();
+ }
+ if (auto) {
+ return null;
+ }
+
+ //ResourceFactory resfactory = (isSNCP() ? appResFactory : resourceFactory);
+ Service service = Modifier.isFinal(resServiceType.getModifiers()) || Sncp.isComponent(resServiceType)
+ ? (Service) resServiceType.getConstructor().newInstance()
+ : Sncp.createLocalService(serverClassLoader, resourceName, resServiceType,
+ appResFactory, application.getSncpRpcGroups(), sncpClient, null, null, null);
+ appResFactory.register(resourceName, resServiceType, service);
+
+ field.set(srcObj, service);
+ rf.inject(resourceName, service, self); // 给其可能包含@Resource的字段赋值;
+ if (!application.isCompileMode()) {
+ service.init(null);
+ }
+ logger.info("Load Service(@Local @AutoLoad service = " + resServiceType.getSimpleName() + ", resourceName = '" + resourceName + "')");
+ return service;
+ } catch (Exception e) {
+ logger.log(Level.SEVERE, "Load @Local @AutoLoad(false) Service inject " + resServiceType + " to " + srcObj + " error", e);
+ return null;
+ }
+ }
+
@SuppressWarnings("unchecked")
protected void loadService(ClassFilter extends Service> serviceFilter) throws Exception {
Objects.requireNonNull(serviceFilter);
diff --git a/src/main/java/org/redkale/boot/PropertiesAgent.java b/src/main/java/org/redkale/boot/PropertiesAgent.java
index e291aecd4..58b6e2f24 100644
--- a/src/main/java/org/redkale/boot/PropertiesAgent.java
+++ b/src/main/java/org/redkale/boot/PropertiesAgent.java
@@ -3,10 +3,7 @@
package org.redkale.boot;
import java.util.*;
-import java.util.concurrent.locks.ReentrantLock;
-import java.util.logging.Level;
import java.util.logging.Logger;
-import org.redkale.net.http.MimeType;
import org.redkale.util.*;
/**
@@ -25,9 +22,6 @@ public abstract class PropertiesAgent {
protected final Logger logger = Logger.getLogger(this.getClass().getSimpleName());
- //envProperties更新锁
- private final ReentrantLock updateLock = new ReentrantLock();
-
/**
* 编译时进行的操作
*
@@ -62,141 +56,15 @@ public abstract class PropertiesAgent {
*/
public abstract void destroy(AnyValue conf);
- protected final void updateEnvironmentProperties(Application application, String namespace, List events) {
- if (Utility.isEmpty(events)) {
- return;
- }
- updateLock.lock();
- try {
- Properties envRegisterProps = new Properties();
- Set envRemovedKeys = new HashSet<>();
- Properties envChangedProps = new Properties();
-
-// Set sourceRemovedKeys = new HashSet<>();
-// Properties sourceChangedProps = new Properties();
- Set loggingRemovedKeys = new HashSet<>();
- Properties loggingChangedProps = new Properties();
-
-// Set clusterRemovedKeys = new HashSet<>();
-// Properties clusterChangedProps = new Properties();
-//
-// Set messageRemovedKeys = new HashSet<>();
-// Properties messageChangedProps = new Properties();
- for (ResourceEvent event : events) {
- if (namespace != null && namespace.startsWith("logging")) {
- if (event.newValue() == null) {
- if (application.loggingProperties.containsKey(event.name())) {
- loggingRemovedKeys.add(event.name());
- }
- } else {
- loggingChangedProps.put(event.name(), event.newValue());
- }
- continue;
- }
- if (event.name().startsWith("redkale.datasource.") || event.name().startsWith("redkale.datasource[")
- || event.name().startsWith("redkale.cachesource.") || event.name().startsWith("redkale.cachesource[")) {
-// if (event.name().endsWith(".name")) {
-// logger.log(Level.WARNING, "skip illegal key " + event.name() + " in source config " + (namespace == null ? "" : namespace) + ", key cannot endsWith '.name'");
-// } else {
-// if (!Objects.equals(event.newValue(), this.sourceProperties.getProperty(event.name()))) {
-// if (event.newValue() == null) {
-// if (this.sourceProperties.containsKey(event.name())) {
-// sourceRemovedKeys.add(event.name());
-// }
-// } else {
-// sourceChangedProps.put(event.name(), event.newValue());
-// }
-// }
-// }
- } else if (event.name().startsWith("redkale.mq.") || event.name().startsWith("redkale.mq[")) {
-// if (event.name().endsWith(".name")) {
-// logger.log(Level.WARNING, "skip illegal key " + event.name() + " in mq config " + (namespace == null ? "" : namespace) + ", key cannot endsWith '.name'");
-// } else {
-// if (!Objects.equals(event.newValue(), this.messageProperties.getProperty(event.name()))) {
-// if (event.newValue() == null) {
-// if (this.messageProperties.containsKey(event.name())) {
-// messageRemovedKeys.add(event.name());
-// }
-// } else {
-// messageChangedProps.put(event.name(), event.newValue());
-// }
-// }
-// }
- } else if (event.name().startsWith("redkale.cluster.")) {
-// if (!Objects.equals(event.newValue(), this.clusterProperties.getProperty(event.name()))) {
-// if (event.newValue() == null) {
-// if (this.clusterProperties.containsKey(event.name())) {
-// clusterRemovedKeys.add(event.name());
-// }
-// } else {
-// clusterChangedProps.put(event.name(), event.newValue());
-// }
-// }
- } else if (event.name().startsWith("system.property.")) {
- String propName = event.name().substring("system.property.".length());
- if (event.newValue() == null) {
- System.getProperties().remove(propName);
- } else {
- System.setProperty(propName, event.newValue());
- }
- } else if (event.name().startsWith("mimetype.property.")) {
- String propName = event.name().substring("system.property.".length());
- if (event.newValue() != null) {
- MimeType.add(propName, event.newValue());
- }
- } else if (event.name().startsWith("redkale.")) {
- logger.log(Level.WARNING, "not support the environment property key " + event.name() + " on change event");
- } else {
- if (!Objects.equals(event.newValue(), application.envProperties.getProperty(event.name()))) {
- envRegisterProps.put(event.name(), event.newValue());
- if (event.newValue() == null) {
- if (application.envProperties.containsKey(event.name())) {
- envRemovedKeys.add(event.name());
- }
- } else {
- envChangedProps.put(event.name(), event.newValue());
- }
- }
- }
- }
- //普通配置项的变更
- if (!envRegisterProps.isEmpty()) {
- application.envProperties.putAll(envChangedProps);
- envRemovedKeys.forEach(application.envProperties::remove);
- AnyValueWriter oldConf = (AnyValueWriter) application.getAppConfig().getAnyValue("properties");
- AnyValueWriter newConf = new AnyValueWriter();
- oldConf.forEach((k, v) -> newConf.addValue(k, v));
- application.envProperties.forEach((k, v) -> {
- newConf.addValue("property", new AnyValueWriter().addValue("name", k.toString()).addValue("value", v.toString()));
- });
- oldConf.replace(newConf);
- application.getResourceFactory().register(envRegisterProps, "", Environment.class);
- }
-
- //日志配置项的变更
- if (!loggingChangedProps.isEmpty() || !loggingRemovedKeys.isEmpty()) {
- //只是简单变更日志级别则直接操作,无需重新配置日志
- if (loggingRemovedKeys.isEmpty() && loggingChangedProps.size() == 1 && loggingChangedProps.containsKey(".level")) {
- try {
- Level logLevel = Level.parse(loggingChangedProps.getProperty(".level"));
- Logger.getGlobal().setLevel(logLevel);
- application.loggingProperties.putAll(loggingChangedProps);
- logger.log(Level.INFO, "Reconfig logging level to " + logLevel);
- } catch (Exception e) {
- logger.log(Level.WARNING, "Reconfig logging level error, new level is " + loggingChangedProps.getProperty(".level"));
- }
- } else {
- Properties newLogProps = new Properties();
- newLogProps.putAll(application.loggingProperties);
- newLogProps.putAll(loggingChangedProps);
- loggingRemovedKeys.forEach(newLogProps::remove);
- application.reconfigLogging(false, newLogProps);
- logger.log(Level.INFO, "Reconfig logging finished ");
- }
- }
- } finally {
- updateLock.unlock();
- }
+ /**
+ * 响应配置项的变更
+ *
+ * @param application Application
+ * @param namespace 命名空间
+ * @param events 变更项集合
+ */
+ protected final void onEnvironmentUpdated(Application application, String namespace, List events) {
+ application.propertiesModule.onEnvironmentUpdated(namespace, events);
}
}
diff --git a/src/main/java/org/redkale/boot/PropertiesModule.java b/src/main/java/org/redkale/boot/PropertiesModule.java
new file mode 100644
index 000000000..9d2c3d91d
--- /dev/null
+++ b/src/main/java/org/redkale/boot/PropertiesModule.java
@@ -0,0 +1,323 @@
+/*
+ *
+ */
+package org.redkale.boot;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Properties;
+import java.util.ServiceLoader;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.locks.ReentrantLock;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import org.redkale.util.AnyValue;
+import org.redkale.util.Environment;
+import org.redkale.util.InstanceProvider;
+import org.redkale.util.RedkaleClassLoader;
+import org.redkale.util.ResourceEvent;
+import org.redkale.util.Utility;
+
+/**
+ *
+ * 配置模块组件
+ *
+ *
+ * 详情见: https://redkale.org
+ *
+ * @author zhangjx
+ *
+ * @since 2.8.0
+ */
+class PropertiesModule {
+
+ private final Logger logger = Logger.getLogger(this.getClass().getSimpleName());
+
+ private final Application application;
+
+ //配置源管理接口
+ //@since 2.7.0
+ private PropertiesAgent propertiesAgent;
+
+ //envProperties更新锁
+ private final ReentrantLock updateLock = new ReentrantLock();
+
+ PropertiesModule(Application application) {
+ this.application = application;
+ }
+
+ public void destroy() {
+ if (this.propertiesAgent != null) {
+ long s = System.currentTimeMillis();
+ this.propertiesAgent.destroy(application.config.getAnyValue("properties"));
+ logger.info(this.propertiesAgent.getClass().getSimpleName() + " destroy in " + (System.currentTimeMillis() - s) + " ms");
+ }
+ }
+
+ /**
+ * 读取远程配置,并合并app.config
+ */
+ public void initRemoteProperties() {
+ final AnyValue config = application.getAppConfig();
+ //所有配置项,包含本地配置项、logging配置项和配置中心获取的配置项
+ final Environment environment = application.getEnvironment();
+ Properties logProps = null; //新的日志配置项
+ //------------------------------------ 读取配置项 ------------------------------------
+ AnyValue propsConf = config.getAnyValue("properties");
+ if (propsConf == null) {
+ final AnyValue resources = config.getAnyValue("resources");
+ if (resources != null) {
+ logger.log(Level.WARNING, " in application config file is deprecated");
+ propsConf = resources.getAnyValue("properties");
+ }
+ }
+ final Properties remoteEnvs = new Properties();
+ if (propsConf != null) {
+ //可能通过系统环境变量配置信息
+ Iterator it = ServiceLoader.load(PropertiesAgentProvider.class, application.getClassLoader()).iterator();
+ RedkaleClassLoader.putServiceLoader(PropertiesAgentProvider.class);
+ List providers = new ArrayList<>();
+ while (it.hasNext()) {
+ PropertiesAgentProvider provider = it.next();
+ if (provider != null && provider.acceptsConf(propsConf)) {
+ RedkaleClassLoader.putReflectionPublicConstructors(provider.getClass(), provider.getClass().getName());
+ providers.add(provider);
+ }
+ }
+ for (PropertiesAgentProvider provider : InstanceProvider.sort(providers)) {
+ long s = System.currentTimeMillis();
+ this.propertiesAgent = provider.createInstance();
+ application.resourceFactory.inject(this.propertiesAgent);
+ if (application.isCompileMode()) {
+ this.propertiesAgent.compile(propsConf);
+ } else {
+ Map propMap = this.propertiesAgent.init(application, propsConf);
+ int propCount = 0;
+ if (propMap != null) {
+ for (Map.Entry en : propMap.entrySet()) {
+ propCount += en.getValue().size();
+ if (en.getKey().contains("logging")) {
+ if (logProps != null) {
+ logger.log(Level.WARNING, "skip repeat logging config properties(" + en.getKey() + ")");
+ } else {
+ logProps = en.getValue();
+ }
+ } else {
+ remoteEnvs.putAll(en.getValue());
+ }
+ }
+ }
+ logger.info("PropertiesAgent (type = " + this.propertiesAgent.getClass().getSimpleName()
+ + ") load " + propCount + " data in " + (System.currentTimeMillis() - s) + " ms");
+ }
+ break; //only first provider
+ }
+ }
+
+ //重置远程日志配置
+ if (Utility.isNotEmpty(logProps)) {
+ application.loggingModule.reconfigLogging(false, logProps);
+ }
+
+ if (!remoteEnvs.isEmpty()) {
+ mergeEnvProperties(remoteEnvs, null);
+ }
+
+ }
+
+ public void onEnvironmentUpdated(String namespace, List events) {
+ if (Utility.isEmpty(events)) {
+ return;
+ }
+ updateLock.lock();
+ try {
+ if (namespace != null && namespace.contains("logging")) {
+ //日志配置单独处理
+ application.loggingModule.onEnvironmentUpdated(events);
+ return;
+ }
+ Set removedKeys = new HashSet<>();
+ Properties newEnvs = new Properties(application.envProperties);
+ for (ResourceEvent event : events) {
+ if (event.newValue() != null) {
+ newEnvs.put(event.name(), event.newValue());
+ } else {
+ newEnvs.remove(event.name());
+ removedKeys.add(event.name());
+ }
+ }
+ mergeEnvProperties(newEnvs, removedKeys);
+ application.onEnvironmentChanged(namespace, events);
+ } finally {
+ updateLock.unlock();
+ }
+ }
+
+ private void mergeEnvProperties(final Properties remoteEnvs, final Set removedKeys) {
+ //此时this.envProperties中的内容:
+ // 1、application.xml的properties.property节点配置项
+ // 2、application.xml的properties.load节点的配置项
+ // 3、logging.properties
+ // 4、source.properties
+ final Properties newMergeProps = new Properties();
+ final AtomicInteger propertyIndex = new AtomicInteger();
+ //remoteEnvs包含redkale.properties.mykey.name自定义配置项,也包含mykey.name的配置项
+ remoteEnvs.forEach((k, v) -> {
+ String key = k.toString();
+ if (key.startsWith("redkale.executor.") //节点全局唯一
+ || key.startsWith("redkale.transport.") //节点全局唯一
+ || key.startsWith("redkale.cluster.") //节点全局唯一
+ || key.startsWith("redkale.cache.") //节点全局唯一
+ || key.startsWith("redkale.schedule.") //节点全局唯一
+ || key.startsWith("redkale.lock.")//节点全局唯一
+ || key.startsWith("redkale.mq.")
+ || key.startsWith("redkale.mq[")
+ || key.startsWith("redkale.group.")
+ || key.startsWith("redkale.group[")
+ || key.startsWith("redkale.listener.")
+ || key.startsWith("redkale.listener[")
+ || key.startsWith("redkale.server.")
+ || key.startsWith("redkale.server[")) {
+ newMergeProps.put(k, v);
+ } else { //其他视为普通配置项
+ if (key.startsWith("system.property.")) {
+ application.envProperties.put(k, v);
+ } else if (key.startsWith("mimetype.property.")) {
+ application.envProperties.put(k, v);
+ } else if (key.startsWith("redkale.properties.property.")) {
+ newMergeProps.put(k, v);
+ String name = key.substring("redkale.properties.".length());
+ application.envProperties.put(name, v);
+ } else if (key.startsWith("redkale.properties.property[")) {
+ newMergeProps.put(k, v);
+ String name = key.substring("redkale.properties[".length());
+ name = name.substring(0, name.indexOf(']'));
+ application.envProperties.put(name, v);
+ } else if (key.startsWith("redkale.properties.")) { //支持 -Dredkale.properties.mykey = myvalue
+ String prefix = "redkale.properties.property[" + propertyIndex.getAndIncrement() + "]";
+ String name = key.substring("redkale.properties.".length());
+ newMergeProps.put(prefix + ".name", name);
+ newMergeProps.put(prefix + ".value", v);
+ application.envProperties.put(name, v);
+ } else { //独立的普通配置项文件,比如:config.properties文件中的配置项
+ String prefix = "redkale.properties.property[" + propertyIndex.getAndIncrement() + "]";
+ newMergeProps.put(prefix + ".name", k);
+ newMergeProps.put(prefix + ".value", v);
+ application.envProperties.put(k, v);
+ }
+ }
+ });
+ if (Utility.isNotEmpty(removedKeys)) {
+ removedKeys.forEach(application.envProperties::remove);
+ }
+ if (!newMergeProps.isEmpty()) {
+ Properties newDyncProps = new Properties();
+ newMergeProps.forEach((k, v) -> newDyncProps.put(k.toString(), application.getEnvironment().getPropertyValue(v.toString(), newMergeProps)));
+ //合并配置
+ application.getAppConfig().merge(AnyValue.loadFromProperties(newDyncProps).getAnyValue("redkale"), createMergeStrategy(application));
+ }
+ }
+
+ /**
+ * 合并系统配置项的策略
+ */
+ static final AnyValue.MergeStrategy createMergeStrategy(final Application application) {
+ return (path, key, val1, val2) -> {
+ for (ModuleEngine m : application.getModuleEngines()) {
+ AnyValue.MergeEnum rs = m.mergeAppConfigStrategy(path, key, val1, val2);
+ if (rs != null) {
+ return rs;
+ }
+ }
+ if ("".equals(path)) {
+ if ("executor".equals(key)) {
+ return AnyValue.MergeEnum.REPLACE;
+ }
+ if ("listener".equals(key)) {
+ if (Objects.equals(val1.getValue("value"), val2.getValue("value"))) {
+ return AnyValue.MergeEnum.IGNORE;
+ } else {
+ return AnyValue.MergeEnum.DEFAULT;
+ }
+ }
+ if ("group".equals(key)) {
+ if (Objects.equals(val1.getValue("name"), val2.getValue("name"))) {
+ return AnyValue.MergeEnum.REPLACE;
+ } else {
+ return AnyValue.MergeEnum.DEFAULT;
+ }
+ }
+ if ("server".equals(key)) {
+ if (Objects.equals(val1.getValue("name", val1.getValue("protocol") + "_" + val1.getValue("port")),
+ val2.getValue("name", val2.getValue("protocol") + "_" + val2.getValue("port")))) {
+ return AnyValue.MergeEnum.REPLACE;
+ } else {
+ return AnyValue.MergeEnum.DEFAULT;
+ }
+ }
+ }
+ if ("properties".equals(path)) {
+ if ("property".equals(key)) {
+ if (Objects.equals(val1.getValue("name"), val2.getValue("name"))) {
+ return AnyValue.MergeEnum.REPLACE;
+ } else {
+ return AnyValue.MergeEnum.DEFAULT;
+ }
+ }
+ }
+ if ("server".equals(path)) {
+ if ("ssl".equals(key)) {
+ return AnyValue.MergeEnum.REPLACE;
+ }
+ if ("render".equals(key)) {
+ return AnyValue.MergeEnum.REPLACE;
+ }
+ if ("resource-servlet".equals(key)) {
+ return AnyValue.MergeEnum.REPLACE;
+ }
+ }
+ if ("server.request".equals(path)) {
+ if ("remoteaddr".equals(key)) {
+ return AnyValue.MergeEnum.REPLACE;
+ }
+ if ("rpc".equals(key)) {
+ return AnyValue.MergeEnum.REPLACE;
+ }
+ if ("locale".equals(key)) {
+ if (Objects.equals(val1.getValue("name"), val2.getValue("name"))) {
+ return AnyValue.MergeEnum.REPLACE;
+ } else {
+ return AnyValue.MergeEnum.DEFAULT;
+ }
+ }
+ }
+ if ("server.response".equals(path)) {
+ if ("content-type".equals(key)) {
+ return AnyValue.MergeEnum.REPLACE;
+ }
+ if ("defcookie".equals(key)) {
+ return AnyValue.MergeEnum.REPLACE;
+ }
+ if ("options".equals(key)) {
+ return AnyValue.MergeEnum.REPLACE;
+ }
+ if ("date".equals(key)) {
+ return AnyValue.MergeEnum.REPLACE;
+ }
+ if ("addheader".equals(key) || "setheader".equals(key)) {
+ if (Objects.equals(val1.getValue("name"), val2.getValue("name"))) {
+ return AnyValue.MergeEnum.REPLACE;
+ } else {
+ return AnyValue.MergeEnum.DEFAULT;
+ }
+ }
+ }
+ return AnyValue.MergeEnum.MERGE;
+ };
+ }
+}
diff --git a/src/main/java/org/redkale/cache/support/CacheModuleEngine.java b/src/main/java/org/redkale/cache/support/CacheModuleEngine.java
index a79654c5e..c8cd71993 100644
--- a/src/main/java/org/redkale/cache/support/CacheModuleEngine.java
+++ b/src/main/java/org/redkale/cache/support/CacheModuleEngine.java
@@ -20,6 +20,24 @@ public class CacheModuleEngine extends ModuleEngine {
super(application);
}
+ /**
+ * 判断模块的配置项合并策略, 返回null表示模块不识别此配置项
+ *
+ * @param path 配置项路径
+ * @param key 配置项名称
+ * @param val1 配置项原值
+ * @param val2 配置项新值
+ *
+ * @return MergeEnum
+ */
+ @Override
+ public AnyValue.MergeEnum mergeAppConfigStrategy(String path, String key, AnyValue val1, AnyValue val2) {
+ if ("".equals(path) && "cache".equals(key)) {
+ return AnyValue.MergeEnum.REPLACE;
+ }
+ return null;
+ }
+
/**
* 结束Application.init方法前被调用
*/
diff --git a/src/main/java/org/redkale/cluster/ClusterModuleEngine.java b/src/main/java/org/redkale/cluster/ClusterModuleEngine.java
index a5c91db8f..4dd21554d 100644
--- a/src/main/java/org/redkale/cluster/ClusterModuleEngine.java
+++ b/src/main/java/org/redkale/cluster/ClusterModuleEngine.java
@@ -46,7 +46,7 @@ public class ClusterModuleEngine extends ModuleEngine {
AnyValue clusterConf = application.getAppConfig().getAnyValue("cluster");
if (clusterConf != null) {
try {
- String classVal = application.getPropertyValue(clusterConf.getValue("type", clusterConf.getValue("value"))); //兼容value字段
+ String classVal = environment.getPropertyValue(clusterConf.getValue("type", clusterConf.getValue("value"))); //兼容value字段
if (classVal == null || classVal.isEmpty() || classVal.indexOf('.') < 0) { //不包含.表示非类名,比如值: consul, nacos
Iterator it = ServiceLoader.load(ClusterAgentProvider.class, application.getClassLoader()).iterator();
RedkaleClassLoader.putServiceLoader(ClusterAgentProvider.class);
@@ -184,9 +184,28 @@ public class ClusterModuleEngine extends ModuleEngine {
}
}
+ /**
+ * 判断模块的配置项合并策略, 返回null表示模块不识别此配置项
+ *
+ * @param path 配置项路径
+ * @param key 配置项名称
+ * @param val1 配置项原值
+ * @param val2 配置项新值
+ *
+ * @return MergeEnum
+ */
+ @Override
+ public AnyValue.MergeEnum mergeAppConfigStrategy(String path, String key, AnyValue val1, AnyValue val2) {
+ if ("".equals(path) && "cluster".equals(key)) {
+ return AnyValue.MergeEnum.REPLACE;
+ }
+ return null;
+ }
+
/**
* 进入Application.start方法被调用
*/
+ @Override
public void onAppPreStart() {
if (!application.isSingletonMode() && !application.isCompileMode() && this.clusterAgent != null) {
this.clusterAgent.register(application);
diff --git a/src/main/java/org/redkale/mq/MessageAgent.java b/src/main/java/org/redkale/mq/MessageAgent.java
index 7bbe119d6..727baedd2 100644
--- a/src/main/java/org/redkale/mq/MessageAgent.java
+++ b/src/main/java/org/redkale/mq/MessageAgent.java
@@ -48,6 +48,9 @@ public abstract class MessageAgent implements Resourcable {
@Resource(required = false)
protected Application application;
+ @Resource(required = false)
+ protected Environment environment;
+
@Resource(name = RESNAME_APP_NODEID)
protected int nodeid;
@@ -244,14 +247,14 @@ public abstract class MessageAgent implements Resourcable {
Map views = new LinkedHashMap<>();
for (MessageConsumer consumer : consumers) {
ResourceConsumer res = consumer.getClass().getAnnotation(ResourceConsumer.class);
- String group = application.getPropertyValue(res.group());
+ String group = environment.getPropertyValue(res.group());
if (Utility.isBlank(group)) {
group = consumer.getClass().getName();
}
Map map = maps.computeIfAbsent(group, g -> new HashMap<>());
List topics = new ArrayList<>();
for (String t : res.topics()) {
- String topic = application.getPropertyValue(t);
+ String topic = environment.getPropertyValue(t);
if (!topic.trim().isEmpty()) {
topics.add(topic);
if (map.containsKey(topic.trim())) {
diff --git a/src/main/java/org/redkale/mq/MessageModuleEngine.java b/src/main/java/org/redkale/mq/MessageModuleEngine.java
index 0f9cf9d41..00a54a416 100644
--- a/src/main/java/org/redkale/mq/MessageModuleEngine.java
+++ b/src/main/java/org/redkale/mq/MessageModuleEngine.java
@@ -21,13 +21,13 @@ import org.redkale.boot.NodeServer;
import org.redkale.convert.json.JsonConvert;
import org.redkale.net.http.RestException;
import org.redkale.util.AnyValue;
+import org.redkale.util.AnyValueWriter;
import org.redkale.util.RedkaleClassLoader;
import org.redkale.util.RedkaleException;
import org.redkale.util.ResourceAnnotationProvider;
import org.redkale.util.ResourceEvent;
import org.redkale.util.ResourceFactory;
import org.redkale.util.ResourceTypeLoader;
-import org.redkale.util.AnyValueWriter;
import org.redkale.util.Utility;
/**
@@ -48,6 +48,28 @@ public class MessageModuleEngine extends ModuleEngine {
super(application);
}
+ /**
+ * 判断模块的配置项合并策略, 返回null表示模块不识别此配置项
+ *
+ * @param path 配置项路径
+ * @param key 配置项名称
+ * @param val1 配置项原值
+ * @param val2 配置项新值
+ *
+ * @return MergeEnum
+ */
+ @Override
+ public AnyValue.MergeEnum mergeAppConfigStrategy(String path, String key, AnyValue val1, AnyValue val2) {
+ if ("".equals(path) && "mq".equals(key)) {
+ if (Objects.equals(val1.getValue("name"), val2.getValue("name"))) {
+ return AnyValue.MergeEnum.REPLACE;
+ } else {
+ return AnyValue.MergeEnum.DEFAULT;
+ }
+ }
+ return null;
+ }
+
/**
* 配置项加载后被调用
*/
@@ -79,7 +101,7 @@ public class MessageModuleEngine extends ModuleEngine {
Set mqnames = new HashSet<>();
for (int i = 0; i < mqConfs.length; i++) {
AnyValue mqConf = mqConfs[i];
- String names = application.getPropertyValue(mqConf.getValue("name")); //含,或者;表示多个别名使用同一mq对象
+ String names = environment.getPropertyValue(mqConf.getValue("name")); //含,或者;表示多个别名使用同一mq对象
if (names != null && !names.isEmpty()) {
for (String n : names.replace(',', ';').split(";")) {
if (n.trim().isEmpty()) {
@@ -98,7 +120,7 @@ public class MessageModuleEngine extends ModuleEngine {
mqnames.add(n);
}
try {
- String classVal = application.getPropertyValue(mqConf.getValue("type", mqConf.getValue("value"))); //兼容value字段
+ String classVal = environment.getPropertyValue(mqConf.getValue("type", mqConf.getValue("value"))); //兼容value字段
if (classVal == null || classVal.isEmpty() || classVal.indexOf('.') < 0) { //不包含.表示非类名,比如值: kafka, pulsar
Iterator it = ServiceLoader.load(MessageAgentProvider.class, application.getClassLoader()).iterator();
RedkaleClassLoader.putServiceLoader(MessageAgentProvider.class);
@@ -343,7 +365,7 @@ public class MessageModuleEngine extends ModuleEngine {
for (ClassFilter.FilterEntry extends MessageConsumer> en : entrys) {
Class extends MessageConsumer> clazz = en.getType();
ResourceConsumer res = clazz.getAnnotation(ResourceConsumer.class);
- if (!Objects.equals(agent.getName(), application.getPropertyValue(res.mq()))) {
+ if (!Objects.equals(agent.getName(), environment.getPropertyValue(res.mq()))) {
continue;
}
RedkaleClassLoader.putReflectionDeclaredConstructors(clazz, clazz.getName());
diff --git a/src/main/java/org/redkale/schedule/support/ScheduleManagerService.java b/src/main/java/org/redkale/schedule/support/ScheduleManagerService.java
index 370a182c8..38eb3ee9d 100644
--- a/src/main/java/org/redkale/schedule/support/ScheduleManagerService.java
+++ b/src/main/java/org/redkale/schedule/support/ScheduleManagerService.java
@@ -31,14 +31,14 @@ import org.redkale.annotation.Nullable;
import org.redkale.annotation.Resource;
import org.redkale.annotation.ResourceType;
import org.redkale.boot.Application;
+import org.redkale.schedule.ScheduleManager;
+import org.redkale.schedule.Scheduled;
import org.redkale.service.Local;
import org.redkale.service.Service;
import org.redkale.util.AnyValue;
import org.redkale.util.RedkaleClassLoader;
import org.redkale.util.RedkaleException;
import org.redkale.util.Utility;
-import org.redkale.schedule.Scheduled;
-import org.redkale.schedule.ScheduleManager;
/**
* 定时任务管理器
@@ -104,7 +104,7 @@ public class ScheduleManagerService implements ScheduleManager, Service {
this.enabled = conf.getBoolValue("enabled", true);
if (this.enabled) {
if (this.propertyFunc == null && application != null) {
- UnaryOperator func = application::getPropertyValue;
+ UnaryOperator func = application.getEnvironment()::getPropertyValue;
this.propertyFunc = func;
}
this.scheduler = new ScheduledThreadPoolExecutor(Utility.cpus(), Utility.newThreadFactory("Scheduled-Task-Thread-%s"));
diff --git a/src/main/java/org/redkale/schedule/support/ScheduleModuleEngine.java b/src/main/java/org/redkale/schedule/support/ScheduleModuleEngine.java
index 282bdd4bc..1dcdd98df 100644
--- a/src/main/java/org/redkale/schedule/support/ScheduleModuleEngine.java
+++ b/src/main/java/org/redkale/schedule/support/ScheduleModuleEngine.java
@@ -21,6 +21,24 @@ public class ScheduleModuleEngine extends ModuleEngine {
super(application);
}
+ /**
+ * 判断模块的配置项合并策略, 返回null表示模块不识别此配置项
+ *
+ * @param path 配置项路径
+ * @param key 配置项名称
+ * @param val1 配置项原值
+ * @param val2 配置项新值
+ *
+ * @return MergeEnum
+ */
+ @Override
+ public AnyValue.MergeEnum mergeAppConfigStrategy(String path, String key, AnyValue val1, AnyValue val2) {
+ if ("".equals(path) && "schedule".equals(key)) {
+ return AnyValue.MergeEnum.REPLACE;
+ }
+ return null;
+ }
+
/**
* 结束Application.init方法前被调用
*/
diff --git a/src/main/java/org/redkale/service/RetLabel.java b/src/main/java/org/redkale/service/RetLabel.java
index 683dfe3ea..19e8be300 100644
--- a/src/main/java/org/redkale/service/RetLabel.java
+++ b/src/main/java/org/redkale/service/RetLabel.java
@@ -13,6 +13,8 @@ import java.lang.reflect.*;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.function.BiFunction;
+import static org.redkale.boot.Application.SYSNAME_APP_CONF_DIR;
+import static org.redkale.boot.Application.SYSNAME_APP_HOME;
import org.redkale.util.RedkaleClassLoader;
/**
@@ -85,8 +87,8 @@ public @interface RetLabel {
}
}
try {
- File homePath = new File(System.getProperty("redkale.application.home", ""), "conf");
- File propPath = new File(System.getProperty("redkale.application.confPath", homePath.getPath()));
+ File homePath = new File(System.getProperty(SYSNAME_APP_HOME, ""), "conf");
+ File propPath = new File(System.getProperty(SYSNAME_APP_CONF_DIR, homePath.getPath()));
if (propPath.isDirectory() && propPath.canRead()) {
final String prefix = clazz.getSimpleName().toLowerCase();
for (File propFile : propPath.listFiles(f -> f.getName().startsWith(prefix) && f.getName().endsWith(".properties"))) {
diff --git a/src/main/java/org/redkale/source/SourceModuleEngine.java b/src/main/java/org/redkale/source/SourceModuleEngine.java
index 6a9d2c45d..061d64735 100644
--- a/src/main/java/org/redkale/source/SourceModuleEngine.java
+++ b/src/main/java/org/redkale/source/SourceModuleEngine.java
@@ -58,6 +58,27 @@ public class SourceModuleEngine extends ModuleEngine {
super(application);
}
+ /**
+ * 判断模块的配置项合并策略, 返回null表示模块不识别此配置项
+ *
+ * @param path 配置项路径
+ * @param key 配置项名称
+ * @param val1 配置项原值
+ * @param val2 配置项新值
+ *
+ * @return MergeEnum
+ */
+ @Override
+ public AnyValue.MergeEnum mergeAppConfigStrategy(String path, String key, AnyValue val1, AnyValue val2) {
+ if ("cachesource".equals(path)) {
+ return AnyValue.MergeEnum.REPLACE;
+ }
+ if ("datasource".equals(path)) {
+ return AnyValue.MergeEnum.REPLACE;
+ }
+ return null;
+ }
+
/**
* 配置项加载后被调用
*/
@@ -98,59 +119,10 @@ public class SourceModuleEngine extends ModuleEngine {
}
//------------------------------------- 注册 DataSource --------------------------------------------------------
- resourceFactory.register((ResourceFactory rf, String srcResourceName, final Object srcObj, String resourceName, Field field, final Object attachment) -> {
- try {
- if (field.getAnnotation(Resource.class) == null && field.getAnnotation(javax.annotation.Resource.class) == null) {
- return null;
- }
- if ((srcObj instanceof Service) && Sncp.isRemote((Service) srcObj)) {
- return null; //远程模式不得注入 DataSource
- }
- DataSource source = loadDataSource(resourceName, false);
- field.set(srcObj, source);
- return source;
- } catch (Exception e) {
- logger.log(Level.SEVERE, "DataSource inject to " + srcObj + " error", e);
- return null;
- }
- }, DataSource.class);
+ resourceFactory.register(new DataSourceLoader(), DataSource.class);
//------------------------------------- 注册 CacheSource --------------------------------------------------------
- resourceFactory.register(new ResourceTypeLoader() {
- @Override
- public Object load(ResourceFactory rf, String srcResourceName, final Object srcObj, final String resourceName, Field field, final Object attachment) {
- try {
- if (field.getAnnotation(Resource.class) == null && field.getAnnotation(javax.annotation.Resource.class) == null) {
- return null;
- }
- if ((srcObj instanceof Service) && Sncp.isRemote((Service) srcObj)) {
- return null; //远程模式不需要注入 CacheSource
- }
- if (srcObj instanceof Servlet) {
- throw new RedkaleException("CacheSource cannot inject in Servlet " + srcObj);
- }
- final boolean ws = (srcObj instanceof org.redkale.net.http.WebSocketNodeService);
- CacheSource source = loadCacheSource(resourceName, ws);
- field.set(srcObj, source);
- Resource res = field.getAnnotation(Resource.class);
- if (res != null && res.required() && source == null) {
- throw new RedkaleException("CacheSource (resourceName = '" + resourceName + "') not found");
- } else {
- logger.info("Load CacheSource (type = " + (source == null ? null : source.getClass().getSimpleName()) + ", resourceName = '" + resourceName + "')");
- }
- return source;
- } catch (Exception e) {
- logger.log(Level.SEVERE, "DataSource inject error", e);
- return null;
- }
- }
-
- @Override
- public boolean autoNone() {
- return false;
- }
- }, CacheSource.class);
-
+ resourceFactory.register(new CacheSourceLoader(), CacheSource.class);
}
/**
@@ -501,4 +473,61 @@ public class SourceModuleEngine extends ModuleEngine {
return conf;
}
+ private class DataSourceLoader implements ResourceTypeLoader {
+
+ @Override
+ public Object load(ResourceFactory rf, String srcResourceName, final Object srcObj, final String resourceName, Field field, final Object attachment) {
+ try {
+ if (field.getAnnotation(Resource.class) == null && field.getAnnotation(javax.annotation.Resource.class) == null) {
+ return null;
+ }
+ if ((srcObj instanceof Service) && Sncp.isRemote((Service) srcObj)) {
+ return null; //远程模式不得注入 DataSource
+ }
+ DataSource source = loadDataSource(resourceName, false);
+ field.set(srcObj, source);
+ return source;
+ } catch (Exception e) {
+ logger.log(Level.SEVERE, "DataSource inject to " + srcObj + " error", e);
+ return null;
+ }
+ }
+ }
+
+ private class CacheSourceLoader implements ResourceTypeLoader {
+
+ @Override
+ public Object load(ResourceFactory rf, String srcResourceName, final Object srcObj, final String resourceName, Field field, final Object attachment) {
+ try {
+ if (field.getAnnotation(Resource.class) == null && field.getAnnotation(javax.annotation.Resource.class) == null) {
+ return null;
+ }
+ if ((srcObj instanceof Service) && Sncp.isRemote((Service) srcObj)) {
+ return null; //远程模式不需要注入 CacheSource
+ }
+ if (srcObj instanceof Servlet) {
+ throw new RedkaleException("CacheSource cannot inject in Servlet " + srcObj);
+ }
+ final boolean ws = (srcObj instanceof org.redkale.net.http.WebSocketNodeService);
+ CacheSource source = loadCacheSource(resourceName, ws);
+ field.set(srcObj, source);
+ Resource res = field.getAnnotation(Resource.class);
+ if (res != null && res.required() && source == null) {
+ throw new RedkaleException("CacheSource (resourceName = '" + resourceName + "') not found");
+ } else {
+ logger.info("Load CacheSource (type = " + (source == null ? null : source.getClass().getSimpleName()) + ", resourceName = '" + resourceName + "')");
+ }
+ return source;
+ } catch (Exception e) {
+ logger.log(Level.SEVERE, "DataSource inject error", e);
+ return null;
+ }
+ }
+
+ @Override
+ public boolean autoNone() {
+ return false;
+ }
+ }
+
}
diff --git a/src/main/java/org/redkale/util/AnyValue.java b/src/main/java/org/redkale/util/AnyValue.java
index b3c71cf99..bdd95b076 100644
--- a/src/main/java/org/redkale/util/AnyValue.java
+++ b/src/main/java/org/redkale/util/AnyValue.java
@@ -33,29 +33,32 @@ public abstract class AnyValue {
* merge两节点是否覆盖的判断函数
*
*/
- public static interface MergeFunction {
-
+ public static enum MergeEnum {
/**
- * 追加
+ * 异常
*/
- public static final int NONE = 0;
-
+ DEFAULT,
/**
* 替换
*/
- public static final int REPLACE = 1;
-
+ REPLACE,
/**
* 合并
*/
- public static final int MERGE = 2;
-
+ MERGE,
/**
* 丢弃
*/
- public static final int SKIP = 3;
+ IGNORE;
+ }
- public int apply(String path, String name, AnyValue val1, AnyValue val2);
+ /**
+ * merge两节点是否覆盖的判断函数
+ *
+ */
+ public static interface MergeStrategy {
+
+ public MergeEnum apply(String path, String name, AnyValue val1, AnyValue val2);
}
/**
@@ -623,7 +626,7 @@ public abstract class AnyValue {
*
* @return AnyValue
*/
- public abstract AnyValue merge(AnyValue node, MergeFunction func);
+ public abstract AnyValue merge(AnyValue node, MergeStrategy func);
/**
* 回调子节点
diff --git a/src/main/java/org/redkale/util/AnyValueWriter.java b/src/main/java/org/redkale/util/AnyValueWriter.java
index 34a648820..e000b5058 100644
--- a/src/main/java/org/redkale/util/AnyValueWriter.java
+++ b/src/main/java/org/redkale/util/AnyValueWriter.java
@@ -180,11 +180,11 @@ public class AnyValueWriter extends AnyValue {
* @return AnyValue
*/
@Override
- public AnyValueWriter merge(AnyValue node, MergeFunction func) {
+ public AnyValueWriter merge(AnyValue node, MergeStrategy func) {
return merge(node, "", func);
}
- protected AnyValueWriter merge(AnyValue node0, String path, MergeFunction func) {
+ protected AnyValueWriter merge(AnyValue node0, String path, MergeStrategy func) {
if (node0 == null) {
return this;
}
@@ -220,17 +220,17 @@ public class AnyValueWriter extends AnyValue {
ok = true;
break;
} else {
- int funcVal = func.apply(path, en.name, en.value, item.value);
- if (funcVal == MergeFunction.MERGE) {
+ MergeEnum funcVal = func.apply(path, en.name, en.value, item.value);
+ if (funcVal == MergeEnum.MERGE) {
String subPath = path.isEmpty() ? en.name : (path + "." + en.name);
((AnyValueWriter) item.value).merge(en.value, subPath, func);
ok = true;
break;
- } else if (funcVal == MergeFunction.REPLACE) {
+ } else if (funcVal == MergeEnum.REPLACE) {
item.value = en.value.copy();
ok = true;
break;
- } else if (funcVal == MergeFunction.SKIP) {
+ } else if (funcVal == MergeEnum.IGNORE) {
ok = true;
break;
}
diff --git a/src/main/java/org/redkale/util/ResourceTypeLoader.java b/src/main/java/org/redkale/util/ResourceTypeLoader.java
index 97ccd3554..262ec43f0 100644
--- a/src/main/java/org/redkale/util/ResourceTypeLoader.java
+++ b/src/main/java/org/redkale/util/ResourceTypeLoader.java
@@ -16,7 +16,8 @@ public interface ResourceTypeLoader {
public Object load(ResourceFactory factory, String srcResourceName, Object srcObj, String resourceName, Field field, Object attachment);
- // 返回true 表示调用ResourceLoader之后资源仍不存在,则会在ResourceFactory里注入默认值null,返回false表示资源不存在下次仍会调用ResourceLoader自行处理
+ //返回true: 表示调用ResourceLoader之后资源仍不存在,则会在ResourceFactory里注入默认值null。
+ //返回false: 表示资源不存在下次仍会调用ResourceLoader自行处理。
default boolean autoNone() {
return true;
}