Application.xml废弃<resources>节点
This commit is contained in:
@@ -3,49 +3,48 @@ redkale.nodeid = 1000
|
||||
redkale.port = 6560
|
||||
redkale.lib = ./
|
||||
|
||||
#\u3010resources\u8282\u70b9\u5168\u5c40\u552f\u4e00\u3011
|
||||
#\u3010executor\u8282\u70b9\u5168\u5c40\u552f\u4e00\u3011
|
||||
redkale.resources.executor.threads = 4
|
||||
redkale.resources.executor.hash = false
|
||||
redkale.executor.threads = 4
|
||||
redkale.executor.hash = false
|
||||
|
||||
#\u3010transport\u8282\u70b9\u5168\u5c40\u552f\u4e00\u3011
|
||||
redkale.resources.transport.bufferCapacity = 32k
|
||||
redkale.resources.transport.bufferPoolSize = 32
|
||||
redkale.transport.bufferCapacity = 32k
|
||||
redkale.transport.bufferPoolSize = 32
|
||||
|
||||
#\u3010excludelibs\u8282\u70b9\u5168\u5c40\u552f\u4e00\u3011
|
||||
redkale.resources.excludelibs.value = ^.*mysql.*$;^.*kafka.*$
|
||||
redkale.excludelibs.value = ^.*mysql.*$;^.*kafka.*$
|
||||
|
||||
#\u3010cluster\u8282\u70b9\u5168\u5c40\u552f\u4e00\u3011
|
||||
redkale.resources.cluster.type = org.redkalex.cluster.consul.ConsulClusterAgent
|
||||
redkale.resources.cluster.waits= = false
|
||||
redkale.resources.cluster.protocols = SNCP
|
||||
redkale.resources.cluster.ports = 7070;7071
|
||||
redkale.cluster.type = org.redkalex.cluster.consul.ConsulClusterAgent
|
||||
redkale.cluster.waits= = false
|
||||
redkale.cluster.protocols = SNCP
|
||||
redkale.cluster.ports = 7070;7071
|
||||
|
||||
redkale.resources.mq[0].name =
|
||||
redkale.resources.mq[0].type = org.redkalex.mq.kafka.KafkaMessageAgent
|
||||
redkale.resources.mq[0].servers.value = 127.0.0.1:9101
|
||||
redkale.mq[0].name =
|
||||
redkale.mq[0].type = org.redkalex.mq.kafka.KafkaMessageAgent
|
||||
redkale.mq[0].servers.value = 127.0.0.1:9101
|
||||
|
||||
redkale.resources.group[0].name =
|
||||
redkale.resources.group[0].protocol = TCP
|
||||
redkale.resources.group[0].node[0].addr = 127.0.0.1
|
||||
redkale.resources.group[0].node[0].port = 7070
|
||||
redkale.group[0].name =
|
||||
redkale.group[0].protocol = TCP
|
||||
redkale.group[0].node[0].addr = 127.0.0.1
|
||||
redkale.group[0].node[0].port = 7070
|
||||
|
||||
#\u3010listener\u8282\u70b9\u5168\u5c40\u552f\u4e00\u3011
|
||||
redkale.resources.listener.value = org.redkalex.xxx.XXXApplicationListener
|
||||
redkale.listener[0].value = org.redkalex.xxx.XXXApplicationListener
|
||||
|
||||
#\u3010properties\u8282\u70b9\u5168\u5c40\u552f\u4e00\u3011
|
||||
redkale.resources.properties.load = config.properties
|
||||
redkale.resources.properties.property[0].name = system.property.yyyy
|
||||
redkale.resources.properties.property[0].value = YYYYYY
|
||||
redkale.resources.properties.property[1].name = xxxxxxx
|
||||
redkale.resources.properties.property[1].value = YYYYYY
|
||||
redkale.properties.load = config.properties
|
||||
redkale.properties.property[0].name = system.property.yyyy
|
||||
redkale.properties.property[0].value = YYYYYY
|
||||
redkale.properties.property[1].name = xxxxxxx
|
||||
redkale.properties.property[1].value = YYYYYY
|
||||
|
||||
redkale.server[0].protocol = HTTP
|
||||
redkale.server[0].host = 127.0.0.1
|
||||
redkale.server[0].port = 6060
|
||||
redkale.server[0].root = root
|
||||
redkale.server[0].lib =
|
||||
#\u3010\u8282\u70b9\u5728<server>\u4e2d\u552f\u4e00\u3011
|
||||
|
||||
#\u3010ssl\u8282\u70b9\u5728<server>\u4e2d\u552f\u4e00\u3011
|
||||
redkale.server[0].ssl.build = org.redkale.net.SSLBuilder\u5b50\u7c7b
|
||||
|
||||
redkale.server[0].services[0].autoload = true
|
||||
@@ -28,124 +28,124 @@
|
||||
<application nodeid="1000" port="6560" lib="">
|
||||
|
||||
<!--
|
||||
【节点全局唯一】
|
||||
【已废弃,不再需要此节点】
|
||||
所有服务所需的资源
|
||||
-->
|
||||
<resources>
|
||||
|
||||
<!--
|
||||
【节点全局唯一】 @since 2.3.0
|
||||
全局Serivce执行的线程池, Application.workExecutor, 没配置该节点将自动创建一个。
|
||||
threads: 线程数,为0表示不启用workExecutor,只用IO线程。默认: CPU核数, 核数=1的情况下默认值为2
|
||||
hash: 是否使用ThreadHashExecutor作为线程池,默认值为:false
|
||||
-->
|
||||
<executor threads="4" hash="false"/>
|
||||
|
||||
<!--
|
||||
【节点全局唯一】
|
||||
transport节点只能有一个,用于配置所有Transport的池参数,没配置该节点将自动创建一个。
|
||||
threads: 线程总数, 默认: <group>节点数*CPU核数*2
|
||||
bufferCapacity: ByteBuffer的初始化大小, 默认: 32K;
|
||||
bufferPoolSize: ByteBuffer池的大小,默认: 线程总数*4
|
||||
readTimeoutSeconds: TCP读取超时秒数, 默认为6秒, 为0表示无超时限制
|
||||
writeTimeoutSeconds: TCP写入超时秒数, 默认为6秒, 为0表示无超时限制
|
||||
strategy: 远程请求的负载均衡策略, 必须是org.redkale.net.TransportStrategy的实现类
|
||||
-->
|
||||
<transport bufferCapacity="32K" bufferPoolSize="32" threads="32" readTimeoutSeconds="6" writeTimeoutSeconds="6"/>
|
||||
|
||||
<!--
|
||||
【节点全局唯一】
|
||||
自动扫描时排除部分包路径
|
||||
value: 排除lib.path与excludes中的正则表达式匹配的路径, 多个正则表达式用分号;隔开
|
||||
-->
|
||||
<excludelibs value="^.*mysql.*$;^.*kafka.*$"/>
|
||||
|
||||
<!--
|
||||
【节点全局唯一】
|
||||
第三方服务发现管理接口
|
||||
type: 类名,必须是org.redkale.cluster.ClusterAgent的子类
|
||||
waits: 注销服务后是否需要等待检查周期时间后再进行Service销毁,默认值为:false
|
||||
当一个Service进行服务注销后,不能立刻销毁Service,因为健康检测是有间隔时间差的,
|
||||
需要等待一个健康检测周期时间,让其他进程都更新完服务列表。
|
||||
如果使用MQ,可以设置为false,如果对服务健壮性要求高,建议设置为true
|
||||
protocols: 服务发现可以处理的协议, 默认值为: SNCP, 多个协议用分号;隔开
|
||||
ports: 服务发现可以处理的端口, 多个端口用分号;隔开
|
||||
ttls: 心跳频率,多少秒一次
|
||||
xxxx: 自定义的字段属性,例如:CacheClusterAgent有source字段; ConsulClusterAgent有apiurl字段;
|
||||
-->
|
||||
<cluster type="org.redkalex.cluster.consul.ConsulClusterAgent" waits="false" protocols="SNCP" ports="7070;7071" xxx="xxx" />
|
||||
|
||||
<!--
|
||||
MQ管理接口配置
|
||||
不同MQ节点所配置的MQ集群不能重复。
|
||||
MQ跟着协议走,所以mq的属性值需要被赋值在rest节点上, 由于SncpServlet是自动生成的,故SNCP协议下,mq属性值被赋值在service/services节点上
|
||||
name: 服务的名称,用于监控识别,多个mq节点时只能有一个name为空的节点,mq.name不能重复,命名规则: 字母、数字、下划线
|
||||
type: 实现类名,必须是org.redkale.mq.MessageAgent的子类
|
||||
coder: MessageRecord的解析器类,必须是org.redkale.mq.MessageCoder<MessageRecord>的实现类,
|
||||
可对数据包进行加密解密,默认值:org.redkale.mq.MessageRecordCoder
|
||||
MQ节点下的子节点配置没有固定格式, 根据MessageAgent实现方的定义来配置
|
||||
-->
|
||||
<mq name="" type="org.redkalex.mq.kafka.KafkaMessageAgent">
|
||||
<servers value="127.0.0.1:9101"/>
|
||||
<consumer>
|
||||
<property name="xxxxxx" value="XXXXXXXX"/>
|
||||
</consumer>
|
||||
<producer>
|
||||
<property name="xxxxxx" value="XXXXXXXX"/>
|
||||
</producer>
|
||||
</mq>
|
||||
|
||||
<!--
|
||||
一个组包含多个node, 同一Service服务可以由多个进程提供,这些进程称为一个GROUP,且同一GROUP内的进程必须在同一机房或局域网内
|
||||
一个group节点对应一个 Transport 对象。
|
||||
name: 服务组ID,长度不能超过11个字节. 默认为空字符串。 注意: name不能包含$符号。
|
||||
protocol: 值范围:UDP TCP, 默认TCP
|
||||
注意: 一个node只能所属一个group。只要存在protocol=SNCP的Server节点信息, 就必须有group节点信息。
|
||||
-->
|
||||
<group name="" protocol="TCP">
|
||||
<!--
|
||||
需要将本地node的addr与port列在此处。
|
||||
同一个<node>节点值只能存在一个<group>节点内,即同一个addr+port只能属于一个group。
|
||||
addr: required IP地址
|
||||
port: required 端口
|
||||
-->
|
||||
<node addr="127.0.0.1" port="7070"/>
|
||||
</group>
|
||||
|
||||
<!--
|
||||
Application启动的监听事件,可配置多个节点
|
||||
value: 类名,必须是ApplicationListener的子类
|
||||
-->
|
||||
<listener value="org.redkalex.xxx.XXXApplicationListener"/>
|
||||
|
||||
<!--
|
||||
【节点全局唯一】
|
||||
全局的参数配置, 可以通过@Resource(name="property.xxxxxx") 进行注入<property>的信息, 被注解的字段类型只能是String、primitive class
|
||||
如果name是system.property.开头的值将会在进程启动时进行System.setProperty("yyyy", "YYYYYY")操作。
|
||||
如果name是mimetype.property.开头的值将会在进程启动时进行MimeType.add("yyyy", "YYYYYY")操作。
|
||||
先加载子节点property,再加载load文件, 最后加载agent的实现子类。
|
||||
load: 加载文件,多个用;隔开。
|
||||
其他属性: 供org.redkale.boot.PropertiesAgentProvider使用判断
|
||||
默认置入的system.property.的有:
|
||||
System.setProperty("redkale.net.transport.poolmaxconns", "100");
|
||||
System.setProperty("redkale.net.transport.pinginterval", "30");
|
||||
System.setProperty("redkale.net.transport.checkinterval", "30");
|
||||
System.setProperty("redkale.convert.tiny", "true");
|
||||
System.setProperty("redkale.convert.pool.size", "128");
|
||||
System.setProperty("redkale.convert.writer.buffer.defsize", "4096");
|
||||
System.setProperty("redkale.trace.enable", "false");
|
||||
|
||||
<properties>节点下也可包含非<property>节点.
|
||||
非<property>其节点可以通过@Resource(name="properties.xxxxxx")进行注入, 被注解的字段类型只能是AnyValue、AnyValue[]
|
||||
-->
|
||||
<properties load="config.properties">
|
||||
<property name="system.property.yyyy" value="YYYYYY"/>
|
||||
<property name="xxxxxx" value="XXXXXXXX"/>
|
||||
<property name="xxxxxx" value="XXXXXXXX"/>
|
||||
<property name="xxxxxx" value="XXXXXXXX"/>
|
||||
</properties>
|
||||
|
||||
<resources>
|
||||
</resources>
|
||||
|
||||
<!--
|
||||
【节点全局唯一】 @since 2.3.0
|
||||
全局Serivce执行的线程池, Application.workExecutor, 没配置该节点将自动创建一个。
|
||||
threads: 线程数,为0表示不启用workExecutor,只用IO线程。默认: CPU核数, 核数=1的情况下默认值为2
|
||||
hash: 是否使用ThreadHashExecutor作为线程池,默认值为:false
|
||||
-->
|
||||
<executor threads="4" hash="false"/>
|
||||
|
||||
<!--
|
||||
【节点全局唯一】
|
||||
transport节点只能有一个,用于配置所有Transport的池参数,没配置该节点将自动创建一个。
|
||||
threads: 线程总数, 默认: <group>节点数*CPU核数*2
|
||||
bufferCapacity: ByteBuffer的初始化大小, 默认: 32K;
|
||||
bufferPoolSize: ByteBuffer池的大小,默认: 线程总数*4
|
||||
readTimeoutSeconds: TCP读取超时秒数, 默认为6秒, 为0表示无超时限制
|
||||
writeTimeoutSeconds: TCP写入超时秒数, 默认为6秒, 为0表示无超时限制
|
||||
strategy: 远程请求的负载均衡策略, 必须是org.redkale.net.TransportStrategy的实现类
|
||||
-->
|
||||
<transport bufferCapacity="32K" bufferPoolSize="32" threads="32" readTimeoutSeconds="6" writeTimeoutSeconds="6"/>
|
||||
|
||||
<!--
|
||||
【节点全局唯一】
|
||||
自动扫描时排除部分包路径
|
||||
value: 排除lib.path与excludes中的正则表达式匹配的路径, 多个正则表达式用分号;隔开
|
||||
-->
|
||||
<excludelibs value="^.*mysql.*$;^.*kafka.*$"/>
|
||||
|
||||
<!--
|
||||
【节点全局唯一】
|
||||
第三方服务发现管理接口
|
||||
type: 类名,必须是org.redkale.cluster.ClusterAgent的子类
|
||||
waits: 注销服务后是否需要等待检查周期时间后再进行Service销毁,默认值为:false
|
||||
当一个Service进行服务注销后,不能立刻销毁Service,因为健康检测是有间隔时间差的,
|
||||
需要等待一个健康检测周期时间,让其他进程都更新完服务列表。
|
||||
如果使用MQ,可以设置为false,如果对服务健壮性要求高,建议设置为true
|
||||
protocols: 服务发现可以处理的协议, 默认值为: SNCP, 多个协议用分号;隔开
|
||||
ports: 服务发现可以处理的端口, 多个端口用分号;隔开
|
||||
ttls: 心跳频率,多少秒一次
|
||||
xxxx: 自定义的字段属性,例如:CacheClusterAgent有source字段; ConsulClusterAgent有apiurl字段;
|
||||
-->
|
||||
<cluster type="org.redkalex.cluster.consul.ConsulClusterAgent" waits="false" protocols="SNCP" ports="7070;7071" xxx="xxx" />
|
||||
|
||||
<!--
|
||||
MQ管理接口配置
|
||||
不同MQ节点所配置的MQ集群不能重复。
|
||||
MQ跟着协议走,所以mq的属性值需要被赋值在rest节点上, 由于SncpServlet是自动生成的,故SNCP协议下,mq属性值被赋值在service/services节点上
|
||||
name: 服务的名称,用于监控识别,多个mq节点时只能有一个name为空的节点,mq.name不能重复,命名规则: 字母、数字、下划线
|
||||
type: 实现类名,必须是org.redkale.mq.MessageAgent的子类
|
||||
coder: MessageRecord的解析器类,必须是org.redkale.mq.MessageCoder<MessageRecord>的实现类,
|
||||
可对数据包进行加密解密,默认值:org.redkale.mq.MessageRecordCoder
|
||||
MQ节点下的子节点配置没有固定格式, 根据MessageAgent实现方的定义来配置
|
||||
-->
|
||||
<mq name="" type="org.redkalex.mq.kafka.KafkaMessageAgent">
|
||||
<servers value="127.0.0.1:9101"/>
|
||||
<consumer>
|
||||
<property name="xxxxxx" value="XXXXXXXX"/>
|
||||
</consumer>
|
||||
<producer>
|
||||
<property name="xxxxxx" value="XXXXXXXX"/>
|
||||
</producer>
|
||||
</mq>
|
||||
|
||||
<!--
|
||||
一个组包含多个node, 同一Service服务可以由多个进程提供,这些进程称为一个GROUP,且同一GROUP内的进程必须在同一机房或局域网内
|
||||
一个group节点对应一个 Transport 对象。
|
||||
name: 服务组ID,长度不能超过11个字节. 默认为空字符串。 注意: name不能包含$符号。
|
||||
protocol: 值范围:UDP TCP, 默认TCP
|
||||
注意: 一个node只能所属一个group。只要存在protocol=SNCP的Server节点信息, 就必须有group节点信息。
|
||||
-->
|
||||
<group name="" protocol="TCP">
|
||||
<!--
|
||||
需要将本地node的addr与port列在此处。
|
||||
同一个<node>节点值只能存在一个<group>节点内,即同一个addr+port只能属于一个group。
|
||||
addr: required IP地址
|
||||
port: required 端口
|
||||
-->
|
||||
<node addr="127.0.0.1" port="7070"/>
|
||||
</group>
|
||||
|
||||
<!--
|
||||
Application启动的监听事件,可配置多个节点
|
||||
value: 类名,必须是ApplicationListener的子类
|
||||
-->
|
||||
<listener value="org.redkalex.xxx.XXXApplicationListener"/>
|
||||
|
||||
<!--
|
||||
【节点全局唯一】
|
||||
全局的参数配置, 可以通过@Resource(name="property.xxxxxx") 进行注入<property>的信息, 被注解的字段类型只能是String、primitive class
|
||||
如果name是system.property.开头的值将会在进程启动时进行System.setProperty("yyyy", "YYYYYY")操作。
|
||||
如果name是mimetype.property.开头的值将会在进程启动时进行MimeType.add("yyyy", "YYYYYY")操作。
|
||||
先加载子节点property,再加载load文件, 最后加载agent的实现子类。
|
||||
load: 加载文件,多个用;隔开。
|
||||
其他属性: 供org.redkale.boot.PropertiesAgentProvider使用判断
|
||||
默认置入的system.property.的有:
|
||||
System.setProperty("redkale.net.transport.poolmaxconns", "100");
|
||||
System.setProperty("redkale.net.transport.pinginterval", "30");
|
||||
System.setProperty("redkale.net.transport.checkinterval", "30");
|
||||
System.setProperty("redkale.convert.tiny", "true");
|
||||
System.setProperty("redkale.convert.pool.size", "128");
|
||||
System.setProperty("redkale.convert.writer.buffer.defsize", "4096");
|
||||
System.setProperty("redkale.trace.enable", "false");
|
||||
|
||||
<properties>节点下也可包含非<property>节点.
|
||||
非<property>其节点可以通过@Resource(name="properties.xxxxxx")进行注入, 被注解的字段类型只能是AnyValue、AnyValue[]
|
||||
-->
|
||||
<properties load="config.properties">
|
||||
<property name="system.property.yyyy" value="YYYYYY"/>
|
||||
<property name="xxxxxx" value="XXXXXXXX"/>
|
||||
<property name="xxxxxx" value="XXXXXXXX"/>
|
||||
<property name="xxxxxx" value="XXXXXXXX"/>
|
||||
</properties>
|
||||
|
||||
<!--
|
||||
protocol: required server所启动的协议,Redkale内置的有HTTP、SNCP、WATCH。协议均使用TCP实现; WATCH服务只能存在一个。
|
||||
name: 服务的名称,用于监控识别,一个配置文件中的server.name不能重复,命名规则: 字母、数字、下划线
|
||||
@@ -366,4 +366,5 @@
|
||||
<!-- 参数完全同上 -->
|
||||
<services autoload="true" includes="" excludes="" />
|
||||
</server>
|
||||
|
||||
</application>
|
||||
|
||||
@@ -82,11 +82,6 @@ public final class Application {
|
||||
*/
|
||||
public static final String RESNAME_APP_CONF_FILE = "APP_CONF_FILE";
|
||||
|
||||
/**
|
||||
* application.xml 文件中resources节点的内容, 类型: AnyValue
|
||||
*/
|
||||
public static final String RESNAME_APP_GRES = "APP_GRES";
|
||||
|
||||
/**
|
||||
* 当前进程节点的nodeid, 类型:int
|
||||
*/
|
||||
@@ -152,9 +147,6 @@ public final class Application {
|
||||
//Source 原始的配置资源, 只会存在redkale.datasource(.|[) redkale.cachesource(.|[)开头的配置项
|
||||
final Properties sourceProperties = new Properties();
|
||||
|
||||
//sourceProperties对应的AnyValue类型对象
|
||||
AnyValue sourceConfig;
|
||||
|
||||
//CacheSource 资源
|
||||
final List<CacheSource> cacheSources = new CopyOnWriteArrayList<>();
|
||||
|
||||
@@ -261,7 +253,7 @@ public final class Application {
|
||||
this.resourceFactory.register(RESNAME_APP_HOME, File.class, root);
|
||||
this.resourceFactory.register(RESNAME_APP_HOME, URI.class, root.toURI());
|
||||
File confFile = null;
|
||||
try {
|
||||
try { //设置APP_HOME
|
||||
this.resourceFactory.register(RESNAME_APP_HOME, root.getCanonicalPath());
|
||||
if (System.getProperty(RESNAME_APP_HOME) == null) {
|
||||
System.setProperty(RESNAME_APP_HOME, root.getCanonicalPath());
|
||||
@@ -415,7 +407,6 @@ public final class Application {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
//------------------------------------ 配置 <transport> 节点 ------------------------------------
|
||||
final AnyValue resources = config.getAnyValue("resources");
|
||||
TransportStrategy strategy = null;
|
||||
String excludelib0 = null;
|
||||
ClusterAgent cluster = null;
|
||||
@@ -425,108 +416,106 @@ public final class Application {
|
||||
int readTimeoutSeconds = TransportFactory.DEFAULT_READTIMEOUTSECONDS;
|
||||
int writeTimeoutSeconds = TransportFactory.DEFAULT_WRITETIMEOUTSECONDS;
|
||||
AnyValue executorConf = null;
|
||||
if (resources != null) {
|
||||
executorConf = resources.getAnyValue("executor");
|
||||
AnyValue excludelibConf = resources.getAnyValue("excludelibs");
|
||||
if (excludelibConf != null) excludelib0 = excludelibConf.getValue("value");
|
||||
AnyValue transportConf = resources.getAnyValue("transport");
|
||||
int groupsize = resources.getAnyValues("group").length;
|
||||
if (groupsize > 0 && transportConf == null) transportConf = new DefaultAnyValue();
|
||||
if (transportConf != null) {
|
||||
//--------------transportBufferPool-----------
|
||||
bufferCapacity = Math.max(parseLenth(transportConf.getValue("bufferCapacity"), bufferCapacity), 32 * 1024);
|
||||
readTimeoutSeconds = transportConf.getIntValue("readTimeoutSeconds", readTimeoutSeconds);
|
||||
writeTimeoutSeconds = transportConf.getIntValue("writeTimeoutSeconds", writeTimeoutSeconds);
|
||||
final int threads = parseLenth(transportConf.getValue("threads"), groupsize * Utility.cpus() * 2);
|
||||
bufferPoolSize = parseLenth(transportConf.getValue("bufferPoolSize"), threads * 4);
|
||||
}
|
||||
executorConf = config.getAnyValue("executor");
|
||||
AnyValue excludelibConf = config.getAnyValue("excludelibs");
|
||||
if (excludelibConf != null) excludelib0 = excludelibConf.getValue("value");
|
||||
AnyValue transportConf = config.getAnyValue("transport");
|
||||
int groupsize = config.getAnyValues("group").length;
|
||||
if (groupsize > 0 && transportConf == null) transportConf = new DefaultAnyValue();
|
||||
if (transportConf != null) {
|
||||
//--------------transportBufferPool-----------
|
||||
bufferCapacity = Math.max(parseLenth(transportConf.getValue("bufferCapacity"), bufferCapacity), 32 * 1024);
|
||||
readTimeoutSeconds = transportConf.getIntValue("readTimeoutSeconds", readTimeoutSeconds);
|
||||
writeTimeoutSeconds = transportConf.getIntValue("writeTimeoutSeconds", writeTimeoutSeconds);
|
||||
final int threads = parseLenth(transportConf.getValue("threads"), groupsize * Utility.cpus() * 2);
|
||||
bufferPoolSize = parseLenth(transportConf.getValue("bufferPoolSize"), threads * 4);
|
||||
}
|
||||
|
||||
AnyValue clusterConf = resources.getAnyValue("cluster");
|
||||
if (clusterConf != null) {
|
||||
try {
|
||||
String classVal = clusterConf.getValue("type", clusterConf.getValue("value")); //兼容value字段
|
||||
if (classVal == null || classVal.isEmpty() || classVal.indexOf('.') < 0) { //不包含.表示非类名,比如值: consul, nacos
|
||||
Iterator<ClusterAgentProvider> it = ServiceLoader.load(ClusterAgentProvider.class, classLoader).iterator();
|
||||
RedkaleClassLoader.putServiceLoader(ClusterAgentProvider.class);
|
||||
while (it.hasNext()) {
|
||||
ClusterAgentProvider provider = it.next();
|
||||
if (provider != null) RedkaleClassLoader.putReflectionPublicConstructors(provider.getClass(), provider.getClass().getName()); //loader class
|
||||
if (provider != null && provider.acceptsConf(clusterConf)) {
|
||||
cluster = provider.createInstance();
|
||||
cluster.setConfig(clusterConf);
|
||||
break;
|
||||
}
|
||||
AnyValue clusterConf = config.getAnyValue("cluster");
|
||||
if (clusterConf != null) {
|
||||
try {
|
||||
String classVal = clusterConf.getValue("type", clusterConf.getValue("value")); //兼容value字段
|
||||
if (classVal == null || classVal.isEmpty() || classVal.indexOf('.') < 0) { //不包含.表示非类名,比如值: consul, nacos
|
||||
Iterator<ClusterAgentProvider> it = ServiceLoader.load(ClusterAgentProvider.class, classLoader).iterator();
|
||||
RedkaleClassLoader.putServiceLoader(ClusterAgentProvider.class);
|
||||
while (it.hasNext()) {
|
||||
ClusterAgentProvider provider = it.next();
|
||||
if (provider != null) RedkaleClassLoader.putReflectionPublicConstructors(provider.getClass(), provider.getClass().getName()); //loader class
|
||||
if (provider != null && provider.acceptsConf(clusterConf)) {
|
||||
cluster = provider.createInstance();
|
||||
cluster.setConfig(clusterConf);
|
||||
break;
|
||||
}
|
||||
if (cluster == null) {
|
||||
ClusterAgent cacheClusterAgent = new CacheClusterAgent();
|
||||
if (cacheClusterAgent.acceptsConf(clusterConf)) {
|
||||
cluster = cacheClusterAgent;
|
||||
cluster.setConfig(clusterConf);
|
||||
}
|
||||
}
|
||||
if (cluster == null) logger.log(Level.SEVERE, "load application cluster resource, but not found name='type' value error: " + clusterConf);
|
||||
} else {
|
||||
Class type = classLoader.loadClass(classVal);
|
||||
if (!ClusterAgent.class.isAssignableFrom(type)) {
|
||||
logger.log(Level.SEVERE, "load application cluster resource, but not found " + ClusterAgent.class.getSimpleName() + " implements class error: " + clusterConf);
|
||||
} else {
|
||||
RedkaleClassLoader.putReflectionDeclaredConstructors(type, type.getName());
|
||||
cluster = (ClusterAgent) type.getDeclaredConstructor().newInstance();
|
||||
}
|
||||
if (cluster == null) {
|
||||
ClusterAgent cacheClusterAgent = new CacheClusterAgent();
|
||||
if (cacheClusterAgent.acceptsConf(clusterConf)) {
|
||||
cluster = cacheClusterAgent;
|
||||
cluster.setConfig(clusterConf);
|
||||
}
|
||||
}
|
||||
//此时不能执行cluster.init,因内置的对象可能依赖config.properties配置项
|
||||
} catch (Exception e) {
|
||||
logger.log(Level.SEVERE, "load application cluster resource error: " + clusterConf, e);
|
||||
if (cluster == null) logger.log(Level.SEVERE, "load application cluster resource, but not found name='type' value error: " + clusterConf);
|
||||
} else {
|
||||
Class type = classLoader.loadClass(classVal);
|
||||
if (!ClusterAgent.class.isAssignableFrom(type)) {
|
||||
logger.log(Level.SEVERE, "load application cluster resource, but not found " + ClusterAgent.class.getSimpleName() + " implements class error: " + clusterConf);
|
||||
} else {
|
||||
RedkaleClassLoader.putReflectionDeclaredConstructors(type, type.getName());
|
||||
cluster = (ClusterAgent) type.getDeclaredConstructor().newInstance();
|
||||
cluster.setConfig(clusterConf);
|
||||
}
|
||||
}
|
||||
//此时不能执行cluster.init,因内置的对象可能依赖config.properties配置项
|
||||
} catch (Exception e) {
|
||||
logger.log(Level.SEVERE, "load application cluster resource error: " + clusterConf, e);
|
||||
}
|
||||
}
|
||||
|
||||
AnyValue[] mqConfs = resources.getAnyValues("mq");
|
||||
if (mqConfs != null && mqConfs.length > 0) {
|
||||
mqs = new MessageAgent[mqConfs.length];
|
||||
Set<String> mqnames = new HashSet<>();
|
||||
for (int i = 0; i < mqConfs.length; i++) {
|
||||
AnyValue mqConf = mqConfs[i];
|
||||
String mqname = mqConf.getValue("name", "");
|
||||
if (mqnames.contains(mqname)) throw new RuntimeException("mq.name(" + mqname + ") is repeat");
|
||||
mqnames.add(mqname);
|
||||
String namex = mqConf.getValue("names");
|
||||
if (namex != null && !namex.isEmpty()) {
|
||||
for (String n : namex.split(";")) {
|
||||
if (n.trim().isEmpty()) continue;
|
||||
if (mqnames.contains(n.trim())) throw new RuntimeException("mq.name(" + n.trim() + ") is repeat");
|
||||
mqnames.add(n.trim());
|
||||
}
|
||||
AnyValue[] mqConfs = config.getAnyValues("mq");
|
||||
if (mqConfs != null && mqConfs.length > 0) {
|
||||
mqs = new MessageAgent[mqConfs.length];
|
||||
Set<String> mqnames = new HashSet<>();
|
||||
for (int i = 0; i < mqConfs.length; i++) {
|
||||
AnyValue mqConf = mqConfs[i];
|
||||
String mqname = mqConf.getValue("name", "");
|
||||
if (mqnames.contains(mqname)) throw new RuntimeException("mq.name(" + mqname + ") is repeat");
|
||||
mqnames.add(mqname);
|
||||
String namex = mqConf.getValue("names");
|
||||
if (namex != null && !namex.isEmpty()) {
|
||||
for (String n : namex.split(";")) {
|
||||
if (n.trim().isEmpty()) continue;
|
||||
if (mqnames.contains(n.trim())) throw new RuntimeException("mq.name(" + n.trim() + ") is repeat");
|
||||
mqnames.add(n.trim());
|
||||
}
|
||||
try {
|
||||
String classVal = mqConf.getValue("type", mqConf.getValue("value")); //兼容value字段
|
||||
if (classVal == null || classVal.isEmpty() || classVal.indexOf('.') < 0) { //不包含.表示非类名,比如值: kafka, pulsar
|
||||
Iterator<MessageAgentProvider> it = ServiceLoader.load(MessageAgentProvider.class, classLoader).iterator();
|
||||
RedkaleClassLoader.putServiceLoader(MessageAgentProvider.class);
|
||||
while (it.hasNext()) {
|
||||
MessageAgentProvider provider = it.next();
|
||||
if (provider != null) RedkaleClassLoader.putReflectionPublicConstructors(provider.getClass(), provider.getClass().getName()); //loader class
|
||||
if (provider != null && provider.acceptsConf(mqConf)) {
|
||||
mqs[i] = provider.createInstance();
|
||||
mqs[i].setConfig(mqConf);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (mqs[i] == null) logger.log(Level.SEVERE, "load application mq resource, but not found name='value' value error: " + mqConf);
|
||||
} else {
|
||||
Class type = classLoader.loadClass(classVal);
|
||||
if (!MessageAgent.class.isAssignableFrom(type)) {
|
||||
logger.log(Level.SEVERE, "load application mq resource, but not found " + MessageAgent.class.getSimpleName() + " implements class error: " + mqConf);
|
||||
} else {
|
||||
RedkaleClassLoader.putReflectionDeclaredConstructors(type, type.getName());
|
||||
mqs[i] = (MessageAgent) type.getDeclaredConstructor().newInstance();
|
||||
}
|
||||
try {
|
||||
String classVal = mqConf.getValue("type", mqConf.getValue("value")); //兼容value字段
|
||||
if (classVal == null || classVal.isEmpty() || classVal.indexOf('.') < 0) { //不包含.表示非类名,比如值: kafka, pulsar
|
||||
Iterator<MessageAgentProvider> it = ServiceLoader.load(MessageAgentProvider.class, classLoader).iterator();
|
||||
RedkaleClassLoader.putServiceLoader(MessageAgentProvider.class);
|
||||
while (it.hasNext()) {
|
||||
MessageAgentProvider provider = it.next();
|
||||
if (provider != null) RedkaleClassLoader.putReflectionPublicConstructors(provider.getClass(), provider.getClass().getName()); //loader class
|
||||
if (provider != null && provider.acceptsConf(mqConf)) {
|
||||
mqs[i] = provider.createInstance();
|
||||
mqs[i].setConfig(mqConf);
|
||||
break;
|
||||
}
|
||||
}
|
||||
//此时不能执行mq.init,因内置的对象可能依赖config.properties配置项
|
||||
} catch (Exception e) {
|
||||
logger.log(Level.SEVERE, "load application mq resource error: " + mqs[i], e);
|
||||
if (mqs[i] == null) logger.log(Level.SEVERE, "load application mq resource, but not found name='value' value error: " + mqConf);
|
||||
} else {
|
||||
Class type = classLoader.loadClass(classVal);
|
||||
if (!MessageAgent.class.isAssignableFrom(type)) {
|
||||
logger.log(Level.SEVERE, "load application mq resource, but not found " + MessageAgent.class.getSimpleName() + " implements class error: " + mqConf);
|
||||
} else {
|
||||
RedkaleClassLoader.putReflectionDeclaredConstructors(type, type.getName());
|
||||
mqs[i] = (MessageAgent) type.getDeclaredConstructor().newInstance();
|
||||
mqs[i].setConfig(mqConf);
|
||||
}
|
||||
}
|
||||
//此时不能执行mq.init,因内置的对象可能依赖config.properties配置项
|
||||
} catch (Exception e) {
|
||||
logger.log(Level.SEVERE, "load application mq resource error: " + mqs[i], e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -591,7 +580,8 @@ public final class Application {
|
||||
}
|
||||
|
||||
private void loadResourceProperties() throws IOException {
|
||||
final String confDir = this.confPath.toString();
|
||||
final Properties dyncProps = new Properties();
|
||||
final AtomicInteger propertyIndex = new AtomicInteger();
|
||||
//------------------------------------ 读取本地DataSource、CacheSource配置 ------------------------------------
|
||||
if ("file".equals(this.confPath.getScheme())) {
|
||||
File sourceFile = new File(new File(confPath), "source.properties");
|
||||
@@ -603,7 +593,9 @@ public final class Application {
|
||||
props.forEach((key, val) -> {
|
||||
if (key.toString().startsWith("redkale.datasource.") || key.toString().startsWith("redkale.datasource[")
|
||||
|| key.toString().startsWith("redkale.cachesource.") || key.toString().startsWith("redkale.cachesource[")) {
|
||||
sourceProperties.put(key, val);
|
||||
dyncProps.put(key, val);
|
||||
} else {
|
||||
logger.log(Level.WARNING, "skip illegal key " + key + " in source.properties");
|
||||
}
|
||||
});
|
||||
} else {
|
||||
@@ -612,13 +604,13 @@ public final class Application {
|
||||
if (persist.isFile() && persist.canRead()) {
|
||||
logger.log(Level.WARNING, "persistence.xml is deprecated, replaced by source.properties");
|
||||
InputStream in = new FileInputStream(persist);
|
||||
sourceProperties.putAll(DataSources.loadSourceProperties(in));
|
||||
dyncProps.putAll(DataSources.loadSourceProperties(in));
|
||||
in.close();
|
||||
}
|
||||
}
|
||||
} else { //从url或jar文件中resources读取
|
||||
try {
|
||||
final URI sourceURI = RedkaleClassLoader.getConfResourceAsURI(configFromCache ? null : confDir, "source.properties");
|
||||
final URI sourceURI = RedkaleClassLoader.getConfResourceAsURI(configFromCache ? null : this.confPath.toString(), "source.properties");
|
||||
InputStream in = sourceURI.toURL().openStream();
|
||||
Properties props = new Properties();
|
||||
props.load(in);
|
||||
@@ -626,85 +618,184 @@ public final class Application {
|
||||
props.forEach((key, val) -> {
|
||||
if (key.toString().startsWith("redkale.datasource.") || key.toString().startsWith("redkale.datasource[")
|
||||
|| key.toString().startsWith("redkale.cachesource.") || key.toString().startsWith("redkale.cachesource[")) {
|
||||
sourceProperties.put(key, val);
|
||||
dyncProps.put(key, val);
|
||||
} else {
|
||||
logger.log(Level.WARNING, "skip illegal key " + key + " in source.properties");
|
||||
}
|
||||
});
|
||||
} catch (Exception e) { //没有文件 跳过
|
||||
}
|
||||
//兼容 persistence.xml 【已废弃】
|
||||
try {
|
||||
final URI xmlURI = RedkaleClassLoader.getConfResourceAsURI(configFromCache ? null : confDir, "persistence.xml");
|
||||
final URI xmlURI = RedkaleClassLoader.getConfResourceAsURI(configFromCache ? null : this.confPath.toString(), "persistence.xml");
|
||||
InputStream in = xmlURI.toURL().openStream();
|
||||
sourceProperties.putAll(DataSources.loadSourceProperties(in));
|
||||
dyncProps.putAll(DataSources.loadSourceProperties(in));
|
||||
in.close();
|
||||
logger.log(Level.WARNING, "persistence.xml is deprecated, replaced by source.properties");
|
||||
} catch (Exception e) { //没有文件 跳过
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------ 读取配置项 ------------------------------------
|
||||
final AnyValue resources = config.getAnyValue("resources");
|
||||
if (resources != null) {
|
||||
resourceFactory.register(RESNAME_APP_GRES, AnyValue.class, resources);
|
||||
final AnyValue propertiesConf = resources.getAnyValue("properties");
|
||||
if (propertiesConf != null) {
|
||||
for (AnyValue prop : propertiesConf.getAnyValues("property")) {
|
||||
String key = prop.getValue("name");
|
||||
String value = prop.getValue("value");
|
||||
if (key == null || value == null) continue;
|
||||
updateEnvironmentProperty(key, value, null, null);
|
||||
}
|
||||
String dfloads = propertiesConf.getValue("load");
|
||||
if (dfloads != null) {
|
||||
for (String dfload : dfloads.split(";")) {
|
||||
if (dfload.trim().isEmpty()) continue;
|
||||
final URI df = RedkaleClassLoader.getConfResourceAsURI(configFromCache ? null : confDir, dfload.trim());
|
||||
if (df != null && (!"file".equals(df.getScheme()) || df.toString().contains("!") || new File(df).isFile())) {
|
||||
Properties ps = new Properties();
|
||||
try {
|
||||
InputStream in = df.toURL().openStream();
|
||||
ps.load(in);
|
||||
in.close();
|
||||
if (logger.isLoggable(Level.FINEST)) logger.log(Level.FINEST, "load properties(" + dfload + ") size = " + ps.size());
|
||||
ps.forEach((x, y) -> { //load中的配置项除了redkale.cachesource.和redkale.datasource.开头,不应该有其他redkale.开头配置项
|
||||
updateEnvironmentProperty(x.toString(), y, null, null);
|
||||
});
|
||||
} catch (Exception e) {
|
||||
logger.log(Level.WARNING, "load properties(" + dfload + ") error", e);
|
||||
}
|
||||
//------------------------------------ 读取配置项 ------------------------------------
|
||||
AnyValue propertiesConf = config.getAnyValue("properties");
|
||||
if (propertiesConf == null) {
|
||||
final AnyValue resources = config.getAnyValue("resources");
|
||||
if (resources != null) {
|
||||
logger.log(Level.WARNING, "<resources> in application config file is deprecated");
|
||||
propertiesConf = resources.getAnyValue("properties");
|
||||
}
|
||||
}
|
||||
if (propertiesConf != null) {
|
||||
final Properties agentEnvs = new Properties();
|
||||
if (propertiesConf.getValue("load") != null) { //本地配置项文件加载
|
||||
for (String dfload : propertiesConf.getValue("load").split(";")) {
|
||||
if (dfload.trim().isEmpty()) continue;
|
||||
final URI df = RedkaleClassLoader.getConfResourceAsURI(configFromCache ? null : this.confPath.toString(), dfload.trim());
|
||||
if (df != null && (!"file".equals(df.getScheme()) || df.toString().contains("!") || new File(df).isFile())) {
|
||||
Properties ps = new Properties();
|
||||
try {
|
||||
InputStream in = df.toURL().openStream();
|
||||
ps.load(in);
|
||||
in.close();
|
||||
if (logger.isLoggable(Level.FINEST)) logger.log(Level.FINEST, "load properties(" + dfload + ") size = " + ps.size());
|
||||
ps.forEach((x, y) -> { //load中的配置项除了redkale.cachesource.和redkale.datasource.开头,不应该有其他redkale.开头配置项
|
||||
if (!x.toString().startsWith("redkale.") && !x.toString().startsWith("property.")) {
|
||||
agentEnvs.put(x, y);
|
||||
} else {
|
||||
logger.log(Level.WARNING, "skip illegal(startswith redkale. or property.) key " + x + " in properties file");
|
||||
}
|
||||
});
|
||||
} catch (Exception e) {
|
||||
logger.log(Level.WARNING, "load properties(" + dfload + ") error", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{ //可能通过系统环境变量配置信息
|
||||
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(propertiesConf)) {
|
||||
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(propertiesConf);
|
||||
} else {
|
||||
this.propertiesAgent.init(this, propertiesConf);
|
||||
}
|
||||
logger.info("PropertiesAgent (type = " + this.propertiesAgent.getClass().getSimpleName() + ") init in " + (System.currentTimeMillis() - s) + " ms");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
final AnyValue[] sourceConfs = resources.getAnyValues("source");
|
||||
if (sourceConfs != null && sourceConfs.length > 0) {
|
||||
//<source>节点 【已废弃】
|
||||
throw new RuntimeException("<source> in application.xml is deprecated, replaced by source.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(propertiesConf)) {
|
||||
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(propertiesConf);
|
||||
} else {
|
||||
Properties props = this.propertiesAgent.init(this, propertiesConf);
|
||||
if (props != null) {
|
||||
agentEnvs.putAll(props);
|
||||
}
|
||||
}
|
||||
logger.info("PropertiesAgent (type = " + this.propertiesAgent.getClass().getSimpleName() + ") init in " + (System.currentTimeMillis() - s) + " ms");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
final Properties oldEnvs = new Properties();
|
||||
for (AnyValue prop : propertiesConf.getAnyValues("property")) {
|
||||
String key = prop.getValue("name");
|
||||
String value = prop.getValue("value");
|
||||
if (key == null || value == null) continue;
|
||||
if (key.startsWith("property.")) {
|
||||
logger.log(Level.WARNING, "property key (" + key + ") startswith 'property.' is illegal, auto remove the prefix 'property.'");
|
||||
key = key.substring("property.".length());
|
||||
}
|
||||
oldEnvs.put(key, value);
|
||||
}
|
||||
agentEnvs.forEach((k, v) -> {
|
||||
if (k.toString().startsWith("redkale.")) {
|
||||
dyncProps.put(k, v);
|
||||
} else if (k.toString().startsWith("property.")) {
|
||||
logger.log(Level.WARNING, "skip illegal(startswith property.) key " + k + " in remote properties agent");
|
||||
} else {
|
||||
oldEnvs.put(k, v); //新配置项会覆盖旧的
|
||||
}
|
||||
});
|
||||
//原有properties节点上的属性同步到dyncEnvs
|
||||
propertiesConf.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);
|
||||
});
|
||||
//移除旧节点
|
||||
((DefaultAnyValue) this.config).removeAnyValues("properties");
|
||||
}
|
||||
//环境变量的优先级最高
|
||||
System.getProperties().forEach((k, v) -> {
|
||||
if (k.toString().startsWith("redkale.executor.") //节点全局唯一
|
||||
|| k.toString().startsWith("redkale.transport.") //节点全局唯一
|
||||
|| k.toString().startsWith("redkale.excludelibs.") //节点全局唯一
|
||||
|| k.toString().startsWith("redkale.cluster.") //节点全局唯一
|
||||
|| 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.properties.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()) {
|
||||
//合并配置
|
||||
this.config.merge(AnyValue.loadFromProperties(dyncProps).getAnyValue("redkale"), NodeServer.appConfigmergeFunction);
|
||||
dyncProps.forEach((key, val) -> {
|
||||
if (key.toString().startsWith("redkale.datasource.") || key.toString().startsWith("redkale.datasource[")
|
||||
|| key.toString().startsWith("redkale.cachesource.") || key.toString().startsWith("redkale.cachesource[")) {
|
||||
if (key.toString().endsWith(".name")) {
|
||||
logger.log(Level.WARNING, "skip illegal key " + key + " in source config, key cannot endsWith '.name'");
|
||||
} else {
|
||||
sourceProperties.put(key, val);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
//使用合并后的新配置节点
|
||||
propertiesConf = this.config.getAnyValue("properties");
|
||||
if (propertiesConf != null) {
|
||||
//清除property节点数组的下坐标
|
||||
((DefaultAnyValue) propertiesConf).clearParentArrayIndex("property");
|
||||
//注入配置项
|
||||
for (AnyValue prop : propertiesConf.getAnyValues("property")) {
|
||||
String key = prop.getValue("name");
|
||||
String value = prop.getValue("value");
|
||||
if (key == null) continue;
|
||||
value = value == null ? value : replaceValue(value);
|
||||
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 if (key.startsWith("property.")) {
|
||||
envProperties.put(key, value);
|
||||
resourceFactory.register(key, value);
|
||||
} else {
|
||||
envProperties.put(key, value);
|
||||
resourceFactory.register(false, "property." + key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -981,23 +1072,13 @@ public final class Application {
|
||||
}
|
||||
|
||||
private AnyValue findSourceConfig(String sourceName, String sourceType) {
|
||||
if (sourceConfig == null) {
|
||||
synchronized ((sourceProperties)) {
|
||||
if (sourceConfig == null) {
|
||||
sourceConfig = AnyValue.loadFromProperties(sourceProperties);
|
||||
}
|
||||
}
|
||||
}
|
||||
AnyValue redNode = sourceConfig.getAnyValue("redkale");
|
||||
if (redNode != null) {
|
||||
AnyValue sourceNode = redNode.getAnyValue(sourceType);
|
||||
if (sourceNode != null) {
|
||||
AnyValue confNode = sourceNode.getAnyValue(sourceName);
|
||||
if (confNode != null) { //必须要设置name属性
|
||||
((DefaultAnyValue) confNode).setValue("name", sourceName);
|
||||
}
|
||||
return confNode;
|
||||
AnyValue sourceNode = config.getAnyValue(sourceType);
|
||||
if (sourceNode != null) {
|
||||
AnyValue confNode = sourceNode.getAnyValue(sourceName);
|
||||
if (confNode != null) { //必须要设置name属性
|
||||
((DefaultAnyValue) confNode).setValue("name", sourceName);
|
||||
}
|
||||
return confNode;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -1126,35 +1207,31 @@ public final class Application {
|
||||
}
|
||||
|
||||
private void initResources() throws Exception {
|
||||
//-------------------------------------------------------------------------
|
||||
final AnyValue resources = config.getAnyValue("resources");
|
||||
if (resources != null) {
|
||||
//------------------------------------------------------------------------
|
||||
for (AnyValue conf : resources.getAnyValues("group")) {
|
||||
final String group = conf.getValue("name", "");
|
||||
final String protocol = conf.getValue("protocol", Transport.DEFAULT_NETPROTOCOL).toUpperCase();
|
||||
if (!"TCP".equalsIgnoreCase(protocol) && !"UDP".equalsIgnoreCase(protocol)) {
|
||||
throw new RuntimeException("Not supported Transport Protocol " + conf.getValue("protocol"));
|
||||
}
|
||||
TransportGroupInfo ginfo = new TransportGroupInfo(group, protocol, new LinkedHashSet<>());
|
||||
for (AnyValue node : conf.getAnyValues("node")) {
|
||||
final InetSocketAddress addr = new InetSocketAddress(node.getValue("addr"), node.getIntValue("port"));
|
||||
ginfo.putAddress(addr);
|
||||
}
|
||||
sncpTransportFactory.addGroupInfo(ginfo);
|
||||
//------------------------------------------------------------------------
|
||||
for (AnyValue conf : config.getAnyValues("group")) {
|
||||
final String group = conf.getValue("name", "");
|
||||
final String protocol = conf.getValue("protocol", Transport.DEFAULT_NETPROTOCOL).toUpperCase();
|
||||
if (!"TCP".equalsIgnoreCase(protocol) && !"UDP".equalsIgnoreCase(protocol)) {
|
||||
throw new RuntimeException("Not supported Transport Protocol " + conf.getValue("protocol"));
|
||||
}
|
||||
for (AnyValue conf : resources.getAnyValues("listener")) {
|
||||
final String listenClass = conf.getValue("value", "");
|
||||
if (listenClass.isEmpty()) continue;
|
||||
Class clazz = classLoader.loadClass(listenClass);
|
||||
if (!ApplicationListener.class.isAssignableFrom(clazz)) continue;
|
||||
RedkaleClassLoader.putReflectionDeclaredConstructors(clazz, clazz.getName());
|
||||
@SuppressWarnings("unchecked")
|
||||
ApplicationListener listener = (ApplicationListener) clazz.getDeclaredConstructor().newInstance();
|
||||
resourceFactory.inject(listener);
|
||||
listener.init(config);
|
||||
this.listeners.add(listener);
|
||||
TransportGroupInfo ginfo = new TransportGroupInfo(group, protocol, new LinkedHashSet<>());
|
||||
for (AnyValue node : conf.getAnyValues("node")) {
|
||||
final InetSocketAddress addr = new InetSocketAddress(node.getValue("addr"), node.getIntValue("port"));
|
||||
ginfo.putAddress(addr);
|
||||
}
|
||||
sncpTransportFactory.addGroupInfo(ginfo);
|
||||
}
|
||||
for (AnyValue conf : config.getAnyValues("listener")) {
|
||||
final String listenClass = conf.getValue("value", "");
|
||||
if (listenClass.isEmpty()) continue;
|
||||
Class clazz = classLoader.loadClass(listenClass);
|
||||
if (!ApplicationListener.class.isAssignableFrom(clazz)) continue;
|
||||
RedkaleClassLoader.putReflectionDeclaredConstructors(clazz, clazz.getName());
|
||||
@SuppressWarnings("unchecked")
|
||||
ApplicationListener listener = (ApplicationListener) clazz.getDeclaredConstructor().newInstance();
|
||||
resourceFactory.inject(listener);
|
||||
listener.init(config);
|
||||
this.listeners.add(listener);
|
||||
}
|
||||
//------------------------------------------------------------------------
|
||||
}
|
||||
@@ -1633,7 +1710,12 @@ public final class Application {
|
||||
}
|
||||
System.setProperty(RESNAME_APP_CONF_DIR, confDir);
|
||||
String text = Utility.readThenClose(appConfFile.toURL().openStream());
|
||||
AnyValue conf = text.trim().startsWith("<") ? AnyValue.loadFromXml(text, (k, v) -> v.replace("${APP_HOME}", home)).getAnyValue("application") : AnyValue.loadFromProperties(text).getAnyValue("redkale");
|
||||
AnyValue conf;
|
||||
if (text.trim().startsWith("<")) {
|
||||
conf = AnyValue.loadFromXml(text, (k, v) -> v.replace("${APP_HOME}", home)).getAnyValue("application");
|
||||
} else {
|
||||
conf = AnyValue.loadFromProperties(text).getAnyValue("redkale");
|
||||
}
|
||||
if (fromCache) ((DefaultAnyValue) conf).addValue("[config-from-cache]", "true");
|
||||
return conf;
|
||||
}
|
||||
@@ -1712,84 +1794,101 @@ public final class Application {
|
||||
return value == null ? value : value.replace("${APP_HOME}", homePath).replace("${APP_NAME}", name);
|
||||
}
|
||||
|
||||
//初始化加载时:envChangeCache=null
|
||||
//配置项动态变更时 envChangeCache!=null, 由调用方统一执行ResourceFactory.register(envChangeCache)
|
||||
//key只会是system.property.、mimetype.property.、redkale.cachesource(.|[)、redkale.datasource(.|[)和其他非redkale.开头的配置项
|
||||
void updateEnvironmentProperty(String key, Object value, Properties envChangeCache, Properties sourceChangeCache) {
|
||||
if (key == null || value == null) return;
|
||||
String val = replaceValue(value.toString()).trim();
|
||||
if (key.startsWith("redkale.datasource.") || key.startsWith("redkale.datasource[")
|
||||
|| key.startsWith("redkale.cachesource.") || key.startsWith("redkale.cachesource[")) {
|
||||
if (!Objects.equals(val, sourceProperties.getProperty(key))) {
|
||||
if (sourceChangeCache == null) {
|
||||
sourceProperties.put(key, val);
|
||||
} else {
|
||||
sourceChangeCache.put(key, val);
|
||||
}
|
||||
}
|
||||
} else if (key.startsWith("system.property.")) {
|
||||
String propName = key.substring("system.property.".length());
|
||||
if (envChangeCache != null || System.getProperty(propName) == null) { //命令行传参数优先级高
|
||||
System.setProperty(propName, val);
|
||||
}
|
||||
} else if (key.startsWith("mimetype.property.")) {
|
||||
MimeType.add(key.substring("mimetype.property.".length()), val);
|
||||
} else if (key.startsWith("property.")) {
|
||||
Object old = resourceFactory.find(key, String.class);
|
||||
if (!Objects.equals(val, old)) {
|
||||
envProperties.put(key, val);
|
||||
if (envChangeCache == null) {
|
||||
resourceFactory.register(key, val);
|
||||
} else {
|
||||
envChangeCache.put(key, val);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (key.startsWith("redkale.")) {
|
||||
throw new RuntimeException("property " + key + " cannot redkale. startsWith");
|
||||
}
|
||||
String newkey = "property." + key;
|
||||
Object old = resourceFactory.find(newkey, String.class);
|
||||
if (!Objects.equals(val, old)) {
|
||||
envProperties.put(key, val);
|
||||
if (envChangeCache == null) {
|
||||
resourceFactory.register(newkey, val);
|
||||
} else {
|
||||
envChangeCache.put(newkey, val);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
void updateEnvironmentProperties(List<ResourceEvent> events) {
|
||||
if (events == null || events.isEmpty()) return;
|
||||
synchronized (envProperties) {
|
||||
Properties envRegisterProps = new Properties();
|
||||
Set<String> envRemovedKeys = new HashSet<>();
|
||||
Properties envChangedProps = new Properties();
|
||||
|
||||
void updateSourceProperties(Properties sourceChangeCache) {
|
||||
if (sourceChangeCache == null || sourceChangeCache.isEmpty()) return;
|
||||
synchronized (sourceProperties) {
|
||||
Properties changedProps = new Properties();
|
||||
for (Map.Entry<Object, Object> en : sourceChangeCache.entrySet()) {
|
||||
String key = en.getKey().toString();
|
||||
if (key.startsWith("redkale.datasource.") || key.startsWith("redkale.datasource[")
|
||||
|| key.startsWith("redkale.cachesource.") || key.startsWith("redkale.cachesource[")) {
|
||||
if (!Objects.equals(en.getValue(), sourceProperties.get(key))) {
|
||||
changedProps.put(en.getKey(), en.getValue());
|
||||
if (key.endsWith(".name")) { //不更改source.name属性
|
||||
throw new RuntimeException("source properties contains illegal key: " + key);
|
||||
Set<String> sourceRemovedKeys = new HashSet<>();
|
||||
Properties sourceChangedProps = new Properties();
|
||||
for (ResourceEvent<String> event : events) {
|
||||
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, key cannot endsWith '.name'");
|
||||
} else {
|
||||
if (!Objects.equals(event.newValue(), sourceProperties.getProperty(event.name()))) {
|
||||
if (event.newValue() == null) {
|
||||
if (sourceProperties.containsKey(event.name())) {
|
||||
sourceRemovedKeys.add(event.name());
|
||||
}
|
||||
} else {
|
||||
sourceChangedProps.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("property.")) {
|
||||
if (!Objects.equals(event.newValue(), envProperties.getProperty(event.name()))) {
|
||||
envRegisterProps.put(event.name(), event.newValue());
|
||||
if (event.newValue() == null) {
|
||||
if (envProperties.containsKey(event.name())) {
|
||||
envRemovedKeys.add(event.name());
|
||||
}
|
||||
} else {
|
||||
envChangedProps.put(event.name(), event.newValue());
|
||||
}
|
||||
}
|
||||
} else if (event.name().startsWith("redkale.")) {
|
||||
logger.log(Level.WARNING, "not support the env property key " + event.name() + " on change event");
|
||||
} else {
|
||||
throw new RuntimeException("source properties contains illegal key: " + key);
|
||||
if (!Objects.equals(event.newValue(), envProperties.getProperty(event.name()))) {
|
||||
envRegisterProps.put("property." + event.name(), event.newValue());
|
||||
if (event.newValue() == null) {
|
||||
if (envProperties.containsKey(event.name())) {
|
||||
envRemovedKeys.add(event.name());
|
||||
}
|
||||
} else {
|
||||
envChangedProps.put(event.name(), event.newValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (changedProps.isEmpty()) return; //无内容改变
|
||||
AnyValue newRedNode = AnyValue.loadFromProperties(changedProps).getAnyValue("redkale");
|
||||
AnyValue newCacheNode = newRedNode.getAnyValue("cachesource");
|
||||
if (newCacheNode != null) {
|
||||
newCacheNode.forEach(null, (sourceName, newConf) -> {
|
||||
|
||||
//普通配置项的变更
|
||||
if (!envRegisterProps.isEmpty()) {
|
||||
envProperties.putAll(envChangedProps);
|
||||
envRemovedKeys.forEach(k -> envProperties.remove(k));
|
||||
resourceFactory.register(envRegisterProps, "", Environment.class);
|
||||
}
|
||||
//数据源配置项的变更
|
||||
if (!sourceChangedProps.isEmpty() || !sourceRemovedKeys.isEmpty()) {
|
||||
Set<String> cacheSourceNames = new LinkedHashSet<>();
|
||||
Set<String> dataSourceNames = new LinkedHashSet<>();
|
||||
List<String> keys = new ArrayList<>();
|
||||
keys.addAll(sourceRemovedKeys);
|
||||
keys.addAll((Set) sourceChangedProps.keySet());
|
||||
for (final String key : keys) {
|
||||
if (key.startsWith("redkale.cachesource[")) {
|
||||
cacheSourceNames.add(key.substring("redkale.cachesource[".length(), key.indexOf(']')));
|
||||
} else if (key.startsWith("redkale.cachesource.")) {
|
||||
cacheSourceNames.add(key.substring("redkale.cachesource.".length(), key.indexOf('.', "redkale.cachesource.".length())));
|
||||
} else if (key.startsWith("redkale.datasource[")) {
|
||||
dataSourceNames.add(key.substring("redkale.datasource[".length(), key.indexOf(']')));
|
||||
} else if (key.startsWith("redkale.datasource.")) {
|
||||
dataSourceNames.add(key.substring("redkale.datasource.".length(), key.indexOf('.', "redkale.datasource.".length())));
|
||||
}
|
||||
}
|
||||
//更新缓存
|
||||
for (String sourceName : cacheSourceNames) {
|
||||
CacheSource source = Utility.find(cacheSources, s -> Objects.equals(s.resourceName(), sourceName));
|
||||
if (source == null) return; //多余的数据源
|
||||
DefaultAnyValue old = (DefaultAnyValue) findSourceConfig(sourceName, "cachesource");
|
||||
old.merge(newConf);
|
||||
List<ResourceEvent> events = new ArrayList<>();
|
||||
changedProps.forEach((k, v) -> {
|
||||
final DefaultAnyValue old = (DefaultAnyValue) findSourceConfig(sourceName, "cachesource");
|
||||
Properties newProps = new Properties();
|
||||
sourceProperties.forEach((k, v) -> {
|
||||
final String key = k.toString();
|
||||
String prefix = "redkale.cachesource[" + sourceName + "].";
|
||||
int pos = key.indexOf(prefix);
|
||||
@@ -1797,21 +1896,52 @@ public final class Application {
|
||||
prefix = "redkale.cachesource." + sourceName + ".";
|
||||
pos = key.indexOf(prefix);
|
||||
}
|
||||
if (pos < 0) return;
|
||||
events.add(ResourceEvent.create(key.substring(prefix.length()), v, sourceProperties.get(key)));
|
||||
if (pos < 0) return; //不是同一name数据源配置项
|
||||
newProps.put(k, v);
|
||||
});
|
||||
((AbstractCacheSource) source).onResourceChange(events.toArray(new ResourceEvent[events.size()]));
|
||||
});
|
||||
}
|
||||
AnyValue newSourceNode = newRedNode.getAnyValue("datasource");
|
||||
if (newSourceNode != null) {
|
||||
newSourceNode.forEach(null, (sourceName, newConf) -> {
|
||||
List<ResourceEvent> changeEvents = new ArrayList<>();
|
||||
sourceChangedProps.forEach((k, v) -> {
|
||||
final String key = k.toString();
|
||||
String prefix = "redkale.cachesource[" + sourceName + "].";
|
||||
int pos = key.indexOf(prefix);
|
||||
if (pos < 0) {
|
||||
prefix = "redkale.cachesource." + sourceName + ".";
|
||||
pos = key.indexOf(prefix);
|
||||
}
|
||||
if (pos < 0) return; //不是同一name数据源配置项
|
||||
newProps.put(k, v);
|
||||
changeEvents.add(ResourceEvent.create(key.substring(prefix.length()), v, sourceProperties.getProperty(key)));
|
||||
});
|
||||
sourceRemovedKeys.forEach(k -> {
|
||||
final String key = k;
|
||||
String prefix = "redkale.cachesource[" + sourceName + "].";
|
||||
int pos = key.indexOf(prefix);
|
||||
if (pos < 0) {
|
||||
prefix = "redkale.cachesource." + sourceName + ".";
|
||||
pos = key.indexOf(prefix);
|
||||
}
|
||||
if (pos < 0) return;
|
||||
newProps.remove(k); //不是同一name数据源配置项
|
||||
changeEvents.add(ResourceEvent.create(key.substring(prefix.length()), null, sourceProperties.getProperty(key)));
|
||||
});
|
||||
if (!changeEvents.isEmpty()) {
|
||||
DefaultAnyValue back = old.copy();
|
||||
old.replace(AnyValue.loadFromProperties(newProps).getAnyValue("redkale").getAnyValue("cachesource").getAnyValue(sourceName));
|
||||
try {
|
||||
((AbstractCacheSource) source).onResourceChange(changeEvents.toArray(new ResourceEvent[changeEvents.size()]));
|
||||
} catch (RuntimeException e) {
|
||||
old.replace(back); //还原配置
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
//更新数据库
|
||||
for (String sourceName : dataSourceNames) {
|
||||
DataSource source = Utility.find(dataSources, s -> Objects.equals(s.resourceName(), sourceName));
|
||||
if (source == null) return; //多余的数据源
|
||||
DefaultAnyValue old = (DefaultAnyValue) findSourceConfig(sourceName, "datasource");
|
||||
old.merge(newConf);
|
||||
List<ResourceEvent> events = new ArrayList<>();
|
||||
changedProps.forEach((k, v) -> {
|
||||
Properties newProps = new Properties();
|
||||
sourceProperties.forEach((k, v) -> {
|
||||
final String key = k.toString();
|
||||
String prefix = "redkale.datasource[" + sourceName + "].";
|
||||
int pos = key.indexOf(prefix);
|
||||
@@ -1819,13 +1949,48 @@ public final class Application {
|
||||
prefix = "redkale.datasource." + sourceName + ".";
|
||||
pos = key.indexOf(prefix);
|
||||
}
|
||||
if (pos < 0) return;
|
||||
events.add(ResourceEvent.create(key.substring(prefix.length()), v, sourceProperties.get(key)));
|
||||
if (pos < 0) return; //不是同一name数据源配置项
|
||||
newProps.put(k, v);
|
||||
});
|
||||
((AbstractDataSource) source).onResourceChange(events.toArray(new ResourceEvent[events.size()]));
|
||||
});
|
||||
List<ResourceEvent> changeEvents = new ArrayList<>();
|
||||
sourceChangedProps.forEach((k, v) -> {
|
||||
final String key = k.toString();
|
||||
String prefix = "redkale.datasource[" + sourceName + "].";
|
||||
int pos = key.indexOf(prefix);
|
||||
if (pos < 0) {
|
||||
prefix = "redkale.datasource." + sourceName + ".";
|
||||
pos = key.indexOf(prefix);
|
||||
}
|
||||
if (pos < 0) return; //不是同一name数据源配置项
|
||||
newProps.put(k, v);
|
||||
changeEvents.add(ResourceEvent.create(key.substring(prefix.length()), v, sourceProperties.getProperty(key)));
|
||||
});
|
||||
sourceRemovedKeys.forEach(k -> {
|
||||
final String key = k;
|
||||
String prefix = "redkale.datasource[" + sourceName + "].";
|
||||
int pos = key.indexOf(prefix);
|
||||
if (pos < 0) {
|
||||
prefix = "redkale.datasource." + sourceName + ".";
|
||||
pos = key.indexOf(prefix);
|
||||
}
|
||||
if (pos < 0) return;
|
||||
newProps.remove(k); //不是同一name数据源配置项
|
||||
changeEvents.add(ResourceEvent.create(key.substring(prefix.length()), null, sourceProperties.getProperty(key)));
|
||||
});
|
||||
if (!changeEvents.isEmpty()) {
|
||||
DefaultAnyValue back = old.copy();
|
||||
old.replace(AnyValue.loadFromProperties(newProps).getAnyValue("redkale").getAnyValue("datasource").getAnyValue(sourceName));
|
||||
try {
|
||||
((AbstractDataSource) source).onResourceChange(changeEvents.toArray(new ResourceEvent[changeEvents.size()]));
|
||||
} catch (RuntimeException e) {
|
||||
old.replace(back); //还原配置
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
sourceRemovedKeys.forEach(k -> sourceProperties.remove(k));
|
||||
sourceProperties.putAll(sourceChangedProps);
|
||||
}
|
||||
sourceProperties.putAll(changedProps);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1946,7 +2111,7 @@ public final class Application {
|
||||
}
|
||||
if (this.propertiesAgent != null) {
|
||||
long s = System.currentTimeMillis();
|
||||
this.propertiesAgent.destroy(config.getAnyValue("resources").getAnyValue("properties"));
|
||||
this.propertiesAgent.destroy(config.getAnyValue("properties"));
|
||||
logger.info(this.propertiesAgent.getClass().getSimpleName() + " destroy in " + (System.currentTimeMillis() - s) + " ms");
|
||||
}
|
||||
if (this.clientAsyncGroup != null) {
|
||||
|
||||
@@ -211,7 +211,6 @@ public abstract class NodeServer {
|
||||
//---------------------------------------------------------------------------------------------
|
||||
final ResourceFactory appResFactory = application.getResourceFactory();
|
||||
final TransportFactory appSncpTranFactory = application.getSncpTransportFactory();
|
||||
final AnyValue resources = application.config.getAnyValue("resources");
|
||||
final String confURI = appResFactory.find(RESNAME_APP_CONF_DIR, String.class);
|
||||
//------------------------------------- 注册 Resource --------------------------------------------------------
|
||||
resourceFactory.register((ResourceFactory rf, String srcResourceName, final Object srcObj, String resourceName, Field field, final Object attachment) -> {
|
||||
@@ -222,7 +221,7 @@ public abstract class NodeServer {
|
||||
Class type = field.getType();
|
||||
if (type != AnyValue.class && type != AnyValue[].class) return;
|
||||
Object resource = null;
|
||||
final AnyValue properties = resources == null ? null : resources.getAnyValue("properties");
|
||||
final AnyValue properties = application.getAppConfig().getAnyValue("properties");
|
||||
if (properties != null && type == AnyValue.class) {
|
||||
resource = properties.getAnyValue(res.name().substring("properties.".length()));
|
||||
appResFactory.register(resourceName, AnyValue.class, resource);
|
||||
@@ -780,4 +779,114 @@ public abstract class NodeServer {
|
||||
public String getThreadName() {
|
||||
return this.threadName;
|
||||
}
|
||||
|
||||
static final AnyValue.MergeFunction appConfigmergeFunction = (path, key, val1, val2) -> {
|
||||
if ("".equals(path)) {
|
||||
if ("executor".equals(key)) {
|
||||
return AnyValue.MergeFunction.REPLACE;
|
||||
}
|
||||
if ("transport".equals(key)) {
|
||||
return AnyValue.MergeFunction.REPLACE;
|
||||
}
|
||||
if ("excludelibs".equals(key)) {
|
||||
return AnyValue.MergeFunction.REPLACE;
|
||||
}
|
||||
if ("cluster".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;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -2,14 +2,14 @@
|
||||
*/
|
||||
package org.redkale.boot;
|
||||
|
||||
import java.util.Properties;
|
||||
import java.util.*;
|
||||
import java.util.logging.Logger;
|
||||
import org.redkale.util.*;
|
||||
|
||||
/**
|
||||
* 配置源Agent, 在init方法内需要实现读取配置信息,如果支持配置更改通知,也需要在init里实现监听
|
||||
*
|
||||
* 配置项优先级: 本地配置 < 配置中心 < 环境变量
|
||||
*
|
||||
* 配置项优先级: 本地配置 < 配置中心 < 环境变量
|
||||
*
|
||||
*
|
||||
* 详情见: https://redkale.org
|
||||
@@ -44,8 +44,10 @@ public abstract class PropertiesAgent {
|
||||
*
|
||||
* @param application Application
|
||||
* @param conf 节点配置
|
||||
*
|
||||
* @return 加载的配置项
|
||||
*/
|
||||
public abstract void init(Application application, AnyValue conf);
|
||||
public abstract Properties init(Application application, AnyValue conf);
|
||||
|
||||
/**
|
||||
* 销毁动作
|
||||
@@ -54,21 +56,18 @@ public abstract class PropertiesAgent {
|
||||
*/
|
||||
public abstract void destroy(AnyValue conf);
|
||||
|
||||
protected void updateEnvironmentProperties(Application application, Properties props) {
|
||||
if (props.isEmpty()) return;
|
||||
Properties envChangeCache = new Properties();
|
||||
Properties sourceChangeCache = new Properties();
|
||||
props.forEach((k, v) -> application.updateEnvironmentProperty(k.toString(), v.toString().trim(), envChangeCache, sourceChangeCache));
|
||||
if (!envChangeCache.isEmpty()) {
|
||||
application.resourceFactory.register(envChangeCache, "", Environment.class);
|
||||
}
|
||||
if (!sourceChangeCache.isEmpty()) {
|
||||
application.updateSourceProperties(sourceChangeCache);
|
||||
}
|
||||
}
|
||||
|
||||
protected void putEnvironmentProperty(Application application, String key, Object value) {
|
||||
application.updateEnvironmentProperty(key, value, null, null);
|
||||
protected void updateEnvironmentProperties(Application application, List<ResourceEvent> events) {
|
||||
if (events == null || events.isEmpty()) return;
|
||||
application.updateEnvironmentProperties(events);
|
||||
// Properties envChangeCache = new Properties();
|
||||
// Properties sourceChangeCache = new Properties();
|
||||
// //props.forEach((k, v) -> application.updateEnvironmentProperty(k.toString(), v.toString().trim(), envChangeCache, sourceChangeCache));
|
||||
// if (!envChangeCache.isEmpty()) {
|
||||
// application.resourceFactory.register(envChangeCache, "", Environment.class);
|
||||
// }
|
||||
// if (!sourceChangeCache.isEmpty()) {
|
||||
// application.updateSourceProperties(sourceChangeCache);
|
||||
// }
|
||||
}
|
||||
|
||||
protected void reconfigLogging(Application application, Properties loggingProperties) {
|
||||
|
||||
@@ -75,7 +75,7 @@ public class TransportWatchService extends AbstractWatchService {
|
||||
}
|
||||
}
|
||||
DefaultAnyValue node = DefaultAnyValue.create("addr", addr).addValue("port", port);
|
||||
for (AnyValue groupconf : application.getAppConfig().getAnyValue("resources").getAnyValues("group")) {
|
||||
for (AnyValue groupconf : application.getAppConfig().getAnyValues("group")) {
|
||||
if (group.equals(groupconf.getValue("name"))) {
|
||||
((DefaultAnyValue) groupconf).addValue("node", node);
|
||||
break;
|
||||
@@ -107,7 +107,7 @@ public class TransportWatchService extends AbstractWatchService {
|
||||
}
|
||||
}
|
||||
}
|
||||
for (AnyValue groupconf : application.getAppConfig().getAnyValue("resources").getAnyValues("group")) {
|
||||
for (AnyValue groupconf : application.getAppConfig().getAnyValues("group")) {
|
||||
if (group.equals(groupconf.getValue("name"))) {
|
||||
((DefaultAnyValue) groupconf).removeValue("node", DefaultAnyValue.create("addr", addr).addValue("port", port));
|
||||
break;
|
||||
|
||||
@@ -140,7 +140,8 @@ public abstract class DataSqlSource extends AbstractDataSource implements Functi
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (readConfProps == writeConfProps) {
|
||||
List<ResourceEvent> allEvents = new ArrayList<>();
|
||||
Properties newProps = new Properties(this.readConfProps);
|
||||
Properties newProps = new Properties();
|
||||
newProps.putAll(this.readConfProps);
|
||||
for (ResourceEvent event : events) { //可能需要解密
|
||||
String newValue = decryptProperty(event.name(), event.newValue().toString());
|
||||
allEvents.add(ResourceEvent.create(event.name(), newValue, event.oldValue()));
|
||||
@@ -154,8 +155,10 @@ public abstract class DataSqlSource extends AbstractDataSource implements Functi
|
||||
} else {
|
||||
List<ResourceEvent> readEvents = new ArrayList<>();
|
||||
List<ResourceEvent> writeEvents = new ArrayList<>();
|
||||
Properties newReadProps = new Properties(this.readConfProps);
|
||||
Properties newWriteProps = new Properties(this.writeConfProps);
|
||||
Properties newReadProps = new Properties();
|
||||
newReadProps.putAll(this.readConfProps);
|
||||
Properties newWriteProps = new Properties();
|
||||
newWriteProps.putAll(this.writeConfProps);
|
||||
for (ResourceEvent event : events) {
|
||||
if (event.name().startsWith("read.")) {
|
||||
String newName = event.name().substring("read.".length());
|
||||
|
||||
@@ -33,11 +33,15 @@ public abstract class AnyValue {
|
||||
*/
|
||||
public static interface MergeFunction {
|
||||
|
||||
public static final int NONE = 0;
|
||||
|
||||
public static final int REPLACE = 1;
|
||||
|
||||
public static final int MERGE = 2;
|
||||
|
||||
public int apply(String name, AnyValue val1, AnyValue val2);
|
||||
public static final int SKIP = 3;
|
||||
|
||||
public int apply(String path, String name, AnyValue val1, AnyValue val2);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -158,6 +162,8 @@ public abstract class AnyValue {
|
||||
@Override
|
||||
public DefaultAnyValue copy() {
|
||||
DefaultAnyValue rs = new DefaultAnyValue(this.ignoreCase);
|
||||
rs.predicate = this.predicate;
|
||||
rs.parentArrayIndex = this.parentArrayIndex;
|
||||
if (this.stringEntrys != null) {
|
||||
rs.stringEntrys = new Entry[this.stringEntrys.length];
|
||||
for (int i = 0; i < rs.stringEntrys.length; i++) {
|
||||
@@ -178,15 +184,39 @@ public abstract class AnyValue {
|
||||
}
|
||||
|
||||
/**
|
||||
* 将另一个对象合并过来
|
||||
* 将另一个对象替换本对象
|
||||
*
|
||||
* @param node0 代合并对象
|
||||
* @param func 判断覆盖方式的函数
|
||||
* @param node 替换的对象
|
||||
*
|
||||
* @return AnyValue
|
||||
*/
|
||||
@Override
|
||||
public DefaultAnyValue merge(AnyValue node0, MergeFunction func) {
|
||||
public DefaultAnyValue replace(AnyValue node) {
|
||||
if (node != null) {
|
||||
DefaultAnyValue rs = (DefaultAnyValue) node;
|
||||
this.ignoreCase = rs.ignoreCase;
|
||||
this.predicate = rs.predicate;
|
||||
this.parentArrayIndex = rs.parentArrayIndex;
|
||||
this.stringEntrys = rs.stringEntrys;
|
||||
this.anyEntrys = rs.anyEntrys;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将另一个对象合并过来
|
||||
*
|
||||
* @param node 代合并对象
|
||||
* @param func 判断覆盖方式的函数
|
||||
*
|
||||
* @return AnyValue
|
||||
*/
|
||||
@Override
|
||||
public DefaultAnyValue merge(AnyValue node, MergeFunction func) {
|
||||
return merge(node, "", func);
|
||||
}
|
||||
|
||||
protected DefaultAnyValue merge(AnyValue node0, String path, MergeFunction func) {
|
||||
if (node0 == null) return this;
|
||||
if (node0 == this) throw new IllegalArgumentException();
|
||||
DefaultAnyValue node = (DefaultAnyValue) node0;
|
||||
@@ -212,15 +242,19 @@ public abstract class AnyValue {
|
||||
ok = true;
|
||||
break;
|
||||
} else {
|
||||
int funcVal = func.apply(en.name, en.value, item.value);
|
||||
int funcVal = func.apply(path, en.name, en.value, item.value);
|
||||
if (funcVal == MergeFunction.MERGE) {
|
||||
item.value.merge(en.value, func);
|
||||
String subPath = path.isEmpty() ? en.name : (path + "." + en.name);
|
||||
((DefaultAnyValue) item.value).merge(en.value, subPath, func);
|
||||
ok = true;
|
||||
break;
|
||||
} else if (funcVal == MergeFunction.REPLACE) {
|
||||
item.value = en.value.copy();
|
||||
ok = true;
|
||||
break;
|
||||
} else if (funcVal == MergeFunction.SKIP) {
|
||||
ok = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -489,12 +523,32 @@ public abstract class AnyValue {
|
||||
return this;
|
||||
}
|
||||
|
||||
public void clearParentArrayIndex(String name) {
|
||||
for (Entry<AnyValue> item : getAnyValueEntrys(name)) {
|
||||
if (item.value != null) {
|
||||
((DefaultAnyValue) item.value).parentArrayIndex = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public DefaultAnyValue removeAnyValues(String name) {
|
||||
if (name == null || this.anyEntrys == null) return this;
|
||||
this.anyEntrys = Utility.remove(this.anyEntrys, (t) -> name.equals(((Entry) t).name));
|
||||
return this;
|
||||
}
|
||||
|
||||
public DefaultAnyValue removeValue(String name, AnyValue value) {
|
||||
if (name == null || value == null || this.anyEntrys == null) return this;
|
||||
this.anyEntrys = Utility.remove(this.anyEntrys, (t) -> name.equals(((Entry) t).name) && ((Entry) t).getValue().equals(value));
|
||||
return this;
|
||||
}
|
||||
|
||||
public DefaultAnyValue removeStringValues(String name) {
|
||||
if (name == null || this.stringEntrys == null) return this;
|
||||
this.stringEntrys = Utility.remove(this.stringEntrys, (t) -> name.equals(((Entry) t).name));
|
||||
return this;
|
||||
}
|
||||
|
||||
public DefaultAnyValue removeValue(String name, String value) {
|
||||
if (name == null || value == null || this.stringEntrys == null) return this;
|
||||
this.stringEntrys = Utility.remove(this.stringEntrys, (t) -> name.equals(((Entry) t).name) && ((Entry) t).getValue().equals(value));
|
||||
@@ -794,7 +848,7 @@ public abstract class AnyValue {
|
||||
}
|
||||
parent = child;
|
||||
} else { //数组或Map结构, []中间是数字开头的视为数组,其他视为map
|
||||
String itemField = item.substring(0, pos); //[前面一部分
|
||||
String itemField = item.substring(0, pos); //[前面一部分'sources[1]'中'sources'
|
||||
String keyOrIndex = item.substring(pos + 1, item.indexOf(']'));
|
||||
int realIndex = -1;
|
||||
if (!keyOrIndex.isEmpty() && keyOrIndex.charAt(0) >= '0' && keyOrIndex.charAt(0) <= '9') {
|
||||
@@ -808,7 +862,7 @@ public abstract class AnyValue {
|
||||
for (int j = 0; j < i; j++) {
|
||||
prefixKey += keys[j] + ".";
|
||||
}
|
||||
DefaultAnyValue array = prefixArray.get(prefixKey + item);
|
||||
DefaultAnyValue array = prefixArray.get(prefixKey + item); //item: [1]
|
||||
if (array == null) {
|
||||
final int ii = i;
|
||||
String findkey = prefixKey + itemField + "[";
|
||||
@@ -1034,21 +1088,19 @@ public abstract class AnyValue {
|
||||
public abstract AnyValue copy();
|
||||
|
||||
/**
|
||||
* 将另一个对象合并过来
|
||||
* 将另一个对象替换本对象
|
||||
*
|
||||
* @param node 代合并对象
|
||||
* @param node 替换的对象
|
||||
*
|
||||
* @return AnyValue
|
||||
*/
|
||||
public AnyValue merge(AnyValue node) {
|
||||
return merge(node, null);
|
||||
}
|
||||
public abstract AnyValue replace(AnyValue node);
|
||||
|
||||
/**
|
||||
* 将另一个对象合并过来
|
||||
*
|
||||
* @param node 代合并对象
|
||||
* @param func 判断覆盖方式的函数
|
||||
* @param func 覆盖方式的函数
|
||||
*
|
||||
* @return AnyValue
|
||||
*/
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
*/
|
||||
package org.redkale.util;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@@ -37,6 +38,31 @@ public interface ResourceEvent<T> {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static List<ResourceEvent> create(Properties oldProps, Properties newProps) {
|
||||
List<ResourceEvent> rs = new ArrayList<>();
|
||||
if (oldProps == null && newProps == null) {
|
||||
return rs;
|
||||
}
|
||||
if (oldProps == null) {
|
||||
newProps.forEach((k, v) -> rs.add(ResourceEvent.create(k.toString(), v, null)));
|
||||
} else if (newProps == null) {
|
||||
oldProps.forEach((k, v) -> rs.add(ResourceEvent.create(k.toString(), null, v)));
|
||||
} else {
|
||||
newProps.forEach((k, v) -> {
|
||||
String oldVal = oldProps.getProperty(k.toString());
|
||||
if (!Objects.equals(v, oldVal)) {
|
||||
rs.add(ResourceEvent.create(k.toString(), v, oldVal));
|
||||
}
|
||||
});
|
||||
oldProps.forEach((k, v) -> {
|
||||
if (!newProps.containsKey(k)) {
|
||||
rs.add(ResourceEvent.create(k.toString(), null, v));
|
||||
}
|
||||
});
|
||||
}
|
||||
return rs;
|
||||
}
|
||||
|
||||
public static <V> ResourceEvent<V> create(String name, V newValue, V oldValue) {
|
||||
return new ResourceChangeEvent<>(name, newValue, oldValue);
|
||||
}
|
||||
|
||||
@@ -434,6 +434,7 @@ public final class ResourceFactory {
|
||||
|
||||
/**
|
||||
* 将多个以指定资源名的String对象注入到资源池中
|
||||
* properties的key一般以"property."开头
|
||||
*
|
||||
* @param properties 资源键值对
|
||||
* @param environmentName 额外的资源名
|
||||
@@ -441,7 +442,7 @@ public final class ResourceFactory {
|
||||
*
|
||||
*/
|
||||
public <A> void register(Properties properties, String environmentName, Class<A> environmentType) {
|
||||
if (properties == null) return;
|
||||
if (properties == null || properties.isEmpty()) return;
|
||||
List<ResourceChangeWrapper> wrappers = new ArrayList<>();
|
||||
List<ResourceEvent> environmentEventList = new ArrayList<>();
|
||||
properties.forEach((k, v) -> {
|
||||
|
||||
Reference in New Issue
Block a user