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"))) {
|
||||
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);
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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) {
|
||||
}
|
||||
}
|
||||
|
||||
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.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()); //测试时间格式是否正确
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
/**
|
||||
* 服务全部启动前被调用
|
||||
*/
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断模块的配置项合并策略, 返回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方法前被调用
|
||||
*/
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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())) {
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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"));
|
||||
|
||||
@@ -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方法前被调用
|
||||
*/
|
||||
|
||||
@@ -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"))) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
/**
|
||||
* 回调子节点
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user