Application优化

This commit is contained in:
redkale
2023-12-18 17:00:39 +08:00
parent 6cb0a05720
commit eb7c44de18
21 changed files with 954 additions and 927 deletions

View File

@@ -398,7 +398,7 @@ public final class ApiDocCommand {
try (FileOutputStream out = new FileOutputStream(new File(app.getHome(), "apidoc.json"))) {
out.write(json.getBytes(StandardCharsets.UTF_8));
}
File doctemplate = new File(app.getConfPath().toString(), "apidoc-template.html");
File doctemplate = new File(app.getConfDir().toString(), "apidoc-template.html");
InputStream in = null;
if (doctemplate.isFile() && doctemplate.canRead()) {
in = new FileInputStream(doctemplate);

View File

@@ -17,7 +17,6 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Objects;
import java.util.Properties;
import java.util.Set;
import java.util.logging.SimpleFormatter;
@@ -36,6 +35,12 @@ import org.redkale.util.Utility;
*/
class AppConfig {
/**
* 当前进程的配置文件, 类型String、URI、File、Path <br>
* 一般命名为: application.xml、application.onlyLogProps 若配置文件不是本地文件, 则File、Path类型的值为null
*/
static final String PARAM_APP_CONF_FILE = "APP_CONF_FILE";
//是否用于main方法运行
final boolean singletonMode;
@@ -57,20 +62,14 @@ class AppConfig {
//本地IP地址
InetSocketAddress localAddress;
//配置信息Properties
Properties envProperties;
//进程根目录
File home;
//进程根目录
String homePath;
//配置文件目录
File confFile;
//配置文件目录
URI confPath;
URI confDir;
//根ClassLoader
RedkaleClassLoader classLoader;
@@ -78,15 +77,12 @@ class AppConfig {
//Server根ClassLoader
RedkaleClassLoader serverClassLoader;
//本地文件所有的配置项, 包含system.property.开头的
final Properties localEnvProperties = new Properties();
//本地文件设置System.properties且不存于System.properties的配置项
final Properties localSysProperties = new Properties();
//本地文件日志配置项
final Properties locaLogProperties = new Properties();
//本地文件除logging配置之外的所有的配置项, 包含system.property.、mimetype.property.开头的
final Properties localEnvProperties = new Properties();
public AppConfig(boolean singletonMode, boolean compileMode) {
this.singletonMode = singletonMode;
this.compileMode = compileMode;
@@ -105,7 +101,7 @@ class AppConfig {
this.configFromCache = "true".equals(config.getValue("[config-from-cache]"));
//初始化classLoader、serverClassLoader
this.initClassLoader();
//初始化home、confPath、localAddress等信息
//初始化home、confDir、localAddress等信息
this.initAppHome();
//读取本地参数配置
this.initLocalProperties();
@@ -156,26 +152,25 @@ class AppConfig {
}
/**
* 初始化home、confPath、localAddress等信息
* 初始化home、confDir、localAddress等信息
*/
private void initAppHome() {
final File root = new File(System.getProperty(RESNAME_APP_HOME, ""));
final String rootPath = getCanonicalPath(root);
this.home = new File(rootPath);
this.homePath = this.home.getPath();
String confDir = System.getProperty(RESNAME_APP_CONF_DIR, "conf");
if (confDir.contains("://") || confDir.startsWith("file:")
|| confDir.startsWith("resource:") || confDir.contains("!")) { //graalvm native-image startwith resource:META-INF
this.confPath = URI.create(confDir);
this.confDir = URI.create(confDir);
if (confDir.startsWith("file:")) {
this.confFile = getCanonicalFile(new File(this.confPath.getPath()));
this.confFile = getCanonicalFile(new File(this.confDir.getPath()));
}
} else if (confDir.charAt(0) == '/' || confDir.indexOf(':') > -1) {
this.confFile = getCanonicalFile(new File(confDir));
this.confPath = confFile.toURI();
this.confDir = confFile.toURI();
} else {
this.confFile = new File(getCanonicalPath(new File(this.home, confDir)));
this.confPath = confFile.toURI();
this.confDir = confFile.toURI();
}
String localaddr = config.getValue("address", "").trim();
InetAddress addr = localaddr.isEmpty() ? Utility.localInetAddress() : new InetSocketAddress(localaddr, config.getIntValue("port")).getAddress();
@@ -186,6 +181,12 @@ class AppConfig {
* 读取本地参数配置
*/
private void initLocalProperties() {
//环境变量的优先级最高
System.getProperties().forEach((k, v) -> {
if (k.toString().startsWith("redkale.")) {
localEnvProperties.put(k, v);
}
});
AnyValue propsConf = this.config.getAnyValue("properties");
if (propsConf == null) {
final AnyValue resources = config.getAnyValue("resources");
@@ -200,12 +201,6 @@ class AppConfig {
String value = prop.getValue("value");
if (value != null) {
localEnvProperties.put(key, value);
if (key.startsWith("system.property.")) {
String propName = key.substring("system.property.".length());
if (System.getProperty(propName) == null) { //命令行传参数优先级高
localSysProperties.put(propName, value);
}
}
}
}
if (propsConf.getValue("load") != null) { //加载本地配置项文件
@@ -213,7 +208,7 @@ class AppConfig {
if (dfload.trim().isEmpty()) {
continue;
}
final URI df = RedkaleClassLoader.getConfResourceAsURI(configFromCache ? null : this.confPath.toString(), dfload.trim());
final URI df = RedkaleClassLoader.getConfResourceAsURI(configFromCache ? null : this.confDir.toString(), dfload.trim());
if (df == null) {
continue;
}
@@ -223,15 +218,6 @@ class AppConfig {
InputStream in = df.toURL().openStream();
props.load(in);
in.close();
props.forEach((x, y) -> {
String key = x.toString();
if (key.startsWith("system.property.")) {
String propName = key.substring("system.property.".length());
if (System.getProperty(propName) == null) { //命令行传参数优先级高
localSysProperties.put(propName, y.toString());
}
}
});
localEnvProperties.putAll(props);
} catch (Exception e) {
throw new RedkaleException(e);
@@ -242,22 +228,21 @@ class AppConfig {
}
//设置Convert默认配置项
if (System.getProperty("redkale.convert.pool.size") == null
&& localSysProperties.getProperty("redkale.convert.pool.size") == null) {
localSysProperties.put("redkale.convert.pool.size", "128");
&& localEnvProperties.getProperty("system.property.redkale.convert.pool.size") == null) {
localEnvProperties.put("system.property.redkale.convert.pool.size", "128");
}
if (System.getProperty("redkale.convert.writer.buffer.defsize") == null
&& localSysProperties.getProperty("redkale.convert.writer.buffer.defsize") == null) {
localSysProperties.put("redkale.convert.writer.buffer.defsize", "4096");
&& localEnvProperties.getProperty("system.property.redkale.convert.writer.buffer.defsize") == null) {
localEnvProperties.put("system.property.redkale.convert.writer.buffer.defsize", "4096");
}
}
/**
* 读取本地数据库配置
* 读取本地DataSource、CacheSource配置
*/
private void initSourceProperties() {
//------------------------------------ 读取本地DataSource、CacheSource配置 ------------------------------------
if ("file".equals(this.confPath.getScheme())) {
File sourceFile = new File(new File(confPath), "source.properties");
if ("file".equals(this.confDir.getScheme())) {
File sourceFile = new File(new File(confDir), "source.properties");
if (sourceFile.isFile() && sourceFile.canRead()) {
Properties props = new Properties();
try {
@@ -267,19 +252,10 @@ class AppConfig {
} catch (IOException e) {
throw new RedkaleException(e);
}
props.forEach((x, y) -> {
String key = x.toString();
if (key.startsWith("system.property.")) {
String propName = key.substring("system.property.".length());
if (System.getProperty(propName) == null) { //命令行传参数优先级高
localSysProperties.put(propName, y.toString());
}
}
});
this.localEnvProperties.putAll(props);
} else {
//兼容 persistence.xml 【已废弃】
File persist = new File(new File(confPath), "persistence.xml");
File persist = new File(new File(confDir), "persistence.xml");
if (persist.isFile() && persist.canRead()) {
System.err.println("persistence.xml is deprecated, replaced by source.properties");
try {
@@ -293,20 +269,11 @@ class AppConfig {
}
} else { //从url或jar文件中resources读取
try {
final URI sourceURI = RedkaleClassLoader.getConfResourceAsURI(configFromCache ? null : this.confPath.toString(), "source.properties");
final URI sourceURI = RedkaleClassLoader.getConfResourceAsURI(configFromCache ? null : this.confDir.toString(), "source.properties");
InputStream in = sourceURI.toURL().openStream();
Properties props = new Properties();
props.load(in);
in.close();
props.forEach((x, y) -> {
String key = x.toString();
if (key.startsWith("system.property.")) {
String propName = key.substring("system.property.".length());
if (System.getProperty(propName) == null) { //命令行传参数优先级高
localSysProperties.put(propName, y.toString());
}
}
});
this.localEnvProperties.putAll(props);
} catch (Exception e) {
//没有文件 跳过
@@ -322,25 +289,22 @@ class AppConfig {
File logConfFile = null;
if (configFromCache) {
logConfURI = RedkaleClassLoader.getConfResourceAsURI(null, "logging.properties");
} else if ("file".equals(confPath.getScheme())) {
logConfFile = new File(confPath.getPath(), "logging.properties");
} else if ("file".equals(confDir.getScheme())) {
logConfFile = new File(confDir.getPath(), "logging.properties");
logConfURI = logConfFile.toURI();
if (!logConfFile.isFile() || !logConfFile.canRead()) {
logConfFile = null;
}
} else {
logConfURI = URI.create(confPath + (confPath.toString().endsWith("/") ? "" : "/") + "logging.properties");
logConfURI = URI.create(confDir + (confDir.toString().endsWith("/") ? "" : "/") + "logging.properties");
}
if (!"file".equals(confPath.getScheme()) || logConfFile != null) {
if (!"file".equals(confDir.getScheme()) || logConfFile != null) {
try {
InputStream fin = logConfURI.toURL().openStream();
Properties properties0 = new Properties();
properties0.load(fin);
fin.close();
properties0.forEach((k, v) -> {
locaLogProperties.put(k.toString(), v.toString());
localEnvProperties.put(k.toString(), v.toString());
});
properties0.forEach(locaLogProperties::put);
} catch (IOException e) {
throw new RedkaleException("read logging.properties error", e);
}
@@ -364,7 +328,7 @@ class AppConfig {
*/
static AnyValue loadAppConfig() throws IOException {
final String home = new File(System.getProperty(RESNAME_APP_HOME, "")).getCanonicalPath().replace('\\', '/');
String sysConfFile = System.getProperty(RESNAME_APP_CONF_FILE);
String sysConfFile = System.getProperty(PARAM_APP_CONF_FILE);
if (sysConfFile != null) {
String text;
if (sysConfFile.contains("://")) {
@@ -483,113 +447,4 @@ class AppConfig {
}
}
static final AnyValue.MergeFunction APP_CONFIG_MERGE_FUNC = (path, key, val1, val2) -> {
if ("".equals(path)) {
if ("executor".equals(key)) {
return AnyValue.MergeFunction.REPLACE;
}
if ("cluster".equals(key)) {
return AnyValue.MergeFunction.REPLACE;
}
if ("cache".equals(key)) {
return AnyValue.MergeFunction.REPLACE;
}
if ("schedule".equals(key)) {
return AnyValue.MergeFunction.REPLACE;
}
if ("listener".equals(key)) {
if (Objects.equals(val1.getValue("value"), val2.getValue("value"))) {
return AnyValue.MergeFunction.SKIP;
} else {
return AnyValue.MergeFunction.NONE;
}
}
if ("mq".equals(key)) {
if (Objects.equals(val1.getValue("name"), val2.getValue("name"))) {
return AnyValue.MergeFunction.REPLACE;
} else {
return AnyValue.MergeFunction.NONE;
}
}
if ("group".equals(key)) {
if (Objects.equals(val1.getValue("name"), val2.getValue("name"))) {
return AnyValue.MergeFunction.REPLACE;
} else {
return AnyValue.MergeFunction.NONE;
}
}
if ("server".equals(key)) {
if (Objects.equals(val1.getValue("name", val1.getValue("protocol") + "_" + val1.getValue("port")),
val2.getValue("name", val2.getValue("protocol") + "_" + val2.getValue("port")))) {
return AnyValue.MergeFunction.REPLACE;
} else {
return AnyValue.MergeFunction.NONE;
}
}
}
if ("cachesource".equals(path)) {
return AnyValue.MergeFunction.REPLACE;
}
if ("datasource".equals(path)) {
return AnyValue.MergeFunction.REPLACE;
}
if ("properties".equals(path)) {
if ("property".equals(key)) {
if (Objects.equals(val1.getValue("name"), val2.getValue("name"))) {
return AnyValue.MergeFunction.REPLACE;
} else {
return AnyValue.MergeFunction.NONE;
}
}
}
if ("server".equals(path)) {
if ("ssl".equals(key)) {
return AnyValue.MergeFunction.REPLACE;
}
if ("render".equals(key)) {
return AnyValue.MergeFunction.REPLACE;
}
if ("resource-servlet".equals(key)) {
return AnyValue.MergeFunction.REPLACE;
}
}
if ("server.request".equals(path)) {
if ("remoteaddr".equals(key)) {
return AnyValue.MergeFunction.REPLACE;
}
if ("rpc".equals(key)) {
return AnyValue.MergeFunction.REPLACE;
}
if ("locale".equals(key)) {
if (Objects.equals(val1.getValue("name"), val2.getValue("name"))) {
return AnyValue.MergeFunction.REPLACE;
} else {
return AnyValue.MergeFunction.NONE;
}
}
}
if ("server.response".equals(path)) {
if ("content-type".equals(key)) {
return AnyValue.MergeFunction.REPLACE;
}
if ("defcookie".equals(key)) {
return AnyValue.MergeFunction.REPLACE;
}
if ("options".equals(key)) {
return AnyValue.MergeFunction.REPLACE;
}
if ("date".equals(key)) {
return AnyValue.MergeFunction.REPLACE;
}
if ("addheader".equals(key) || "setheader".equals(key)) {
if (Objects.equals(val1.getValue("name"), val2.getValue("name"))) {
return AnyValue.MergeFunction.REPLACE;
} else {
return AnyValue.MergeFunction.NONE;
}
}
}
return AnyValue.MergeFunction.MERGE;
};
}

View File

@@ -76,12 +76,6 @@ public final class Application {
*/
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
*/
@@ -127,15 +121,29 @@ public final class Application {
*/
public static final String RESNAME_SERVER_RESFACTORY = "SERVER_RESFACTORY";
public static final String SYSNAME_APP_NAME = "redkale.application.name";
public static final String SYSNAME_APP_NODEID = "redkale.application.nodeid";
public static final String SYSNAME_APP_HOME = "redkale.application.home";
public static final String SYSNAME_APP_CONF_DIR = "redkale.application.confdir";
public static final Set<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
private static final int UDP_CAPACITY = 1024;
//日志
private final Logger logger = Logger.getLogger(this.getClass().getSimpleName());
//系统初始化时的原始配置项,启动后是不可更改的配置项
final Set<String> sysPropNames;
//本进程节点ID
final int nodeid;
@@ -145,9 +153,9 @@ public final class Application {
//本地IP地址
final InetSocketAddress localAddress;
//日志配置资源
//日志组件
//@since 2.8.0
final Properties loggingProperties = new Properties();
final LoggingModule loggingModule = new LoggingModule(this);
//NodeServer 资源, 顺序必须是sncps, others, watchs
final List<NodeServer> servers = new CopyOnWriteArrayList<>();
@@ -163,11 +171,10 @@ public final class Application {
//给客户端使用包含SNCP客户端、自定义数据库客户端连接池
private AsyncIOGroup clientAsyncGroup;
//配置源管理接口
//@since 2.7.0
private PropertiesAgent propertiesAgent;
//配置组件
final PropertiesModule propertiesModule = new PropertiesModule(this);
//所有配置项包含本地配置项、logging配置项和配置中心获取的配置项
//除logging配置之外的所有配置项包含本地和远程配置项
final Properties envProperties = new Properties();
//配置信息只读版Properties
@@ -192,11 +199,8 @@ public final class Application {
//进程根目录
private final File home;
//进程根目录
private final String homePath;
//配置文件目录
private final URI confPath;
private final URI confDir;
//监听事件
private final List<ApplicationListener> listeners = new CopyOnWriteArrayList<>();
@@ -240,18 +244,17 @@ public final class Application {
this.name = appConfig.name;
this.nodeid = appConfig.nodeid;
this.home = appConfig.home;
this.homePath = appConfig.homePath;
this.confPath = appConfig.confPath;
this.confDir = appConfig.confDir;
this.localAddress = appConfig.localAddress;
this.classLoader = appConfig.classLoader;
this.serverClassLoader = appConfig.serverClassLoader;
//设置基础信息资源
this.resourceFactory.register(RESNAME_APP_NAME, String.class, this.name);
this.resourceFactory.register(RESNAME_APP_NODEID, int.class, this.nodeid);
this.resourceFactory.register(RESNAME_APP_NODEID, Integer.class, this.nodeid);
this.resourceFactory.register(RESNAME_APP_TIME, long.class, this.startTime);
this.resourceFactory.register(RESNAME_APP_TIME, Long.class, this.startTime);
@@ -264,30 +267,25 @@ public final class Application {
this.resourceFactory.register(RESNAME_APP_ADDR, InetAddress.class, this.localAddress.getAddress());
this.resourceFactory.register(RESNAME_APP_ADDR, String.class, this.localAddress.getAddress().getHostAddress());
this.resourceFactory.register(RESNAME_APP_CONF_DIR, URI.class, this.confPath);
this.resourceFactory.register(RESNAME_APP_CONF_DIR, URI.class, this.confDir);
this.resourceFactory.register(RESNAME_APP_CONF_DIR, File.class, appConfig.confFile);
this.resourceFactory.register(RESNAME_APP_CONF_DIR, String.class, this.confPath.toString());
this.resourceFactory.register(RESNAME_APP_CONF_DIR, String.class, this.confDir.toString());
System.setProperty("redkale.version", Redkale.getDotedVersion());
System.setProperty("redkale.application.name", this.name);
System.setProperty("redkale.application.nodeid", String.valueOf(this.nodeid));
System.setProperty("redkale.application.home", this.home.getPath());
System.setProperty("redkale.application.confPath", this.confPath.toString());
System.setProperty(SYSNAME_APP_NAME, this.name);
System.setProperty(SYSNAME_APP_NODEID, String.valueOf(this.nodeid));
System.setProperty(SYSNAME_APP_HOME, this.home.getPath());
System.setProperty(SYSNAME_APP_CONF_DIR, this.confDir.toString());
this.envProperties.put(RESNAME_APP_NAME, this.name);
this.envProperties.put(RESNAME_APP_NODEID, String.valueOf(this.nodeid));
this.envProperties.put(RESNAME_APP_TIME, String.valueOf(this.startTime));
this.envProperties.put(RESNAME_APP_HOME, this.home.getPath());
this.envProperties.put(RESNAME_APP_ADDR, this.localAddress.getAddress().getHostAddress());
this.envProperties.put(RESNAME_APP_CONF_DIR, this.confPath.toString());
this.envProperties.put(RESNAME_APP_CONF_DIR, this.confDir.toString());
this.sysPropNames = Collections.unmodifiableSet((Set) System.getProperties().keySet());
//初始化本地配置的System.properties
appConfig.localSysProperties.forEach((k, v) -> {
String key = k.toString();
if (System.getProperty(key) == null) {
System.setProperty(key, getPropertyValue(v.toString(), appConfig.localSysProperties));
}
});
//初始化本地配置的System.properties、mimetypes
this.registerResourceEnvs(true, appConfig.localEnvProperties);
//需要在加载properties初始化System.properties之后再注册
this.resourceFactory.register(Environment.class, environment);
@@ -309,12 +307,12 @@ public final class Application {
moduleEngines.add(new ScheduleModuleEngine(this));
//根据本地日志配置文件初始化日志
reconfigLogging(true, appConfig.locaLogProperties);
loggingModule.reconfigLogging(true, appConfig.locaLogProperties);
//打印基础信息日志
logger.log(Level.INFO, colorMessage(logger, 36, 1, "-------------------------------- Redkale " + Redkale.getDotedVersion() + " --------------------------------"));
final String confDir = this.confPath.toString();
final String confDir = this.confDir.toString();
logger.log(Level.INFO, "APP_OS = " + System.getProperty("os.name") + " " + System.getProperty("os.version") + " " + System.getProperty("os.arch") + "\r\n"
+ "APP_JAVA = " + System.getProperty("java.runtime.name", System.getProperty("org.graalvm.nativeimage.kind") != null ? "Nativeimage" : "")
+ " " + System.getProperty("java.runtime.version", System.getProperty("java.vendor.version", System.getProperty("java.vm.version"))) + "\r\n" //graalvm.nativeimage 模式下无 java.runtime.xxx 属性
@@ -323,11 +321,11 @@ public final class Application {
+ RESNAME_APP_NODEID + " = " + this.nodeid + "\r\n"
+ "APP_LOADER = " + this.classLoader.getClass().getSimpleName() + "\r\n"
+ RESNAME_APP_ADDR + " = " + this.localAddress.getHostString() + ":" + this.localAddress.getPort() + "\r\n"
+ RESNAME_APP_HOME + " = " + homePath + "\r\n"
+ RESNAME_APP_HOME + " = " + this.home.getPath().replace('\\', '/') + "\r\n"
+ RESNAME_APP_CONF_DIR + " = " + confDir.substring(confDir.indexOf('!') + 1));
if (!compileMode && !(classLoader instanceof RedkaleClassLoader.RedkaleCacheClassLoader)) {
String lib = getPropertyValue(config.getValue("lib", "${APP_HOME}/libs/*").trim());
String lib = environment.getPropertyValue(config.getValue("lib", "${APP_HOME}/libs/*").trim());
lib = Utility.isEmpty(lib) ? confDir : (lib + ";" + confDir);
Server.loadLib(classLoader, logger, lib.isEmpty() ? confDir : (lib + ";" + confDir));
}
@@ -337,8 +335,8 @@ public final class Application {
public void init() throws Exception {
//注册ResourceType
this.initResourceTypeLoader();
//读取远程配置
this.initRemoteProperties();
//读取远程配置并合并app.config
this.propertiesModule.initRemoteProperties();
//解析配置
this.onEnvironmentLoaded();
//init起始回调
@@ -351,6 +349,25 @@ public final class Application {
this.onAppPostInit();
}
private void registerResourceEnvs(boolean first, Properties... envs) {
for (Properties props : envs) {
props.forEach((k, v) -> {
String val = environment.getPropertyValue(v.toString(), envs);
if (k.toString().startsWith("system.property.")) {
String key = k.toString().substring("system.property.".length());
if (System.getProperty(key) == null || !first) {
System.setProperty(key, val);
}
resourceFactory.register(!first, k.toString(), val);
} else if (k.toString().startsWith("mimetype.property.")) {
MimeType.add(k.toString().substring("mimetype.property.".length()), val);
} else {
resourceFactory.register(!first, k.toString(), val);
}
});
}
}
/**
* 设置WorkExecutor
*/
@@ -366,11 +383,11 @@ public final class Application {
? WorkThread.createExecutor(workThreads, "Redkale-WorkThread-%s")
: WorkThread.createWorkExecutor(workThreads, "Redkale-WorkThread-%s");
String executorName = this.workExecutor.getClass().getSimpleName();
executorLog.append("defaultWorkExecutor: {type=" + executorName);
executorLog.append("defaultWorkExecutor: {type=").append(executorName);
if (executorName.contains("VirtualExecutor") || executorName.contains("PerTaskExecutor")) {
executorLog.append(", threads=[virtual]}");
} else {
executorLog.append(", threads=" + workThreads + "}");
executorLog.append(", threads=").append(workThreads).append("}");
}
ExecutorService clientWorkExecutor = this.workExecutor;
@@ -380,7 +397,7 @@ public final class Application {
//给所有client给一个新的默认ExecutorService
int clientThreads = executorConf.getIntValue("clients", Utility.cpus() * 4);
clientWorkExecutor = WorkThread.createWorkExecutor(clientThreads, "Redkale-DefaultClient-WorkThread-%s");
executorLog.append(", threads=" + clientThreads + "}");
executorLog.append(", threads=").append(clientThreads).append("}");
}
AsyncIOGroup ioGroup = new AsyncIOGroup("Redkale-DefaultClient-IOThread-%s", clientWorkExecutor, bufferCapacity, bufferPoolSize).skipClose(true);
this.clientAsyncGroup = ioGroup.start();
@@ -594,263 +611,6 @@ public final class Application {
//------------------------------------------------------------------------
}
private void initRemoteProperties() {
final Properties dyncProps = new Properties();
final AtomicInteger propertyIndex = new AtomicInteger();
Properties logProps = null; //新的日志配置项
//------------------------------------ 读取配置项 ------------------------------------
AnyValue propsConf = config.getAnyValue("properties");
if (propsConf == null) {
final AnyValue resources = config.getAnyValue("resources");
if (resources != null) {
logger.log(Level.WARNING, "<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) {
final boolean linux = System.getProperty("os.name").toLowerCase(Locale.ENGLISH).contains("linux");
if (linux) { //Windows PowerShell 也能正常着色
@@ -1093,7 +853,7 @@ public final class Application {
*/
private void onAppPreStart() {
for (ApplicationListener listener : this.listeners) {
listener.preStart(this);
listener.onPreStart(this);
}
for (ModuleEngine item : moduleEngines) {
item.onAppPostInit();
@@ -1105,7 +865,7 @@ public final class Application {
*/
private void onAppPostStart() {
for (ApplicationListener listener : this.listeners) {
listener.postStart(this);
listener.onPostStart(this);
}
for (ModuleEngine item : moduleEngines) {
item.onAppPostStart();
@@ -1118,6 +878,7 @@ public final class Application {
* @param props 配置项全量
*/
private void onEnvironmentLoaded() {
this.registerResourceEnvs(true, this.envProperties);
for (ModuleEngine item : moduleEngines) {
item.onEnvironmentLoaded(this.envProperties);
}
@@ -1129,7 +890,7 @@ public final class Application {
* @param namespace 命名空间
* @param events 变更项
*/
private void onEnvironmentChanged(String namespace, List<ResourceEvent> events) {
void onEnvironmentChanged(String namespace, List<ResourceEvent> events) {
for (ModuleEngine item : moduleEngines) {
item.onEnvironmentChanged(namespace, events);
}
@@ -1193,6 +954,9 @@ public final class Application {
* 服务全部停掉前被调用
*/
private void onServersPreStop() {
for (ApplicationListener listener : listeners) {
listener.onServersPreStop(this);
}
for (ModuleEngine item : moduleEngines) {
item.onServersPreStop();
}
@@ -1202,6 +966,9 @@ public final class Application {
* 服务全部停掉后被调用
*/
private void onServersPostStop() {
for (ApplicationListener listener : listeners) {
listener.onServersPostStop(this);
}
for (ModuleEngine item : moduleEngines) {
item.onServersPostStop();
}
@@ -1213,7 +980,7 @@ public final class Application {
private void onAppPreShutdown() {
for (ApplicationListener listener : this.listeners) {
try {
listener.preShutdown(this);
listener.onPreShutdown(this);
} catch (Exception e) {
logger.log(Level.WARNING, listener.getClass() + " preShutdown erroneous", e);
}
@@ -1234,13 +1001,19 @@ public final class Application {
void onPreCompile() {
for (ApplicationListener listener : listeners) {
listener.preCompile(this);
listener.onPreCompile(this);
}
for (ModuleEngine item : moduleEngines) {
item.onPreCompile();
}
}
void onPostCompile() {
for (ApplicationListener listener : listeners) {
listener.postCompile(this);
listener.onPostCompile(this);
}
for (ModuleEngine item : moduleEngines) {
item.onPostCompile();
}
}
@@ -1293,6 +1066,10 @@ public final class Application {
ClassFilter.Loader.load(getHome(), this.serverClassLoader, filters);
}
List<ModuleEngine> getModuleEngines() {
return moduleEngines;
}
//使用了nohup或使用了后台&Runtime.getRuntime().addShutdownHook失效
private void signalShutdownHandle() {
Consumer<Consumer<String>> signalShutdownConsumer = Utility.signalShutdownConsumer();
@@ -1479,7 +1256,7 @@ public final class Application {
if (args != null && args.length > 0) {
for (int i = 0; i < args.length; i++) {
if (args[i] != null && args[i].toLowerCase().startsWith("--conf-file=")) {
System.setProperty(RESNAME_APP_CONF_FILE, args[i].substring("--conf-file=".length()));
System.setProperty(AppConfig.PARAM_APP_CONF_FILE, args[i].substring("--conf-file=".length()));
String[] newargs = new String[args.length - 1];
System.arraycopy(args, 0, newargs, 0, i);
System.arraycopy(args, i + 1, newargs, i, args.length - 1 - i);
@@ -1537,49 +1314,6 @@ public final class Application {
System.exit(0); //必须要有
}
public String getPropertyValue(String value, Properties... envs) {
if (value == null || value.isBlank()) {
return value;
}
final String val = value;
//${domain}/${path}/xxx ${aa${bbb}}
int pos2 = val.indexOf("}");
int pos1 = val.lastIndexOf("${", pos2);
if (pos1 >= 0 && pos2 > 0) {
String key = val.substring(pos1 + 2, pos2);
String newVal = null;
if (RESNAME_APP_NAME.equals(key)) {
newVal = getName();
} else if (RESNAME_APP_HOME.equals(key)) {
newVal = getHome().getPath().replace('\\', '/');
} else if (RESNAME_APP_NODEID.equals(key)) {
newVal = String.valueOf(getNodeid());
} else if (RESNAME_APP_TIME.equals(key)) {
newVal = String.valueOf(getStartTime());
} else {
List<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() {
return ""
+ "Usage: redkale [command] [arguments]\r\n"
@@ -1616,11 +1350,7 @@ public final class Application {
long f = System.currentTimeMillis();
this.onAppPreShutdown();
stopServers();
if (this.propertiesAgent != null) {
long s = System.currentTimeMillis();
this.propertiesAgent.destroy(config.getAnyValue("properties"));
logger.info(this.propertiesAgent.getClass().getSimpleName() + " destroy in " + (System.currentTimeMillis() - s) + " ms");
}
this.propertiesModule.destroy();
if (this.workExecutor != null) {
this.workExecutor.shutdownNow();
}
@@ -1699,8 +1429,8 @@ public final class Application {
return home;
}
public URI getConfPath() {
return confPath;
public URI getConfDir() {
return confDir;
}
public long getStartTime() {

View File

@@ -28,42 +28,58 @@ public interface ApplicationListener {
}
/**
* Application 在运行start前调用
* Application在运行start前调用
*
* @param application Application
*/
default void preStart(Application application) {
default void onPreStart(Application application) {
}
/**
* Application 在运行start后调用
* 服务全部停掉前被调用
*
* @param application Application
*/
default void postStart(Application application) {
default void onServersPreStop(Application application) {
}
/**
* Application 在运行Compile前调用
* 服务全部停掉后被调用
*
* @param application Application
*/
default void preCompile(Application application) {
default void onServersPostStop(Application application) {
}
/**
* Application 在运行Compile后调用
* Application在运行start后调用
*
* @param application Application
*/
default void postCompile(Application application) {
default void onPostStart(Application application) {
}
/**
* Application 在运行shutdown前调用
* Application在运行Compile前调用
*
* @param application Application
*/
default void preShutdown(Application application) {
default void onPreCompile(Application application) {
}
/**
* Application在运行Compile后调用
*
* @param application Application
*/
default void onPostCompile(Application application) {
}
/**
* Application在运行shutdown前调用
*
* @param application Application
*/
default void onPreShutdown(Application application) {
}
}

View 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) { //不会发生
}
}
}

View File

@@ -10,6 +10,7 @@ import java.util.logging.*;
import java.util.logging.Formatter;
import java.util.regex.Pattern;
import static org.redkale.boot.Application.RESNAME_APP_NAME;
import static org.redkale.boot.Application.SYSNAME_APP_NAME;
import org.redkale.convert.*;
import org.redkale.convert.json.JsonConvert;
import org.redkale.persistence.*;
@@ -160,7 +161,7 @@ public class LoggingSearchHandler extends LoggingBaseHandler {
if (!checkTagName(tagStr.replaceAll("\\$\\{.+\\}", ""))) {
throw new RedkaleException("found illegal logging.property " + cname + ".tag = " + tagStr);
}
this.tag = tagStr.replace("${" + RESNAME_APP_NAME + "}", System.getProperty("redkale.application.name", ""));
this.tag = tagStr.replace("${" + RESNAME_APP_NAME + "}", System.getProperty(SYSNAME_APP_NAME, ""));
if (this.tag.contains("%")) {
this.tagDateFormat = this.tag;
Times.formatTime(this.tagDateFormat, -1, System.currentTimeMillis()); //测试时间格式是否正确

View File

@@ -7,6 +7,7 @@ import java.util.List;
import java.util.Properties;
import java.util.logging.Logger;
import org.redkale.service.Service;
import org.redkale.util.AnyValue;
import org.redkale.util.Environment;
import org.redkale.util.ResourceEvent;
import org.redkale.util.ResourceFactory;
@@ -38,6 +39,20 @@ public abstract class ModuleEngine {
this.environment = application.getEnvironment();
}
/**
* 判断模块的配置项合并策略, 返回null表示模块不识别此配置项
*
* @param path 配置项路径
* @param key 配置项名称
* @param val1 配置项原值
* @param val2 配置项新值
*
* @return MergeEnum
*/
public AnyValue.MergeEnum mergeAppConfigStrategy(String path, String key, AnyValue val1, AnyValue val2) {
return null;
}
/**
* 进入Application.init方法时被调用
* 此时状态:
@@ -88,6 +103,22 @@ public abstract class ModuleEngine {
//do nothing
}
/**
* Application 在运行Compile前调用
*
*/
public void onPreCompile() {
//do nothing
}
/**
* Application 在运行Compile后调用
*
*/
public void onPostCompile() {
//do nothing
}
/**
* 服务全部启动前被调用
*/

View File

@@ -174,7 +174,7 @@ public abstract class NodeServer {
this.sncpAddress, new ClientAddress(this.sncpAddress), server.getNetprotocol(), Utility.cpus(), 1000);
}
initResource(); //给DataSource、CacheSource注册依赖注入时的监听回调事件。
registerResTypeLoader(); //给DataSource、CacheSource注册依赖注入时的监听回调事件。
String interceptorClass = this.serverConf.getValue("interceptor", "");
if (!interceptorClass.isEmpty()) {
Class clazz = serverClassLoader.loadClass(interceptorClass);
@@ -238,155 +238,12 @@ public abstract class NodeServer {
protected abstract void loadServlet(ClassFilter<? extends Servlet> servletFilter) throws Exception;
private void initResource() {
private void registerResTypeLoader() {
//--------------------- 注册 Local AutoLoad(false) Service ---------------------
resourceFactory.register(this::loadService, Service.class);
//----------------------------- 注册 WebSocketNode -----------------------------
final NodeServer self = this;
//---------------------------------------------------------------------------------------------
final ResourceFactory appResFactory = application.getResourceFactory();
//------------------------------------- 注册 Resource --------------------------------------------------------
// resourceFactory.register((ResourceFactory rf, String srcResourceName, final Object srcObj, String resourceName, Field field, final Object attachment) -> {
// try {
// String resName = null;
// Resource res = field.getAnnotation(Resource.class);
// if (res != null) {
// resName = res.name();
// } else {
// javax.annotation.Resource res2 = field.getAnnotation(javax.annotation.Resource.class);
// if (res2 != null) {
// resName = res2.name();
// }
// }
// if (resName == null || !resName.startsWith("properties.")) {
// return null;
// }
// if ((srcObj instanceof Service) && Sncp.isRemote((Service) srcObj)) {
// return null; //远程模式不得注入 DataSource
// }
// Class type = field.getType();
// if (type != AnyValue.class && type != AnyValue[].class) {
// return null;
// }
// Object resource = null;
// final AnyValue properties = application.getAppConfig().getAnyValue("properties");
// if (properties != null && type == AnyValue.class) {
// resource = properties.getAnyValue(resName.substring("properties.".length()));
// appResFactory.register(resourceName, AnyValue.class, resource);
// } else if (properties != null && type == AnyValue[].class) {
// resource = properties.getAnyValues(resName.substring("properties.".length()));
// appResFactory.register(resourceName, AnyValue[].class, resource);
// }
// field.set(srcObj, resource);
// return resource;
// } catch (Exception e) {
// logger.log(Level.SEVERE, "Resource inject error", e);
// return null;
// }
// }, AnyValue.class, AnyValue[].class);
//------------------------------------- 注册 Local AutoLoad(false) Service --------------------------------------------------------
resourceFactory.register((ResourceFactory rf, String srcResourceName, final Object srcObj, String resourceName, Field field, final Object attachment) -> {
Class<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() {
@Override
public Object load(ResourceFactory rf, String srcResourceName, final Object srcObj, final String resourceName, Field field, final Object attachment) {
@@ -433,6 +290,57 @@ public abstract class NodeServer {
}, WebSocketNode.class);
}
private Object loadService(ResourceFactory rf, String srcResourceName, Object srcObj, String resourceName, Field field, Object attachment) {
final NodeServer self = this;
final ResourceFactory appResFactory = application.getResourceFactory();
Class<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")
protected void loadService(ClassFilter<? extends Service> serviceFilter) throws Exception {
Objects.requireNonNull(serviceFilter);

View File

@@ -3,10 +3,7 @@
package org.redkale.boot;
import java.util.*;
import java.util.concurrent.locks.ReentrantLock;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.redkale.net.http.MimeType;
import org.redkale.util.*;
/**
@@ -25,9 +22,6 @@ public abstract class PropertiesAgent {
protected final Logger logger = Logger.getLogger(this.getClass().getSimpleName());
//envProperties更新锁
private final ReentrantLock updateLock = new ReentrantLock();
/**
* 编译时进行的操作
*
@@ -62,141 +56,15 @@ public abstract class PropertiesAgent {
*/
public abstract void destroy(AnyValue conf);
protected final void updateEnvironmentProperties(Application application, String namespace, List<ResourceEvent> events) {
if (Utility.isEmpty(events)) {
return;
}
updateLock.lock();
try {
Properties envRegisterProps = new Properties();
Set<String> envRemovedKeys = new HashSet<>();
Properties envChangedProps = new Properties();
// 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();
}
/**
* 响应配置项的变更
*
* @param application Application
* @param namespace 命名空间
* @param events 变更项集合
*/
protected final void onEnvironmentUpdated(Application application, String namespace, List<ResourceEvent> events) {
application.propertiesModule.onEnvironmentUpdated(namespace, events);
}
}

View 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;
};
}
}

View File

@@ -20,6 +20,24 @@ public class CacheModuleEngine extends ModuleEngine {
super(application);
}
/**
* 判断模块的配置项合并策略, 返回null表示模块不识别此配置项
*
* @param path 配置项路径
* @param key 配置项名称
* @param val1 配置项原值
* @param val2 配置项新值
*
* @return MergeEnum
*/
@Override
public AnyValue.MergeEnum mergeAppConfigStrategy(String path, String key, AnyValue val1, AnyValue val2) {
if ("".equals(path) && "cache".equals(key)) {
return AnyValue.MergeEnum.REPLACE;
}
return null;
}
/**
* 结束Application.init方法前被调用
*/

View File

@@ -46,7 +46,7 @@ public class ClusterModuleEngine extends ModuleEngine {
AnyValue clusterConf = application.getAppConfig().getAnyValue("cluster");
if (clusterConf != null) {
try {
String classVal = application.getPropertyValue(clusterConf.getValue("type", clusterConf.getValue("value"))); //兼容value字段
String classVal = environment.getPropertyValue(clusterConf.getValue("type", clusterConf.getValue("value"))); //兼容value字段
if (classVal == null || classVal.isEmpty() || classVal.indexOf('.') < 0) { //不包含.表示非类名,比如值: consul, nacos
Iterator<ClusterAgentProvider> it = ServiceLoader.load(ClusterAgentProvider.class, application.getClassLoader()).iterator();
RedkaleClassLoader.putServiceLoader(ClusterAgentProvider.class);
@@ -184,9 +184,28 @@ public class ClusterModuleEngine extends ModuleEngine {
}
}
/**
* 判断模块的配置项合并策略, 返回null表示模块不识别此配置项
*
* @param path 配置项路径
* @param key 配置项名称
* @param val1 配置项原值
* @param val2 配置项新值
*
* @return MergeEnum
*/
@Override
public AnyValue.MergeEnum mergeAppConfigStrategy(String path, String key, AnyValue val1, AnyValue val2) {
if ("".equals(path) && "cluster".equals(key)) {
return AnyValue.MergeEnum.REPLACE;
}
return null;
}
/**
* 进入Application.start方法被调用
*/
@Override
public void onAppPreStart() {
if (!application.isSingletonMode() && !application.isCompileMode() && this.clusterAgent != null) {
this.clusterAgent.register(application);

View File

@@ -48,6 +48,9 @@ public abstract class MessageAgent implements Resourcable {
@Resource(required = false)
protected Application application;
@Resource(required = false)
protected Environment environment;
@Resource(name = RESNAME_APP_NODEID)
protected int nodeid;
@@ -244,14 +247,14 @@ public abstract class MessageAgent implements Resourcable {
Map<String, String> views = new LinkedHashMap<>();
for (MessageConsumer consumer : consumers) {
ResourceConsumer res = consumer.getClass().getAnnotation(ResourceConsumer.class);
String group = application.getPropertyValue(res.group());
String group = environment.getPropertyValue(res.group());
if (Utility.isBlank(group)) {
group = consumer.getClass().getName();
}
Map<String, MessageConsumerWrapper> map = maps.computeIfAbsent(group, g -> new HashMap<>());
List<String> topics = new ArrayList<>();
for (String t : res.topics()) {
String topic = application.getPropertyValue(t);
String topic = environment.getPropertyValue(t);
if (!topic.trim().isEmpty()) {
topics.add(topic);
if (map.containsKey(topic.trim())) {

View File

@@ -21,13 +21,13 @@ import org.redkale.boot.NodeServer;
import org.redkale.convert.json.JsonConvert;
import org.redkale.net.http.RestException;
import org.redkale.util.AnyValue;
import org.redkale.util.AnyValueWriter;
import org.redkale.util.RedkaleClassLoader;
import org.redkale.util.RedkaleException;
import org.redkale.util.ResourceAnnotationProvider;
import org.redkale.util.ResourceEvent;
import org.redkale.util.ResourceFactory;
import org.redkale.util.ResourceTypeLoader;
import org.redkale.util.AnyValueWriter;
import org.redkale.util.Utility;
/**
@@ -48,6 +48,28 @@ public class MessageModuleEngine extends ModuleEngine {
super(application);
}
/**
* 判断模块的配置项合并策略, 返回null表示模块不识别此配置项
*
* @param path 配置项路径
* @param key 配置项名称
* @param val1 配置项原值
* @param val2 配置项新值
*
* @return MergeEnum
*/
@Override
public AnyValue.MergeEnum mergeAppConfigStrategy(String path, String key, AnyValue val1, AnyValue val2) {
if ("".equals(path) && "mq".equals(key)) {
if (Objects.equals(val1.getValue("name"), val2.getValue("name"))) {
return AnyValue.MergeEnum.REPLACE;
} else {
return AnyValue.MergeEnum.DEFAULT;
}
}
return null;
}
/**
* 配置项加载后被调用
*/
@@ -79,7 +101,7 @@ public class MessageModuleEngine extends ModuleEngine {
Set<String> mqnames = new HashSet<>();
for (int i = 0; i < mqConfs.length; i++) {
AnyValue mqConf = mqConfs[i];
String names = application.getPropertyValue(mqConf.getValue("name")); //含,或者;表示多个别名使用同一mq对象
String names = environment.getPropertyValue(mqConf.getValue("name")); //含,或者;表示多个别名使用同一mq对象
if (names != null && !names.isEmpty()) {
for (String n : names.replace(',', ';').split(";")) {
if (n.trim().isEmpty()) {
@@ -98,7 +120,7 @@ public class MessageModuleEngine extends ModuleEngine {
mqnames.add(n);
}
try {
String classVal = application.getPropertyValue(mqConf.getValue("type", mqConf.getValue("value"))); //兼容value字段
String classVal = environment.getPropertyValue(mqConf.getValue("type", mqConf.getValue("value"))); //兼容value字段
if (classVal == null || classVal.isEmpty() || classVal.indexOf('.') < 0) { //不包含.表示非类名,比如值: kafka, pulsar
Iterator<MessageAgentProvider> it = ServiceLoader.load(MessageAgentProvider.class, application.getClassLoader()).iterator();
RedkaleClassLoader.putServiceLoader(MessageAgentProvider.class);
@@ -343,7 +365,7 @@ public class MessageModuleEngine extends ModuleEngine {
for (ClassFilter.FilterEntry<? extends MessageConsumer> en : entrys) {
Class<? extends MessageConsumer> clazz = en.getType();
ResourceConsumer res = clazz.getAnnotation(ResourceConsumer.class);
if (!Objects.equals(agent.getName(), application.getPropertyValue(res.mq()))) {
if (!Objects.equals(agent.getName(), environment.getPropertyValue(res.mq()))) {
continue;
}
RedkaleClassLoader.putReflectionDeclaredConstructors(clazz, clazz.getName());

View File

@@ -31,14 +31,14 @@ import org.redkale.annotation.Nullable;
import org.redkale.annotation.Resource;
import org.redkale.annotation.ResourceType;
import org.redkale.boot.Application;
import org.redkale.schedule.ScheduleManager;
import org.redkale.schedule.Scheduled;
import org.redkale.service.Local;
import org.redkale.service.Service;
import org.redkale.util.AnyValue;
import org.redkale.util.RedkaleClassLoader;
import org.redkale.util.RedkaleException;
import org.redkale.util.Utility;
import org.redkale.schedule.Scheduled;
import org.redkale.schedule.ScheduleManager;
/**
* 定时任务管理器
@@ -104,7 +104,7 @@ public class ScheduleManagerService implements ScheduleManager, Service {
this.enabled = conf.getBoolValue("enabled", true);
if (this.enabled) {
if (this.propertyFunc == null && application != null) {
UnaryOperator<String> func = application::getPropertyValue;
UnaryOperator<String> func = application.getEnvironment()::getPropertyValue;
this.propertyFunc = func;
}
this.scheduler = new ScheduledThreadPoolExecutor(Utility.cpus(), Utility.newThreadFactory("Scheduled-Task-Thread-%s"));

View File

@@ -21,6 +21,24 @@ public class ScheduleModuleEngine extends ModuleEngine {
super(application);
}
/**
* 判断模块的配置项合并策略, 返回null表示模块不识别此配置项
*
* @param path 配置项路径
* @param key 配置项名称
* @param val1 配置项原值
* @param val2 配置项新值
*
* @return MergeEnum
*/
@Override
public AnyValue.MergeEnum mergeAppConfigStrategy(String path, String key, AnyValue val1, AnyValue val2) {
if ("".equals(path) && "schedule".equals(key)) {
return AnyValue.MergeEnum.REPLACE;
}
return null;
}
/**
* 结束Application.init方法前被调用
*/

View File

@@ -13,6 +13,8 @@ import java.lang.reflect.*;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.function.BiFunction;
import static org.redkale.boot.Application.SYSNAME_APP_CONF_DIR;
import static org.redkale.boot.Application.SYSNAME_APP_HOME;
import org.redkale.util.RedkaleClassLoader;
/**
@@ -85,8 +87,8 @@ public @interface RetLabel {
}
}
try {
File homePath = new File(System.getProperty("redkale.application.home", ""), "conf");
File propPath = new File(System.getProperty("redkale.application.confPath", homePath.getPath()));
File homePath = new File(System.getProperty(SYSNAME_APP_HOME, ""), "conf");
File propPath = new File(System.getProperty(SYSNAME_APP_CONF_DIR, homePath.getPath()));
if (propPath.isDirectory() && propPath.canRead()) {
final String prefix = clazz.getSimpleName().toLowerCase();
for (File propFile : propPath.listFiles(f -> f.getName().startsWith(prefix) && f.getName().endsWith(".properties"))) {

View File

@@ -58,6 +58,27 @@ public class SourceModuleEngine extends ModuleEngine {
super(application);
}
/**
* 判断模块的配置项合并策略, 返回null表示模块不识别此配置项
*
* @param path 配置项路径
* @param key 配置项名称
* @param val1 配置项原值
* @param val2 配置项新值
*
* @return MergeEnum
*/
@Override
public AnyValue.MergeEnum mergeAppConfigStrategy(String path, String key, AnyValue val1, AnyValue val2) {
if ("cachesource".equals(path)) {
return AnyValue.MergeEnum.REPLACE;
}
if ("datasource".equals(path)) {
return AnyValue.MergeEnum.REPLACE;
}
return null;
}
/**
* 配置项加载后被调用
*/
@@ -98,59 +119,10 @@ public class SourceModuleEngine extends ModuleEngine {
}
//------------------------------------- 注册 DataSource --------------------------------------------------------
resourceFactory.register((ResourceFactory rf, String srcResourceName, final Object srcObj, String resourceName, Field field, final Object attachment) -> {
try {
if (field.getAnnotation(Resource.class) == null && field.getAnnotation(javax.annotation.Resource.class) == null) {
return null;
}
if ((srcObj instanceof Service) && Sncp.isRemote((Service) srcObj)) {
return null; //远程模式不得注入 DataSource
}
DataSource source = loadDataSource(resourceName, false);
field.set(srcObj, source);
return source;
} catch (Exception e) {
logger.log(Level.SEVERE, "DataSource inject to " + srcObj + " error", e);
return null;
}
}, DataSource.class);
resourceFactory.register(new DataSourceLoader(), DataSource.class);
//------------------------------------- 注册 CacheSource --------------------------------------------------------
resourceFactory.register(new ResourceTypeLoader() {
@Override
public Object load(ResourceFactory rf, String srcResourceName, final Object srcObj, final String resourceName, Field field, final Object attachment) {
try {
if (field.getAnnotation(Resource.class) == null && field.getAnnotation(javax.annotation.Resource.class) == null) {
return null;
}
if ((srcObj instanceof Service) && Sncp.isRemote((Service) srcObj)) {
return null; //远程模式不需要注入 CacheSource
}
if (srcObj instanceof Servlet) {
throw new RedkaleException("CacheSource cannot inject in Servlet " + srcObj);
}
final boolean ws = (srcObj instanceof org.redkale.net.http.WebSocketNodeService);
CacheSource source = loadCacheSource(resourceName, ws);
field.set(srcObj, source);
Resource res = field.getAnnotation(Resource.class);
if (res != null && res.required() && source == null) {
throw new RedkaleException("CacheSource (resourceName = '" + resourceName + "') not found");
} else {
logger.info("Load CacheSource (type = " + (source == null ? null : source.getClass().getSimpleName()) + ", resourceName = '" + resourceName + "')");
}
return source;
} catch (Exception e) {
logger.log(Level.SEVERE, "DataSource inject error", e);
return null;
}
}
@Override
public boolean autoNone() {
return false;
}
}, CacheSource.class);
resourceFactory.register(new CacheSourceLoader(), CacheSource.class);
}
/**
@@ -501,4 +473,61 @@ public class SourceModuleEngine extends ModuleEngine {
return conf;
}
private class DataSourceLoader implements ResourceTypeLoader {
@Override
public Object load(ResourceFactory rf, String srcResourceName, final Object srcObj, final String resourceName, Field field, final Object attachment) {
try {
if (field.getAnnotation(Resource.class) == null && field.getAnnotation(javax.annotation.Resource.class) == null) {
return null;
}
if ((srcObj instanceof Service) && Sncp.isRemote((Service) srcObj)) {
return null; //远程模式不得注入 DataSource
}
DataSource source = loadDataSource(resourceName, false);
field.set(srcObj, source);
return source;
} catch (Exception e) {
logger.log(Level.SEVERE, "DataSource inject to " + srcObj + " error", e);
return null;
}
}
}
private class CacheSourceLoader implements ResourceTypeLoader {
@Override
public Object load(ResourceFactory rf, String srcResourceName, final Object srcObj, final String resourceName, Field field, final Object attachment) {
try {
if (field.getAnnotation(Resource.class) == null && field.getAnnotation(javax.annotation.Resource.class) == null) {
return null;
}
if ((srcObj instanceof Service) && Sncp.isRemote((Service) srcObj)) {
return null; //远程模式不需要注入 CacheSource
}
if (srcObj instanceof Servlet) {
throw new RedkaleException("CacheSource cannot inject in Servlet " + srcObj);
}
final boolean ws = (srcObj instanceof org.redkale.net.http.WebSocketNodeService);
CacheSource source = loadCacheSource(resourceName, ws);
field.set(srcObj, source);
Resource res = field.getAnnotation(Resource.class);
if (res != null && res.required() && source == null) {
throw new RedkaleException("CacheSource (resourceName = '" + resourceName + "') not found");
} else {
logger.info("Load CacheSource (type = " + (source == null ? null : source.getClass().getSimpleName()) + ", resourceName = '" + resourceName + "')");
}
return source;
} catch (Exception e) {
logger.log(Level.SEVERE, "DataSource inject error", e);
return null;
}
}
@Override
public boolean autoNone() {
return false;
}
}
}

View File

@@ -33,29 +33,32 @@ public abstract class AnyValue {
* merge两节点是否覆盖的判断函数
*
*/
public static interface MergeFunction {
public static enum MergeEnum {
/**
* 追加
* 异常
*/
public static final int NONE = 0;
DEFAULT,
/**
* 替换
*/
public static final int REPLACE = 1;
REPLACE,
/**
* 合并
*/
public static final int MERGE = 2;
MERGE,
/**
* 丢弃
*/
public static final int SKIP = 3;
IGNORE;
}
public int apply(String path, String name, AnyValue val1, AnyValue val2);
/**
* merge两节点是否覆盖的判断函数
*
*/
public static interface MergeStrategy {
public MergeEnum apply(String path, String name, AnyValue val1, AnyValue val2);
}
/**
@@ -623,7 +626,7 @@ public abstract class AnyValue {
*
* @return AnyValue
*/
public abstract AnyValue merge(AnyValue node, MergeFunction func);
public abstract AnyValue merge(AnyValue node, MergeStrategy func);
/**
* 回调子节点

View File

@@ -180,11 +180,11 @@ public class AnyValueWriter extends AnyValue {
* @return AnyValue
*/
@Override
public AnyValueWriter merge(AnyValue node, MergeFunction func) {
public AnyValueWriter merge(AnyValue node, MergeStrategy func) {
return merge(node, "", func);
}
protected AnyValueWriter merge(AnyValue node0, String path, MergeFunction func) {
protected AnyValueWriter merge(AnyValue node0, String path, MergeStrategy func) {
if (node0 == null) {
return this;
}
@@ -220,17 +220,17 @@ public class AnyValueWriter extends AnyValue {
ok = true;
break;
} else {
int funcVal = func.apply(path, en.name, en.value, item.value);
if (funcVal == MergeFunction.MERGE) {
MergeEnum funcVal = func.apply(path, en.name, en.value, item.value);
if (funcVal == MergeEnum.MERGE) {
String subPath = path.isEmpty() ? en.name : (path + "." + en.name);
((AnyValueWriter) item.value).merge(en.value, subPath, func);
ok = true;
break;
} else if (funcVal == MergeFunction.REPLACE) {
} else if (funcVal == MergeEnum.REPLACE) {
item.value = en.value.copy();
ok = true;
break;
} else if (funcVal == MergeFunction.SKIP) {
} else if (funcVal == MergeEnum.IGNORE) {
ok = true;
break;
}

View File

@@ -16,7 +16,8 @@ public interface ResourceTypeLoader {
public Object load(ResourceFactory factory, String srcResourceName, Object srcObj, String resourceName, Field field, Object attachment);
// 返回true 表示调用ResourceLoader之后资源仍不存在则会在ResourceFactory里注入默认值null返回false表示资源不存在下次仍会调用ResourceLoader自行处理
//返回true: 表示调用ResourceLoader之后资源仍不存在则会在ResourceFactory里注入默认值null
//返回false: 表示资源不存在下次仍会调用ResourceLoader自行处理。
default boolean autoNone() {
return true;
}