Application优化
This commit is contained in:
@@ -398,7 +398,7 @@ public final class ApiDocCommand {
|
|||||||
try (FileOutputStream out = new FileOutputStream(new File(app.getHome(), "apidoc.json"))) {
|
try (FileOutputStream out = new FileOutputStream(new File(app.getHome(), "apidoc.json"))) {
|
||||||
out.write(json.getBytes(StandardCharsets.UTF_8));
|
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;
|
InputStream in = null;
|
||||||
if (doctemplate.isFile() && doctemplate.canRead()) {
|
if (doctemplate.isFile() && doctemplate.canRead()) {
|
||||||
in = new FileInputStream(doctemplate);
|
in = new FileInputStream(doctemplate);
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ import java.util.ArrayList;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.logging.SimpleFormatter;
|
import java.util.logging.SimpleFormatter;
|
||||||
@@ -36,6 +35,12 @@ import org.redkale.util.Utility;
|
|||||||
*/
|
*/
|
||||||
class AppConfig {
|
class AppConfig {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当前进程的配置文件, 类型:String、URI、File、Path <br>
|
||||||
|
* 一般命名为: application.xml、application.onlyLogProps, 若配置文件不是本地文件, 则File、Path类型的值为null
|
||||||
|
*/
|
||||||
|
static final String PARAM_APP_CONF_FILE = "APP_CONF_FILE";
|
||||||
|
|
||||||
//是否用于main方法运行
|
//是否用于main方法运行
|
||||||
final boolean singletonMode;
|
final boolean singletonMode;
|
||||||
|
|
||||||
@@ -57,20 +62,14 @@ class AppConfig {
|
|||||||
//本地IP地址
|
//本地IP地址
|
||||||
InetSocketAddress localAddress;
|
InetSocketAddress localAddress;
|
||||||
|
|
||||||
//配置信息Properties
|
|
||||||
Properties envProperties;
|
|
||||||
//进程根目录
|
//进程根目录
|
||||||
|
|
||||||
File home;
|
File home;
|
||||||
|
|
||||||
//进程根目录
|
|
||||||
String homePath;
|
|
||||||
|
|
||||||
//配置文件目录
|
//配置文件目录
|
||||||
File confFile;
|
File confFile;
|
||||||
|
|
||||||
//配置文件目录
|
//配置文件目录
|
||||||
URI confPath;
|
URI confDir;
|
||||||
|
|
||||||
//根ClassLoader
|
//根ClassLoader
|
||||||
RedkaleClassLoader classLoader;
|
RedkaleClassLoader classLoader;
|
||||||
@@ -78,15 +77,12 @@ class AppConfig {
|
|||||||
//Server根ClassLoader
|
//Server根ClassLoader
|
||||||
RedkaleClassLoader serverClassLoader;
|
RedkaleClassLoader serverClassLoader;
|
||||||
|
|
||||||
//本地文件所有的配置项, 包含system.property.开头的
|
|
||||||
final Properties localEnvProperties = new Properties();
|
|
||||||
|
|
||||||
//本地文件设置System.properties且不存于System.properties的配置项
|
|
||||||
final Properties localSysProperties = new Properties();
|
|
||||||
|
|
||||||
//本地文件日志配置项
|
//本地文件日志配置项
|
||||||
final Properties locaLogProperties = new Properties();
|
final Properties locaLogProperties = new Properties();
|
||||||
|
|
||||||
|
//本地文件除logging配置之外的所有的配置项, 包含system.property.、mimetype.property.开头的
|
||||||
|
final Properties localEnvProperties = new Properties();
|
||||||
|
|
||||||
public AppConfig(boolean singletonMode, boolean compileMode) {
|
public AppConfig(boolean singletonMode, boolean compileMode) {
|
||||||
this.singletonMode = singletonMode;
|
this.singletonMode = singletonMode;
|
||||||
this.compileMode = compileMode;
|
this.compileMode = compileMode;
|
||||||
@@ -105,7 +101,7 @@ class AppConfig {
|
|||||||
this.configFromCache = "true".equals(config.getValue("[config-from-cache]"));
|
this.configFromCache = "true".equals(config.getValue("[config-from-cache]"));
|
||||||
//初始化classLoader、serverClassLoader
|
//初始化classLoader、serverClassLoader
|
||||||
this.initClassLoader();
|
this.initClassLoader();
|
||||||
//初始化home、confPath、localAddress等信息
|
//初始化home、confDir、localAddress等信息
|
||||||
this.initAppHome();
|
this.initAppHome();
|
||||||
//读取本地参数配置
|
//读取本地参数配置
|
||||||
this.initLocalProperties();
|
this.initLocalProperties();
|
||||||
@@ -156,26 +152,25 @@ class AppConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 初始化home、confPath、localAddress等信息
|
* 初始化home、confDir、localAddress等信息
|
||||||
*/
|
*/
|
||||||
private void initAppHome() {
|
private void initAppHome() {
|
||||||
final File root = new File(System.getProperty(RESNAME_APP_HOME, ""));
|
final File root = new File(System.getProperty(RESNAME_APP_HOME, ""));
|
||||||
final String rootPath = getCanonicalPath(root);
|
final String rootPath = getCanonicalPath(root);
|
||||||
this.home = new File(rootPath);
|
this.home = new File(rootPath);
|
||||||
this.homePath = this.home.getPath();
|
|
||||||
String confDir = System.getProperty(RESNAME_APP_CONF_DIR, "conf");
|
String confDir = System.getProperty(RESNAME_APP_CONF_DIR, "conf");
|
||||||
if (confDir.contains("://") || confDir.startsWith("file:")
|
if (confDir.contains("://") || confDir.startsWith("file:")
|
||||||
|| confDir.startsWith("resource:") || confDir.contains("!")) { //graalvm native-image startwith resource:META-INF
|
|| 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:")) {
|
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) {
|
} else if (confDir.charAt(0) == '/' || confDir.indexOf(':') > -1) {
|
||||||
this.confFile = getCanonicalFile(new File(confDir));
|
this.confFile = getCanonicalFile(new File(confDir));
|
||||||
this.confPath = confFile.toURI();
|
this.confDir = confFile.toURI();
|
||||||
} else {
|
} else {
|
||||||
this.confFile = new File(getCanonicalPath(new File(this.home, confDir)));
|
this.confFile = new File(getCanonicalPath(new File(this.home, confDir)));
|
||||||
this.confPath = confFile.toURI();
|
this.confDir = confFile.toURI();
|
||||||
}
|
}
|
||||||
String localaddr = config.getValue("address", "").trim();
|
String localaddr = config.getValue("address", "").trim();
|
||||||
InetAddress addr = localaddr.isEmpty() ? Utility.localInetAddress() : new InetSocketAddress(localaddr, config.getIntValue("port")).getAddress();
|
InetAddress addr = localaddr.isEmpty() ? Utility.localInetAddress() : new InetSocketAddress(localaddr, config.getIntValue("port")).getAddress();
|
||||||
@@ -186,6 +181,12 @@ class AppConfig {
|
|||||||
* 读取本地参数配置
|
* 读取本地参数配置
|
||||||
*/
|
*/
|
||||||
private void initLocalProperties() {
|
private void initLocalProperties() {
|
||||||
|
//环境变量的优先级最高
|
||||||
|
System.getProperties().forEach((k, v) -> {
|
||||||
|
if (k.toString().startsWith("redkale.")) {
|
||||||
|
localEnvProperties.put(k, v);
|
||||||
|
}
|
||||||
|
});
|
||||||
AnyValue propsConf = this.config.getAnyValue("properties");
|
AnyValue propsConf = this.config.getAnyValue("properties");
|
||||||
if (propsConf == null) {
|
if (propsConf == null) {
|
||||||
final AnyValue resources = config.getAnyValue("resources");
|
final AnyValue resources = config.getAnyValue("resources");
|
||||||
@@ -200,12 +201,6 @@ class AppConfig {
|
|||||||
String value = prop.getValue("value");
|
String value = prop.getValue("value");
|
||||||
if (value != null) {
|
if (value != null) {
|
||||||
localEnvProperties.put(key, value);
|
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) { //加载本地配置项文件
|
if (propsConf.getValue("load") != null) { //加载本地配置项文件
|
||||||
@@ -213,7 +208,7 @@ class AppConfig {
|
|||||||
if (dfload.trim().isEmpty()) {
|
if (dfload.trim().isEmpty()) {
|
||||||
continue;
|
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) {
|
if (df == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -223,15 +218,6 @@ class AppConfig {
|
|||||||
InputStream in = df.toURL().openStream();
|
InputStream in = df.toURL().openStream();
|
||||||
props.load(in);
|
props.load(in);
|
||||||
in.close();
|
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);
|
localEnvProperties.putAll(props);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new RedkaleException(e);
|
throw new RedkaleException(e);
|
||||||
@@ -242,22 +228,21 @@ class AppConfig {
|
|||||||
}
|
}
|
||||||
//设置Convert默认配置项
|
//设置Convert默认配置项
|
||||||
if (System.getProperty("redkale.convert.pool.size") == null
|
if (System.getProperty("redkale.convert.pool.size") == null
|
||||||
&& localSysProperties.getProperty("redkale.convert.pool.size") == null) {
|
&& localEnvProperties.getProperty("system.property.redkale.convert.pool.size") == null) {
|
||||||
localSysProperties.put("redkale.convert.pool.size", "128");
|
localEnvProperties.put("system.property.redkale.convert.pool.size", "128");
|
||||||
}
|
}
|
||||||
if (System.getProperty("redkale.convert.writer.buffer.defsize") == null
|
if (System.getProperty("redkale.convert.writer.buffer.defsize") == null
|
||||||
&& localSysProperties.getProperty("redkale.convert.writer.buffer.defsize") == null) {
|
&& localEnvProperties.getProperty("system.property.redkale.convert.writer.buffer.defsize") == null) {
|
||||||
localSysProperties.put("redkale.convert.writer.buffer.defsize", "4096");
|
localEnvProperties.put("system.property.redkale.convert.writer.buffer.defsize", "4096");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 读取本地数据库配置
|
* 读取本地DataSource、CacheSource配置
|
||||||
*/
|
*/
|
||||||
private void initSourceProperties() {
|
private void initSourceProperties() {
|
||||||
//------------------------------------ 读取本地DataSource、CacheSource配置 ------------------------------------
|
if ("file".equals(this.confDir.getScheme())) {
|
||||||
if ("file".equals(this.confPath.getScheme())) {
|
File sourceFile = new File(new File(confDir), "source.properties");
|
||||||
File sourceFile = new File(new File(confPath), "source.properties");
|
|
||||||
if (sourceFile.isFile() && sourceFile.canRead()) {
|
if (sourceFile.isFile() && sourceFile.canRead()) {
|
||||||
Properties props = new Properties();
|
Properties props = new Properties();
|
||||||
try {
|
try {
|
||||||
@@ -267,19 +252,10 @@ class AppConfig {
|
|||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new RedkaleException(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);
|
this.localEnvProperties.putAll(props);
|
||||||
} else {
|
} else {
|
||||||
//兼容 persistence.xml 【已废弃】
|
//兼容 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()) {
|
if (persist.isFile() && persist.canRead()) {
|
||||||
System.err.println("persistence.xml is deprecated, replaced by source.properties");
|
System.err.println("persistence.xml is deprecated, replaced by source.properties");
|
||||||
try {
|
try {
|
||||||
@@ -293,20 +269,11 @@ class AppConfig {
|
|||||||
}
|
}
|
||||||
} else { //从url或jar文件中resources读取
|
} else { //从url或jar文件中resources读取
|
||||||
try {
|
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();
|
InputStream in = sourceURI.toURL().openStream();
|
||||||
Properties props = new Properties();
|
Properties props = new Properties();
|
||||||
props.load(in);
|
props.load(in);
|
||||||
in.close();
|
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);
|
this.localEnvProperties.putAll(props);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
//没有文件 跳过
|
//没有文件 跳过
|
||||||
@@ -322,25 +289,22 @@ class AppConfig {
|
|||||||
File logConfFile = null;
|
File logConfFile = null;
|
||||||
if (configFromCache) {
|
if (configFromCache) {
|
||||||
logConfURI = RedkaleClassLoader.getConfResourceAsURI(null, "logging.properties");
|
logConfURI = RedkaleClassLoader.getConfResourceAsURI(null, "logging.properties");
|
||||||
} else if ("file".equals(confPath.getScheme())) {
|
} else if ("file".equals(confDir.getScheme())) {
|
||||||
logConfFile = new File(confPath.getPath(), "logging.properties");
|
logConfFile = new File(confDir.getPath(), "logging.properties");
|
||||||
logConfURI = logConfFile.toURI();
|
logConfURI = logConfFile.toURI();
|
||||||
if (!logConfFile.isFile() || !logConfFile.canRead()) {
|
if (!logConfFile.isFile() || !logConfFile.canRead()) {
|
||||||
logConfFile = null;
|
logConfFile = null;
|
||||||
}
|
}
|
||||||
} else {
|
} 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 {
|
try {
|
||||||
InputStream fin = logConfURI.toURL().openStream();
|
InputStream fin = logConfURI.toURL().openStream();
|
||||||
Properties properties0 = new Properties();
|
Properties properties0 = new Properties();
|
||||||
properties0.load(fin);
|
properties0.load(fin);
|
||||||
fin.close();
|
fin.close();
|
||||||
properties0.forEach((k, v) -> {
|
properties0.forEach(locaLogProperties::put);
|
||||||
locaLogProperties.put(k.toString(), v.toString());
|
|
||||||
localEnvProperties.put(k.toString(), v.toString());
|
|
||||||
});
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new RedkaleException("read logging.properties error", e);
|
throw new RedkaleException("read logging.properties error", e);
|
||||||
}
|
}
|
||||||
@@ -364,7 +328,7 @@ class AppConfig {
|
|||||||
*/
|
*/
|
||||||
static AnyValue loadAppConfig() throws IOException {
|
static AnyValue loadAppConfig() throws IOException {
|
||||||
final String home = new File(System.getProperty(RESNAME_APP_HOME, "")).getCanonicalPath().replace('\\', '/');
|
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) {
|
if (sysConfFile != null) {
|
||||||
String text;
|
String text;
|
||||||
if (sysConfFile.contains("://")) {
|
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;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -76,12 +76,6 @@ public final class Application {
|
|||||||
*/
|
*/
|
||||||
public static final String RESNAME_APP_CONF_DIR = "APP_CONF_DIR";
|
public static final String RESNAME_APP_CONF_DIR = "APP_CONF_DIR";
|
||||||
|
|
||||||
/**
|
|
||||||
* 当前进程的配置文件, 类型:String、URI、File、Path <br>
|
|
||||||
* 一般命名为: application.xml、application.onlyLogProps, 若配置文件不是本地文件, 则File、Path类型的值为null
|
|
||||||
*/
|
|
||||||
public static final String RESNAME_APP_CONF_FILE = "APP_CONF_FILE";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 当前进程节点的nodeid, 类型:int
|
* 当前进程节点的nodeid, 类型:int
|
||||||
*/
|
*/
|
||||||
@@ -127,15 +121,29 @@ public final class Application {
|
|||||||
*/
|
*/
|
||||||
public static final String RESNAME_SERVER_RESFACTORY = "SERVER_RESFACTORY";
|
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<String> 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
|
//UDP协议的ByteBuffer Capacity
|
||||||
private static final int UDP_CAPACITY = 1024;
|
private static final int UDP_CAPACITY = 1024;
|
||||||
|
|
||||||
//日志
|
//日志
|
||||||
private final Logger logger = Logger.getLogger(this.getClass().getSimpleName());
|
private final Logger logger = Logger.getLogger(this.getClass().getSimpleName());
|
||||||
|
|
||||||
//系统初始化时的原始配置项,启动后是不可更改的配置项
|
|
||||||
final Set<String> sysPropNames;
|
|
||||||
|
|
||||||
//本进程节点ID
|
//本进程节点ID
|
||||||
final int nodeid;
|
final int nodeid;
|
||||||
|
|
||||||
@@ -145,9 +153,9 @@ public final class Application {
|
|||||||
//本地IP地址
|
//本地IP地址
|
||||||
final InetSocketAddress localAddress;
|
final InetSocketAddress localAddress;
|
||||||
|
|
||||||
//日志配置资源
|
//日志组件
|
||||||
//@since 2.8.0
|
//@since 2.8.0
|
||||||
final Properties loggingProperties = new Properties();
|
final LoggingModule loggingModule = new LoggingModule(this);
|
||||||
|
|
||||||
//NodeServer 资源, 顺序必须是sncps, others, watchs
|
//NodeServer 资源, 顺序必须是sncps, others, watchs
|
||||||
final List<NodeServer> servers = new CopyOnWriteArrayList<>();
|
final List<NodeServer> servers = new CopyOnWriteArrayList<>();
|
||||||
@@ -163,11 +171,10 @@ public final class Application {
|
|||||||
//给客户端使用,包含SNCP客户端、自定义数据库客户端连接池
|
//给客户端使用,包含SNCP客户端、自定义数据库客户端连接池
|
||||||
private AsyncIOGroup clientAsyncGroup;
|
private AsyncIOGroup clientAsyncGroup;
|
||||||
|
|
||||||
//配置源管理接口
|
//配置组件
|
||||||
//@since 2.7.0
|
final PropertiesModule propertiesModule = new PropertiesModule(this);
|
||||||
private PropertiesAgent propertiesAgent;
|
|
||||||
|
|
||||||
//所有配置项,包含本地配置项、logging配置项和配置中心获取的配置项
|
//除logging配置之外的所有配置项,包含本地和远程配置项
|
||||||
final Properties envProperties = new Properties();
|
final Properties envProperties = new Properties();
|
||||||
|
|
||||||
//配置信息,只读版Properties
|
//配置信息,只读版Properties
|
||||||
@@ -192,11 +199,8 @@ public final class Application {
|
|||||||
//进程根目录
|
//进程根目录
|
||||||
private final File home;
|
private final File home;
|
||||||
|
|
||||||
//进程根目录
|
|
||||||
private final String homePath;
|
|
||||||
|
|
||||||
//配置文件目录
|
//配置文件目录
|
||||||
private final URI confPath;
|
private final URI confDir;
|
||||||
|
|
||||||
//监听事件
|
//监听事件
|
||||||
private final List<ApplicationListener> listeners = new CopyOnWriteArrayList<>();
|
private final List<ApplicationListener> listeners = new CopyOnWriteArrayList<>();
|
||||||
@@ -240,8 +244,7 @@ public final class Application {
|
|||||||
this.name = appConfig.name;
|
this.name = appConfig.name;
|
||||||
this.nodeid = appConfig.nodeid;
|
this.nodeid = appConfig.nodeid;
|
||||||
this.home = appConfig.home;
|
this.home = appConfig.home;
|
||||||
this.homePath = appConfig.homePath;
|
this.confDir = appConfig.confDir;
|
||||||
this.confPath = appConfig.confPath;
|
|
||||||
this.localAddress = appConfig.localAddress;
|
this.localAddress = appConfig.localAddress;
|
||||||
this.classLoader = appConfig.classLoader;
|
this.classLoader = appConfig.classLoader;
|
||||||
this.serverClassLoader = appConfig.serverClassLoader;
|
this.serverClassLoader = appConfig.serverClassLoader;
|
||||||
@@ -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, InetAddress.class, this.localAddress.getAddress());
|
||||||
this.resourceFactory.register(RESNAME_APP_ADDR, String.class, this.localAddress.getAddress().getHostAddress());
|
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, 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.version", Redkale.getDotedVersion());
|
||||||
System.setProperty("redkale.application.name", this.name);
|
System.setProperty(SYSNAME_APP_NAME, this.name);
|
||||||
System.setProperty("redkale.application.nodeid", String.valueOf(this.nodeid));
|
System.setProperty(SYSNAME_APP_NODEID, String.valueOf(this.nodeid));
|
||||||
System.setProperty("redkale.application.home", this.home.getPath());
|
System.setProperty(SYSNAME_APP_HOME, this.home.getPath());
|
||||||
System.setProperty("redkale.application.confPath", this.confPath.toString());
|
System.setProperty(SYSNAME_APP_CONF_DIR, this.confDir.toString());
|
||||||
|
|
||||||
this.envProperties.put(RESNAME_APP_NAME, this.name);
|
this.envProperties.put(RESNAME_APP_NAME, this.name);
|
||||||
this.envProperties.put(RESNAME_APP_NODEID, String.valueOf(this.nodeid));
|
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_TIME, String.valueOf(this.startTime));
|
||||||
this.envProperties.put(RESNAME_APP_HOME, this.home.getPath());
|
this.envProperties.put(RESNAME_APP_HOME, this.home.getPath());
|
||||||
this.envProperties.put(RESNAME_APP_ADDR, this.localAddress.getAddress().getHostAddress());
|
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、mimetypes
|
||||||
//初始化本地配置的System.properties
|
this.registerResourceEnvs(true, appConfig.localEnvProperties);
|
||||||
appConfig.localSysProperties.forEach((k, v) -> {
|
|
||||||
String key = k.toString();
|
|
||||||
if (System.getProperty(key) == null) {
|
|
||||||
System.setProperty(key, getPropertyValue(v.toString(), appConfig.localSysProperties));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
//需要在加载properties初始化System.properties之后再注册
|
//需要在加载properties初始化System.properties之后再注册
|
||||||
this.resourceFactory.register(Environment.class, environment);
|
this.resourceFactory.register(Environment.class, environment);
|
||||||
@@ -309,12 +307,12 @@ public final class Application {
|
|||||||
moduleEngines.add(new ScheduleModuleEngine(this));
|
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() + " --------------------------------"));
|
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"
|
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" : "")
|
+ "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 属性
|
+ " " + 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"
|
+ RESNAME_APP_NODEID + " = " + this.nodeid + "\r\n"
|
||||||
+ "APP_LOADER = " + this.classLoader.getClass().getSimpleName() + "\r\n"
|
+ "APP_LOADER = " + this.classLoader.getClass().getSimpleName() + "\r\n"
|
||||||
+ RESNAME_APP_ADDR + " = " + this.localAddress.getHostString() + ":" + this.localAddress.getPort() + "\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));
|
+ RESNAME_APP_CONF_DIR + " = " + confDir.substring(confDir.indexOf('!') + 1));
|
||||||
|
|
||||||
if (!compileMode && !(classLoader instanceof RedkaleClassLoader.RedkaleCacheClassLoader)) {
|
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);
|
lib = Utility.isEmpty(lib) ? confDir : (lib + ";" + confDir);
|
||||||
Server.loadLib(classLoader, logger, lib.isEmpty() ? 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 {
|
public void init() throws Exception {
|
||||||
//注册ResourceType
|
//注册ResourceType
|
||||||
this.initResourceTypeLoader();
|
this.initResourceTypeLoader();
|
||||||
//读取远程配置
|
//读取远程配置,并合并app.config
|
||||||
this.initRemoteProperties();
|
this.propertiesModule.initRemoteProperties();
|
||||||
//解析配置
|
//解析配置
|
||||||
this.onEnvironmentLoaded();
|
this.onEnvironmentLoaded();
|
||||||
//init起始回调
|
//init起始回调
|
||||||
@@ -351,6 +349,25 @@ public final class Application {
|
|||||||
this.onAppPostInit();
|
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
|
* 设置WorkExecutor
|
||||||
*/
|
*/
|
||||||
@@ -366,11 +383,11 @@ public final class Application {
|
|||||||
? WorkThread.createExecutor(workThreads, "Redkale-WorkThread-%s")
|
? WorkThread.createExecutor(workThreads, "Redkale-WorkThread-%s")
|
||||||
: WorkThread.createWorkExecutor(workThreads, "Redkale-WorkThread-%s");
|
: WorkThread.createWorkExecutor(workThreads, "Redkale-WorkThread-%s");
|
||||||
String executorName = this.workExecutor.getClass().getSimpleName();
|
String executorName = this.workExecutor.getClass().getSimpleName();
|
||||||
executorLog.append("defaultWorkExecutor: {type=" + executorName);
|
executorLog.append("defaultWorkExecutor: {type=").append(executorName);
|
||||||
if (executorName.contains("VirtualExecutor") || executorName.contains("PerTaskExecutor")) {
|
if (executorName.contains("VirtualExecutor") || executorName.contains("PerTaskExecutor")) {
|
||||||
executorLog.append(", threads=[virtual]}");
|
executorLog.append(", threads=[virtual]}");
|
||||||
} else {
|
} else {
|
||||||
executorLog.append(", threads=" + workThreads + "}");
|
executorLog.append(", threads=").append(workThreads).append("}");
|
||||||
}
|
}
|
||||||
|
|
||||||
ExecutorService clientWorkExecutor = this.workExecutor;
|
ExecutorService clientWorkExecutor = this.workExecutor;
|
||||||
@@ -380,7 +397,7 @@ public final class Application {
|
|||||||
//给所有client给一个新的默认ExecutorService
|
//给所有client给一个新的默认ExecutorService
|
||||||
int clientThreads = executorConf.getIntValue("clients", Utility.cpus() * 4);
|
int clientThreads = executorConf.getIntValue("clients", Utility.cpus() * 4);
|
||||||
clientWorkExecutor = WorkThread.createWorkExecutor(clientThreads, "Redkale-DefaultClient-WorkThread-%s");
|
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);
|
AsyncIOGroup ioGroup = new AsyncIOGroup("Redkale-DefaultClient-IOThread-%s", clientWorkExecutor, bufferCapacity, bufferPoolSize).skipClose(true);
|
||||||
this.clientAsyncGroup = ioGroup.start();
|
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, "<resources> in application config file is deprecated");
|
|
||||||
propsConf = resources.getAnyValue("properties");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (propsConf != null) {
|
|
||||||
final Properties remoteEnvs = new Properties();
|
|
||||||
//可能通过系统环境变量配置信息
|
|
||||||
Iterator<PropertiesAgentProvider> it = ServiceLoader.load(PropertiesAgentProvider.class, classLoader).iterator();
|
|
||||||
RedkaleClassLoader.putServiceLoader(PropertiesAgentProvider.class);
|
|
||||||
List<PropertiesAgentProvider> 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<String, Properties> propMap = this.propertiesAgent.init(this, propsConf);
|
|
||||||
int propCount = 0;
|
|
||||||
if (propMap != null) {
|
|
||||||
for (Map.Entry<String, Properties> 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<String> 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) {
|
private static String colorMessage(Logger logger, int color, int type, String msg) {
|
||||||
final boolean linux = System.getProperty("os.name").toLowerCase(Locale.ENGLISH).contains("linux");
|
final boolean linux = System.getProperty("os.name").toLowerCase(Locale.ENGLISH).contains("linux");
|
||||||
if (linux) { //Windows PowerShell 也能正常着色
|
if (linux) { //Windows PowerShell 也能正常着色
|
||||||
@@ -1093,7 +853,7 @@ public final class Application {
|
|||||||
*/
|
*/
|
||||||
private void onAppPreStart() {
|
private void onAppPreStart() {
|
||||||
for (ApplicationListener listener : this.listeners) {
|
for (ApplicationListener listener : this.listeners) {
|
||||||
listener.preStart(this);
|
listener.onPreStart(this);
|
||||||
}
|
}
|
||||||
for (ModuleEngine item : moduleEngines) {
|
for (ModuleEngine item : moduleEngines) {
|
||||||
item.onAppPostInit();
|
item.onAppPostInit();
|
||||||
@@ -1105,7 +865,7 @@ public final class Application {
|
|||||||
*/
|
*/
|
||||||
private void onAppPostStart() {
|
private void onAppPostStart() {
|
||||||
for (ApplicationListener listener : this.listeners) {
|
for (ApplicationListener listener : this.listeners) {
|
||||||
listener.postStart(this);
|
listener.onPostStart(this);
|
||||||
}
|
}
|
||||||
for (ModuleEngine item : moduleEngines) {
|
for (ModuleEngine item : moduleEngines) {
|
||||||
item.onAppPostStart();
|
item.onAppPostStart();
|
||||||
@@ -1118,6 +878,7 @@ public final class Application {
|
|||||||
* @param props 配置项全量
|
* @param props 配置项全量
|
||||||
*/
|
*/
|
||||||
private void onEnvironmentLoaded() {
|
private void onEnvironmentLoaded() {
|
||||||
|
this.registerResourceEnvs(true, this.envProperties);
|
||||||
for (ModuleEngine item : moduleEngines) {
|
for (ModuleEngine item : moduleEngines) {
|
||||||
item.onEnvironmentLoaded(this.envProperties);
|
item.onEnvironmentLoaded(this.envProperties);
|
||||||
}
|
}
|
||||||
@@ -1129,7 +890,7 @@ public final class Application {
|
|||||||
* @param namespace 命名空间
|
* @param namespace 命名空间
|
||||||
* @param events 变更项
|
* @param events 变更项
|
||||||
*/
|
*/
|
||||||
private void onEnvironmentChanged(String namespace, List<ResourceEvent> events) {
|
void onEnvironmentChanged(String namespace, List<ResourceEvent> events) {
|
||||||
for (ModuleEngine item : moduleEngines) {
|
for (ModuleEngine item : moduleEngines) {
|
||||||
item.onEnvironmentChanged(namespace, events);
|
item.onEnvironmentChanged(namespace, events);
|
||||||
}
|
}
|
||||||
@@ -1193,6 +954,9 @@ public final class Application {
|
|||||||
* 服务全部停掉前被调用
|
* 服务全部停掉前被调用
|
||||||
*/
|
*/
|
||||||
private void onServersPreStop() {
|
private void onServersPreStop() {
|
||||||
|
for (ApplicationListener listener : listeners) {
|
||||||
|
listener.onServersPreStop(this);
|
||||||
|
}
|
||||||
for (ModuleEngine item : moduleEngines) {
|
for (ModuleEngine item : moduleEngines) {
|
||||||
item.onServersPreStop();
|
item.onServersPreStop();
|
||||||
}
|
}
|
||||||
@@ -1202,6 +966,9 @@ public final class Application {
|
|||||||
* 服务全部停掉后被调用
|
* 服务全部停掉后被调用
|
||||||
*/
|
*/
|
||||||
private void onServersPostStop() {
|
private void onServersPostStop() {
|
||||||
|
for (ApplicationListener listener : listeners) {
|
||||||
|
listener.onServersPostStop(this);
|
||||||
|
}
|
||||||
for (ModuleEngine item : moduleEngines) {
|
for (ModuleEngine item : moduleEngines) {
|
||||||
item.onServersPostStop();
|
item.onServersPostStop();
|
||||||
}
|
}
|
||||||
@@ -1213,7 +980,7 @@ public final class Application {
|
|||||||
private void onAppPreShutdown() {
|
private void onAppPreShutdown() {
|
||||||
for (ApplicationListener listener : this.listeners) {
|
for (ApplicationListener listener : this.listeners) {
|
||||||
try {
|
try {
|
||||||
listener.preShutdown(this);
|
listener.onPreShutdown(this);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
logger.log(Level.WARNING, listener.getClass() + " preShutdown erroneous", e);
|
logger.log(Level.WARNING, listener.getClass() + " preShutdown erroneous", e);
|
||||||
}
|
}
|
||||||
@@ -1234,13 +1001,19 @@ public final class Application {
|
|||||||
|
|
||||||
void onPreCompile() {
|
void onPreCompile() {
|
||||||
for (ApplicationListener listener : listeners) {
|
for (ApplicationListener listener : listeners) {
|
||||||
listener.preCompile(this);
|
listener.onPreCompile(this);
|
||||||
|
}
|
||||||
|
for (ModuleEngine item : moduleEngines) {
|
||||||
|
item.onPreCompile();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void onPostCompile() {
|
void onPostCompile() {
|
||||||
for (ApplicationListener listener : listeners) {
|
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);
|
ClassFilter.Loader.load(getHome(), this.serverClassLoader, filters);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
List<ModuleEngine> getModuleEngines() {
|
||||||
|
return moduleEngines;
|
||||||
|
}
|
||||||
|
|
||||||
//使用了nohup或使用了后台&,Runtime.getRuntime().addShutdownHook失效
|
//使用了nohup或使用了后台&,Runtime.getRuntime().addShutdownHook失效
|
||||||
private void signalShutdownHandle() {
|
private void signalShutdownHandle() {
|
||||||
Consumer<Consumer<String>> signalShutdownConsumer = Utility.signalShutdownConsumer();
|
Consumer<Consumer<String>> signalShutdownConsumer = Utility.signalShutdownConsumer();
|
||||||
@@ -1479,7 +1256,7 @@ public final class Application {
|
|||||||
if (args != null && args.length > 0) {
|
if (args != null && args.length > 0) {
|
||||||
for (int i = 0; i < args.length; i++) {
|
for (int i = 0; i < args.length; i++) {
|
||||||
if (args[i] != null && args[i].toLowerCase().startsWith("--conf-file=")) {
|
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];
|
String[] newargs = new String[args.length - 1];
|
||||||
System.arraycopy(args, 0, newargs, 0, i);
|
System.arraycopy(args, 0, newargs, 0, i);
|
||||||
System.arraycopy(args, i + 1, newargs, i, args.length - 1 - i);
|
System.arraycopy(args, i + 1, newargs, i, args.length - 1 - i);
|
||||||
@@ -1537,49 +1314,6 @@ public final class Application {
|
|||||||
System.exit(0); //必须要有
|
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<Properties> 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() {
|
private static String generateHelp() {
|
||||||
return ""
|
return ""
|
||||||
+ "Usage: redkale [command] [arguments]\r\n"
|
+ "Usage: redkale [command] [arguments]\r\n"
|
||||||
@@ -1616,11 +1350,7 @@ public final class Application {
|
|||||||
long f = System.currentTimeMillis();
|
long f = System.currentTimeMillis();
|
||||||
this.onAppPreShutdown();
|
this.onAppPreShutdown();
|
||||||
stopServers();
|
stopServers();
|
||||||
if (this.propertiesAgent != null) {
|
this.propertiesModule.destroy();
|
||||||
long s = System.currentTimeMillis();
|
|
||||||
this.propertiesAgent.destroy(config.getAnyValue("properties"));
|
|
||||||
logger.info(this.propertiesAgent.getClass().getSimpleName() + " destroy in " + (System.currentTimeMillis() - s) + " ms");
|
|
||||||
}
|
|
||||||
if (this.workExecutor != null) {
|
if (this.workExecutor != null) {
|
||||||
this.workExecutor.shutdownNow();
|
this.workExecutor.shutdownNow();
|
||||||
}
|
}
|
||||||
@@ -1699,8 +1429,8 @@ public final class Application {
|
|||||||
return home;
|
return home;
|
||||||
}
|
}
|
||||||
|
|
||||||
public URI getConfPath() {
|
public URI getConfDir() {
|
||||||
return confPath;
|
return confDir;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getStartTime() {
|
public long getStartTime() {
|
||||||
|
|||||||
@@ -28,42 +28,58 @@ public interface ApplicationListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Application 在运行start前调用
|
* Application在运行start前调用
|
||||||
*
|
*
|
||||||
* @param application Application
|
* @param application Application
|
||||||
*/
|
*/
|
||||||
default void preStart(Application application) {
|
default void onPreStart(Application application) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Application 在运行start后调用
|
* 服务全部停掉前被调用
|
||||||
*
|
*
|
||||||
* @param application Application
|
* @param application Application
|
||||||
*/
|
*/
|
||||||
default void postStart(Application application) {
|
default void onServersPreStop(Application application) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Application 在运行Compile前调用
|
* 服务全部停掉后被调用
|
||||||
*
|
*
|
||||||
* @param application Application
|
* @param application Application
|
||||||
*/
|
*/
|
||||||
default void preCompile(Application application) {
|
default void onServersPostStop(Application application) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Application 在运行Compile后调用
|
* Application在运行start后调用
|
||||||
*
|
*
|
||||||
* @param application Application
|
* @param application Application
|
||||||
*/
|
*/
|
||||||
default void postCompile(Application application) {
|
default void onPostStart(Application application) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Application 在运行shutdown前调用
|
* Application在运行Compile前调用
|
||||||
*
|
*
|
||||||
* @param application Application
|
* @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) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
180
src/main/java/org/redkale/boot/LoggingModule.java
Normal file
180
src/main/java/org/redkale/boot/LoggingModule.java
Normal file
@@ -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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 日志模块组件
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* 详情见: 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<ResourceEvent> events) {
|
||||||
|
Set<String> 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<String> 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) { //不会发生
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,6 +10,7 @@ import java.util.logging.*;
|
|||||||
import java.util.logging.Formatter;
|
import java.util.logging.Formatter;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
import static org.redkale.boot.Application.RESNAME_APP_NAME;
|
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.*;
|
||||||
import org.redkale.convert.json.JsonConvert;
|
import org.redkale.convert.json.JsonConvert;
|
||||||
import org.redkale.persistence.*;
|
import org.redkale.persistence.*;
|
||||||
@@ -160,7 +161,7 @@ public class LoggingSearchHandler extends LoggingBaseHandler {
|
|||||||
if (!checkTagName(tagStr.replaceAll("\\$\\{.+\\}", ""))) {
|
if (!checkTagName(tagStr.replaceAll("\\$\\{.+\\}", ""))) {
|
||||||
throw new RedkaleException("found illegal logging.property " + cname + ".tag = " + tagStr);
|
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("%")) {
|
if (this.tag.contains("%")) {
|
||||||
this.tagDateFormat = this.tag;
|
this.tagDateFormat = this.tag;
|
||||||
Times.formatTime(this.tagDateFormat, -1, System.currentTimeMillis()); //测试时间格式是否正确
|
Times.formatTime(this.tagDateFormat, -1, System.currentTimeMillis()); //测试时间格式是否正确
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import java.util.List;
|
|||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
import org.redkale.service.Service;
|
import org.redkale.service.Service;
|
||||||
|
import org.redkale.util.AnyValue;
|
||||||
import org.redkale.util.Environment;
|
import org.redkale.util.Environment;
|
||||||
import org.redkale.util.ResourceEvent;
|
import org.redkale.util.ResourceEvent;
|
||||||
import org.redkale.util.ResourceFactory;
|
import org.redkale.util.ResourceFactory;
|
||||||
@@ -38,6 +39,20 @@ public abstract class ModuleEngine {
|
|||||||
this.environment = application.getEnvironment();
|
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方法时被调用
|
* 进入Application.init方法时被调用
|
||||||
* 此时状态:
|
* 此时状态:
|
||||||
@@ -88,6 +103,22 @@ public abstract class ModuleEngine {
|
|||||||
//do nothing
|
//do nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Application 在运行Compile前调用
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public void onPreCompile() {
|
||||||
|
//do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Application 在运行Compile后调用
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public void onPostCompile() {
|
||||||
|
//do nothing
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 服务全部启动前被调用
|
* 服务全部启动前被调用
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -174,7 +174,7 @@ public abstract class NodeServer {
|
|||||||
this.sncpAddress, new ClientAddress(this.sncpAddress), server.getNetprotocol(), Utility.cpus(), 1000);
|
this.sncpAddress, new ClientAddress(this.sncpAddress), server.getNetprotocol(), Utility.cpus(), 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
initResource(); //给DataSource、CacheSource注册依赖注入时的监听回调事件。
|
registerResTypeLoader(); //给DataSource、CacheSource注册依赖注入时的监听回调事件。
|
||||||
String interceptorClass = this.serverConf.getValue("interceptor", "");
|
String interceptorClass = this.serverConf.getValue("interceptor", "");
|
||||||
if (!interceptorClass.isEmpty()) {
|
if (!interceptorClass.isEmpty()) {
|
||||||
Class clazz = serverClassLoader.loadClass(interceptorClass);
|
Class clazz = serverClassLoader.loadClass(interceptorClass);
|
||||||
@@ -238,155 +238,12 @@ public abstract class NodeServer {
|
|||||||
|
|
||||||
protected abstract void loadServlet(ClassFilter<? extends Servlet> servletFilter) throws Exception;
|
protected abstract void loadServlet(ClassFilter<? extends Servlet> servletFilter) throws Exception;
|
||||||
|
|
||||||
private void initResource() {
|
private void registerResTypeLoader() {
|
||||||
|
//--------------------- 注册 Local AutoLoad(false) Service ---------------------
|
||||||
|
resourceFactory.register(this::loadService, Service.class);
|
||||||
|
//----------------------------- 注册 WebSocketNode -----------------------------
|
||||||
final NodeServer self = this;
|
final NodeServer self = this;
|
||||||
//---------------------------------------------------------------------------------------------
|
|
||||||
final ResourceFactory appResFactory = application.getResourceFactory();
|
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<Service> 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() {
|
resourceFactory.register(new ResourceTypeLoader() {
|
||||||
@Override
|
@Override
|
||||||
public Object load(ResourceFactory rf, String srcResourceName, final Object srcObj, final String resourceName, Field field, final Object attachment) {
|
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);
|
}, 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<Service> 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")
|
@SuppressWarnings("unchecked")
|
||||||
protected void loadService(ClassFilter<? extends Service> serviceFilter) throws Exception {
|
protected void loadService(ClassFilter<? extends Service> serviceFilter) throws Exception {
|
||||||
Objects.requireNonNull(serviceFilter);
|
Objects.requireNonNull(serviceFilter);
|
||||||
|
|||||||
@@ -3,10 +3,7 @@
|
|||||||
package org.redkale.boot;
|
package org.redkale.boot;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
|
||||||
import java.util.logging.Level;
|
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
import org.redkale.net.http.MimeType;
|
|
||||||
import org.redkale.util.*;
|
import org.redkale.util.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -25,9 +22,6 @@ public abstract class PropertiesAgent {
|
|||||||
|
|
||||||
protected final Logger logger = Logger.getLogger(this.getClass().getSimpleName());
|
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);
|
public abstract void destroy(AnyValue conf);
|
||||||
|
|
||||||
protected final void updateEnvironmentProperties(Application application, String namespace, List<ResourceEvent> events) {
|
/**
|
||||||
if (Utility.isEmpty(events)) {
|
* 响应配置项的变更
|
||||||
return;
|
*
|
||||||
}
|
* @param application Application
|
||||||
updateLock.lock();
|
* @param namespace 命名空间
|
||||||
try {
|
* @param events 变更项集合
|
||||||
Properties envRegisterProps = new Properties();
|
*/
|
||||||
Set<String> envRemovedKeys = new HashSet<>();
|
protected final void onEnvironmentUpdated(Application application, String namespace, List<ResourceEvent> events) {
|
||||||
Properties envChangedProps = new Properties();
|
application.propertiesModule.onEnvironmentUpdated(namespace, events);
|
||||||
|
|
||||||
// Set<String> sourceRemovedKeys = new HashSet<>();
|
|
||||||
// Properties sourceChangedProps = new Properties();
|
|
||||||
Set<String> loggingRemovedKeys = new HashSet<>();
|
|
||||||
Properties loggingChangedProps = new Properties();
|
|
||||||
|
|
||||||
// Set<String> clusterRemovedKeys = new HashSet<>();
|
|
||||||
// Properties clusterChangedProps = new Properties();
|
|
||||||
//
|
|
||||||
// Set<String> messageRemovedKeys = new HashSet<>();
|
|
||||||
// Properties messageChangedProps = new Properties();
|
|
||||||
for (ResourceEvent<String> 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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
323
src/main/java/org/redkale/boot/PropertiesModule.java
Normal file
323
src/main/java/org/redkale/boot/PropertiesModule.java
Normal file
@@ -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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 配置模块组件
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* 详情见: 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, "<resources> in application config file is deprecated");
|
||||||
|
propsConf = resources.getAnyValue("properties");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
final Properties remoteEnvs = new Properties();
|
||||||
|
if (propsConf != null) {
|
||||||
|
//可能通过系统环境变量配置信息
|
||||||
|
Iterator<PropertiesAgentProvider> it = ServiceLoader.load(PropertiesAgentProvider.class, application.getClassLoader()).iterator();
|
||||||
|
RedkaleClassLoader.putServiceLoader(PropertiesAgentProvider.class);
|
||||||
|
List<PropertiesAgentProvider> 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<String, Properties> propMap = this.propertiesAgent.init(application, propsConf);
|
||||||
|
int propCount = 0;
|
||||||
|
if (propMap != null) {
|
||||||
|
for (Map.Entry<String, Properties> 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<ResourceEvent> events) {
|
||||||
|
if (Utility.isEmpty(events)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
updateLock.lock();
|
||||||
|
try {
|
||||||
|
if (namespace != null && namespace.contains("logging")) {
|
||||||
|
//日志配置单独处理
|
||||||
|
application.loggingModule.onEnvironmentUpdated(events);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Set<String> removedKeys = new HashSet<>();
|
||||||
|
Properties newEnvs = new Properties(application.envProperties);
|
||||||
|
for (ResourceEvent<String> 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<String> 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;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -20,6 +20,24 @@ public class CacheModuleEngine extends ModuleEngine {
|
|||||||
super(application);
|
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方法前被调用
|
* 结束Application.init方法前被调用
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ public class ClusterModuleEngine extends ModuleEngine {
|
|||||||
AnyValue clusterConf = application.getAppConfig().getAnyValue("cluster");
|
AnyValue clusterConf = application.getAppConfig().getAnyValue("cluster");
|
||||||
if (clusterConf != null) {
|
if (clusterConf != null) {
|
||||||
try {
|
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
|
if (classVal == null || classVal.isEmpty() || classVal.indexOf('.') < 0) { //不包含.表示非类名,比如值: consul, nacos
|
||||||
Iterator<ClusterAgentProvider> it = ServiceLoader.load(ClusterAgentProvider.class, application.getClassLoader()).iterator();
|
Iterator<ClusterAgentProvider> it = ServiceLoader.load(ClusterAgentProvider.class, application.getClassLoader()).iterator();
|
||||||
RedkaleClassLoader.putServiceLoader(ClusterAgentProvider.class);
|
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方法被调用
|
* 进入Application.start方法被调用
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public void onAppPreStart() {
|
public void onAppPreStart() {
|
||||||
if (!application.isSingletonMode() && !application.isCompileMode() && this.clusterAgent != null) {
|
if (!application.isSingletonMode() && !application.isCompileMode() && this.clusterAgent != null) {
|
||||||
this.clusterAgent.register(application);
|
this.clusterAgent.register(application);
|
||||||
|
|||||||
@@ -48,6 +48,9 @@ public abstract class MessageAgent implements Resourcable {
|
|||||||
@Resource(required = false)
|
@Resource(required = false)
|
||||||
protected Application application;
|
protected Application application;
|
||||||
|
|
||||||
|
@Resource(required = false)
|
||||||
|
protected Environment environment;
|
||||||
|
|
||||||
@Resource(name = RESNAME_APP_NODEID)
|
@Resource(name = RESNAME_APP_NODEID)
|
||||||
protected int nodeid;
|
protected int nodeid;
|
||||||
|
|
||||||
@@ -244,14 +247,14 @@ public abstract class MessageAgent implements Resourcable {
|
|||||||
Map<String, String> views = new LinkedHashMap<>();
|
Map<String, String> views = new LinkedHashMap<>();
|
||||||
for (MessageConsumer consumer : consumers) {
|
for (MessageConsumer consumer : consumers) {
|
||||||
ResourceConsumer res = consumer.getClass().getAnnotation(ResourceConsumer.class);
|
ResourceConsumer res = consumer.getClass().getAnnotation(ResourceConsumer.class);
|
||||||
String group = application.getPropertyValue(res.group());
|
String group = environment.getPropertyValue(res.group());
|
||||||
if (Utility.isBlank(group)) {
|
if (Utility.isBlank(group)) {
|
||||||
group = consumer.getClass().getName();
|
group = consumer.getClass().getName();
|
||||||
}
|
}
|
||||||
Map<String, MessageConsumerWrapper> map = maps.computeIfAbsent(group, g -> new HashMap<>());
|
Map<String, MessageConsumerWrapper> map = maps.computeIfAbsent(group, g -> new HashMap<>());
|
||||||
List<String> topics = new ArrayList<>();
|
List<String> topics = new ArrayList<>();
|
||||||
for (String t : res.topics()) {
|
for (String t : res.topics()) {
|
||||||
String topic = application.getPropertyValue(t);
|
String topic = environment.getPropertyValue(t);
|
||||||
if (!topic.trim().isEmpty()) {
|
if (!topic.trim().isEmpty()) {
|
||||||
topics.add(topic);
|
topics.add(topic);
|
||||||
if (map.containsKey(topic.trim())) {
|
if (map.containsKey(topic.trim())) {
|
||||||
|
|||||||
@@ -21,13 +21,13 @@ import org.redkale.boot.NodeServer;
|
|||||||
import org.redkale.convert.json.JsonConvert;
|
import org.redkale.convert.json.JsonConvert;
|
||||||
import org.redkale.net.http.RestException;
|
import org.redkale.net.http.RestException;
|
||||||
import org.redkale.util.AnyValue;
|
import org.redkale.util.AnyValue;
|
||||||
|
import org.redkale.util.AnyValueWriter;
|
||||||
import org.redkale.util.RedkaleClassLoader;
|
import org.redkale.util.RedkaleClassLoader;
|
||||||
import org.redkale.util.RedkaleException;
|
import org.redkale.util.RedkaleException;
|
||||||
import org.redkale.util.ResourceAnnotationProvider;
|
import org.redkale.util.ResourceAnnotationProvider;
|
||||||
import org.redkale.util.ResourceEvent;
|
import org.redkale.util.ResourceEvent;
|
||||||
import org.redkale.util.ResourceFactory;
|
import org.redkale.util.ResourceFactory;
|
||||||
import org.redkale.util.ResourceTypeLoader;
|
import org.redkale.util.ResourceTypeLoader;
|
||||||
import org.redkale.util.AnyValueWriter;
|
|
||||||
import org.redkale.util.Utility;
|
import org.redkale.util.Utility;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -48,6 +48,28 @@ public class MessageModuleEngine extends ModuleEngine {
|
|||||||
super(application);
|
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<String> mqnames = new HashSet<>();
|
Set<String> mqnames = new HashSet<>();
|
||||||
for (int i = 0; i < mqConfs.length; i++) {
|
for (int i = 0; i < mqConfs.length; i++) {
|
||||||
AnyValue mqConf = mqConfs[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()) {
|
if (names != null && !names.isEmpty()) {
|
||||||
for (String n : names.replace(',', ';').split(";")) {
|
for (String n : names.replace(',', ';').split(";")) {
|
||||||
if (n.trim().isEmpty()) {
|
if (n.trim().isEmpty()) {
|
||||||
@@ -98,7 +120,7 @@ public class MessageModuleEngine extends ModuleEngine {
|
|||||||
mqnames.add(n);
|
mqnames.add(n);
|
||||||
}
|
}
|
||||||
try {
|
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
|
if (classVal == null || classVal.isEmpty() || classVal.indexOf('.') < 0) { //不包含.表示非类名,比如值: kafka, pulsar
|
||||||
Iterator<MessageAgentProvider> it = ServiceLoader.load(MessageAgentProvider.class, application.getClassLoader()).iterator();
|
Iterator<MessageAgentProvider> it = ServiceLoader.load(MessageAgentProvider.class, application.getClassLoader()).iterator();
|
||||||
RedkaleClassLoader.putServiceLoader(MessageAgentProvider.class);
|
RedkaleClassLoader.putServiceLoader(MessageAgentProvider.class);
|
||||||
@@ -343,7 +365,7 @@ public class MessageModuleEngine extends ModuleEngine {
|
|||||||
for (ClassFilter.FilterEntry<? extends MessageConsumer> en : entrys) {
|
for (ClassFilter.FilterEntry<? extends MessageConsumer> en : entrys) {
|
||||||
Class<? extends MessageConsumer> clazz = en.getType();
|
Class<? extends MessageConsumer> clazz = en.getType();
|
||||||
ResourceConsumer res = clazz.getAnnotation(ResourceConsumer.class);
|
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;
|
continue;
|
||||||
}
|
}
|
||||||
RedkaleClassLoader.putReflectionDeclaredConstructors(clazz, clazz.getName());
|
RedkaleClassLoader.putReflectionDeclaredConstructors(clazz, clazz.getName());
|
||||||
|
|||||||
@@ -31,14 +31,14 @@ import org.redkale.annotation.Nullable;
|
|||||||
import org.redkale.annotation.Resource;
|
import org.redkale.annotation.Resource;
|
||||||
import org.redkale.annotation.ResourceType;
|
import org.redkale.annotation.ResourceType;
|
||||||
import org.redkale.boot.Application;
|
import org.redkale.boot.Application;
|
||||||
|
import org.redkale.schedule.ScheduleManager;
|
||||||
|
import org.redkale.schedule.Scheduled;
|
||||||
import org.redkale.service.Local;
|
import org.redkale.service.Local;
|
||||||
import org.redkale.service.Service;
|
import org.redkale.service.Service;
|
||||||
import org.redkale.util.AnyValue;
|
import org.redkale.util.AnyValue;
|
||||||
import org.redkale.util.RedkaleClassLoader;
|
import org.redkale.util.RedkaleClassLoader;
|
||||||
import org.redkale.util.RedkaleException;
|
import org.redkale.util.RedkaleException;
|
||||||
import org.redkale.util.Utility;
|
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);
|
this.enabled = conf.getBoolValue("enabled", true);
|
||||||
if (this.enabled) {
|
if (this.enabled) {
|
||||||
if (this.propertyFunc == null && application != null) {
|
if (this.propertyFunc == null && application != null) {
|
||||||
UnaryOperator<String> func = application::getPropertyValue;
|
UnaryOperator<String> func = application.getEnvironment()::getPropertyValue;
|
||||||
this.propertyFunc = func;
|
this.propertyFunc = func;
|
||||||
}
|
}
|
||||||
this.scheduler = new ScheduledThreadPoolExecutor(Utility.cpus(), Utility.newThreadFactory("Scheduled-Task-Thread-%s"));
|
this.scheduler = new ScheduledThreadPoolExecutor(Utility.cpus(), Utility.newThreadFactory("Scheduled-Task-Thread-%s"));
|
||||||
|
|||||||
@@ -21,6 +21,24 @@ public class ScheduleModuleEngine extends ModuleEngine {
|
|||||||
super(application);
|
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方法前被调用
|
* 结束Application.init方法前被调用
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ import java.lang.reflect.*;
|
|||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.function.BiFunction;
|
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;
|
import org.redkale.util.RedkaleClassLoader;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -85,8 +87,8 @@ public @interface RetLabel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
File homePath = new File(System.getProperty("redkale.application.home", ""), "conf");
|
File homePath = new File(System.getProperty(SYSNAME_APP_HOME, ""), "conf");
|
||||||
File propPath = new File(System.getProperty("redkale.application.confPath", homePath.getPath()));
|
File propPath = new File(System.getProperty(SYSNAME_APP_CONF_DIR, homePath.getPath()));
|
||||||
if (propPath.isDirectory() && propPath.canRead()) {
|
if (propPath.isDirectory() && propPath.canRead()) {
|
||||||
final String prefix = clazz.getSimpleName().toLowerCase();
|
final String prefix = clazz.getSimpleName().toLowerCase();
|
||||||
for (File propFile : propPath.listFiles(f -> f.getName().startsWith(prefix) && f.getName().endsWith(".properties"))) {
|
for (File propFile : propPath.listFiles(f -> f.getName().startsWith(prefix) && f.getName().endsWith(".properties"))) {
|
||||||
|
|||||||
@@ -58,6 +58,27 @@ public class SourceModuleEngine extends ModuleEngine {
|
|||||||
super(application);
|
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 --------------------------------------------------------
|
//------------------------------------- 注册 DataSource --------------------------------------------------------
|
||||||
resourceFactory.register((ResourceFactory rf, String srcResourceName, final Object srcObj, String resourceName, Field field, final Object attachment) -> {
|
resourceFactory.register(new DataSourceLoader(), DataSource.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; //远程模式不得注入 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);
|
|
||||||
|
|
||||||
//------------------------------------- 注册 CacheSource --------------------------------------------------------
|
//------------------------------------- 注册 CacheSource --------------------------------------------------------
|
||||||
resourceFactory.register(new ResourceTypeLoader() {
|
resourceFactory.register(new CacheSourceLoader(), CacheSource.class);
|
||||||
@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);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -501,4 +473,61 @@ public class SourceModuleEngine extends ModuleEngine {
|
|||||||
return conf;
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,29 +33,32 @@ public abstract class AnyValue {
|
|||||||
* merge两节点是否覆盖的判断函数
|
* 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
|
* @return AnyValue
|
||||||
*/
|
*/
|
||||||
public abstract AnyValue merge(AnyValue node, MergeFunction func);
|
public abstract AnyValue merge(AnyValue node, MergeStrategy func);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 回调子节点
|
* 回调子节点
|
||||||
|
|||||||
@@ -180,11 +180,11 @@ public class AnyValueWriter extends AnyValue {
|
|||||||
* @return AnyValue
|
* @return AnyValue
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public AnyValueWriter merge(AnyValue node, MergeFunction func) {
|
public AnyValueWriter merge(AnyValue node, MergeStrategy func) {
|
||||||
return merge(node, "", 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) {
|
if (node0 == null) {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@@ -220,17 +220,17 @@ public class AnyValueWriter extends AnyValue {
|
|||||||
ok = true;
|
ok = true;
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
int funcVal = func.apply(path, en.name, en.value, item.value);
|
MergeEnum funcVal = func.apply(path, en.name, en.value, item.value);
|
||||||
if (funcVal == MergeFunction.MERGE) {
|
if (funcVal == MergeEnum.MERGE) {
|
||||||
String subPath = path.isEmpty() ? en.name : (path + "." + en.name);
|
String subPath = path.isEmpty() ? en.name : (path + "." + en.name);
|
||||||
((AnyValueWriter) item.value).merge(en.value, subPath, func);
|
((AnyValueWriter) item.value).merge(en.value, subPath, func);
|
||||||
ok = true;
|
ok = true;
|
||||||
break;
|
break;
|
||||||
} else if (funcVal == MergeFunction.REPLACE) {
|
} else if (funcVal == MergeEnum.REPLACE) {
|
||||||
item.value = en.value.copy();
|
item.value = en.value.copy();
|
||||||
ok = true;
|
ok = true;
|
||||||
break;
|
break;
|
||||||
} else if (funcVal == MergeFunction.SKIP) {
|
} else if (funcVal == MergeEnum.IGNORE) {
|
||||||
ok = true;
|
ok = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,8 @@ public interface ResourceTypeLoader {
|
|||||||
|
|
||||||
public Object load(ResourceFactory factory, String srcResourceName, Object srcObj, String resourceName, Field field, Object attachment);
|
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() {
|
default boolean autoNone() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user