diff --git a/src/main/java/org/redkale/boot/ApiDocCommand.java b/src/main/java/org/redkale/boot/ApiDocCommand.java index d7b63da18..5077008a3 100644 --- a/src/main/java/org/redkale/boot/ApiDocCommand.java +++ b/src/main/java/org/redkale/boot/ApiDocCommand.java @@ -398,7 +398,7 @@ public final class ApiDocCommand { try (FileOutputStream out = new FileOutputStream(new File(app.getHome(), "apidoc.json"))) { out.write(json.getBytes(StandardCharsets.UTF_8)); } - File doctemplate = new File(app.getConfPath().toString(), "apidoc-template.html"); + File doctemplate = new File(app.getConfDir().toString(), "apidoc-template.html"); InputStream in = null; if (doctemplate.isFile() && doctemplate.canRead()) { in = new FileInputStream(doctemplate); diff --git a/src/main/java/org/redkale/boot/AppConfig.java b/src/main/java/org/redkale/boot/AppConfig.java index 6b7c1317b..171718c32 100644 --- a/src/main/java/org/redkale/boot/AppConfig.java +++ b/src/main/java/org/redkale/boot/AppConfig.java @@ -17,7 +17,6 @@ import java.util.ArrayList; import java.util.Collections; import java.util.LinkedHashSet; import java.util.List; -import java.util.Objects; import java.util.Properties; import java.util.Set; import java.util.logging.SimpleFormatter; @@ -36,6 +35,12 @@ import org.redkale.util.Utility; */ class AppConfig { + /** + * 当前进程的配置文件, 类型:String、URI、File、Path
+ * 一般命名为: application.xml、application.onlyLogProps, 若配置文件不是本地文件, 则File、Path类型的值为null + */ + static final String PARAM_APP_CONF_FILE = "APP_CONF_FILE"; + //是否用于main方法运行 final boolean singletonMode; @@ -57,20 +62,14 @@ class AppConfig { //本地IP地址 InetSocketAddress localAddress; - //配置信息Properties - Properties envProperties; //进程根目录 - File home; - //进程根目录 - String homePath; - //配置文件目录 File confFile; //配置文件目录 - URI confPath; + URI confDir; //根ClassLoader RedkaleClassLoader classLoader; @@ -78,15 +77,12 @@ class AppConfig { //Server根ClassLoader RedkaleClassLoader serverClassLoader; - //本地文件所有的配置项, 包含system.property.开头的 - final Properties localEnvProperties = new Properties(); - - //本地文件设置System.properties且不存于System.properties的配置项 - final Properties localSysProperties = new Properties(); - //本地文件日志配置项 final Properties locaLogProperties = new Properties(); + //本地文件除logging配置之外的所有的配置项, 包含system.property.、mimetype.property.开头的 + final Properties localEnvProperties = new Properties(); + public AppConfig(boolean singletonMode, boolean compileMode) { this.singletonMode = singletonMode; this.compileMode = compileMode; @@ -105,7 +101,7 @@ class AppConfig { this.configFromCache = "true".equals(config.getValue("[config-from-cache]")); //初始化classLoader、serverClassLoader this.initClassLoader(); - //初始化home、confPath、localAddress等信息 + //初始化home、confDir、localAddress等信息 this.initAppHome(); //读取本地参数配置 this.initLocalProperties(); @@ -156,26 +152,25 @@ class AppConfig { } /** - * 初始化home、confPath、localAddress等信息 + * 初始化home、confDir、localAddress等信息 */ private void initAppHome() { final File root = new File(System.getProperty(RESNAME_APP_HOME, "")); final String rootPath = getCanonicalPath(root); this.home = new File(rootPath); - this.homePath = this.home.getPath(); String confDir = System.getProperty(RESNAME_APP_CONF_DIR, "conf"); if (confDir.contains("://") || confDir.startsWith("file:") || confDir.startsWith("resource:") || confDir.contains("!")) { //graalvm native-image startwith resource:META-INF - this.confPath = URI.create(confDir); + this.confDir = URI.create(confDir); if (confDir.startsWith("file:")) { - this.confFile = getCanonicalFile(new File(this.confPath.getPath())); + this.confFile = getCanonicalFile(new File(this.confDir.getPath())); } } else if (confDir.charAt(0) == '/' || confDir.indexOf(':') > -1) { this.confFile = getCanonicalFile(new File(confDir)); - this.confPath = confFile.toURI(); + this.confDir = confFile.toURI(); } else { this.confFile = new File(getCanonicalPath(new File(this.home, confDir))); - this.confPath = confFile.toURI(); + this.confDir = confFile.toURI(); } String localaddr = config.getValue("address", "").trim(); InetAddress addr = localaddr.isEmpty() ? Utility.localInetAddress() : new InetSocketAddress(localaddr, config.getIntValue("port")).getAddress(); @@ -186,6 +181,12 @@ class AppConfig { * 读取本地参数配置 */ private void initLocalProperties() { + //环境变量的优先级最高 + System.getProperties().forEach((k, v) -> { + if (k.toString().startsWith("redkale.")) { + localEnvProperties.put(k, v); + } + }); AnyValue propsConf = this.config.getAnyValue("properties"); if (propsConf == null) { final AnyValue resources = config.getAnyValue("resources"); @@ -200,12 +201,6 @@ class AppConfig { String value = prop.getValue("value"); if (value != null) { localEnvProperties.put(key, value); - if (key.startsWith("system.property.")) { - String propName = key.substring("system.property.".length()); - if (System.getProperty(propName) == null) { //命令行传参数优先级高 - localSysProperties.put(propName, value); - } - } } } if (propsConf.getValue("load") != null) { //加载本地配置项文件 @@ -213,7 +208,7 @@ class AppConfig { if (dfload.trim().isEmpty()) { continue; } - final URI df = RedkaleClassLoader.getConfResourceAsURI(configFromCache ? null : this.confPath.toString(), dfload.trim()); + final URI df = RedkaleClassLoader.getConfResourceAsURI(configFromCache ? null : this.confDir.toString(), dfload.trim()); if (df == null) { continue; } @@ -223,15 +218,6 @@ class AppConfig { InputStream in = df.toURL().openStream(); props.load(in); in.close(); - props.forEach((x, y) -> { - String key = x.toString(); - if (key.startsWith("system.property.")) { - String propName = key.substring("system.property.".length()); - if (System.getProperty(propName) == null) { //命令行传参数优先级高 - localSysProperties.put(propName, y.toString()); - } - } - }); localEnvProperties.putAll(props); } catch (Exception e) { throw new RedkaleException(e); @@ -242,22 +228,21 @@ class AppConfig { } //设置Convert默认配置项 if (System.getProperty("redkale.convert.pool.size") == null - && localSysProperties.getProperty("redkale.convert.pool.size") == null) { - localSysProperties.put("redkale.convert.pool.size", "128"); + && localEnvProperties.getProperty("system.property.redkale.convert.pool.size") == null) { + localEnvProperties.put("system.property.redkale.convert.pool.size", "128"); } if (System.getProperty("redkale.convert.writer.buffer.defsize") == null - && localSysProperties.getProperty("redkale.convert.writer.buffer.defsize") == null) { - localSysProperties.put("redkale.convert.writer.buffer.defsize", "4096"); + && localEnvProperties.getProperty("system.property.redkale.convert.writer.buffer.defsize") == null) { + localEnvProperties.put("system.property.redkale.convert.writer.buffer.defsize", "4096"); } } /** - * 读取本地数据库配置 + * 读取本地DataSource、CacheSource配置 */ private void initSourceProperties() { - //------------------------------------ 读取本地DataSource、CacheSource配置 ------------------------------------ - if ("file".equals(this.confPath.getScheme())) { - File sourceFile = new File(new File(confPath), "source.properties"); + if ("file".equals(this.confDir.getScheme())) { + File sourceFile = new File(new File(confDir), "source.properties"); if (sourceFile.isFile() && sourceFile.canRead()) { Properties props = new Properties(); try { @@ -267,19 +252,10 @@ class AppConfig { } catch (IOException e) { throw new RedkaleException(e); } - props.forEach((x, y) -> { - String key = x.toString(); - if (key.startsWith("system.property.")) { - String propName = key.substring("system.property.".length()); - if (System.getProperty(propName) == null) { //命令行传参数优先级高 - localSysProperties.put(propName, y.toString()); - } - } - }); this.localEnvProperties.putAll(props); } else { //兼容 persistence.xml 【已废弃】 - File persist = new File(new File(confPath), "persistence.xml"); + File persist = new File(new File(confDir), "persistence.xml"); if (persist.isFile() && persist.canRead()) { System.err.println("persistence.xml is deprecated, replaced by source.properties"); try { @@ -293,20 +269,11 @@ class AppConfig { } } else { //从url或jar文件中resources读取 try { - final URI sourceURI = RedkaleClassLoader.getConfResourceAsURI(configFromCache ? null : this.confPath.toString(), "source.properties"); + final URI sourceURI = RedkaleClassLoader.getConfResourceAsURI(configFromCache ? null : this.confDir.toString(), "source.properties"); InputStream in = sourceURI.toURL().openStream(); Properties props = new Properties(); props.load(in); in.close(); - props.forEach((x, y) -> { - String key = x.toString(); - if (key.startsWith("system.property.")) { - String propName = key.substring("system.property.".length()); - if (System.getProperty(propName) == null) { //命令行传参数优先级高 - localSysProperties.put(propName, y.toString()); - } - } - }); this.localEnvProperties.putAll(props); } catch (Exception e) { //没有文件 跳过 @@ -322,25 +289,22 @@ class AppConfig { File logConfFile = null; if (configFromCache) { logConfURI = RedkaleClassLoader.getConfResourceAsURI(null, "logging.properties"); - } else if ("file".equals(confPath.getScheme())) { - logConfFile = new File(confPath.getPath(), "logging.properties"); + } else if ("file".equals(confDir.getScheme())) { + logConfFile = new File(confDir.getPath(), "logging.properties"); logConfURI = logConfFile.toURI(); if (!logConfFile.isFile() || !logConfFile.canRead()) { logConfFile = null; } } else { - logConfURI = URI.create(confPath + (confPath.toString().endsWith("/") ? "" : "/") + "logging.properties"); + logConfURI = URI.create(confDir + (confDir.toString().endsWith("/") ? "" : "/") + "logging.properties"); } - if (!"file".equals(confPath.getScheme()) || logConfFile != null) { + if (!"file".equals(confDir.getScheme()) || logConfFile != null) { try { InputStream fin = logConfURI.toURL().openStream(); Properties properties0 = new Properties(); properties0.load(fin); fin.close(); - properties0.forEach((k, v) -> { - locaLogProperties.put(k.toString(), v.toString()); - localEnvProperties.put(k.toString(), v.toString()); - }); + properties0.forEach(locaLogProperties::put); } catch (IOException e) { throw new RedkaleException("read logging.properties error", e); } @@ -364,7 +328,7 @@ class AppConfig { */ static AnyValue loadAppConfig() throws IOException { final String home = new File(System.getProperty(RESNAME_APP_HOME, "")).getCanonicalPath().replace('\\', '/'); - String sysConfFile = System.getProperty(RESNAME_APP_CONF_FILE); + String sysConfFile = System.getProperty(PARAM_APP_CONF_FILE); if (sysConfFile != null) { String text; if (sysConfFile.contains("://")) { @@ -483,113 +447,4 @@ class AppConfig { } } - static final AnyValue.MergeFunction APP_CONFIG_MERGE_FUNC = (path, key, val1, val2) -> { - if ("".equals(path)) { - if ("executor".equals(key)) { - return AnyValue.MergeFunction.REPLACE; - } - if ("cluster".equals(key)) { - return AnyValue.MergeFunction.REPLACE; - } - if ("cache".equals(key)) { - return AnyValue.MergeFunction.REPLACE; - } - if ("schedule".equals(key)) { - return AnyValue.MergeFunction.REPLACE; - } - if ("listener".equals(key)) { - if (Objects.equals(val1.getValue("value"), val2.getValue("value"))) { - return AnyValue.MergeFunction.SKIP; - } else { - return AnyValue.MergeFunction.NONE; - } - } - if ("mq".equals(key)) { - if (Objects.equals(val1.getValue("name"), val2.getValue("name"))) { - return AnyValue.MergeFunction.REPLACE; - } else { - return AnyValue.MergeFunction.NONE; - } - } - if ("group".equals(key)) { - if (Objects.equals(val1.getValue("name"), val2.getValue("name"))) { - return AnyValue.MergeFunction.REPLACE; - } else { - return AnyValue.MergeFunction.NONE; - } - } - 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.MergeFunction.REPLACE; - } else { - return AnyValue.MergeFunction.NONE; - } - } - } - if ("cachesource".equals(path)) { - return AnyValue.MergeFunction.REPLACE; - } - if ("datasource".equals(path)) { - return AnyValue.MergeFunction.REPLACE; - } - if ("properties".equals(path)) { - if ("property".equals(key)) { - if (Objects.equals(val1.getValue("name"), val2.getValue("name"))) { - return AnyValue.MergeFunction.REPLACE; - } else { - return AnyValue.MergeFunction.NONE; - } - } - } - if ("server".equals(path)) { - if ("ssl".equals(key)) { - return AnyValue.MergeFunction.REPLACE; - } - if ("render".equals(key)) { - return AnyValue.MergeFunction.REPLACE; - } - if ("resource-servlet".equals(key)) { - return AnyValue.MergeFunction.REPLACE; - } - } - if ("server.request".equals(path)) { - if ("remoteaddr".equals(key)) { - return AnyValue.MergeFunction.REPLACE; - } - if ("rpc".equals(key)) { - return AnyValue.MergeFunction.REPLACE; - } - if ("locale".equals(key)) { - if (Objects.equals(val1.getValue("name"), val2.getValue("name"))) { - return AnyValue.MergeFunction.REPLACE; - } else { - return AnyValue.MergeFunction.NONE; - } - } - } - if ("server.response".equals(path)) { - if ("content-type".equals(key)) { - return AnyValue.MergeFunction.REPLACE; - } - if ("defcookie".equals(key)) { - return AnyValue.MergeFunction.REPLACE; - } - if ("options".equals(key)) { - return AnyValue.MergeFunction.REPLACE; - } - if ("date".equals(key)) { - return AnyValue.MergeFunction.REPLACE; - } - if ("addheader".equals(key) || "setheader".equals(key)) { - if (Objects.equals(val1.getValue("name"), val2.getValue("name"))) { - return AnyValue.MergeFunction.REPLACE; - } else { - return AnyValue.MergeFunction.NONE; - } - } - } - return AnyValue.MergeFunction.MERGE; - }; - } diff --git a/src/main/java/org/redkale/boot/Application.java b/src/main/java/org/redkale/boot/Application.java index bd52ce34f..1aa5b61d7 100644 --- a/src/main/java/org/redkale/boot/Application.java +++ b/src/main/java/org/redkale/boot/Application.java @@ -76,12 +76,6 @@ public final class Application { */ public static final String RESNAME_APP_CONF_DIR = "APP_CONF_DIR"; - /** - * 当前进程的配置文件, 类型:String、URI、File、Path
- * 一般命名为: application.xml、application.onlyLogProps, 若配置文件不是本地文件, 则File、Path类型的值为null - */ - public static final String RESNAME_APP_CONF_FILE = "APP_CONF_FILE"; - /** * 当前进程节点的nodeid, 类型:int */ @@ -127,15 +121,29 @@ public final class Application { */ public static final String RESNAME_SERVER_RESFACTORY = "SERVER_RESFACTORY"; + public static final String SYSNAME_APP_NAME = "redkale.application.name"; + + public static final String SYSNAME_APP_NODEID = "redkale.application.nodeid"; + + public static final String SYSNAME_APP_HOME = "redkale.application.home"; + + public static final String SYSNAME_APP_CONF_DIR = "redkale.application.confdir"; + + public static final Set REDKALE_RESNAMES = Collections.unmodifiableSet(Set.of( + RESNAME_APP_NAME, + RESNAME_APP_NODEID, + RESNAME_APP_TIME, + RESNAME_APP_HOME, + RESNAME_APP_ADDR, + RESNAME_APP_CONF_DIR + )); + //UDP协议的ByteBuffer Capacity private static final int UDP_CAPACITY = 1024; //日志 private final Logger logger = Logger.getLogger(this.getClass().getSimpleName()); - //系统初始化时的原始配置项,启动后是不可更改的配置项 - final Set sysPropNames; - //本进程节点ID final int nodeid; @@ -145,9 +153,9 @@ public final class Application { //本地IP地址 final InetSocketAddress localAddress; - //日志配置资源 + //日志组件 //@since 2.8.0 - final Properties loggingProperties = new Properties(); + final LoggingModule loggingModule = new LoggingModule(this); //NodeServer 资源, 顺序必须是sncps, others, watchs final List servers = new CopyOnWriteArrayList<>(); @@ -163,11 +171,10 @@ public final class Application { //给客户端使用,包含SNCP客户端、自定义数据库客户端连接池 private AsyncIOGroup clientAsyncGroup; - //配置源管理接口 - //@since 2.7.0 - private PropertiesAgent propertiesAgent; + //配置组件 + final PropertiesModule propertiesModule = new PropertiesModule(this); - //所有配置项,包含本地配置项、logging配置项和配置中心获取的配置项 + //除logging配置之外的所有配置项,包含本地和远程配置项 final Properties envProperties = new Properties(); //配置信息,只读版Properties @@ -192,11 +199,8 @@ public final class Application { //进程根目录 private final File home; - //进程根目录 - private final String homePath; - //配置文件目录 - private final URI confPath; + private final URI confDir; //监听事件 private final List listeners = new CopyOnWriteArrayList<>(); @@ -240,18 +244,17 @@ public final class Application { this.name = appConfig.name; this.nodeid = appConfig.nodeid; this.home = appConfig.home; - this.homePath = appConfig.homePath; - this.confPath = appConfig.confPath; + this.confDir = appConfig.confDir; this.localAddress = appConfig.localAddress; this.classLoader = appConfig.classLoader; this.serverClassLoader = appConfig.serverClassLoader; //设置基础信息资源 this.resourceFactory.register(RESNAME_APP_NAME, String.class, this.name); - + this.resourceFactory.register(RESNAME_APP_NODEID, int.class, this.nodeid); this.resourceFactory.register(RESNAME_APP_NODEID, Integer.class, this.nodeid); - + this.resourceFactory.register(RESNAME_APP_TIME, long.class, this.startTime); this.resourceFactory.register(RESNAME_APP_TIME, Long.class, this.startTime); @@ -264,30 +267,25 @@ public final class Application { this.resourceFactory.register(RESNAME_APP_ADDR, InetAddress.class, this.localAddress.getAddress()); this.resourceFactory.register(RESNAME_APP_ADDR, String.class, this.localAddress.getAddress().getHostAddress()); - this.resourceFactory.register(RESNAME_APP_CONF_DIR, URI.class, this.confPath); + this.resourceFactory.register(RESNAME_APP_CONF_DIR, URI.class, this.confDir); this.resourceFactory.register(RESNAME_APP_CONF_DIR, File.class, appConfig.confFile); - this.resourceFactory.register(RESNAME_APP_CONF_DIR, String.class, this.confPath.toString()); + this.resourceFactory.register(RESNAME_APP_CONF_DIR, String.class, this.confDir.toString()); System.setProperty("redkale.version", Redkale.getDotedVersion()); - System.setProperty("redkale.application.name", this.name); - System.setProperty("redkale.application.nodeid", String.valueOf(this.nodeid)); - System.setProperty("redkale.application.home", this.home.getPath()); - System.setProperty("redkale.application.confPath", this.confPath.toString()); + System.setProperty(SYSNAME_APP_NAME, this.name); + System.setProperty(SYSNAME_APP_NODEID, String.valueOf(this.nodeid)); + System.setProperty(SYSNAME_APP_HOME, this.home.getPath()); + System.setProperty(SYSNAME_APP_CONF_DIR, this.confDir.toString()); + this.envProperties.put(RESNAME_APP_NAME, this.name); this.envProperties.put(RESNAME_APP_NODEID, String.valueOf(this.nodeid)); this.envProperties.put(RESNAME_APP_TIME, String.valueOf(this.startTime)); this.envProperties.put(RESNAME_APP_HOME, this.home.getPath()); this.envProperties.put(RESNAME_APP_ADDR, this.localAddress.getAddress().getHostAddress()); - this.envProperties.put(RESNAME_APP_CONF_DIR, this.confPath.toString()); + this.envProperties.put(RESNAME_APP_CONF_DIR, this.confDir.toString()); - this.sysPropNames = Collections.unmodifiableSet((Set) System.getProperties().keySet()); - //初始化本地配置的System.properties - appConfig.localSysProperties.forEach((k, v) -> { - String key = k.toString(); - if (System.getProperty(key) == null) { - System.setProperty(key, getPropertyValue(v.toString(), appConfig.localSysProperties)); - } - }); + //初始化本地配置的System.properties、mimetypes + this.registerResourceEnvs(true, appConfig.localEnvProperties); //需要在加载properties初始化System.properties之后再注册 this.resourceFactory.register(Environment.class, environment); @@ -309,12 +307,12 @@ public final class Application { moduleEngines.add(new ScheduleModuleEngine(this)); //根据本地日志配置文件初始化日志 - reconfigLogging(true, appConfig.locaLogProperties); + loggingModule.reconfigLogging(true, appConfig.locaLogProperties); //打印基础信息日志 logger.log(Level.INFO, colorMessage(logger, 36, 1, "-------------------------------- Redkale " + Redkale.getDotedVersion() + " --------------------------------")); - final String confDir = this.confPath.toString(); + final String confDir = this.confDir.toString(); logger.log(Level.INFO, "APP_OS = " + System.getProperty("os.name") + " " + System.getProperty("os.version") + " " + System.getProperty("os.arch") + "\r\n" + "APP_JAVA = " + System.getProperty("java.runtime.name", System.getProperty("org.graalvm.nativeimage.kind") != null ? "Nativeimage" : "") + " " + System.getProperty("java.runtime.version", System.getProperty("java.vendor.version", System.getProperty("java.vm.version"))) + "\r\n" //graalvm.nativeimage 模式下无 java.runtime.xxx 属性 @@ -323,11 +321,11 @@ public final class Application { + RESNAME_APP_NODEID + " = " + this.nodeid + "\r\n" + "APP_LOADER = " + this.classLoader.getClass().getSimpleName() + "\r\n" + RESNAME_APP_ADDR + " = " + this.localAddress.getHostString() + ":" + this.localAddress.getPort() + "\r\n" - + RESNAME_APP_HOME + " = " + homePath + "\r\n" + + RESNAME_APP_HOME + " = " + this.home.getPath().replace('\\', '/') + "\r\n" + RESNAME_APP_CONF_DIR + " = " + confDir.substring(confDir.indexOf('!') + 1)); if (!compileMode && !(classLoader instanceof RedkaleClassLoader.RedkaleCacheClassLoader)) { - String lib = getPropertyValue(config.getValue("lib", "${APP_HOME}/libs/*").trim()); + String lib = environment.getPropertyValue(config.getValue("lib", "${APP_HOME}/libs/*").trim()); lib = Utility.isEmpty(lib) ? confDir : (lib + ";" + confDir); Server.loadLib(classLoader, logger, lib.isEmpty() ? confDir : (lib + ";" + confDir)); } @@ -337,8 +335,8 @@ public final class Application { public void init() throws Exception { //注册ResourceType this.initResourceTypeLoader(); - //读取远程配置 - this.initRemoteProperties(); + //读取远程配置,并合并app.config + this.propertiesModule.initRemoteProperties(); //解析配置 this.onEnvironmentLoaded(); //init起始回调 @@ -351,6 +349,25 @@ public final class Application { this.onAppPostInit(); } + private void registerResourceEnvs(boolean first, Properties... envs) { + for (Properties props : envs) { + props.forEach((k, v) -> { + String val = environment.getPropertyValue(v.toString(), envs); + if (k.toString().startsWith("system.property.")) { + String key = k.toString().substring("system.property.".length()); + if (System.getProperty(key) == null || !first) { + System.setProperty(key, val); + } + resourceFactory.register(!first, k.toString(), val); + } else if (k.toString().startsWith("mimetype.property.")) { + MimeType.add(k.toString().substring("mimetype.property.".length()), val); + } else { + resourceFactory.register(!first, k.toString(), val); + } + }); + } + } + /** * 设置WorkExecutor */ @@ -366,11 +383,11 @@ public final class Application { ? WorkThread.createExecutor(workThreads, "Redkale-WorkThread-%s") : WorkThread.createWorkExecutor(workThreads, "Redkale-WorkThread-%s"); String executorName = this.workExecutor.getClass().getSimpleName(); - executorLog.append("defaultWorkExecutor: {type=" + executorName); + executorLog.append("defaultWorkExecutor: {type=").append(executorName); if (executorName.contains("VirtualExecutor") || executorName.contains("PerTaskExecutor")) { executorLog.append(", threads=[virtual]}"); } else { - executorLog.append(", threads=" + workThreads + "}"); + executorLog.append(", threads=").append(workThreads).append("}"); } ExecutorService clientWorkExecutor = this.workExecutor; @@ -380,7 +397,7 @@ public final class Application { //给所有client给一个新的默认ExecutorService int clientThreads = executorConf.getIntValue("clients", Utility.cpus() * 4); clientWorkExecutor = WorkThread.createWorkExecutor(clientThreads, "Redkale-DefaultClient-WorkThread-%s"); - executorLog.append(", threads=" + clientThreads + "}"); + executorLog.append(", threads=").append(clientThreads).append("}"); } AsyncIOGroup ioGroup = new AsyncIOGroup("Redkale-DefaultClient-IOThread-%s", clientWorkExecutor, bufferCapacity, bufferPoolSize).skipClose(true); this.clientAsyncGroup = ioGroup.start(); @@ -594,263 +611,6 @@ public final class Application { //------------------------------------------------------------------------ } - private void initRemoteProperties() { - final Properties dyncProps = new Properties(); - final AtomicInteger propertyIndex = new AtomicInteger(); - 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"); - } - } - if (propsConf != null) { - final Properties remoteEnvs = new Properties(); - //可能通过系统环境变量配置信息 - Iterator it = ServiceLoader.load(PropertiesAgentProvider.class, classLoader).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(); - this.resourceFactory.inject(this.propertiesAgent); - if (compileMode) { - this.propertiesAgent.compile(propsConf); - } else { - Map propMap = this.propertiesAgent.init(this, 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; - } - - final Properties oldEnvs = new Properties(); - for (AnyValue prop : propsConf.getAnyValues("property")) { - String key = prop.getValue("name"); - String value = prop.getValue("value"); - if (key == null || value == null) { - continue; - } - oldEnvs.put(key, value); - } - remoteEnvs.forEach((k, v) -> { - if (k.toString().startsWith("redkale.")) { - dyncProps.put(k, v); - } else { - oldEnvs.put(k, v); //新配置项会覆盖旧的 - } - }); - //原有properties节点上的属性同步到dyncEnvs - propsConf.forEach((k, v) -> dyncProps.put("redkale.properties[" + k + "]", v)); - oldEnvs.forEach((k, v) -> { //去重后的配置项 - String prefix = "redkale.properties.property[" + propertyIndex.getAndIncrement() + "]"; - dyncProps.put(prefix + ".name", k); - dyncProps.put(prefix + ".value", v); - }); - //移除旧节点 - ((AnyValueWriter) this.config).removeAnyValues("properties"); - } - //环境变量的优先级最高 - System.getProperties().forEach((k, v) -> { - if (k.toString().startsWith("redkale.executor.") //节点全局唯一 - || k.toString().startsWith("redkale.transport.") //节点全局唯一 - || k.toString().startsWith("redkale.cluster.") //节点全局唯一 - || k.toString().startsWith("redkale.cache.") //节点全局唯一 - || k.toString().startsWith("redkale.schedule.") //节点全局唯一 - || k.toString().startsWith("redkale.mq.") - || k.toString().startsWith("redkale.mq[") - || k.toString().startsWith("redkale.group.") - || k.toString().startsWith("redkale.group[") - || k.toString().startsWith("redkale.listener.") - || k.toString().startsWith("redkale.listener[") - || k.toString().startsWith("redkale.server.") - || k.toString().startsWith("redkale.server[")) { - dyncProps.put(k, v); - } else if (k.toString().startsWith("redkale.properties.")) { - if (k.toString().startsWith("redkale.properties.property.") - || k.toString().startsWith("redkale.properties.property[")) { - dyncProps.put(k, v); - } else { - //支持系统变量 -Dredkale.onlyLogProps.mykey=my-value - String prefix = "redkale.properties.property[" + propertyIndex.getAndIncrement() + "]"; - dyncProps.put(prefix + ".name", k.toString().substring("redkale.properties.".length())); - dyncProps.put(prefix + ".value", v); - } - } - }); - - if (!dyncProps.isEmpty()) { - Properties newDyncProps = new Properties(); - dyncProps.forEach((k, v) -> newDyncProps.put(k.toString(), getPropertyValue(v.toString(), dyncProps))); - //合并配置 - this.config.merge(AnyValue.loadFromProperties(newDyncProps).getAnyValue("redkale"), AppConfig.APP_CONFIG_MERGE_FUNC); - } - //使用合并后的新配置节点 - propsConf = this.config.getAnyValue("properties"); - if (propsConf != null) { - //清除property节点数组的下坐标 - ((AnyValueWriter) propsConf).clearParentArrayIndex("property"); - //注入配置项 - for (AnyValue prop : propsConf.getAnyValues("property")) { - String key = prop.getValue("name"); - String value = prop.getValue("value"); - if (key == null) { - continue; - } - value = value == null ? value : getPropertyValue(value, dyncProps); - if (key.startsWith("system.property.")) { - String propName = key.substring("system.property.".length()); - if (System.getProperty(propName) == null) { //命令行传参数优先级高 - System.setProperty(propName, value); - } - } else if (key.startsWith("mimetype.property.")) { - MimeType.add(key.substring("mimetype.property.".length()), value); - } else { - this.envProperties.put(key, value); - resourceFactory.register(false, key, value); - } - } - } - //重置远程日志配置 - if (logProps != null && !logProps.isEmpty()) { - reconfigLogging(false, logProps); - } - } - - /** - * 设置日志策略 - * - * @param first 是否首次设置 - * @param allProps 配置项全量 - */ - void reconfigLogging(boolean first, Properties allProps) { - String searchRawHandler = "java.util.logging.SearchHandler"; - String searchReadHandler = LoggingSearchHandler.class.getName(); - Properties onlyLogProps = new Properties(); - - allProps.entrySet().forEach(x -> { - String key = x.getKey().toString(); - if (key.startsWith("java.util.logging.") || key.contains(".level") || key.contains("handlers")) { - String val = 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 (compileMode) { - 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 (compileMode) { - 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 (!compileMode) { //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", singletonMode || compileMode ? "" : 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 (!compileMode) { - onlyLogProps.put(SncpClient.class.getSimpleName() + ".handlers", LoggingFileHandler.LoggingSncpFileHandler.class.getName()); - } - } - if (compileMode) { - 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 = this; - } - } - } - } catch (IOException e) { //不会发生 - } - } - private static String colorMessage(Logger logger, int color, int type, String msg) { final boolean linux = System.getProperty("os.name").toLowerCase(Locale.ENGLISH).contains("linux"); if (linux) { //Windows PowerShell 也能正常着色 @@ -1093,7 +853,7 @@ public final class Application { */ private void onAppPreStart() { for (ApplicationListener listener : this.listeners) { - listener.preStart(this); + listener.onPreStart(this); } for (ModuleEngine item : moduleEngines) { item.onAppPostInit(); @@ -1105,7 +865,7 @@ public final class Application { */ private void onAppPostStart() { for (ApplicationListener listener : this.listeners) { - listener.postStart(this); + listener.onPostStart(this); } for (ModuleEngine item : moduleEngines) { item.onAppPostStart(); @@ -1118,6 +878,7 @@ public final class Application { * @param props 配置项全量 */ private void onEnvironmentLoaded() { + this.registerResourceEnvs(true, this.envProperties); for (ModuleEngine item : moduleEngines) { item.onEnvironmentLoaded(this.envProperties); } @@ -1129,7 +890,7 @@ public final class Application { * @param namespace 命名空间 * @param events 变更项 */ - private void onEnvironmentChanged(String namespace, List events) { + void onEnvironmentChanged(String namespace, List events) { for (ModuleEngine item : moduleEngines) { item.onEnvironmentChanged(namespace, events); } @@ -1193,6 +954,9 @@ public final class Application { * 服务全部停掉前被调用 */ private void onServersPreStop() { + for (ApplicationListener listener : listeners) { + listener.onServersPreStop(this); + } for (ModuleEngine item : moduleEngines) { item.onServersPreStop(); } @@ -1202,6 +966,9 @@ public final class Application { * 服务全部停掉后被调用 */ private void onServersPostStop() { + for (ApplicationListener listener : listeners) { + listener.onServersPostStop(this); + } for (ModuleEngine item : moduleEngines) { item.onServersPostStop(); } @@ -1213,7 +980,7 @@ public final class Application { private void onAppPreShutdown() { for (ApplicationListener listener : this.listeners) { try { - listener.preShutdown(this); + listener.onPreShutdown(this); } catch (Exception e) { logger.log(Level.WARNING, listener.getClass() + " preShutdown erroneous", e); } @@ -1234,13 +1001,19 @@ public final class Application { void onPreCompile() { for (ApplicationListener listener : listeners) { - listener.preCompile(this); + listener.onPreCompile(this); + } + for (ModuleEngine item : moduleEngines) { + item.onPreCompile(); } } void onPostCompile() { for (ApplicationListener listener : listeners) { - listener.postCompile(this); + listener.onPostCompile(this); + } + for (ModuleEngine item : moduleEngines) { + item.onPostCompile(); } } @@ -1293,6 +1066,10 @@ public final class Application { ClassFilter.Loader.load(getHome(), this.serverClassLoader, filters); } + List getModuleEngines() { + return moduleEngines; + } + //使用了nohup或使用了后台&,Runtime.getRuntime().addShutdownHook失效 private void signalShutdownHandle() { Consumer> signalShutdownConsumer = Utility.signalShutdownConsumer(); @@ -1479,7 +1256,7 @@ public final class Application { if (args != null && args.length > 0) { for (int i = 0; i < args.length; i++) { if (args[i] != null && args[i].toLowerCase().startsWith("--conf-file=")) { - System.setProperty(RESNAME_APP_CONF_FILE, args[i].substring("--conf-file=".length())); + System.setProperty(AppConfig.PARAM_APP_CONF_FILE, args[i].substring("--conf-file=".length())); String[] newargs = new String[args.length - 1]; System.arraycopy(args, 0, newargs, 0, i); System.arraycopy(args, i + 1, newargs, i, args.length - 1 - i); @@ -1537,49 +1314,6 @@ public final class Application { System.exit(0); //必须要有 } - public String getPropertyValue(String value, Properties... envs) { - if (value == null || value.isBlank()) { - return value; - } - final String val = value; - //${domain}/${path}/xxx ${aa${bbb}} - int pos2 = val.indexOf("}"); - int pos1 = val.lastIndexOf("${", pos2); - if (pos1 >= 0 && pos2 > 0) { - String key = val.substring(pos1 + 2, pos2); - String newVal = null; - if (RESNAME_APP_NAME.equals(key)) { - newVal = getName(); - } else if (RESNAME_APP_HOME.equals(key)) { - newVal = getHome().getPath().replace('\\', '/'); - } else if (RESNAME_APP_NODEID.equals(key)) { - newVal = String.valueOf(getNodeid()); - } else if (RESNAME_APP_TIME.equals(key)) { - newVal = String.valueOf(getStartTime()); - } else { - List 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 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 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 en : entrys) { Class 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; }