391 Commits

Author SHA1 Message Date
redkale
2202465e31 修复JsonByteBuffer解析bug 2023-05-09 14:45:25 +08:00
redkale
454e6b60d7 修复json在ByteBuffer、InputSteam参数下无法解决数组的问题 2023-05-08 19:38:47 +08:00
redkale
6ff04b408c DataSqlSource 变量由${}改成#{}, 为了区别于配置项${} 2023-05-08 14:29:23 +08:00
redkale
de7c5e84f4 Response增加afterFinishListeners 2023-05-08 08:25:36 +08:00
redkale
18932bf48b DataJdbcSource优化 2023-05-06 08:21:27 +08:00
redkale
1b1bfbb3ac DataJdbcSource优化 2023-05-05 20:31:21 +08:00
redkale
20a98e2a95 优化mq 2023-05-05 08:12:03 +08:00
redkale
8dbf474662 优化mq 2023-05-04 21:35:59 +08:00
redkale
26d0cce404 优化mq 2023-05-04 14:06:29 +08:00
redkale
eb5142a125 优化NodeServer 2023-05-01 09:30:17 +08:00
redkale
4911aa3f15 修改module-info 2023-04-28 14:21:45 +08:00
redkale
4a8fc9d771 修复URISimpledCoder的常量笔误问题 2023-04-28 14:18:57 +08:00
redkale
0d9216dd35 DataJdbcSource增加PreparedStatement缓存 2023-04-22 14:37:48 +08:00
redkale
331047957a DataSqlSource方法名优化 2023-04-20 21:49:16 +08:00
redkale
bec1c0c2d8 DataSqlSource方法名优化 2023-04-20 21:47:01 +08:00
redkale
82fa56d66c 废弃ThreadHashExecutor 2023-04-20 19:56:02 +08:00
redkale
8db6fd7b73 优化@Local的Service 2023-04-20 19:38:06 +08:00
redkale
b82a7d86e5 NodeServer优化 2023-04-20 17:58:09 +08:00
redkale
698269f8b0 增加MessageConsumer、MessageProducer功能 2023-04-20 14:30:39 +08:00
redkale
5e9c85e0fc DataJdbcSource优化 2023-04-18 22:30:25 +08:00
redkale
0fca7cd47b DataJdbcSource优化 2023-04-18 08:51:07 +08:00
redkale
d56af6043d 修复checkValid问题 2023-04-18 08:38:20 +08:00
redkale
021bf8ce51 优化DataJdbcSource 2023-04-17 23:44:39 +08:00
redkale
53e8f44088 优化ByteArray 2023-04-11 08:11:14 +08:00
redkale
3f244b2cff 修复SncpServlet的asm问题 2023-04-10 08:27:57 +08:00
redkale
3178221c44 优化ByteArray 2023-04-09 21:28:55 +08:00
redkale
41d0cbcb46 优化iothread 2023-04-07 14:57:43 +08:00
redkale
e6a2167261 优化client 2023-04-07 14:05:13 +08:00
redkale
7286531bc5 WebSocket优化 2023-04-06 21:23:27 +08:00
redkale
91d7f51678 修复Rest将Future<HttpResult<byte[]>>类型用finishJsonFuture格式输出 2023-04-06 11:07:09 +08:00
redkale
5746449cfb 优化sncp版WebSocketNode 2023-04-05 22:52:17 +08:00
redkale
4bdbf0f493 优化WebSocket 2023-04-05 18:43:38 +08:00
redkale
68b9d955f6 优化uriPathCaches 2023-04-05 17:07:59 +08:00
redkale
39ac48884f 优化Utility 2023-04-03 23:24:22 +08:00
redkale
663ca4f441 jdbc优化 2023-04-03 22:17:46 +08:00
redkale
8f3ae4b5a7 jdbc优化 2023-04-03 21:39:36 +08:00
redkale
db77b8c8cb jdbc优化 2023-04-03 20:38:47 +08:00
redkale
dc6d53e6be 日志优化 2023-04-03 14:48:01 +08:00
redkale
849d628a75 增加测试用例 2023-04-03 11:02:15 +08:00
redkale
22fd2212de mq命名优化 2023-04-03 09:32:44 +08:00
redkale
188a74423b mq优化命名 2023-04-03 08:48:43 +08:00
redkale
8727b5165a client还原 2023-04-02 23:41:22 +08:00
redkale
aa03d356b8 client优化 2023-04-02 23:32:48 +08:00
redkale
d417fb7232 HttpRequest优化 2023-04-02 22:34:11 +08:00
redkale
156131d4b5 实现DataBatch 2023-04-01 14:43:41 +08:00
redkale
dba72cab46 client优化 2023-03-31 20:06:54 +08:00
redkale
0b4a52ccb1 client优化 2023-03-31 14:22:00 +08:00
redkale
6b92748b7c client优化 2023-03-31 12:07:39 +08:00
redkale
00829cf198 convert优化 2023-03-31 11:09:15 +08:00
redkale
20ebcad982 client优化 2023-03-31 08:11:19 +08:00
redkale
6f03f38222 增加AnonymousVirtualExecutor 2023-03-30 23:05:38 +08:00
redkale
5c6b9dcec8 Client.connect 2023-03-30 20:21:53 +08:00
redkale
c9be4a89af isThreadLocalConnMode 2023-03-30 19:54:19 +08:00
redkale
41e1ffa6e2 Nonnull 2023-03-30 18:29:12 +08:00
redkale
c9c202f63f 优化Source 2023-03-30 12:56:32 +08:00
redkale
1dbaf107ca EntityCache优化 2023-03-29 21:36:51 +08:00
redkale
ee535692b4 EntityCache优化 2023-03-29 21:34:55 +08:00
redkale
df0a290032 EntityCache优化 2023-03-29 21:05:18 +08:00
redkale
7de19f142f 增加Cacheable.continuousid功能 2023-03-29 20:06:54 +08:00
redkale
0cfb00e40b ClientConnection优化 2023-03-28 23:36:18 +08:00
redkale
3cf560f220 修复EntityCache 2023-03-28 23:31:45 +08:00
redkale
3bb287b3ef EntityCache临时屏蔽 2023-03-28 23:18:02 +08:00
redkale
49662a7d5f client优化 2023-03-28 15:04:43 +08:00
redkale
d7655aa2be 优化client 2023-03-28 13:16:10 +08:00
redkale
a61d515a49 优化client 2023-03-28 08:12:58 +08:00
redkale
94185cc23e 优化client 2023-03-28 08:05:04 +08:00
redkale
9ef977aee9 优化WebSocket.IOThread 2023-03-27 21:36:22 +08:00
redkale
34fb441817 优化workexecutor 2023-03-27 21:18:16 +08:00
redkale
ac33b36d20 update pom 2023-03-27 20:04:43 +08:00
redkale
372656fea9 临时屏蔽workExecutor 2023-03-27 19:56:52 +08:00
redkale
a872c6e75f 增加APP_GLOBAL_IOGROUP功能 2023-03-27 19:45:39 +08:00
redkale
067b88ab72 废弃ClientWriteIOThread 2023-03-27 18:55:27 +08:00
redkale
ffbad698b4 AsyncConnection增加readRegister方法 2023-03-26 21:15:00 +08:00
redkale
71d3c015d9 readTimeoutSeconds优化 2023-03-25 10:18:54 +08:00
redkale
051299d4a5 优化sncp cluster配置 2023-03-23 15:21:53 +08:00
redkale
ac9995fb1a 优化sncp 2023-03-23 13:11:41 +08:00
redkale
83d04d02da SncpClientRequest.seqno生成规则优化 2023-03-23 13:03:13 +08:00
redkale
80bad30811 SncpClient优化 2023-03-23 11:56:13 +08:00
redkale
f34554f2cb 修复AsyncNioConnection 2023-03-22 23:51:55 +08:00
redkale
e2f331ab6b 优化SncpClient 2023-03-22 23:24:01 +08:00
redkale
039ed0f569 优化SncpClient的新实现 2023-03-22 16:02:17 +08:00
redkale
358ad80f21 优化HttpScope 2023-03-20 14:31:48 +08:00
redkale
f9a65f7492 http优化 2023-03-19 19:26:11 +08:00
redkale
32cae92848 http优化 2023-03-19 10:05:03 +08:00
redkale
e168c1368c rest优化 2023-03-17 18:42:26 +08:00
redkale
9cab0c6443 http优化 2023-03-17 13:39:20 +08:00
redkale
9e7e4cc177 http优化 2023-03-16 22:09:58 +08:00
redkale
523c101e25 优化http注释 2023-03-15 16:23:30 +08:00
redkale
1428cd8f10 增加Nonnull、Nullable注解 2023-03-15 09:36:40 +08:00
redkale
1edd256028 Resource支持@name、@type 2023-03-14 10:56:19 +08:00
redkale
42201c7c11 HTTP支持Expect:100-continue 2023-03-13 18:55:04 +08:00
redkale
aec65a2ff5 加强注释 2023-03-12 17:31:37 +08:00
redkale
c2b5733ceb sncp优化 2023-02-08 23:07:50 +08:00
redkale
2e40c98b81 sncp优化 2023-02-08 22:44:00 +08:00
redkale
6622e88232 sncp优化 2023-02-08 21:33:14 +08:00
redkale
67cd0b1b46 sncp优化 2023-02-08 19:06:22 +08:00
redkale
3ec4f9f96d sncp优化 2023-02-08 17:57:28 +08:00
redkale
530bf8078e udp优化 2023-02-07 17:34:33 +08:00
redkale
848f33bd2b udp优化 2023-02-07 17:27:55 +08:00
redkale
1d6b76b182 udp优化 2023-02-07 16:43:47 +08:00
redkale
bab857778b udp优化 2023-02-07 15:02:19 +08:00
redkale
75469a49e8 udp优化 2023-02-07 14:55:58 +08:00
redkale
7d2a9f6d94 udp优化 2023-02-07 14:26:14 +08:00
redkale
35fddb48de 优化sncp.udp 2023-02-07 14:08:13 +08:00
redkale
89f9baee46 sncp优化 2023-02-07 01:18:06 +08:00
redkale
797d04fea7 sncp优化 2023-02-07 00:50:53 +08:00
redkale
5df83b2649 移除ChannelContext 2023-02-06 19:08:20 +08:00
redkale
0aa8e8653c 增加RedkaleException 2023-02-05 17:19:03 +08:00
redkale
2751e6475e 优化client 2023-02-04 21:20:35 +08:00
redkale
e9d25a67f8 优化client 2023-02-04 20:21:41 +08:00
redkale
eef43e8edc 优化client 2023-02-04 20:19:35 +08:00
redkale
b60e5fef96 Context.getWorkHashExecutor 2023-02-04 16:10:08 +08:00
redkale
b9c1fa723c redkale.convert.tiny默认值改为false 2023-02-04 15:32:30 +08:00
redkale
63f4a6ee0d 实现@NonBlocking 2023-02-04 14:59:30 +08:00
redkale
894ea65a35 Filter.isNonBlocking 2023-02-03 22:10:42 +08:00
redkale
73c9a3cdb4 增加NonBlocking 2023-02-03 21:47:39 +08:00
redkale
de39ac1981 优化掉Array.newInstance 2023-02-02 23:16:24 +08:00
redkale
6973e6b159 SncpClientCodecTest 2023-02-02 21:40:58 +08:00
redkale
7f379f9874 Server.changeAddress 2023-02-02 17:54:19 +08:00
redkale
3c6b15ee9d Context.updateServerAddress 2023-02-02 17:42:33 +08:00
redkale
c6ef28c358 sncp优化 2023-02-02 15:31:19 +08:00
redkale
2ef5eb6cd0 优化client 2023-02-02 15:02:43 +08:00
redkale
cfc20c6248 增加SncpClientRequest 2023-02-02 13:47:34 +08:00
redkale
ea9505c2da EntityCache优化synchronized 2023-02-01 20:41:34 +08:00
redkale
1c1c54ea8a 优化Array.newInstance 2023-02-01 20:34:01 +08:00
redkale
851c81e096 优化MessageProducer的closed 2023-02-01 19:53:55 +08:00
redkale
78f969d2cc synchronized优化 2023-02-01 19:17:32 +08:00
redkale
ad981835f9 synchronized优化 2023-02-01 17:23:33 +08:00
redkale
f7f9e8db41 优化DataMemorySource 2023-02-01 14:45:52 +08:00
redkale
44f0fe1852 DataJdbcSource读操作不自动建表 2023-02-01 14:37:39 +08:00
redkale
8088197e29 增加AbstractDataSqlSource 2023-02-01 14:23:51 +08:00
redkale
76797228a0 ResourceFactory支持BigDecimal 2023-01-31 22:03:07 +08:00
redkale
ba3c0fdf72 DataTransaction 2023-01-31 20:39:02 +08:00
redkale
c6a1d584ea ConvertFactory优化 2023-01-31 17:05:26 +08:00
redkale
be5da6e287 移除默认tiny=true系统变量 2023-01-31 13:20:07 +08:00
redkale
7c8f54dd5c ClusterAgent优化 2023-01-31 11:08:25 +08:00
redkale
7b2dc52a35 ClusterAgent优化 2023-01-31 10:59:25 +08:00
redkale
e55d991bce UDP优化 2023-01-31 10:24:52 +08:00
redkale
e47abd6417 命名优化 2023-01-30 22:29:13 +08:00
redkale
afaf97aaf8 优化命名 2023-01-30 21:15:42 +08:00
redkale
9bafeccd38 CacheSource和DataSource支持资源复用 2023-01-30 21:10:28 +08:00
redkale
18afbd6bae 优化命名 2023-01-30 20:13:58 +08:00
redkale
4d2458da64 writePipeline优化 2023-01-30 18:50:53 +08:00
redkale
737d36be67 优化SNCP.UDP 2023-01-30 17:52:58 +08:00
redkale
6d1cf4b6bf 优化sncp 2023-01-30 16:32:36 +08:00
redkale
7dc57c67ed AsyncNioConnection优化 2023-01-30 13:53:03 +08:00
redkale
823b89ec48 Rest优化 2023-01-30 12:10:41 +08:00
redkale
d428c58e15 ProtocolCodec优化 2023-01-30 10:49:55 +08:00
redkale
4b70e19211 Request增加getRequestid方法 2023-01-30 10:33:00 +08:00
redkale
ae27fffdb0 重写Sncp.getServiceType 2023-01-29 22:22:12 +08:00
redkale
f41a1bc3a1 重写Sncp.getServiceType 2023-01-29 22:21:05 +08:00
redkale
ed5c52cfdc EnumSimpledCoder支持字段名作为setter方法名 2023-01-29 20:11:17 +08:00
redkale
5740d2704a 优化Creator 2023-01-29 19:45:38 +08:00
redkale
56e7775c5a Convert不再限制setter要求void返回类型 2023-01-29 19:11:23 +08:00
redkale
d4e807ada3 ConvertCoder优化 2023-01-29 18:05:29 +08:00
redkale
0b5a8863f3 Creator增加paramTypes方法 2023-01-29 17:37:28 +08:00
redkale
83b4887dd6 优化doWrite 2023-01-28 11:58:27 +08:00
redkale
2a7f0901af 优化pipeline 2023-01-28 11:28:10 +08:00
Redkale
71fb4102f6 Sncp.getServiceType 优化 2023-01-27 17:31:00 +08:00
Redkale
a492cbd815 net浼樺寲璁℃暟鍣? 2023-01-27 15:59:09 +08:00
Redkale
8d4ebe653d net浼樺寲璁℃暟鍣? 2023-01-27 15:39:12 +08:00
Redkale
88026fae3c Client浼樺寲connIndex 2023-01-23 20:38:25 +08:00
Redkale
f34ec61458 ClientFuture优化 2023-01-18 11:22:09 +08:00
Redkale
4d42f94be4 ClientFuture优化 2023-01-18 11:19:15 +08:00
Redkale
961ff7fa22 ClientConnection优化 2023-01-17 22:40:00 +08:00
Redkale
4d41b2afda 浼樺寲AsyncIOThread 2023-01-17 18:22:12 +08:00
Redkale
ec5b337460 EntityInfo优化 2023-01-17 14:28:42 +08:00
Redkale
1d559ef4d4 EntityInfo优化 2023-01-17 12:06:11 +08:00
Redkale
732e855daa EntityInfo优化 2023-01-17 09:59:19 +08:00
Redkale
b74bc43007 Client优化 2023-01-16 08:50:13 +08:00
Redkale
f5d79c7035 DataSqlSource命名优化 2023-01-15 23:11:16 +08:00
Redkale
19c8ffb79d Response优化finish方法 2023-01-15 21:11:59 +08:00
Redkale
39ade6f3ab CacheSource优化 2023-01-15 19:39:04 +08:00
Redkale
8789c0915b CacheSource增加setnxex系列方法 2023-01-15 16:21:37 +08:00
Redkale
55ddf7c417 优化WebSocket的写操作 2023-01-14 22:33:05 +08:00
Redkale
58e206d0e9 增加WebSocketWriteIOThread 2023-01-14 21:04:44 +08:00
Redkale
dc0849d82a 优化ByteBuffer对象池 2023-01-14 19:45:57 +08:00
Redkale
9192cb4606 优化AsyncConnection 2023-01-14 18:09:49 +08:00
Redkale
87f7b82e0a Server优化 2023-01-14 17:08:04 +08:00
Redkale
21df7f05dd WorkThread优化 2023-01-14 16:13:46 +08:00
Redkale
e6150b3469 优化WebSocket 2023-01-14 14:44:46 +08:00
Redkale
68bfa944fe ProtocolCodec优化 2023-01-14 13:17:37 +08:00
Redkale
a973834325 ProtocolCodec优化 2023-01-14 11:58:15 +08:00
Redkale
6c8b482f65 AsyncNioTcpProtocolServer优化 2023-01-14 11:36:07 +08:00
Redkale
0712b71b71 浼樺寲AsyncNioTcpProtocolServer 2023-01-14 11:17:58 +08:00
Redkale
52b9fd8326 浼樺寲ClientCodec 2023-01-13 22:39:02 +08:00
Redkale
8e7b27eb16 浼樺寲ClientCodec 2023-01-13 22:38:00 +08:00
Redkale
ab79359eff ClientRequest增加transfer功能 2023-01-13 21:31:38 +08:00
Redkale
f904af3da6 优化loadEntityInfo 2023-01-13 19:42:57 +08:00
Redkale
48e1c5dc86 浼樺寲ClientExecutor鐨勭嚎绋嬫暟 2023-01-13 19:17:49 +08:00
Redkale
25214db1dd CacheSource修改setnx返回值 2023-01-13 17:15:02 +08:00
Redkale
091a08b783 优化SncpDyn 2023-01-13 13:52:09 +08:00
Redkale
cf37303b5e client泛型优化 2023-01-13 11:21:54 +08:00
Redkale
ad059eb3d6 client泛型优化 2023-01-13 11:05:04 +08:00
Redkale
41028384af 重构Client模块的IO读写策略 2023-01-13 09:33:23 +08:00
Redkale
43ff13867f 重构Client模块的IO读写策略 2023-01-12 20:26:39 +08:00
Redkale
9b66bd186f DataSqlSource优化UpdateSqlInfo 2023-01-12 20:04:06 +08:00
Redkale
851efa5097 Client优化 2023-01-12 10:57:47 +08:00
Redkale
35d923d856 Client优化 2023-01-11 11:49:31 +08:00
Redkale
bf3bf836ac AsyncConnection增加writeInIOThread方法 2023-01-10 20:41:20 +08:00
Redkale
8f8a2ef325 【不兼容】移除RpcCall、RpcCallAttribute功能 2023-01-10 16:12:20 +08:00
Redkale
eeaefb1ed2 优化命名 2023-01-10 13:13:41 +08:00
Redkale
6a605359d7 优化ClientExecutor 2023-01-09 17:46:44 +08:00
Redkale
d603915d2b 优化ClientWriteIOThread 2023-01-09 16:37:22 +08:00
Redkale
bb4482c08c 移除MAX_INVOKER_ONSTACK 2023-01-09 12:18:32 +08:00
Redkale
645ecc3a32 增加自定义Exception 2023-01-09 10:37:30 +08:00
Redkale
da96d2ef9f 增加部分package-info 2023-01-07 20:19:46 +08:00
Redkale
084ba6609d 优化线程名 2023-01-06 22:09:48 +08:00
Redkale
9cef4b4f79 优化线程名 2023-01-06 22:08:49 +08:00
Redkale
1898fa7717 优化命名 2023-01-06 19:47:22 +08:00
Redkale
159c7f9e1b 优化HttpRequest 2023-01-06 16:05:48 +08:00
Redkale
158ea68265 优化ClientAddress 2023-01-06 15:16:58 +08:00
Redkale
7ce7c71163 优化命名 2023-01-06 13:31:57 +08:00
Redkale
4e5a03bb65 Deprecated方法增加since描述 2023-01-06 12:47:12 +08:00
Redkale
a986becb70 优化HttpRequest 2023-01-06 12:21:21 +08:00
Redkale
aa78b98ebf 浼樺寲ByteArray鏋勯€犲嚱鏁? 2023-01-06 10:26:26 +08:00
Redkale
442d806161 优化ClientAddress 2023-01-05 22:31:05 +08:00
Redkale
310d6fe217 新增WeightAddress 2023-01-05 22:29:45 +08:00
Redkale
288cab7c4f redkale.net.invoker.max.onstack榛樿鍊兼敼鎴? 2023-01-05 11:06:13 +08:00
Redkale
6f9a6e32bd 优化HttpRequest 2023-01-05 10:19:33 +08:00
Redkale
bb8faf14cb 澧炲姞ObjectReference宸ュ叿绫? 2023-01-04 20:48:30 +08:00
Redkale
9be0afacef 修复ArrayEncoder并发下componentEncoder偶尔为null的bug 2023-01-04 16:38:20 +08:00
Redkale
809b574f12 【不兼容】DLong更名为Uint128 2023-01-04 13:56:31 +08:00
Redkale
5975be44d9 优化ClientFuture 2023-01-04 11:53:17 +08:00
Redkale
7680b4e165 优化net.client 2023-01-04 11:32:48 +08:00
Redkale
80c04d9645 修复JDK15下StringBuilder.isEmpty方法 2023-01-04 10:44:50 +08:00
Redkale
abe73c4022 优化Client的pingRequest和closeRequest 2023-01-04 10:21:07 +08:00
Redkale
13ef219ab1 绉婚櫎ioThread澶氫綑浠g爜 2023-01-03 18:52:42 +08:00
Redkale
d6d3fd0966 优化AsyncConnection的Thread 2023-01-03 16:57:21 +08:00
Redkale
43f2f38ae3 优化AsyncConnection的Thread 2023-01-03 15:59:05 +08:00
Redkale
44500b6500 AsyncConnection区分read/write 2023-01-03 14:46:28 +08:00
Redkale
979a263c88 优化DEFAULT_MAX_PIPELINES 2023-01-03 12:08:42 +08:00
Redkale
c72d0bec8c 优化ClientConnection.responseQueue命名 2023-01-03 10:56:32 +08:00
Redkale
ba82ca3051 DataSource增加createTable方法 2023-01-03 10:03:23 +08:00
Redkale
0032c06498 优化HttpRequest 2023-01-02 18:54:32 +08:00
Redkale
0c0cee756a 优化AsyncIOGroup 2023-01-02 16:24:56 +08:00
Redkale
21f66d13ee 优化DataSqlSource 2023-01-02 11:37:48 +08:00
Redkale
496b165d42 优化DataJdbcSource 2023-01-02 10:01:24 +08:00
Redkale
3a306a6235 优化DataJdbcSource 2023-01-02 08:43:34 +08:00
Redkale
6b75e950ec 优化DataJdbcSource 2023-01-01 22:07:24 +08:00
Redkale
f09a323b20 优化DataJdbcSource 2023-01-01 20:50:29 +08:00
Redkale
6f6c3f70ff 优化AsyncConnection 2023-01-01 19:52:44 +08:00
Redkale
1c1211a298 优化Response.channel.write 2023-01-01 17:51:52 +08:00
Redkale
b3862cea72 Client实现requestid 2023-01-01 13:53:19 +08:00
Redkale
391352e077 优化命名 2023-01-01 13:02:54 +08:00
Redkale
de089072fa 临时优化Client runWork 2022-12-31 09:58:51 +08:00
Redkale
2542eb959a 临时优化Client runWork 2022-12-30 10:08:50 +08:00
Redkale
76a85a6e3d 优化Client 2022-12-30 00:07:50 +08:00
Redkale
2c861a5ed4 优化DataJdbcSource 2022-12-29 14:56:24 +08:00
Redkale
8701450940 优化DataJdbcSource 2022-12-29 13:35:40 +08:00
Redkale
478b22e7c8 优化DataJdbcSource 2022-12-29 12:15:51 +08:00
Redkale
38436e7f37 格式化代码 2022-12-28 22:43:34 +08:00
Redkale
43a665497d 优化DataJdbcSource 2022-12-28 21:26:12 +08:00
Redkale
1622cb0285 DataJdbcSource优化事务 2022-12-28 19:36:22 +08:00
Redkale
3a28111cfc 优化TableStrategy 2022-12-28 19:18:15 +08:00
Redkale
b8b8873eaf Application加锁cacheSources 2022-12-28 17:07:19 +08:00
Redkale
34023f6d08 优化DataJdbcSource 2022-12-28 15:28:52 +08:00
Redkale
65f7692116 优化DataJdbcSource 2022-12-28 14:30:24 +08:00
Redkale
2af90d790b DataJdbcSource支持分表分库insert 2022-12-28 11:31:37 +08:00
Redkale
daa6fe4cbb 日志优化 2022-12-28 10:14:37 +08:00
Redkale
9c7676a3f2 Utility增加indexOf方法 2022-12-27 13:53:19 +08:00
Redkale
06bd653b24 优化CacheSource 2022-12-26 22:59:16 +08:00
Redkale
441a74a7c9 优化CacheSource 2022-12-26 22:48:59 +08:00
Redkale
ebd010b6d9 优化CacheSource 2022-12-26 22:27:24 +08:00
Redkale
9200a3a32b 优化CacheSource 2022-12-26 19:57:53 +08:00
Redkale
54ea96b820 CacheSource增加incrbyFloat方法 2022-12-26 14:46:49 +08:00
Redkale
ef6b90c2f6 EntityInfo浼樺寲 2022-12-26 11:12:55 +08:00
Redkale
bcb2a89388 优化DataSource 2022-12-25 17:54:37 +08:00
Redkale
9e37f693c3 DistributeTableStrategy增加getTables方法 2022-12-25 17:36:35 +08:00
Redkale
337377c001 浼樺寲HttpSimpleClient 2022-12-25 09:35:20 +08:00
Redkale
8636a1a43d 优化ConvertException 2022-12-23 21:15:42 +08:00
Redkale
b656c8877b 增加SourceException 2022-12-23 21:12:10 +08:00
Redkale
48ba0edd2e 优化日志 2022-12-23 20:56:27 +08:00
Redkale
e44bfbe9f3 优化CacheSource 2022-12-23 17:45:04 +08:00
Redkale
5750dd5dc3 优化CacheSource 2022-12-23 14:00:44 +08:00
Redkale
bb750d3689 优化CacheSource 2022-12-23 13:09:22 +08:00
Redkale
6940b7af81 优化CacheSource 2022-12-23 12:08:09 +08:00
Redkale
31eb6f8701 优化CacheSource 2022-12-23 10:48:27 +08:00
Redkale
989f1cddf8 打印慢sql日志 2022-12-22 21:49:11 +08:00
Redkale
2d06fd6ea9 优化CacheSource 2022-12-22 15:02:41 +08:00
Redkale
e79427f708 优化CacheSource 2022-12-22 13:05:14 +08:00
Redkale
68ff0f7bab 优化CacheSource 2022-12-22 10:48:08 +08:00
Redkale
19b22161c9 Convert兼容setter返回值是void或类本身对象 2022-12-22 09:55:35 +08:00
Redkale
2d84fc3eda 优化CacheSource 2022-12-22 09:46:56 +08:00
Redkale
e823c2e4e1 优化CacheSource 2022-12-22 08:28:31 +08:00
Redkale
e5a905f04c CacheSource增加getex系列方法 2022-12-21 22:46:11 +08:00
Redkale
616a501af7 优化CacheSource部分方法名 2022-12-21 17:35:43 +08:00
Redkale
c48ba58d55 优化CacheSource部分方法名 2022-12-21 16:43:32 +08:00
Redkale
d3236f57d2 CacheSource增加setnx、hsetnx系列方法 2022-12-21 16:33:44 +08:00
Redkale
f327378d18 修复APP_EXECUTOR资源为null时inject报错的bug 2022-12-21 14:43:13 +08:00
Redkale
66a1850c49 优化createDataSource和createCacheSource 2022-12-21 13:43:25 +08:00
Redkale
3ac01eca15 PrepareCompiler兼容旧注解 2022-12-21 12:17:10 +08:00
Redkale
e7aac019e1 javax.annotation包迁移至org.redkale.annotation; javax.persistence包迁移至org.redkale.persistence 2022-12-21 11:42:01 +08:00
Redkale
628e3f15b1 增加"redkale.resource.skip.check"系统变量 2022-12-18 23:58:28 +08:00
Redkale
321ce372d2 增加"redkale.resource.skip.check"系统变量 2022-12-18 23:52:02 +08:00
Redkale
4fa449990f 优化Traces 2022-12-18 21:25:52 +08:00
Redkale
d57b4715d0 修复Application.replaceValue空指针问题 2022-12-18 17:39:15 +08:00
Redkale
664ad9e4aa 修复Application.replaceValue空指针问题 2022-12-18 17:35:30 +08:00
Redkale
a31e47ea42 优化SncpResponse.fillRespHeader 2022-12-18 15:51:47 +08:00
Redkale
1334e2439d 修改Traces方法名 2022-12-17 14:22:18 +08:00
Redkale
543db6f8ab 增加慢sql告警日志 2022-12-17 11:07:34 +08:00
Redkale
8fd679d21f 优化命名规范 2022-12-16 09:52:34 +08:00
Redkale
d4def48c99 优化命名规范 2022-12-15 20:58:30 +08:00
Redkale
c805beeb34 优化DataBatch 2022-12-15 13:38:27 +08:00
Redkale
a2331ad71a 增加DefaultDataBatch类 2022-12-13 21:31:11 +08:00
Redkale
eaa2c4c269 ColumnValue.name做空判断 2022-12-13 20:17:41 +08:00
Redkale
bab765a8f8 优化变量名 2022-12-12 19:24:15 +08:00
Redkale
348b27365b 调整Application设置系统变量优先级 2022-12-12 11:08:48 +08:00
Redkale
164dd3d8ea Environment增加forEach方法 2022-12-12 09:36:22 +08:00
Redkale
4a91e6eb18 废弃依赖注入配置项时自动加入"property."前缀 2022-12-11 21:37:23 +08:00
Redkale
b6a0885927 优化LoggingSearchHandler 2022-12-11 19:24:13 +08:00
Redkale
93ce83f137 优化AnyValue.loadFromProperties 2022-12-11 17:57:44 +08:00
Redkale
d36c168faa 配置中心支持动态更改mq和cluster配置 2022-12-11 13:29:33 +08:00
Redkale
86c66aab6d 配置中心支持动态更改日志配置 2022-12-11 10:45:47 +08:00
Redkale
8c20ba96f6 Application.xml废弃<resources>节点 2022-12-09 21:54:51 +08:00
Redkale
8a630ff007 优化AnyValue.toString 2022-12-08 23:15:44 +08:00
Redkale
8e55ddfcae 优化AnyValue.toString 2022-12-08 22:46:45 +08:00
Redkale
1e49fa50b5 优化AnyValue.merge方法 2022-12-08 19:36:26 +08:00
Redkale
5093663cfd 修复WebSocketNodeService无sncp服务情况下不注入CacheSource的bug 2022-12-08 17:18:55 +08:00
Redkale
b41f34cade 优化DataSource配置中心通知 2022-12-07 22:21:47 +08:00
Redkale
1972e6308c AnyValue增加copy和merge方法 2022-12-07 21:28:12 +08:00
Redkale
c0c5cb7e93 修复mysql下 DELETE FROM table a别名问题 2022-12-07 20:10:10 +08:00
Redkale
186b6c8649 FilterNode.filter方法废弃 2022-12-07 19:55:21 +08:00
Redkale
23e68e2d0d CacheSource.getSet系列方法还原 2022-12-07 19:19:30 +08:00
Redkale
1247c37d71 Utility.md5默认改成utf-8 2022-12-07 16:16:02 +08:00
Redkale
2d92c78c0b Application初始化顺序优化 2022-12-07 14:31:14 +08:00
Redkale
07ed7163ea PropertiesAgent优化 2022-12-07 13:26:52 +08:00
Redkale
4560c231ce CacheSource.getSet系列方法改成setGet 2022-12-07 10:04:57 +08:00
Redkale
5a1f6c8b1a 日志优化 2022-12-07 09:56:03 +08:00
Redkale
7a915c7015 优化DataSqlSource.onResourceChange 2022-12-06 21:32:21 +08:00
Redkale
2663b6dea0 DataJdbcSource支持配置中心动态变更配置 2022-12-06 19:53:15 +08:00
Redkale
cc3c07d0c2 移除SourceChangeable 2022-12-06 13:38:21 +08:00
Redkale
e01cb1b94d 修改SourceChangeable类接口 2022-12-05 20:04:10 +08:00
Redkale
709d320a5a DataResultSetRow增加getColumnLabels方法 2022-12-05 19:44:07 +08:00
Redkale
e781be25a0 优化Application.updateSourceProperties方法实现 2022-12-05 17:43:39 +08:00
Redkale
f8eb3d03ad 增加SourceChangeable 2022-12-04 15:45:27 +08:00
Redkale
b2e7160ce7 ResourceListener支持对Environment环境变量的支持 2022-12-01 20:31:28 +08:00
Redkale
18bb3b807b 优化Application 2022-11-30 10:15:56 +08:00
Redkale
af92ac4048 优化updateEnvironmentProperty方法 2022-11-29 21:13:08 +08:00
Redkale
6ab8aa8e72 优化PropertiesAgent 2022-11-29 20:14:11 +08:00
Redkale
595e2b83f5 优化PropertiesAgent 2022-11-29 18:26:28 +08:00
Redkale
ea8ffbc510 优化PropertiesAgent 2022-11-29 12:00:57 +08:00
Redkale
2663fb318c Utility优化参数名 2022-11-28 13:33:20 +08:00
Redkale
1c70fd201a Application增加reconfigLogging方法 2022-11-27 15:46:25 +08:00
Redkale
6e635d4272 修复LoggingConsoleHandler.denyreg相关bug 2022-11-26 14:47:41 +08:00
Redkale
2c41a354f3 优化日志级别调用方式 2022-11-26 14:00:27 +08:00
Redkale
b24eb1ce9e 优化PropertiesAgent接口 2022-11-25 20:27:41 +08:00
Redkale
d6b626fd47 Resource增加required属性 2022-11-25 17:29:31 +08:00
Redkale
53f7e5d337 优化PropertiesAgent 2022-11-25 17:14:23 +08:00
Redkale
232accc0da 浼樺寲PropertiesAgent 2022-11-25 17:04:42 +08:00
Redkale
56119d2aab 浼樺寲PropertiesAgent 2022-11-25 17:00:22 +08:00
Redkale
53d35fa02f 优化PropertiesAgent.init接口参数 2022-11-25 16:55:27 +08:00
Redkale
a68d63d2be Utility增加remove方法 2022-11-25 14:31:04 +08:00
Redkale
17dcddcd80 ResourceEvent增加containsName方法 2022-11-25 13:46:23 +08:00
Redkale
7621c4bdc3 增加InstanceProvider,统一Provider接口 2022-11-25 13:34:52 +08:00
Redkale
949498f3a7 PropertiesAgent加强注释 2022-11-24 22:31:18 +08:00
Redkale
0b2f2b189c 优化PropertiesAgent 2022-11-24 20:01:41 +08:00
Redkale
050ebc673a HttpSimpleRequest和client模块增加链路ID 2022-11-24 15:31:24 +08:00
Redkale
cc397ed07b redkale.convert.tiny默认值还原成true 2022-11-24 13:44:34 +08:00
Redkale
5c7e0b8098 convert/BsonMainTest.tiny 默认为true 2022-11-24 10:33:55 +08:00
Redkale
16ebdcde85 客户端组AsyncGroup不再使用WorkExecutor线程池而是单独新建一个 2022-11-24 10:09:44 +08:00
Redkale
4e675d007e redkale.convert.tiny默认值由true改成false 2022-11-18 15:23:53 +08:00
Redkale
a4dd37fff2 增加ConvertEnumValue功能 2022-11-16 11:25:15 +08:00
Redkale
20a545825c 优化Sheet 2022-09-27 13:44:10 +08:00
Redkale
b912e3a35f HttpServlet提供finish404、finish405的可定制化接口 2022-09-06 22:08:36 +08:00
Redkale
86a7ffb642 http协议请求不符合method要求时改成返回405 2022-09-06 17:39:23 +08:00
Redkale
cd3e5bdd14 支持redkale.datasource.xxx 和 redkale.cachesource.xxx 配置格式 2022-07-12 09:36:05 +08:00
Redkale
48db5a76b0 Redkale 2.8.0 开始 2022-07-12 07:14:14 +08:00
Redkale
630f18792a 2022-07-07 09:22:31 +08:00
Redkale
d0cb04a224 Redkale 2.7.0 结束 2022-07-06 23:23:09 +08:00
Redkale
0e8ac2f43c 2022-07-06 23:21:14 +08:00
Redkale
0c60700d82 增加ResourceEvent 2022-07-06 22:44:44 +08:00
Redkale
dc285b6c2f 2022-07-06 22:03:29 +08:00
Redkale
74009b38c4 2022-07-06 16:42:39 +08:00
Redkale
e820be1de9 2022-07-06 16:29:56 +08:00
Redkale
7db3cbd03d 增加Environment 2022-07-06 16:09:30 +08:00
Redkale
27d2433993 增加ResourceListener.different功能 2022-07-05 14:34:59 +08:00
Redkale
64eda4cdf7 2022-07-04 09:18:24 +08:00
Redkale
f05961cf07 @WebServlet合并url,例如: /shop/*,/shop/info 合并成一个 /shop/* 2022-07-03 23:43:22 +08:00
Redkale
be713c9ccf 2022-07-02 22:45:11 +08:00
Redkale
00dc3ee945 2022-07-02 22:10:32 +08:00
Redkale
927007774b PrepareServlet 更名为 DispatcherServlet 2022-07-02 21:33:52 +08:00
Redkale
f4994f66c9 2022-07-02 21:02:21 +08:00
Redkale
aef973a4d9 增加RestLocale功能 2022-07-02 20:47:50 +08:00
Redkale
ba618ceba0 2022-06-28 12:08:03 +08:00
Redkale
7f22eca8dc 2022-06-27 20:04:14 +08:00
Redkale
862018b63f 修改getCreatetime 2022-06-27 19:56:07 +08:00
Redkale
f38143ff7b 2022-06-20 11:18:51 +08:00
Redkale
481cde05bf 2022-06-20 11:08:23 +08:00
Redkale
a1e6413704 Update README.md 2022-05-27 10:40:16 +08:00
Redkale
8d1b9a18b4 2.7.0-SNAPSHOT 2022-05-27 10:39:58 +08:00
456 changed files with 42380 additions and 17484 deletions

5
.gitignore vendored
View File

@@ -11,3 +11,8 @@
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
/target/
/.idea/
/redkale.iml
/ClientConnection.java
/nbactions.xml
/nb-configuration.xml

View File

@@ -1,27 +1,27 @@
<h1>项目介绍</h1>
<b>项目介绍</b>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Redkale (中文名: 红菜苔,一种湖北特产蔬菜) 是基于Java 11全新的微服务框架 包含HTTP、WebSocket、TCP/UDP、数据序列化、数据缓存、依赖注入等功能。 本框架致力于简化集中式和微服务架构的开发,在增强开发敏捷性的同时保持高性能。
</p>
<strong>RedKale 有如下主要特点:</strong>
<ol>
<li>大量使用Java 8新特性接口默认值、Stream、Lambda、JDk8内置的ASM等</li>
<li>大量使用Java 8+新特性接口默认值、Stream、Lambda、内置的ASM、HttpClient等)</li>
<li>提供HTTP服务同时内置JSON功能与限时缓存功能</li>
<li>TCP层完全使用NIO并统一TCP与UDP的接口换</li>
<li>提供分布式与集中式部署的无缝切换</li>
<li>提供类似JPA功能包含数据缓存自动同步、分表分库与简洁的数据层操作接口</li>
<li>可以动态修改已依赖注入的资源</li>
</ol>
</ol>
<strong>Redkale 设计理念</strong>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;作为一个全新的微服务框架Redkale在接口定义上使用了Java 8大量的新语法接口有默认实现、接口带静态方法、重复注解等特性同时在设计上与主流框架有很大不同。Redkale是按组件形式设计的而非以容器为主几乎每个子包都是能提供独立功能的组件。如Tomcat是按容器设计的所有web资源/配置由Tomcat控制开发者很能难控制到Tomcat内部而Redkale的HTTP服务只是个组件开发者既可以自己启动和配置HttpServer也可以把Redkale当成容器通过Redkale进程来初始化服务。Spring的Ioc容器也是如此Redkale提供的依赖注入仅通过ResouceFactory一个类来控制非常轻量并且可动态更改已注入的资源。Spring提倡控制反转思想而自身的容器却让开发者很难控制。Redkale是一个既能以组件形式也能以容器形式存在的框架。从整体上看Redkale的架构分两层接口和默认实现。开发者若想替换掉Redkale内置的HTTP服务而使用符合JavaEE规范的HttpServlet, 可以采用自定义协议基于JSR 340(Servlet 3.1)来实现自己的HTTP服务若想使用Hibernate作为数据库操作可以写一个自己的DataSource实现类JSON的序列化和反序列化也可以使用第三方的实现Memcached或Redis也可以作为另一个CacheSource的实现替换Redkale的默认实现。这其实包含了控制反转的思想让框架里的各个组件均可让开发者控制。<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;与主流框架比功能上Redkale显得很简单这体现了Redkale的简易性而并非是不足从一个良好的设计习惯或架构上来看有些常用功能是不需要提供的如Redkale的HTTP服务不支持HTTPS和JSPHTTPS比HTTP多了一层加密解密这种密集型的计算不是Java的专长通常提供HTTP服务的架构不会将Java动态服务器放在最前端而是在前方会放nginx或apache除了负载均衡还能静动分离因此HTTPS的加解密应交给nginx这样的高性能服务器处理。Redkale再提供HTTPS服务就显得鸡肋。JSP其实算是一个落后的技术现在是一个多样化终端的时代终端不只局限于桌面程序和PC浏览器还有原生App、混合式App、微信端、移动H5、提供第三方接口等各种形式的终端这些都不是JSP能方便兼顾的而HTTP+JSON作为通用性接口可以避免重复开发模版引擎的功能加上各种强大的JS框架足以取代JSP。Redkale在功能上做了筛选不会为了迎合主流而提供而是以良好的设计思想为指导。这是Redkale的主导思维。
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;作为一个全新的微服务框架Redkale在接口定义上使用了Java 8以上版本的大量新特性接口有默认实现、接口带静态方法、重复注解等特性同时在设计上与主流框架有很大不同。Redkale是按组件形式设计的而非以容器为主几乎每个子包都是能提供独立功能的组件。如Tomcat是按容器设计的所有web资源/配置由Tomcat控制开发者很能难控制到Tomcat内部而Redkale的HTTP服务只是个组件开发者既可以自己启动和配置HttpServer也可以把Redkale当成容器通过Redkale进程来初始化服务。Spring的Ioc容器也是如此Redkale提供的依赖注入仅通过ResouceFactory一个类来控制非常轻量并且可动态更改已注入的资源。Spring提倡控制反转思想而自身的容器却让开发者很难控制。Redkale是一个既能以组件形式也能以容器形式存在的框架。从整体上看Redkale的架构分两层接口和默认实现。开发者若想替换掉Redkale内置的HTTP服务而使用符合JavaEE规范的HttpServlet, 可以采用自定义协议基于JSR 340(Servlet 3.1)来实现自己的HTTP服务若想使用Hibernate作为数据库操作可以写一个自己的DataSource实现类JSON的序列化和反序列化也可以使用第三方的实现Memcached或Redis也可以作为另一个CacheSource的实现替换Redkale的默认实现。这其实包含了控制反转的思想让框架里的各个组件均可让开发者控制。<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;与主流框架比功能上Redkale显得很简单这体现了Redkale的简易性而并非是不足从一个良好的设计习惯或架构上来看有些常用功能是不需要提供的如Redkale的HTTP服务不支持JSP, JSP其实算是一个落后的技术现在是一个多样化终端的时代终端不只局限于桌面程序和PC浏览器还有原生App、混合式App、微信端、移动H5、提供第三方接口等各种形式的终端这些都不是JSP能方便兼顾的而HTTP+JSON作为通用性接口可以避免重复开发模版引擎的功能加上各种强大的JS框架足以取代JSP。Redkale在功能上做了筛选不会为了迎合主流而提供而是以良好的设计思想为指导。这是Redkale的主导思维。
</p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<h5>详情请访问:&nbsp;&nbsp;&nbsp;&nbsp;<a href='https://redkale.org' target='_blank'>https://redkale.org</a></h5>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>详情请访问:&nbsp;&nbsp;&nbsp;&nbsp;<a href='https://redkale.org' target='_blank'>https://redkale.org</a></b>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<h5>基本文档:&nbsp;&nbsp;&nbsp;&nbsp;<a href='https://redkale.org/articles.html' target='_blank'>https://redkale.org/articles.html</a></h5>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>基本文档:&nbsp;&nbsp;&nbsp;&nbsp;<a href='https://redkale.org/articles.html' target='_blank'>https://redkale.org/articles.html</a></b>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<h5>欢迎加入Redkale QQ群: 527523235</h5>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>欢迎加入Redkale QQ群: 527523235</b>
&nbsp;

View File

@@ -1,7 +0,0 @@
@ECHO OFF
SET APP_HOME=%~dp0
IF NOT EXIST "%APP_HOME%\conf\application.xml" SET APP_HOME=%~dp0..
java -DCMD=APIDOC -DAPP_HOME="%APP_HOME%" -classpath "%APP_HOME%"\lib\* org.redkale.boot.Application

7
bin/apidoc.cmd Normal file
View File

@@ -0,0 +1,7 @@
@ECHO OFF
SET APP_HOME=%~dp0
IF NOT EXIST "%APP_HOME%\conf\application.xml" SET APP_HOME=%~dp0..
java -DAPP_HOME="%APP_HOME%" -classpath "%APP_HOME%"\lib\* org.redkale.boot.Application apidoc

View File

@@ -6,7 +6,7 @@ APP_HOME=`dirname "$0"`
if [ ! -f "$APP_HOME"/conf/application.xml ]; then
APP_HOME="$APP_HOME"/..
fi
fi
lib='.'
for jar in `ls $APP_HOME/lib/*.jar`
@@ -15,4 +15,4 @@ do
done
export CLASSPATH=$CLASSPATH:$lib
echo "$APP_HOME"
java -DCMD=APIDOC -DAPP_HOME="$APP_HOME" org.redkale.boot.Application
java -DAPP_HOME="$APP_HOME" org.redkale.boot.Application apidoc

View File

@@ -1,7 +0,0 @@
@ECHO OFF
SET APP_HOME=%~dp0
IF NOT EXIST "%APP_HOME%\conf\application.xml" SET APP_HOME=%~dp0..
java -DCMD=%1 -DAPP_HOME="%APP_HOME%" -classpath "%APP_HOME%"\lib\* org.redkale.boot.Application

7
bin/redkale.cmd Normal file
View File

@@ -0,0 +1,7 @@
@ECHO OFF
SET APP_HOME=%~dp0
IF NOT EXIST "%APP_HOME%\conf\application.xml" SET APP_HOME=%~dp0..
java -DAPP_HOME="%APP_HOME%" -classpath "%APP_HOME%"\lib\* org.redkale.boot.Application %*

View File

@@ -20,4 +20,4 @@ done
export CLASSPATH=$CLASSPATH:$lib
echo "$APP_HOME"
java -DCMD=$1 -DAPP_HOME="$APP_HOME" org.redkale.boot.Application
java -DAPP_HOME="$APP_HOME" org.redkale.boot.Application $@ &

View File

@@ -4,6 +4,6 @@ SET APP_HOME=%~dp0
IF NOT EXIST "%APP_HOME%\conf\application.xml" SET APP_HOME=%~dp0..
call "%APP_HOME%\bin\shutdown.bat"
call "%APP_HOME%\bin\shutdown.cmd"
call "%APP_HOME%\bin\start.bat"
call "%APP_HOME%\bin\start.cmd"

View File

@@ -2,16 +2,15 @@
<application nodeid="10000" port="2020">
<resources>
</resources>
<properties load="config.properties">
<property name="system.property.redkale.convert.protobuf.enumtostring" value="true"/>
</properties>
<server protocol="HTTP" port="5050">
<server protocol="HTTP" port="5050">
<request>
<remoteaddr value="request.headers.X-RemoteAddress"/>
</request>
<response>
<defcookie domain="" path="/"/>
<addheader name="Access-Control-Allow-Origin" value="request.headers.Origin" />
@@ -24,8 +23,7 @@
<rest path="/pipes" />
<servlets path="/pipes" autoload="true" />
<servlets path="/pipes" autoload="true" />
</server>
</application>

2
conf/config.properties Normal file
View File

@@ -0,0 +1,2 @@
#

View File

@@ -18,8 +18,8 @@ java.util.logging.FileHandler.level = FINER
java.util.logging.FileHandler.limit = 10M
java.util.logging.FileHandler.count = 20
java.util.logging.FileHandler.encoding = UTF-8
java.util.logging.FileHandler.pattern = ${APP_HOME}/logs-%m/log-%d.log
java.util.logging.FileHandler.unusual = ${APP_HOME}/logs-%m/log-warnerr-%d.log
java.util.logging.FileHandler.pattern = ${APP_HOME}/logs-%tY%tm/log-%tY%tm%td.log
java.util.logging.FileHandler.unusual = ${APP_HOME}/logs-%tY%tm/log-warnerr-%tY%tm%td.log
java.util.logging.FileHandler.append = true
java.util.logging.ConsoleHandler.level = FINEST

View File

@@ -1,33 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0">
<persistence-unit name="" transaction-type="RESOURCE_LOCAL">
<shared-cache-mode>ALL</shared-cache-mode>
<properties>
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/center?autoReconnect=true&amp;characterEncoding=utf8"/>
<property name="javax.persistence.jdbc.user" value="root"/>
<property name="javax.persistence.jdbc.password" value="1234"/>
</properties>
</persistence-unit>
<!--
<persistence-unit name="user.read" transaction-type="RESOURCE_LOCAL">
<shared-cache-mode>ALL</shared-cache-mode>
<properties>
<property name="javax.persistence.jdbc.url" value="jdbc:oracle:thin:@localhost:1521:orcl"/>
<property name="javax.persistence.jdbc.user" value="system"/>
<property name="javax.persistence.jdbc.password" value="1234"/>
</properties>
</persistence-unit>
<persistence-unit name="user.write" transaction-type="RESOURCE_LOCAL">
<shared-cache-mode>ALL</shared-cache-mode>
<properties>
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/center?characterEncoding=utf8&useSSL=false&serverTimezone=UTC&rewriteBatchedStatements=true"/>
<property name="javax.persistence.jdbc.user" value="root"/>
<property name="javax.persistence.jdbc.password" value="1234"/>
</properties>
</persistence-unit>
-->
</persistence>

22
conf/source.properties Normal file
View File

@@ -0,0 +1,22 @@
############ DataSource @Resource(name="platf") ############
#redkale.datasource[platf].url = jdbc:mysql://127.0.0.1:3306/platf?allowPublicKeyRetrieval=true&amp;rewriteBatchedStatements=true&amp;serverTimezone=UTC&amp;characterEncoding=utf8
#redkale.datasource[platf].user = root
#redkale.datasource[platf].password = 12345678
### true: auto ddl;
#redkale.datasource[platf].table-autoddl = true
############ DataSource @Resource(name="user") ############
#redkale.datasource[user].read.url = jdbc:mysql://127.0.0.1:3306/user_r?allowPublicKeyRetrieval=true&amp;rewriteBatchedStatements=true&amp;serverTimezone=UTC&amp;characterEncoding=utf8
#redkale.datasource[user].read.user = root
#redkale.datasource[user].read.password = 12345678
#redkale.datasource[user].write.url = jdbc:mysql://127.0.0.1:3306/user_w?allowPublicKeyRetrieval=true&amp;rewriteBatchedStatements=true&amp;serverTimezone=UTC&amp;characterEncoding=utf8
#redkale.datasource[user].write.user = root
#redkale.datasource[user].write.password = 12345678
############ CacheSource @Resource(name="usersession") ############
#redkale.cachesource[usersession].node[0].url = redis://127.0.0.1:6363
#redkale.cachesource[usersession].node[0].password = 12345678
#redkale.cachesource[usersession].node[0].db = 0

18
my/gitrun.sh Normal file
View File

@@ -0,0 +1,18 @@
#!/bin/sh
export LC_ALL="zh_CN.UTF-8"
rm -fr redkale
rm -fr src
rm -fr bin
rm -fr conf
git clone https://github.com/redkale/redkale.git
cp -fr redkale/src ./
cp -fr redkale/bin ./
cp -fr redkale/conf ./
mvn clean
mvn deploy

View File

@@ -7,19 +7,26 @@
<name>RedkaleProject</name>
<url>http://redkale.org</url>
<description>redkale -- java framework</description>
<version>2.5.0</version>
<version>2.7.0-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<junit.version>5.7.0</junit.version>
<maven-plugin.version>3.2.0</maven-plugin.version>
<maven-gpg-plugin.version>3.0.1</maven-gpg-plugin.version>
<maven-compiler-plugin.version>3.8.0</maven-compiler-plugin.version>
<maven-surefire-plugin.version>3.0.0-M5</maven-surefire-plugin.version>
<maven-failsafe-plugin.version>3.0.0-M5</maven-failsafe-plugin.version>
</properties>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.7.0</version>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
@@ -74,7 +81,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<version>${maven-compiler-plugin.version}</version>
<configuration>
<compilerArgument>-parameters</compilerArgument>
<encoding>UTF-8</encoding>
@@ -87,7 +94,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.2.0</version>
<version>${maven-plugin.version}</version>
<configuration>
<archive>
<addMavenDescriptor>false</addMavenDescriptor>
@@ -101,7 +108,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>1.6</version>
<version>${maven-gpg-plugin.version}</version>
<executions>
<execution>
<id>sign-artifacts</id>
@@ -116,7 +123,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.2.0</version>
<version>${maven-plugin.version}</version>
<executions>
<execution>
<goals>
@@ -129,7 +136,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.2.0</version>
<version>${maven-plugin.version}</version>
<executions>
<execution>
<goals>
@@ -142,7 +149,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.2.0</version>
<version>${maven-plugin.version}</version>
<configuration>
<appendAssemblyId>false</appendAssemblyId>
<descriptors>

View File

@@ -1 +1,9 @@
<EFBFBD><EFBFBD>Ŀ¼<EFBFBD>µ<EFBFBD><EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>sonatypeʱʹ<EFBFBD>ã<EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڹ<EFBFBD><DAB9>̴<EFBFBD><CCB4><EFBFBD><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD>Ŀ¼<EFBFBD>µ<EFBFBD><EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>sonatypeʱʹ<EFBFBD>ã<EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڹ<EFBFBD><DAB9>̴<EFBFBD><CCB4><EFBFBD><EFBFBD><EFBFBD>
ʹ<EFBFBD><EFBFBD>gpg<EFBFBD><EFBFBD><EFBFBD><EFBFBD>sonatype<EFBFBD><EFBFBD>Կ:
1<EFBFBD><EFBFBD> gpg <20>C-gen-key
2<EFBFBD><EFBFBD> gpg --keyserver keys.openpgp.org --send-keys <20><><EFBFBD>Ĺ<EFBFBD>Կ(һ<><D2BB>ʮ<EFBFBD><CAAE><EFBFBD><EFBFBD><EFBFBD>Ƶ<EFBFBD><C6B5><EFBFBD><EFBFBD>֣<EFBFBD><D6A3><EFBFBD><EFBFBD><EFBFBD>DE346FA5)
<20><>ʾ<EFBFBD><CABE> gpg: <20>ӹ<EFBFBD>Կ<EFBFBD><D4BF><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʧ<EFBFBD>ܣ<EFBFBD>Server indicated a failure <20><>ʾ<EFBFBD><CABE><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>

View File

@@ -20,7 +20,7 @@
</profile>
<profile>
<id>release</id>
<id>release</id>
<!--
<build>
<plugins>

18
pom.xml
View File

@@ -7,18 +7,18 @@
<name>RedkaleProject</name>
<url>https://redkale.org</url>
<description>redkale -- java framework</description>
<version>2.6.0</version>
<version>2.8.0-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<junit.version>5.7.0</junit.version>
<maven-jar-plugin.version>3.2.0</maven-jar-plugin.version>
<maven-compiler-plugin.version>3.8.0</maven-compiler-plugin.version>
<maven-surefire-plugin.version>3.0.0-M5</maven-surefire-plugin.version>
<maven-failsafe-plugin.version>3.0.0-M5</maven-failsafe-plugin.version>
<junit.version>5.9.0</junit.version>
<maven-jar-plugin.version>3.3.0</maven-jar-plugin.version>
<maven-compiler-plugin.version>3.9.0</maven-compiler-plugin.version>
<maven-surefire-plugin.version>3.0.0</maven-surefire-plugin.version>
<maven-failsafe-plugin.version>3.0.0</maven-failsafe-plugin.version>
</properties>
<licenses>
@@ -95,7 +95,7 @@
<plugin>
<groupId>org.redkale.maven.plugins</groupId>
<artifactId>redkale-maven-plugin</artifactId>
<version>1.0.0-SNAPSHOT</version>
<version>1.1.0</version>
<executions>
<execution>
<id>redkale-compile</id>
@@ -125,6 +125,10 @@
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>${maven-surefire-plugin.version}</version>
<configuration>
<forkMode>once</forkMode>
<argLine>-Dfile.encoding=UTF-8</argLine>
</configuration>
</plugin>
<plugin>

View File

@@ -103,7 +103,7 @@
</script>
<script>
var jsoncontent = '${content}'; //这里必须要用单引号引起来
var jsoncontent = '#{content}'; //这里必须要用单引号引起来
document.write(createhtml(jsoncontent));
</script>
</body>

View File

@@ -0,0 +1,46 @@
redkale.nodeid = 1000
redkale.port = 6560
redkale.lib = ./
#\u3010executor\u8282\u70b9\u5168\u5c40\u552f\u4e00\u3011
redkale.executor.threads = 4
redkale.executor.hash = false
#\u3010excludelibs\u8282\u70b9\u5168\u5c40\u552f\u4e00\u3011
redkale.excludelibs.value = ^.*mysql.*$;^.*kafka.*$
#\u3010cluster\u8282\u70b9\u5168\u5c40\u552f\u4e00\u3011
redkale.cluster.type = org.redkalex.cluster.consul.ConsulClusterAgent
redkale.cluster.waits= = false
redkale.cluster.protocols = SNCP
redkale.cluster.ports = 7070;7071
redkale.mq[0].name =
redkale.mq[0].type = org.redkalex.mq.kafka.KafkaMessageAgent
redkale.mq[0].servers.value = 127.0.0.1:9101
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
redkale.listener[0].value = org.redkalex.xxx.XXXApplicationListener
#\u3010properties\u8282\u70b9\u5168\u5c40\u552f\u4e00\u3011
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 =
#\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

View File

@@ -20,7 +20,7 @@
-->
<!--
nodeid: int 进程的节点ID用于分布式环境一个系统中节点ID必须全局唯一使用cluster时框架会进行唯一性校验
name: 进程的名称,用于监控识别,命名规则: 字母、数字、下划线
name: 进程的名称,用于监控识别,命名规则: 字母、数字、下划线、短横、点
address: 本地局域网的IP地址 默认值为默认网卡的ip当不使用默认值需要指定值如192.168.1.22
port: required 程序的管理Server的端口用于关闭或者与监管系统进行数据交互
lib: 加上额外的lib路径,多个路径用分号;隔开; 默认为空。 例如: ${APP_HOME}/lib/a.jar;${APP_HOME}/lib2/b.jar;
@@ -28,132 +28,106 @@
<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.*$"/>
<!--
【节点全局唯一】
第三方服务发现管理接口
value 类名必须是org.redkale.cluster.ClusterAgent的子类
waits: 注销服务后是否需要等待检查周期时间后再进行Service销毁默认值为false
当一个Service进行服务注销后不能立刻销毁Service因为健康检测是有间隔时间差的
需要等待一个健康检测周期时间,让其他进程都更新完服务列表。
如果使用MQ可以设置为false如果对服务健壮性要求高建议设置为true
protocols: 服务发现可以处理的协议, 默认值为: SNCP, 多个协议用分号;隔开
ports: 服务发现可以处理的端口, 多个端口用分号;隔开
-->
<!--
<cluster value="org.redkalex.cluster.consul.ConsulClusterAgent" waits="false" protocols="SNCP" ports="7070;7071">
<property name="xxxxxx" value="XXXXXXXX"/>
</cluster>
-->
<!--
MQ管理接口配置
不同MQ节点所配置的MQ集群不能重复。
MQ跟着协议走所以mq的属性值需要被赋值在rest节点上, 由于SncpServlet是自动生成的故SNCP协议下mq属性值被赋值在service/services节点上
name: 服务的名称用于监控识别多个mq节点时只能有一个name为空的节点mq.name不能重复,命名规则: 字母、数字、下划线
value 实现类名必须是org.redkale.mq.MessageAgent的子类
MQ节点下的子节点配置没有固定格式, 根据MessageAgent实现方的定义来配置
-->
<!--
<mq name="" value="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>
<!--
全局的数据源设置, 可以是CacheSource、DataSource JDBC的DataSource通常通过persistence.xml配置此处多用于CacheSource的配置
name: 资源名,用于依赖注入。
value 类名必须是CacheSource或DataSource的子类且必须实现Service接口。如果是DataSource.class系统自动映射成DataJdbcSource.class
groups: 指定groups。
xxx: 其他属性与子节点通过Service.init方法传入的AnyValue获取。
-->
<source name="redis" value="org.redkalex.cache.RedisCacheSource" xxx="16">
<node addr="127.0.0.1" port="7070"/>
</source>
<!--
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")操作。
load: 加载文件,多个用;隔开。
默认置入的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");
<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
-->
<executor threads="4"/>
<!--
【节点全局唯一】
自动扫描时排除部分包路径
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内的进程必须在同一机房或局域网内
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.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不能重复,命名规则: 字母、数字、下划线
@@ -167,12 +141,12 @@
threads【已废弃】 线程数, 默认: CPU核数*2最小8个【已废弃 @since 2.3.0】
maxconns 最大连接数, 小于1表示无限制 默认: 0
maxbody: request.body最大值 默认: 64K
bufferCapacity: ByteBuffer的初始化大小 TCP默认: 32K; (HTTP 2.0、WebSocket必须要16k以上); UDP默认: 1350B
bufferCapacity: ByteBuffer的初始化大小 TCP默认: 32K; (HTTP 2.0、WebSocket必须要16k以上); UDP默认: 8K
bufferPoolSize ByteBuffer池的大小默认: 线程数*4
responsePoolSize Response池的大小默认: 1024
aliveTimeoutSeconds: KeepAlive读操作超时秒数 默认30 0表示永久不超时; -1表示禁止KeepAlive
readTimeoutSeconds: 读操作超时秒数, 默认0 表示永久不超时
writeTimeoutSeconds: 写操作超时秒数, 默认0 表示永久不超时
readTimeoutSeconds: 读操作超时秒数, 默认0 0表示永久不超时
writeTimeoutSeconds: 写操作超时秒数, 默认0 0表示永久不超时
interceptor: 启动/关闭NodeServer时被调用的拦截器实现类必须是org.redkale.boot.NodeInterceptor的子类默认为null
-->
<server protocol="HTTP" host="127.0.0.1" port="6060" root="root" lib="">
@@ -205,10 +179,10 @@
mq: 所属的MQ管理器当 protocol == SNCP 时该值才有效, 存在该属性表示Service的SNCP协议采用消息总线代理模式
includes 当autoload="true" 拉取类名与includes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
excludes 当autoload="true" 排除类名与excludes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
groups: 所属组的节点,多个节点值用;隔开,如果配置文件中存在多个SNCP协议的Server节点需要显式指定group属性.
group: 所属组的节点, 不能指定多个group, 如果配置文件中存在多个SNCP协议的Server节点需要显式指定group属性.
当 protocol == SNCP 时 group表示当前Server与哪些节点组关联。
当 protocol != SNCP 时 group只能是空或者一个group的节点值,不能为多个节点值
特殊值"$cluster", 视为通过第三方服务注册发现管理工具来获取远程模式的ip端口信息
当 protocol != SNCP 时 group只能是空或者一个group的节点值。
特殊值"$remote", 视为通过第三方服务注册发现管理工具来获取远程模式的ip端口信息
-->
<services autoload="true" includes="" excludes="">
@@ -217,10 +191,10 @@
<!--
name: 显式指定name覆盖默认的空字符串值。 注意: name不能包含$符号。
mq: 所属的MQ管理器当 protocol == SNCP 时该值才有效, 存在该属性表示Service的SNCP协议采用消息总线代理模式
groups: 显式指定groups,覆盖<services>节点的groups默认值。
group: 显式指定group覆盖<services>节点的group默认值。
ignore: 是否禁用, 默认为false。
-->
<service value="com.xxx.XXX2Service" name="" groups="xxx;yyy"/>
<service value="com.xxx.XXX2Service" name="" group="xxx"/>
<!-- 给Service增加配置属性 -->
<service value="com.xxx.XXX1Service">
<!-- property值在public void init(AnyValue conf)方法中可以通过AnyValue properties=conf.getAnyValue("properties")获取 -->
@@ -282,10 +256,13 @@
当Server为HTTP协议时, request节点才有效。
remoteaddr 节点: 替换请求方节点的IP地址 通常请求方是由nginx等web静态服务器转发过的则需要配置该节点。
且value值只能是以request.headers.开头表示从request.headers中获取对应的header值。
locale value值必须是request.headers.或request.parameters.开头。
例如下面例子获取request.getRemoteAddr()值如果header存在X-RemoteAddress值则返回X-RemoteAddress值不存在返回getRemoteAddress()。
-->
<request>
<remoteaddr value="request.headers.X-RemoteAddress"/>
<locale value="request.headers.locale" />
<rpc authenticator="org.redkale.net.http.HttpRpcAuthenticator的实现类"/>
</request>
<!--
@@ -294,8 +271,8 @@
contenttype: plain值为调用finish时的ContentType; 默认值: text/plain; charset=utf-8
json值为调用finishJson时的ContentType; 默认值: application/json; charset=utf-8
defcookie 节点: 当response里输出的cookie没有指定domain 和path时使用该节点的默认值。
如果addheader、setheader 的value值以request.parameters.开头则表示从request.parameters中获取对应的parameter值
如果addheader、setheader 的value值以request.headers.开头则表示从request.headers中获取对应的header值
addheader、setheader 的value值以request.parameters.开头则表示从request.parameters中获取对应的parameter值
addheader、setheader 的value值以request.headers.开头则表示从request.headers中获取对应的header值
例如下面例子是在Response输出header时添加两个header一个addHeader 一个setHeader
options 节点: 设置了该节点且auto=true当request的method=OPTIONS自动设置addheader、setheader并返回200状态码
date 节点: 设置了该节点且period有值(单位:毫秒);返回response会包含Date头信息默认为period=0
@@ -306,8 +283,8 @@
<response>
<content-type plain="text/plain; charset=utf-8" json="application/json; charset=utf-8"/>
<defcookie domain="" path=""/>
<addheader name="Access-Control-Allow-Origin" value="request.headers.Origin" />
<setheader name="Access-Control-Allow-Headers" value="request.headers.Access-Control-Request-Headers"/>
<addheader name="Access-Control-Allow-Origin" value="request.headers.Origin" /> <!-- 可多节点 -->
<setheader name="Access-Control-Allow-Headers" value="request.headers.Access-Control-Request-Headers"/> <!-- 可多节点 -->
<setheader name="Access-Control-Allow-Credentials" value="true"/>
<options auto="true" />
<date period="0" />
@@ -371,4 +348,5 @@
<!-- 参数完全同上 -->
<services autoload="true" includes="" excludes="" />
</server>
</application>

View File

@@ -15,11 +15,16 @@ com.sun.level = INFO
java.util.logging.FileHandler.limit = 20M
java.util.logging.FileHandler.count = 100
java.util.logging.FileHandler.encoding = UTF-8
java.util.logging.FileHandler.pattern = ${APP_HOME}/logs-%m/log-%d.log
java.util.logging.FileHandler.pattern = ${APP_HOME}/logs-%tY%tm/log-%tY%tm%td.log
#java.util.logging.FileHandler.unusual \u5c5e\u6027\u8868\u793a\u5c06 WARNING\u3001SEVERE \u7ea7\u522b\u7684\u65e5\u5fd7\u590d\u5236\u5199\u5165\u5355\u72ec\u7684\u6587\u4ef6\u4e2d
java.util.logging.FileHandler.unusual = ${APP_HOME}/logs-%m/log-warnerr-%d.log
java.util.logging.FileHandler.unusual = ${APP_HOME}/logs-%tY%tm/log-warnerr-%tY%tm%td.log
#\u9700\u8981\u5c4f\u853d\u6d88\u606f\u5185\u5bb9\u7684\u6b63\u5219\u8868\u8fbe\u5f0f
java.util.logging.FileHandler.denyreg =
java.util.logging.FileHandler.denyregx =
java.util.logging.FileHandler.append = true
#java.util.logging.ConsoleHandler.level = FINE
#\u5c06\u65e5\u5fd7\u5199\u8fdbSearchSource, \u5fc5\u987b\u6307\u5b9asource\u8d44\u6e90\u540d\uff0c\u5728source.properties\u4e2d\u5b9a\u4e49
#java.util.logging.SearchHandler.source = platfsearch
#\u6307\u5b9a\u5199\u8fdbSearchSource\u7684\u8868\u540d\uff0c\u9ed8\u8ba4\u503c\u4e3alog-record
#java.util.logging.SearchHandler.tag = log-${APP_NAME}-%tY%tm%td

View File

@@ -1,5 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- 其配置算是标准的JPA配置文件的缩略版 -->
<!--
【================================================ 已废弃 ================================================】建议使用 source.properties
其配置算是标准的JPA配置文件的缩略版
-->
<persistence>
<!-- 系统基本库 -->
<persistence-unit name="demouser">
@@ -26,19 +29,19 @@
<property name="javax.persistence.connections.limit" value="12"/>
<!-- 包含的SQL模板相当于反向LIKE不同的JDBC驱动的SQL语句不一样Redkale内置了MySQL的语句 -->
<property name="javax.persistence.contain.sqltemplate" value="LOCATE(${keystr}, ${column}) > 0"/>
<property name="javax.persistence.notcontain.sqltemplate" value="LOCATE(${keystr}, ${column}) = 0"/>
<property name="javax.persistence.contain.sqltemplate" value="LOCATE(#{keystr}, #{column}) > 0"/>
<property name="javax.persistence.notcontain.sqltemplate" value="LOCATE(#{keystr}, #{column}) = 0"/>
<!-- 复制表结构的SQL模板Redkale内置了MySQL的语句 -->
<property name="javax.persistence.tablenotexist.sqlstates" value="42000;42S02"/>
<property name="javax.persistence.tablecopy.sqltemplate" value="CREATE TABLE IF NOT EXISTS ${newtable} LIKE ${oldtable}"/>
<property name="javax.persistence.tablecopy.sqltemplate" value="CREATE TABLE IF NOT EXISTS #{newtable} LIKE #{oldtable}"/>
</properties>
</persistence-unit>
<!-- IM消息库 -->
<persistence-unit name="demoim">
<properties>
<!-- jdbc:mysql://127.0.0.1:3306/dbim?autoReconnect=true&amp;autoReconnectForPools=true&amp;characterEncoding=utf8 -->
<!-- jdbc:mysql://127.0.0.1:3306/dbim?allowPublicKeyRetrieval=true&amp;rewriteBatchedStatements=true&amp;serverTimezone=UTC&amp;characterEncoding=utf8 -->
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://127.0.0.1:3306/dbim?characterEncoding=utf8"/>
<property name="javax.persistence.jdbc.user" value="root"/>
<property name="javax.persistence.jdbc.password" value="123456"/>

View File

@@ -0,0 +1,50 @@
# CacheSource @Resource(name="usersession")
# type\u53ef\u4ee5\u4e0d\u7528\u8bbe\u7f6e\uff0c\u6846\u67b6\u4f1a\u6839\u636eurl\u5224\u65ad\u4f7f\u7528\u54ea\u4e2aCacheSource\u5b9e\u73b0\u7c7b
redkale.cachesource.usersession.type = org.redkalex.cache.redis.RedisCacheSource
# \u6700\u5927\u8fde\u63a5\u6570
redkale.cachesource.usersession.maxconns = 16
# \u8282\u70b9\u5730\u5740
redkale.cachesource.usersession.node[0].url = redis://127.0.0.1:6363
# \u8282\u70b9\u5bc6\u7801
redkale.cachesource.usersession.node[0].password = 12345678
# \u8282\u70b9db
redkale.cachesource.usersession.node[0].db = 0
#\u7b80\u5316\u5199\u6cd5: \u53ef\u4ee5\u4e0d\u7528.node[0], \u5c06\u53c2\u6570\u90fd\u5408\u5e76\u5230url\u4e2d
redkale.cachesource.usersession.url = redis://user:123456@127.0.0.1:6363?db=0
# DataSource @Resource(name="platf")
# type\u53ef\u4ee5\u4e0d\u7528\u8bbe\u7f6e\uff0c\u6846\u67b6\u4f1a\u6839\u636eurl\u5224\u65ad\u4f7f\u7528\u54ea\u4e2aDataSource\u5b9e\u73b0\u7c7b\uff0c\u9ed8\u8ba4\u503c: org.redkale.source.DataJdbcSource
redkale.datasource.platf.type = org.redkale.source.DataJdbcSource
# \u662f\u5426\u5f00\u542f\u7f13\u5b58(\u6807\u8bb0\u4e3a@Cacheable\u7684Entity\u7c7b)\uff0c\u503c\u76ee\u524d\u53ea\u652f\u6301\u4e24\u79cd\uff1a ALL: \u6240\u6709\u5f00\u542f\u7f13\u5b58\u3002 NONE: \u5173\u95ed\u6240\u6709\u7f13\u5b58\uff0c \u975eNONE\u5b57\u6837\u7edf\u4e00\u89c6\u4e3aALL
redkale.datasource.platf.cachemode = ALL
# \u662f\u5426\u81ea\u52a8\u5efa\u8868\u5f53\u8868\u4e0d\u5b58\u5728\u7684\u65f6\u5019\uff0c \u76ee\u524d\u53ea\u652f\u6301mysql\u3001postgres\uff0c \u9ed8\u8ba4\u4e3afalse
redkale.datasource.platf.table-autoddl = false
# \u7528\u6237
redkale.datasource.platf.user = root
# \u5bc6\u7801
redkale.datasource.platf.password = 12345678
# \u591a\u4e2aURL\u7528;\u9694\u5f00\uff0c\u5982\u5206\u5e03\u5f0fSearchSource\u9700\u8981\u914d\u591a\u4e2aURL
redkale.datasource.platf.url = jdbc:mysql://127.0.0.1:3306/platf?allowPublicKeyRetrieval=true&rewriteBatchedStatements=true&serverTimezone=UTC&characterEncoding=utf8
# \u6700\u5927\u8fde\u63a5\u6570\uff0c\u9ed8\u8ba4\u503c\uff1aCPU\u6570
redkale.datasource.platf.maxconns = 16
# \u5305\u542b\u7684SQL\u6a21\u677f\uff0c\u76f8\u5f53\u4e8e\u53cd\u5411LIKE\uff0c\u4e0d\u540c\u7684JDBC\u9a71\u52a8\u7684SQL\u8bed\u53e5\u4e0d\u4e00\u6837\uff0cRedkale\u5185\u7f6e\u4e86MySQL\u7684\u8bed\u53e5
redkale.datasource.platf.contain-sqltemplate = LOCATE(#{keystr}, #{column}) > 0
# \u5305\u542b\u7684SQL\u6a21\u677f\uff0c\u76f8\u5f53\u4e8e\u53cd\u5411LIKE\uff0c\u4e0d\u540c\u7684JDBC\u9a71\u52a8\u7684SQL\u8bed\u53e5\u4e0d\u4e00\u6837\uff0cRedkale\u5185\u7f6e\u4e86MySQL\u7684\u8bed\u53e5
redkale.datasource.platf.notcontain-sqltemplate = LOCATE(#{keystr}, #{column}) = 0
# \u590d\u5236\u8868\u7ed3\u6784\u7684SQL\u6a21\u677f\uff0cRedkale\u5185\u7f6e\u4e86MySQL\u7684\u8bed\u53e5
redkale.datasource.platf.tablenotexist-sqlstates = 42000;42S02
# \u590d\u5236\u8868\u7ed3\u6784\u7684SQL\u6a21\u677f\uff0cRedkale\u5185\u7f6e\u4e86MySQL\u7684\u8bed\u53e5
redkale.datasource.platf.tablecopy-sqltemplate = CREATE TABLE IF NOT EXISTS #{newtable} LIKE #{oldtable}
# DataSource \u8bfb\u5199\u5206\u79bb
redkale.datasource.platf.read.url = jdbc:mysql://127.0.0.1:3306/platf_r?allowPublicKeyRetrieval=true&rewriteBatchedStatements=true&serverTimezone=UTC&characterEncoding=utf8
redkale.datasource.platf.read.user = root
redkale.datasource.platf.read.password = 12345678
redkale.datasource.platf.write.url = jdbc:mysql://127.0.0.1:3306/platf_w?allowPublicKeyRetrieval=true&rewriteBatchedStatements=true&serverTimezone=UTC&characterEncoding=utf8
redkale.datasource.platf.write.user = root
redkale.datasource.platf.write.password = 12345678

View File

@@ -16,16 +16,16 @@
*/
package javax.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.annotation.*;
/**
* 值越大,优先级越高
*
* @since Common Annotations 1.2
*
* @deprecated replace by org.redkale.annotation.Priority
*/
@Deprecated(since = "2.8.0")
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Priority {

View File

@@ -5,33 +5,33 @@
*/
package javax.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.annotation.*;
/**
* @since Common Annotations 1.0
*
* @deprecated replace by org.redkale.annotation.Resource
*/
@Deprecated(since = "2.8.0")
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Resource {
/**
* AuthenticationType
*/
@Deprecated
public enum AuthenticationType {
/**
* @deprecated
*/
CONTAINER,
/**
* @deprecated
*/
APPLICATION
}
// /**
// * AuthenticationType
// */
// @Deprecated
// public enum AuthenticationType {
// /**
// * @deprecated
// */
// CONTAINER,
// /**
// * @deprecated
// */
// APPLICATION
// }
//
/**
* 资源名称
*
@@ -45,39 +45,39 @@ public @interface Resource {
* @return Class
*/
public Class<?> type() default Object.class;
/**
*
* @return AuthenticationType
*/
@Deprecated
public AuthenticationType authenticationType() default AuthenticationType.CONTAINER;
/**
*
* @return boolean
*/
@Deprecated
public boolean shareable() default true;
/**
*
* @return String
*/
@Deprecated
public String description() default "";
/**
*
* @return String
*/
@Deprecated
public String mappedName() default "";
/**
*
* @return String
*/
@Deprecated
public String lookup() default "";
//
// /**
// *
// * @return AuthenticationType
// */
// @Deprecated
// public AuthenticationType authenticationType() default AuthenticationType.CONTAINER;
//
// /**
// *
// * @return boolean
// */
// @Deprecated
// public boolean shareable() default true;
//
// /**
// *
// * @return String
// */
// @Deprecated
// public String description() default "";
//
// /**
// *
// * @return String
// */
// @Deprecated
// public String mappedName() default "";
//
// /**
// *
// * @return String
// */
// @Deprecated
// public String lookup() default "";
}

View File

@@ -17,8 +17,7 @@ package javax.persistence;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.lang.annotation.*;
/**
* Specifies whether an entity should be cached if caching is enabled
@@ -33,7 +32,10 @@ import java.lang.annotation.Target;
* not be cached by the provider.
*
* @since Java Persistence 2.0
*
* @deprecated replace by org.redkale.persistence.Cacheable
*/
@Deprecated(since = "2.8.0")
@Target({TYPE})
@Retention(RUNTIME)
public @interface Cacheable {

View File

@@ -15,11 +15,9 @@
***************************************************************************** */
package javax.persistence;
import java.lang.annotation.Target;
import java.lang.annotation.Retention;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.*;
import static java.lang.annotation.ElementType.*;
/**
* Specifies the mapped column for a persistent property or field.
@@ -48,7 +46,10 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
*
*
* @since Java Persistence 1.0
*
* @deprecated replace by org.redkale.persistence.Column
*/
@Deprecated(since = "2.8.0")
@Target({METHOD, FIELD})
@Retention(RUNTIME)
public @interface Column {
@@ -89,11 +90,11 @@ public @interface Column {
/**
* for OpenAPI Specification 3
*
*
* @return String
*/
String example() default "";
String example() default "";
/**
* (Optional) Whether the column is included in SQL INSERT
* statements generated by the persistence provider.
@@ -122,7 +123,12 @@ public @interface Column {
/**
* (Optional) The column length. (Applies only if a
* string-valued column is used.)
* if type==String and length == 65535 then sqltype is text
* if type==String and length == 65535 then sqltype is TEXT <br>
* if type==String and length &#60;= 16777215 then sqltype is MEDIUMTEXT <br>
* if type==String and length &#62; 16777215 then sqltype is LONGTEXT <br>
* if type==byte[] and length &#60;= 65535 then sqltype is BLOB <br>
* if type==byte[] and length &#60;= 16777215 then sqltype is MEDIUMBLOB <br>
* if type==byte[] and length &#62; 16777215 then sqltype is LONGBLOB <br>
*
* @return int
*/

View File

@@ -15,16 +15,19 @@
******************************************************************************/
package javax.persistence;
import java.lang.annotation.*;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.*;
/**
* Specifies that the class is an entity. This annotation is applied to the
* entity class.
*
* @since Java Persistence 1.0
*
* @deprecated replace by org.redkale.persistence.Entity
*/
@Deprecated(since = "2.8.0")
@Inherited
@Documented
@Target(TYPE)

View File

@@ -15,11 +15,9 @@
******************************************************************************/
package javax.persistence;
import java.lang.annotation.Target;
import java.lang.annotation.Retention;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.*;
import static java.lang.annotation.ElementType.*;
/**
* Specifies the primary key of an entity.
@@ -48,7 +46,10 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
* see GeneratedValue
*
* @since Java Persistence 1.0
*
* @deprecated replace by org.redkale.persistence.Id
*/
@Deprecated(since = "2.8.0")
@Target({METHOD, FIELD})
@Retention(RUNTIME)

View File

@@ -15,8 +15,7 @@
package javax.persistence;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.lang.annotation.*;
/**
* Used in schema generation to specify creation of an index.
@@ -38,8 +37,11 @@ import java.lang.annotation.Target;
* <code>ASC</code> (ascending order) is assumed.
*
* @since Java Persistence 2.1
*
* @deprecated replace by org.redkale.persistence.Index
*
*/
@Deprecated(since = "2.8.0")
@Target({})
@Retention(RUNTIME)
public @interface Index {

View File

@@ -15,10 +15,9 @@
***************************************************************************** */
package javax.persistence;
import java.lang.annotation.Target;
import java.lang.annotation.Retention;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.*;
/**
* Specifies the primary table for the annotated entity. Additional
@@ -37,7 +36,10 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
* </pre>
*
* @since Java Persistence 1.0
*
* @deprecated replace by org.redkale.persistence.Table
*/
@Deprecated(since = "2.8.0")
@Target(TYPE)
@Retention(RUNTIME)
public @interface Table {

View File

@@ -15,11 +15,9 @@
******************************************************************************/
package javax.persistence;
import java.lang.annotation.Target;
import java.lang.annotation.Retention;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.*;
import static java.lang.annotation.ElementType.*;
/**
* Specifies that the property or field is not persistent. It is used
@@ -38,7 +36,10 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
* </pre>
*
* @since Java Persistence 1.0
*
* @deprecated replace by org.redkale.persistence.Transient
*/
@Deprecated(since = "2.8.0")
@Target({METHOD, FIELD})
@Retention(RUNTIME)

View File

@@ -15,9 +15,8 @@
***************************************************************************** */
package javax.persistence;
import java.lang.annotation.Target;
import java.lang.annotation.Retention;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.*;
/**
* Specifies that a unique constraint is to be included in
@@ -35,7 +34,10 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
* </pre>
*
* @since Java Persistence 1.0
*
* @deprecated replace by org.redkale.persistence.UniqueConstraint
*/
@Deprecated(since = "2.8.0")
@Target({})
@Retention(RUNTIME)
public @interface UniqueConstraint {

View File

@@ -5,7 +5,7 @@
* @author zhangjx
*
*/
module redkale {
module org.redkale {
requires java.base;
requires java.logging;
@@ -13,9 +13,7 @@ module redkale {
requires java.sql;
requires jdk.unsupported; //sun.misc.Unsafe
exports javax.annotation;
exports javax.persistence;
exports org.redkale.annotation;
exports org.redkale.asm;
exports org.redkale.boot;
exports org.redkale.boot.watch;
@@ -29,16 +27,18 @@ module redkale {
exports org.redkale.net.client;
exports org.redkale.net.http;
exports org.redkale.net.sncp;
exports org.redkale.persistence;
exports org.redkale.service;
exports org.redkale.source;
exports org.redkale.util;
exports org.redkale.watch;
uses org.redkale.mq.MessageAgent;
uses org.redkale.cluster.ClusterAgent;
uses org.redkale.boot.PropertiesAgentProvider;
uses org.redkale.cluster.ClusterAgentProvider;
uses org.redkale.convert.ConvertProvider;
uses org.redkale.mq.MessageAgentProvider;
uses org.redkale.source.CacheSourceProvider;
uses org.redkale.source.DataSourceProvider;
uses org.redkale.util.ResourceInjectLoader;
uses org.redkale.util.ResourceAnnotationProvider;
}

View File

@@ -0,0 +1,26 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.annotation;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.*;
/**
* 自动加载。 使用场景:
* 1、被标记为&#64;AutoLoad(false)的Service类不会被自动加载, 当被依赖时才会被加载
* 2、被标记为&#64;AutoLoad(false)的Servlet类不会被自动加载
*
* <p> 详情见: https://redkale.org
* @author zhangjx
*/
@Documented
@Target({TYPE})
@Retention(RUNTIME)
public @interface AutoLoad {
boolean value() default true;
}

View File

@@ -0,0 +1,23 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.annotation;
import java.lang.annotation.*;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* 标记参数bean
*
* @since 2.5.0
*/
@Inherited
@Documented
@Target(TYPE)
@Retention(RUNTIME)
public @interface Bean {
}

View File

@@ -0,0 +1,50 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.annotation;
import java.lang.annotation.*;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* 接收命令的标记, 只能标记在本地模式下Service里参数为(String)或(String, String[])的public方法上
*
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
*
* @since 2.1.0
*/
@Inherited
@Documented
@Target({METHOD})
@Retention(RUNTIME)
public @interface Command {
/**
* 命令号,没有指定值则接收所有的命令
*
* @return String
*/
String value() default "";
/**
* 参数帮助说明在value不为空命令redkale --help时显示
*
* @return String
*
* @since 2.7.0
*/
String description() default "";
/**
* 描述
*
* @return String
*/
String comment() default "";
}

View File

@@ -0,0 +1,29 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.annotation;
import java.lang.annotation.*;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* 标记注释,备注
*
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
*/
@Inherited
@Documented
@Target({TYPE, METHOD, FIELD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE, ANNOTATION_TYPE, TYPE_PARAMETER})
@Retention(RUNTIME)
public @interface Comment {
String name() default "";
String value();
}

View File

@@ -0,0 +1,24 @@
package org.redkale.annotation;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.*;
/**
* 标记Component的Service类特点: <br>
* 1、直接构造, 不使用Sncp动态构建对象 <br>
* 2、不会生成对应协议的Servlet <br>
*
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
* @since 2.8.0
*/
@Inherited
@Documented
@Target({TYPE})
@Retention(RUNTIME)
public @interface Component {
}

View File

@@ -3,23 +3,24 @@
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.service;
package org.redkale.annotation;
import java.lang.annotation.*;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import org.redkale.util.*;
/**
* 参数回写, 当Service的方法需要更改参数对象内部的数据时需要使用RpcCall
* 类似java.beans.ConstructorProperties, 必须配合Creator使用
*
* <p>
* 详情见: https://redkale.org
*
* <p> 详情见: https://redkale.org
* @author zhangjx
*/
@Inherited
@Documented
@Target({ElementType.PARAMETER})
@Target({METHOD, CONSTRUCTOR})
@Retention(RUNTIME)
public @interface RpcCall {
public @interface ConstructorParameters {
Class<? extends Attribute> value();
String[] value();
}

View File

@@ -0,0 +1,46 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.annotation;
import java.lang.annotation.*;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* 等于level日志级别且包含keys字符串的日志才会被排除 <br>
*
* <blockquote><pre>
* &#64;LogExcludeLevel(levels = {"FINEST"}, keys = {"SET username ="})
* public class UserRecord {
* public int userid;
* public String username = "";
* }
*
* 这样当调用DataSource对UserRecord对象进行操作时拼接的SQL语句含"SET username ="字样的都会在FINEST日志级别过滤掉
* </pre></blockquote>
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
*/
@Documented
@Target({TYPE})
@Retention(RUNTIME)
@Repeatable(LogExcludeLevel.LogExcludeLevels.class)
public @interface LogExcludeLevel {
String[] levels();
String[] keys();
@Documented
@Target({TYPE})
@Retention(RUNTIME)
@interface LogExcludeLevels {
LogExcludeLevel[] value();
}
}

View File

@@ -0,0 +1,26 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.annotation;
import java.lang.annotation.*;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* 被标记的日志级别以上的才会被记录
*
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
*/
@Documented
@Target({TYPE})
@Retention(RUNTIME)
public @interface LogLevel {
String value();
}

View File

@@ -0,0 +1,27 @@
/*
*
*/
package org.redkale.annotation;
import java.lang.annotation.*;
/**
* 非阻塞模式标记, 标记在Service类和方法、Filter类、HttpServlet类上 <br>
* 一般情况下,没有显注此注解的方法视为阻塞时, 以下两种情况除外: <br>
* 1、返回类型是CompletionStage <br>
* 2、返回类型是void且参数存在CompletionHandler类型 <br>
* 阻塞模式的方法会在work线程池中运行 非阻塞在IO线程中运行。
*
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
*
* @since 2.8.0
*/
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface NonBlocking { //不可使用@Inherited防止被继承, 见HttpServlet.preExecute/authenticate/execute
boolean value() default true;
}

View File

@@ -0,0 +1,21 @@
/*
*
*/
package org.redkale.annotation;
import java.lang.annotation.*;
/**
* 标记值可以为null
*
* 详情见: https://redkale.org
*
* @author zhangjx
*
* @since 2.8.0
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface Nonnull {
}

View File

@@ -0,0 +1,21 @@
/*
*
*/
package org.redkale.annotation;
import java.lang.annotation.*;
/**
* 标记值可以为null
*
* 详情见: https://redkale.org
*
* @author zhangjx
*
* @since 2.8.0
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface Nullable {
}

View File

@@ -0,0 +1,39 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.redkale.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 值越大,优先级越高
*
* @since Common Annotations 1.2
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Priority {
/**
* 优先级值
*
* @return int
*/
int value();
}

View File

@@ -0,0 +1,52 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.annotation;
import java.lang.annotation.*;
/**
* &#64;Resource(name = "$") 表示资源name采用所属对象的name <br>
* &#64;Resource(name = "@name") 表示资源对象自身的name <br>
* &#64;Resource(name = "@type") 表示资源对象自身的类型 <br>
*
* @since Common Annotations 1.0
*
* @since 2.8.0
*/
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Resource {
/**
* 是否必须存在
*
* @return boolean
*
* @since 2.8.0
*/
public boolean required() default true;
/**
* 资源名称 <br>
* <blockquote><pre>
* name规则:
* 1: "$"有特殊含义, 表示资源本身,"$"不能单独使用
* 2: "@name"、"@type"有特殊含义
* 3: 只能是字母、数字、(短横)-、(下划线)_、点(.)的组合
* </pre></blockquote>
*
* @return String
*/
public String name() default "";
/**
* 依赖注入的类型
*
* @return Class
*/
public Class<?> type() default Object.class;
}

View File

@@ -0,0 +1,64 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.annotation;
import java.lang.annotation.*;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* &#64;Resource资源被更新时的监听事件, 本注解只能标记在方法参数为ResourceEvent[]上 <br>
* 注意: 一个类只能存在一个&#64;ResourceListener的方法 多余的会被忽略 <br>
* 方法在资源被更新以后调用。
*
* <blockquote><pre>
* public class RecordService implements Service {
*
* &#64;Resource(name = "record.id")
* private int id;
*
* &#64;Resource(name = "record.name")
* private String name;
*
* &#64;ResourceListener
* private void changeResource(ResourceEvent[] events) {
* for(ResourceEvent event : events) {
* System.out.println("@Resource = " + event.name() + " 资源变更: newVal = " + event.newValue() + ", oldVal = " + event.oldValue());
* }
* }
*
* public static void main(String[] args) throws Exception {
* ResourceFactory factory = ResourceFactory.root();
* factory.register("record.id", "2345");
* factory.register("record.name", "my old name");
* Record record = new Record();
* factory.inject(record);
* factory.register("record.name", "my new name");
* }
*
* }
* </pre></blockquote>
*
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
*/
@Documented
@Target({METHOD})
@Retention(RUNTIME)
public @interface ResourceListener {
/**
* 新旧值是否不同时才回调方法 <br>
* true: 新值与旧值不同时才回调ResourceListener方法
* false: 只要执行了ResourceFactory.register 就回调ResourceListener方法
*
* @since 2.7.0
* @return boolean
*/
boolean different() default true;
}

View File

@@ -0,0 +1,29 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.annotation;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.*;
/**
* 显式的指明资源类型。
* 调用ResourceFactory.register(Object rs)时通常执行的是ResourceFactory.register(rs.getClass(), Object rs);
* 若rs.getClass()的类标记了&#64;ResourceType, 则使用&#64;ResourceType.value()的class值进行注入。
*
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
*/
@Inherited
@Documented
@Target({TYPE})
@Retention(RUNTIME)
public @interface ResourceType {
Class value();
}

View File

@@ -0,0 +1,4 @@
/**
* 提供基础注解包
*/
package org.redkale.annotation;

View File

@@ -10,13 +10,15 @@ import java.lang.reflect.*;
import java.math.*;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.*;
import java.util.logging.*;
import javax.persistence.*;
import org.redkale.annotation.Comment;
import org.redkale.convert.*;
import org.redkale.convert.json.*;
import org.redkale.mq.MessageMultiConsumer;
import org.redkale.net.http.*;
import org.redkale.persistence.*;
import org.redkale.service.RetResult;
import org.redkale.source.*;
import org.redkale.util.*;
@@ -31,7 +33,7 @@ import org.redkale.util.*;
*
* @author zhangjx
*/
public final class ApiDocsService {
public final class ApiDocCommand {
private static final java.lang.reflect.Type TYPE_RETRESULT_OBJECT = new TypeToken<RetResult<Object>>() {
}.getType();
@@ -47,13 +49,26 @@ public final class ApiDocsService {
private final Application app; //Application全局对象
public ApiDocsService(Application app) {
public ApiDocCommand(Application app) {
this.app = app;
}
public void run(String[] args) throws Exception {
public String command(String cmd, String[] params) throws Exception {
//是否跳过RPC接口
final boolean skipRPC = Arrays.toString(args).toLowerCase().contains("skip-rpc") && !Arrays.toString(args).toLowerCase().contains("skip-rpc=false");
boolean skipRPC = true;
String apiHost = "http://localhost";
if (params != null && params.length > 0) {
for (String param : params) {
if (param == null) continue;
param = param.toLowerCase();
if (param.startsWith("--api-skiprpc=")) {
skipRPC = "true".equalsIgnoreCase(param.substring("--api-skiprpc=".length()));
} else if (param.startsWith("--api-host=")) {
apiHost = param.substring("--api-host=".length());
}
}
}
List<Map> serverList = new ArrayList<>();
Field __prefix = HttpServlet.class.getDeclaredField("_prefix");
@@ -70,14 +85,14 @@ public final class ApiDocsService {
serverList.add(map);
HttpServer server = node.getServer();
map.put("address", server.getSocketAddress());
swaggerServers.add(Utility.ofMap("url", "http://localhost:" + server.getSocketAddress().getPort()));
swaggerServers.add(Utility.ofMap("url", apiHost + ":" + server.getSocketAddress().getPort()));
List<Map<String, Object>> servletsList = new ArrayList<>();
map.put("servlets", servletsList);
String plainContentType = server.getResponseConfig() == null ? "application/json" : server.getResponseConfig().plainContentType;
if (plainContentType == null || plainContentType.isEmpty()) plainContentType = "application/json";
if (plainContentType.indexOf(';') > 0) plainContentType = plainContentType.substring(0, plainContentType.indexOf(';'));
for (HttpServlet servlet : server.getPrepareServlet().getServlets()) {
for (HttpServlet servlet : server.getDispatcherServlet().getServlets()) {
if (!(servlet instanceof HttpServlet)) continue;
if (servlet instanceof WebSocketServlet) continue;
if (servlet.getClass().getAnnotation(MessageMultiConsumer.class) != null) {
@@ -135,8 +150,8 @@ public final class ApiDocsService {
mappingMap.put("params", paramsList);
List<String> results = new ArrayList<>();
Type resultType = action.result();
if (!action.resultref().isEmpty()) {
Field f = servlet.getClass().getDeclaredField(action.resultref());
if (!action.resultRef().isEmpty()) {
Field f = servlet.getClass().getDeclaredField(action.resultRef());
f.setAccessible(true);
resultType = (Type) f.get(servlet);
}
@@ -200,7 +215,7 @@ public final class ApiDocsService {
f.setAccessible(true);
paramGenericType = (Type) f.get(servlet);
}
simpleSchemaType(node.getLogger(), swaggerComponentsMap, param.type(), paramGenericType, paramSchemaMap, true);
simpleSchemaType(null, node.getLogger(), swaggerComponentsMap, param.type(), paramGenericType, paramSchemaMap, true);
if (param.style() == HttpParam.HttpParameterStyle.BODY) {
swaggerRequestBody.put("description", param.comment());
swaggerRequestBody.put("content", Utility.ofMap(plainContentType, Utility.ofMap("schema", paramSchemaMap)));
@@ -217,9 +232,10 @@ public final class ApiDocsService {
swaggerParamMap.put("style", param.style() == HttpParam.HttpParameterStyle.HEADER || param.name().indexOf('#') == 0 ? "simple" : "form");
swaggerParamMap.put("explode", true);
swaggerParamMap.put("schema", paramSchemaMap);
Object example = formatExample(param.example(), param.type(), paramGenericType);
if (example != null) swaggerParamMap.put("example", example);
if (!param.example().isEmpty()) {
Object example = formatExample(null, param.example(), param.type(), paramGenericType);
if (example != null) {
swaggerParamMap.put("example", example);
} else if (!param.example().isEmpty()) {
swaggerParamMap.put("example", param.example());
}
swaggerParamsList.add(swaggerParamMap);
@@ -246,14 +262,17 @@ public final class ApiDocsService {
Column col = field.getAnnotation(Column.class);
FilterColumn fc = field.getAnnotation(FilterColumn.class);
Comment comment = field.getAnnotation(Comment.class);
org.redkale.util.Comment comment2 = field.getAnnotation(org.redkale.util.Comment.class);
if (comment != null) {
fieldmap.put("comment", comment.value());
} else if (comment2 != null) {
fieldmap.put("comment", comment2.value());
} else if (col != null) {
fieldmap.put("comment", col.comment());
} else if (fc != null) {
fieldmap.put("comment", fc.comment());
}
fieldmap.put("primary", !filter && (field.getAnnotation(Id.class) != null));
fieldmap.put("primary", !filter && (field.getAnnotation(Id.class) != null || field.getAnnotation(javax.persistence.Id.class) != null));
fieldmap.put("updatable", (filter || col == null || col.updatable()));
if (servlet.getClass().getAnnotation(Rest.RestDyn.class) != null) {
@@ -276,12 +295,13 @@ public final class ApiDocsService {
swaggerOperatMap.put("deprecated", true);
}
Map<String, Object> respSchemaMap = new LinkedHashMap<>();
simpleSchemaType(node.getLogger(), swaggerComponentsMap, action.result(), resultType, respSchemaMap, true);
JsonFactory returnFactory = Rest.createJsonFactory(false, method.getAnnotationsByType(RestConvert.class), method.getAnnotationsByType(RestConvertCoder.class));
simpleSchemaType(returnFactory, node.getLogger(), swaggerComponentsMap, action.result(), resultType, respSchemaMap, true);
Map<String, Object> respMap = new LinkedHashMap<>();
respMap.put("schema", respSchemaMap);
Object example = formatExample(action.example(), action.result(), resultType);
if (example != null) swaggerOperatMap.put("example", example);
Object example = formatExample(returnFactory, action.example(), action.result(), resultType);
if (example != null) respSchemaMap.put("example", example);
if (!swaggerRequestBody.isEmpty()) swaggerOperatMap.put("requestBody", swaggerRequestBody);
swaggerOperatMap.put("parameters", swaggerParamsList);
String actiondesc = action.comment();
@@ -335,16 +355,18 @@ public final class ApiDocsService {
if (doctemplate.isFile() && doctemplate.canRead()) {
in = new FileInputStream(doctemplate);
}
if (in == null) in = ApiDocsService.class.getResourceAsStream("apidoc-template.html");
String content = Utility.read(in).replace("'${content}'", json);
in.close();
FileOutputStream outhtml = new FileOutputStream(new File(app.getHome(), "apidoc.html"));
outhtml.write(content.getBytes(StandardCharsets.UTF_8));
outhtml.close();
if (in != null) {
String content = Utility.read(in).replace("'#{content}'", json);
in.close();
FileOutputStream outhtml = new FileOutputStream(new File(app.getHome(), "apidoc.html"));
outhtml.write(content.getBytes(StandardCharsets.UTF_8));
outhtml.close();
}
}
return "apidoc success";
}
private static void simpleSchemaType(Logger logger, Map<String, Map<String, Object>> componentsMap, Class type, Type genericType, Map<String, Object> schemaMap, boolean recursive) {
private static void simpleSchemaType(JsonFactory factory, Logger logger, Map<String, Map<String, Object>> componentsMap, Class type, Type genericType, Map<String, Object> schemaMap, boolean recursive) {
if (type == int.class || type == Integer.class || type == AtomicInteger.class) {
schemaMap.put("type", "integer");
schemaMap.put("format", "int32");
@@ -368,13 +390,13 @@ public final class ApiDocsService {
schemaMap.put("type", "array");
Map<String, Object> sbumap = new LinkedHashMap<>();
if (type.isArray()) {
simpleSchemaType(logger, componentsMap, type.getComponentType(), type.getComponentType(), sbumap, false);
simpleSchemaType(factory, logger, componentsMap, type.getComponentType(), type.getComponentType(), sbumap, false);
} else if (genericType instanceof ParameterizedType) {
Type subpt = ((ParameterizedType) genericType).getActualTypeArguments()[0];
if (subpt instanceof Class) {
simpleSchemaType(logger, componentsMap, (Class) subpt, subpt, sbumap, false);
simpleSchemaType(factory, logger, componentsMap, (Class) subpt, subpt, sbumap, false);
} else if (subpt instanceof ParameterizedType && ((ParameterizedType) subpt).getOwnerType() instanceof Class) {
simpleSchemaType(logger, componentsMap, (Class) ((ParameterizedType) subpt).getOwnerType(), subpt, sbumap, false);
simpleSchemaType(factory, logger, componentsMap, (Class) ((ParameterizedType) subpt).getOwnerType(), subpt, sbumap, false);
} else {
sbumap.put("type", "object");
}
@@ -383,7 +405,7 @@ public final class ApiDocsService {
}
schemaMap.put("items", sbumap);
} else if (!type.getName().startsWith("java.") && !type.getName().startsWith("javax.")) {
String ct = simpleComponentType(logger, componentsMap, type, genericType);
String ct = simpleComponentType(factory, logger, componentsMap, type, genericType);
if (ct == null) {
schemaMap.put("type", "object");
} else {
@@ -394,10 +416,11 @@ public final class ApiDocsService {
}
}
private static String simpleComponentType(Logger logger, Map<String, Map<String, Object>> componentsMap, Class type, Type genericType) {
private static String simpleComponentType(JsonFactory factory, Logger logger, Map<String, Map<String, Object>> componentsMap, Class type, Type genericType) {
try {
Set<Type> types = new HashSet<>();
Encodeable encodeable = JsonFactory.root().loadEncoder(genericType);
String ct = componentKey(logger, componentsMap, null, encodeable, true);
String ct = componentKey(factory, logger, types, componentsMap, null, encodeable, true);
if (ct == null || ct.length() == 0) return null;
if (componentsMap.containsKey(ct)) return ct;
Map<String, Object> cmap = new LinkedHashMap<>();
@@ -409,7 +432,7 @@ public final class ApiDocsService {
if (encodeable instanceof ObjectEncoder) {
for (EnMember member : ((ObjectEncoder) encodeable).getMembers()) {
Map<String, Object> schemaMap = new LinkedHashMap<>();
simpleSchemaType(logger, componentsMap, TypeToken.typeToClassOrElse(member.getEncoder().getType(), Object.class), member.getEncoder().getType(), schemaMap, true);
simpleSchemaType(factory, logger, componentsMap, TypeToken.typeToClassOrElse(member.getEncoder().getType(), Object.class), member.getEncoder().getType(), schemaMap, true);
String desc = "";
if (member.getField() != null) {
Column col = member.getField().getAnnotation(Column.class);
@@ -425,6 +448,8 @@ public final class ApiDocsService {
}
if (desc.isEmpty() && member.getField().getAnnotation(Comment.class) != null) {
desc = member.getField().getAnnotation(Comment.class).value();
} else if (desc.isEmpty() && member.getField().getAnnotation(org.redkale.util.Comment.class) != null) {
desc = member.getField().getAnnotation(org.redkale.util.Comment.class).value();
}
} else if (member.getMethod() != null) {
Column col = member.getMethod().getAnnotation(Column.class);
@@ -440,6 +465,8 @@ public final class ApiDocsService {
}
if (desc.isEmpty() && member.getMethod().getAnnotation(Comment.class) != null) {
desc = member.getMethod().getAnnotation(Comment.class).value();
} else if (desc.isEmpty() && member.getMethod().getAnnotation(org.redkale.util.Comment.class) != null) {
desc = member.getMethod().getAnnotation(org.redkale.util.Comment.class).value();
}
}
if (!desc.isEmpty()) schemaMap.put("description", desc);
@@ -455,35 +482,41 @@ public final class ApiDocsService {
}
}
private static String componentKey(Logger logger, Map<String, Map<String, Object>> componentsMap, EnMember field, Encodeable encodeable, boolean first) {
private static String componentKey(JsonFactory factory, Logger logger, Set<Type> types, Map<String, Map<String, Object>> componentsMap, EnMember field, Encodeable encodeable, boolean first) {
if (encodeable instanceof ObjectEncoder) {
if (types.contains(encodeable.getType())) return "";
types.add(encodeable.getType());
StringBuilder sb = new StringBuilder();
sb.append(((ObjectEncoder) encodeable).getTypeClass().getSimpleName());
for (EnMember member : ((ObjectEncoder) encodeable).getMembers()) {
if (member.getEncoder() instanceof ArrayEncoder
|| member.getEncoder() instanceof CollectionEncoder) {
String subsb = componentKey(logger, componentsMap, member, member.getEncoder(), false);
String subsb = componentKey(factory, logger, types, componentsMap, member, member.getEncoder(), false);
if (subsb == null) return null;
AccessibleObject real = member.getField() == null ? member.getMethod() : member.getField();
if (real == null) continue;
Class cz = real instanceof Field ? ((Field) real).getType() : ((Method) real).getReturnType();
Type ct = real instanceof Field ? ((Field) real).getGenericType() : ((Method) real).getGenericReturnType();
if (cz == ct) continue;
if (field == null && encodeable.getType() instanceof Class) continue;
if (sb.length() > 0 && subsb.length() > 0) sb.append("_");
sb.append(subsb);
} else if (member.getEncoder() instanceof ObjectEncoder || member.getEncoder() instanceof SimpledCoder) {
AccessibleObject real = member.getField() == null ? member.getMethod() : member.getField();
if (real == null) continue;
if (types.contains(member.getEncoder().getType())) continue;
types.add(member.getEncoder().getType());
if (member.getEncoder() instanceof SimpledCoder) {
simpleSchemaType(logger, componentsMap, ((SimpledCoder) member.getEncoder()).getType(), ((SimpledCoder) member.getEncoder()).getType(), new LinkedHashMap<>(), true);
simpleSchemaType(factory, logger, componentsMap, ((SimpledCoder) member.getEncoder()).getType(), ((SimpledCoder) member.getEncoder()).getType(), new LinkedHashMap<>(), true);
} else {
simpleSchemaType(logger, componentsMap, ((ObjectEncoder) member.getEncoder()).getTypeClass(), ((ObjectEncoder) member.getEncoder()).getType(), new LinkedHashMap<>(), true);
simpleSchemaType(factory, logger, componentsMap, ((ObjectEncoder) member.getEncoder()).getTypeClass(), ((ObjectEncoder) member.getEncoder()).getType(), new LinkedHashMap<>(), true);
}
Class cz = real instanceof Field ? ((Field) real).getType() : ((Method) real).getReturnType();
Type ct = real instanceof Field ? ((Field) real).getGenericType() : ((Method) real).getGenericReturnType();
if (cz == ct) continue;
String subsb = componentKey(logger, componentsMap, member, member.getEncoder(), false);
String subsb = componentKey(factory, logger, types, componentsMap, member, member.getEncoder(), false);
if (subsb == null) return null;
if (field == null && member.getEncoder().getType() instanceof Class) continue;
if (sb.length() > 0 && subsb.length() > 0) sb.append("_");
sb.append(subsb);
} else if (member.getEncoder() instanceof MapEncoder) {
@@ -497,7 +530,7 @@ public final class ApiDocsService {
final boolean array = (encodeable instanceof ArrayEncoder);
Encodeable subEncodeable = array ? ((ArrayEncoder) encodeable).getComponentEncoder() : ((CollectionEncoder) encodeable).getComponentEncoder();
if (subEncodeable instanceof SimpledCoder && field != null) return "";
final String sb = componentKey(logger, componentsMap, null, subEncodeable, false);
final String sb = componentKey(factory, logger, types, componentsMap, null, subEncodeable, false);
if (sb == null || sb.isEmpty()) return sb;
if (field != null && field.getField() != null && field.getField().getDeclaringClass() == Sheet.class) {
return sb;
@@ -516,8 +549,9 @@ public final class ApiDocsService {
}
}
private static Object formatExample(String example, Class type, Type genericType) {
if (example == null || example.isEmpty()) return null;
private static Object formatExample(JsonFactory factory, String example, Class type, Type genericType) {
if (example != null && !example.isEmpty()) return example;
JsonFactory jsonFactory = factory == null || factory == JsonFactory.root() ? exampleFactory : factory;
if (type == Flipper.class) {
return new Flipper();
} else if (TYPE_RETRESULT_OBJECT.equals(genericType)) {
@@ -528,8 +562,103 @@ public final class ApiDocsService {
return RetResult.success(0);
} else if (TYPE_RETRESULT_LONG.equals(genericType)) {
return RetResult.success(0L);
} else if (type == boolean.class || type == Boolean.class) {
return true;
} else if (type.isPrimitive()) {
return 0;
} else if (type == boolean[].class || type == Boolean[].class) {
return new boolean[]{true, false};
} else if (type == byte[].class || type == Byte[].class) {
return new byte[]{0, 0};
} else if (type == char[].class || type == Character[].class) {
return new char[]{'a', 'b'};
} else if (type == short[].class || type == Short[].class) {
return new short[]{0, 0};
} else if (type == int[].class || type == Integer[].class) {
return new int[]{0, 0};
} else if (type == long[].class || type == Long[].class) {
return new long[]{0, 0};
} else if (type == float[].class || type == Float[].class) {
return new float[]{0, 0};
} else if (type == double[].class || type == Double[].class) {
return new double[]{0, 0};
} else if (Number.class.isAssignableFrom(type)) {
return 0;
} else if (CharSequence.class.isAssignableFrom(type)) {
return "";
} else if (CompletableFuture.class.isAssignableFrom(type)) {
if (genericType instanceof ParameterizedType) {
try {
ParameterizedType pt = (ParameterizedType) genericType;
Type valType = pt.getActualTypeArguments()[0];
return formatExample(factory, example, valType instanceof ParameterizedType ? (Class) ((ParameterizedType) valType).getRawType() : ((Class) valType), valType);
} catch (Throwable t) {
}
}
} else if (Sheet.class.isAssignableFrom(type)) { //要在Collection前面
if (genericType instanceof ParameterizedType) {
try {
ParameterizedType pt = (ParameterizedType) genericType;
Type valType = pt.getActualTypeArguments()[0];
Class valClass = valType instanceof ParameterizedType ? (Class) ((ParameterizedType) valType).getRawType() : (Class) valType;
Object val = formatExample(factory, example, valClass, valType);
return new StringWrapper(jsonFactory.getConvert().convertTo(jsonFactory.getConvert().convertFrom(genericType, "{'rows':[" + val + "," + val + "]}")));
} catch (Throwable t) {
}
}
} else if (type.isArray()) {
try {
Object val = formatExample(factory, example, type.getComponentType(), type.getComponentType());
return new StringWrapper(jsonFactory.getConvert().convertTo(jsonFactory.getConvert().convertFrom(genericType, "[" + val + "," + val + "]")));
} catch (Throwable t) {
}
} else if (Collection.class.isAssignableFrom(type)) {
if (genericType instanceof ParameterizedType) {
try {
ParameterizedType pt = (ParameterizedType) genericType;
Type valType = pt.getActualTypeArguments()[0];
Class valClass = valType instanceof ParameterizedType ? (Class) ((ParameterizedType) valType).getRawType() : (Class) valType;
Object val = formatExample(factory, example, valClass, valType);
return new StringWrapper(jsonFactory.getConvert().convertTo(jsonFactory.getConvert().convertFrom(genericType, "[" + val + "," + val + "]")));
} catch (Throwable t) {
}
}
} else if (type == RetResult.class) {
if (genericType instanceof ParameterizedType) {
try {
ParameterizedType pt = (ParameterizedType) genericType;
Type valType = pt.getActualTypeArguments()[0];
Class valClass = valType instanceof ParameterizedType ? (Class) ((ParameterizedType) valType).getRawType() : (Class) valType;
Object val = formatExample(factory, example, valClass, valType);
return new StringWrapper(jsonFactory.getConvert().convertTo(jsonFactory.getConvert().convertFrom(genericType, "{'result':" + val + "}")));
} catch (Throwable t) {
}
}
} else if (type != void.class) {
try {
Decodeable decoder = jsonFactory.loadDecoder(genericType);
if (decoder instanceof ObjectDecoder) {
StringBuilder json = new StringBuilder();
json.append("{");
int index = 0;
for (DeMember member : ((ObjectDecoder) decoder).getMembers()) {
if (!(member.getDecoder() instanceof ObjectDecoder)) continue;
if (index > 0) json.append(",");
json.append('"').append(member.getAttribute().field()).append("\":{}");
index++;
}
json.append("}");
Object val = jsonFactory.getConvert().convertFrom(genericType, json.toString());
return new StringWrapper(jsonFactory.getConvert().convertTo(val));
}
Creator creator = Creator.create(type);
return new StringWrapper(jsonFactory.getConvert().convertTo(creator.create()));
} catch (Throwable t) {
}
}
return example;
}
private static final JsonFactory exampleFactory = JsonFactory.create().tiny(false);
}

File diff suppressed because it is too large Load Diff

View File

@@ -6,7 +6,7 @@
package org.redkale.boot;
import java.io.*;
import java.lang.annotation.*;
import java.lang.annotation.Annotation;
import java.lang.reflect.Modifier;
import java.net.*;
import java.nio.charset.StandardCharsets;
@@ -15,9 +15,11 @@ import java.util.concurrent.*;
import java.util.function.Predicate;
import java.util.jar.*;
import java.util.logging.*;
import java.util.regex.*;
import org.redkale.util.*;
import java.util.regex.Pattern;
import org.redkale.annotation.AutoLoad;
import org.redkale.annotation.*;
import org.redkale.util.AnyValue.DefaultAnyValue;
import org.redkale.util.*;
/**
* class过滤器 符合条件的class会保留下来存入FilterEntry。
@@ -32,8 +34,6 @@ public final class ClassFilter<T> {
private static final Logger logger = Logger.getLogger(ClassFilter.class.getName()); //日志对象
private static final boolean finest = logger.isLoggable(Level.FINEST); //日志级别
private final Set<FilterEntry<T>> entrys = new HashSet<>(); //符合条件的结果
private final Set<FilterEntry<T>> expectEntrys = new HashSet<>(); //准备符合条件的结果
@@ -86,13 +86,17 @@ public final class ClassFilter<T> {
}
public ClassFilter<T> or(ClassFilter<T> filter) {
if (ors == null) ors = new ArrayList<>();
if (ors == null) {
ors = new ArrayList<>();
}
ors.add(filter);
return this;
}
public ClassFilter<T> and(ClassFilter<T> filter) {
if (ands == null) ands = new ArrayList<>();
if (ands == null) {
ands = new ArrayList<>();
}
ands.add(filter);
return this;
}
@@ -103,11 +107,16 @@ public final class ClassFilter<T> {
* @return Set&lt;FilterEntry&lt;T&gt;&gt;
*/
public final Set<FilterEntry<T>> getFilterEntrys() {
HashSet<FilterEntry<T>> set = new HashSet<>();
set.addAll(entrys);
if (ors != null) ors.forEach(f -> set.addAll(f.getFilterEntrys()));
if (ands != null) ands.forEach(f -> set.addAll(f.getFilterEntrys()));
return set;
List<FilterEntry<T>> list = new ArrayList<>();
list.addAll(entrys);
if (ors != null) {
ors.forEach(f -> list.addAll(f.getFilterEntrys()));
}
if (ands != null) {
ands.forEach(f -> list.addAll(f.getFilterEntrys()));
}
Collections.sort(list);
return new LinkedHashSet<>(list);
}
/**
@@ -116,11 +125,16 @@ public final class ClassFilter<T> {
* @return Set&lt;FilterEntry&lt;T&gt;&gt;
*/
public final Set<FilterEntry<T>> getFilterExpectEntrys() {
HashSet<FilterEntry<T>> set = new HashSet<>();
set.addAll(expectEntrys);
if (ors != null) ors.forEach(f -> set.addAll(f.getFilterExpectEntrys()));
if (ands != null) ands.forEach(f -> set.addAll(f.getFilterExpectEntrys()));
return set;
List<FilterEntry<T>> list = new ArrayList<>();
list.addAll(expectEntrys);
if (ors != null) {
ors.forEach(f -> list.addAll(f.getFilterExpectEntrys()));
}
if (ands != null) {
ands.forEach(f -> list.addAll(f.getFilterExpectEntrys()));
}
Collections.sort(list);
return new LinkedHashSet<>(list);
}
/**
@@ -129,7 +143,7 @@ public final class ClassFilter<T> {
* @return Set&lt;FilterEntry&lt;T&gt;&gt;
*/
public final Set<FilterEntry<T>> getAllFilterEntrys() {
HashSet<FilterEntry<T>> rs = new HashSet<>();
HashSet<FilterEntry<T>> rs = new LinkedHashSet<>();
rs.addAll(getFilterEntrys());
rs.addAll(getFilterExpectEntrys());
return rs;
@@ -163,15 +177,17 @@ public final class ClassFilter<T> {
*
* @param property application.xml中对应class节点下的property属性项
* @param clazzname class名称
* @param autoscan 为true表示自动扫描的 false表示显著调用filter AutoLoad的注解将被忽略
* @param autoScan 为true表示自动扫描的 false表示显著调用filter AutoLoad的注解将被忽略
* @param url URL
*/
public final void filter(AnyValue property, String clazzname, boolean autoscan, URL url) {
public final void filter(AnyValue property, String clazzname, boolean autoScan, URL url) {
boolean r = accept0(property, clazzname);
ClassFilter cf = r ? this : null;
if (r && ands != null) {
for (ClassFilter filter : ands) {
if (!filter.accept(property, clazzname)) return;
if (!filter.accept(property, clazzname)) {
return;
}
}
}
if (!r && ors != null) {
@@ -183,10 +199,14 @@ public final class ClassFilter<T> {
}
}
}
if (cf == null || clazzname.startsWith("sun.") || clazzname.contains("module-info")) return;
if (cf == null || clazzname.startsWith("sun.") || clazzname.contains("module-info")) {
return;
}
try {
Class clazz = classLoader.loadClass(clazzname);
if (!cf.accept(property, clazz, autoscan)) return;
if (!cf.accept(property, clazz, autoScan)) {
return;
}
if (cf.conf != null) {
if (property == null) {
property = cf.conf;
@@ -201,16 +221,24 @@ public final class ClassFilter<T> {
}
AutoLoad auto = (AutoLoad) clazz.getAnnotation(AutoLoad.class);
if ((expectPredicate != null && expectPredicate.test(clazzname)) || (autoscan && auto != null && !auto.value())) { //自动扫描且被标记为@AutoLoad(false)的
expectEntrys.add(new FilterEntry(clazz, autoscan, true, property));
org.redkale.util.AutoLoad auto2 = (org.redkale.util.AutoLoad) clazz.getAnnotation(org.redkale.util.AutoLoad.class);
if ((expectPredicate != null && expectPredicate.test(clazzname)) || (autoScan && auto != null && !auto.value())
|| (autoScan && auto2 != null && !auto2.value())) { //自动扫描且被标记为@AutoLoad(false)的
expectEntrys.add(new FilterEntry(clazz, autoScan, true, property));
} else {
entrys.add(new FilterEntry(clazz, autoscan, false, property));
entrys.add(new FilterEntry(clazz, autoScan, false, property));
}
} catch (Throwable cfe) {
if (finest && !clazzname.startsWith("sun.") && !clazzname.startsWith("javax.")
if (logger.isLoggable(Level.FINEST) && !clazzname.startsWith("sun.") && !clazzname.startsWith("javax.")
&& !clazzname.startsWith("com.sun.") && !clazzname.startsWith("jdk.") && !clazzname.startsWith("META-INF")
&& !clazzname.startsWith("com.mysql.") && !clazzname.startsWith("com.microsoft.") && !clazzname.startsWith("freemarker.")
&& !clazzname.startsWith("org.redkale") && (clazzname.contains("Service") || clazzname.contains("Servlet"))) {
if (cfe instanceof NoClassDefFoundError) {
String msg = ((NoClassDefFoundError) cfe).getMessage();
if (msg.startsWith("java.lang.NoClassDefFoundError: java") || msg.startsWith("javax/")) {
return;
}
}
//&& (!(cfe instanceof NoClassDefFoundError) || (cfe instanceof UnsupportedClassVersionError) || ((NoClassDefFoundError) cfe).getMessage().startsWith("java.lang.NoClassDefFoundError: java"))) {
logger.log(Level.FINEST, ClassFilter.class.getSimpleName() + " filter error for class: " + clazzname + (url == null ? "" : (" in " + url)), cfe);
}
@@ -240,30 +268,46 @@ public final class ClassFilter<T> {
boolean r = accept0(property, classname);
if (r && ands != null) {
for (ClassFilter filter : ands) {
if (!filter.accept(property, classname)) return false;
if (!filter.accept(property, classname)) {
return false;
}
}
}
if (!r && ors != null) {
for (ClassFilter filter : ors) {
if (filter.accept(filter.conf, classname)) return true;
if (filter.accept(filter.conf, classname)) {
return true;
}
}
}
return r;
}
private boolean accept0(AnyValue property, String classname) {
if (this.refused) return false;
if (this.privilegeIncludes != null && this.privilegeIncludes.contains(classname)) return true;
if (this.privilegeExcludes != null && this.privilegeExcludes.contains(classname)) return false;
if (classname.startsWith("java.") || classname.startsWith("javax.")) return false;
if (this.refused) {
return false;
}
if (this.privilegeIncludes != null && this.privilegeIncludes.contains(classname)) {
return true;
}
if (this.privilegeExcludes != null && this.privilegeExcludes.contains(classname)) {
return false;
}
if (classname.startsWith("java.") || classname.startsWith("javax.")) {
return false;
}
if (excludePatterns != null) {
for (Pattern reg : excludePatterns) {
if (reg.matcher(classname).matches()) return false;
if (reg.matcher(classname).matches()) {
return false;
}
}
}
if (includePatterns != null) {
for (Pattern reg : includePatterns) {
if (reg.matcher(classname).matches()) return true;
if (reg.matcher(classname).matches()) {
return true;
}
}
}
return includePatterns == null;
@@ -280,27 +324,41 @@ public final class ClassFilter<T> {
*/
@SuppressWarnings("unchecked")
public boolean accept(AnyValue property, Class clazz, boolean autoscan) {
if (this.refused || !Modifier.isPublic(clazz.getModifiers())) return false;
if (annotationClass != null && clazz.getAnnotation(annotationClass) == null) return false;
if (this.refused || !Modifier.isPublic(clazz.getModifiers())) {
return false;
}
if (annotationClass != null && clazz.getAnnotation(annotationClass) == null) {
return false;
}
boolean rs = superClass == null || (clazz != superClass && superClass.isAssignableFrom(clazz));
if (rs && this.excludeSuperClasses != null && this.excludeSuperClasses.length > 0) {
for (Class c : this.excludeSuperClasses) {
if (c != null && (clazz == c || c.isAssignableFrom(clazz))) return false;
if (c != null && (clazz == c || c.isAssignableFrom(clazz))) {
return false;
}
}
}
return rs;
}
public static Pattern[] toPattern(String[] regs) {
if (regs == null || regs.length == 0) return null;
if (regs == null || regs.length == 0) {
return null;
}
int i = 0;
Pattern[] rs = new Pattern[regs.length];
for (String reg : regs) {
if (reg == null || reg.trim().isEmpty()) continue;
if (reg == null || reg.trim().isEmpty()) {
continue;
}
rs[i++] = Pattern.compile(reg.trim());
}
if (i == 0) return null;
if (i == rs.length) return rs;
if (i == 0) {
return null;
}
if (i == rs.length) {
return rs;
}
Pattern[] ps = new Pattern[i];
System.arraycopy(rs, 0, ps, 0, i);
return ps;
@@ -384,9 +442,9 @@ public final class ClassFilter<T> {
*
* @param <T> 泛型
*/
public static final class FilterEntry<T> {
public static final class FilterEntry<T> implements Comparable<FilterEntry<T>> {
private final HashSet<String> groups = new LinkedHashSet<>();
private final String group; //优先级高于remote属性
private final String name;
@@ -404,22 +462,26 @@ public final class ClassFilter<T> {
public FilterEntry(Class<T> type, final boolean autoload, boolean expect, AnyValue property) {
this.type = type;
String str = property == null ? null : property.getValue("groups");
if (str != null) {
str = str.trim();
if (str.endsWith(";")) str = str.substring(0, str.length() - 1);
}
if (str != null) this.groups.addAll(Arrays.asList(str.split(";")));
this.property = property;
this.autoload = autoload;
this.expect = expect;
this.group = property == null ? null : property.getValue("group", "").trim();
this.name = property == null ? "" : property.getValue("name", "");
}
@Override //@Priority值越大优先级越高, 需要排前面
public int compareTo(FilterEntry o) {
if (!(o instanceof FilterEntry)) {
return 1;
}
Priority p1 = this.type.getAnnotation(Priority.class);
Priority p2 = ((FilterEntry<T>) o).type.getAnnotation(Priority.class);
return (p2 == null ? 0 : p2.value()) - (p1 == null ? 0 : p1.value());
}
@Override
public String toString() {
return this.getClass().getSimpleName() + "[thread=" + Thread.currentThread().getName()
+ ", type=" + this.type.getSimpleName() + ", name=" + name + ", groups=" + this.groups + "]";
return this.getClass().getSimpleName() + "[type=" + this.type.getSimpleName() + ", name=" + name + ", group=" + this.group + "]";
}
@Override
@@ -429,9 +491,13 @@ public final class ClassFilter<T> {
@Override
public boolean equals(Object obj) {
if (obj == null) return false;
if (getClass() != obj.getClass()) return false;
return (this.type == ((FilterEntry<?>) obj).type && this.groups.equals(((FilterEntry<?>) obj).groups) && this.name.equals(((FilterEntry<?>) obj).name));
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
return (this.type == ((FilterEntry<?>) obj).type && this.name.equals(((FilterEntry<?>) obj).name));
}
public Class<T> getType() {
@@ -446,16 +512,16 @@ public final class ClassFilter<T> {
return property;
}
public boolean containsGroup(String group) {
return groups != null && groups.contains(group);
public boolean isEmptyGroup() {
return group == null || group.isEmpty();
}
public boolean isEmptyGroups() {
return groups == null || groups.isEmpty();
public String getGroup() {
return group;
}
public HashSet<String> getGroups() {
return groups;
public boolean isRemote() {
return "$remote".equalsIgnoreCase(group);
}
public boolean isAutoload() {
@@ -465,6 +531,7 @@ public final class ClassFilter<T> {
public boolean isExpect() {
return expect;
}
}
/**
@@ -496,7 +563,9 @@ public final class ClassFilter<T> {
final URL exurl = excludeFile != null ? excludeFile.toURI().toURL() : null;
final Pattern[] excludePatterns = toPattern(excludeRegs);
for (URL url : loader.getAllURLs()) {
if (exurl != null && exurl.sameFile(url)) continue;
if (exurl != null && exurl.sameFile(url)) {
continue;
}
if (excludePatterns != null && url != RedkaleClassLoader.URL_NONE) {
boolean skip = false;
for (Pattern p : excludePatterns) {
@@ -505,7 +574,9 @@ public final class ClassFilter<T> {
break;
}
}
if (skip) continue;
if (skip) {
continue;
}
}
if (url.getPath().endsWith(".jar")) {
urljares.add(url);
@@ -526,18 +597,42 @@ public final class ClassFilter<T> {
String entryname = it.nextElement().getName().replace('/', '.');
if (entryname.endsWith(".class") && entryname.indexOf('$') < 0) {
String classname = entryname.substring(0, entryname.length() - 6);
if (classname.startsWith("javax.") || classname.startsWith("com.sun.")) continue;
if (classname.startsWith("javax.") || classname.startsWith("com.sun.")) {
continue;
}
//常见的jar跳过
if (classname.startsWith("com.redkaledyn.")) break; //redkale动态生成的类
if (classname.startsWith("com.mysql.")) break;
if (classname.startsWith("org.mariadb.")) break;
if (classname.startsWith("oracle.jdbc.")) break;
if (classname.startsWith("org.postgresql.")) break;
if (classname.startsWith("com.microsoft.sqlserver.")) break;
if (classname.startsWith("com.redkaledyn.")) {
break; //redkale动态生成的类
}
if (classname.startsWith("com.mysql.")) {
break;
}
if (classname.startsWith("org.junit.")) {
break;
}
if (classname.startsWith("org.openjfx.")) {
break;
}
if (classname.startsWith("org.mariadb.")) {
break;
}
if (classname.startsWith("oracle.jdbc.")) {
break;
}
if (classname.startsWith("org.postgresql.")) {
break;
}
if (classname.startsWith("com.microsoft.sqlserver.")) {
break;
}
classes.add(classname);
if (debug) debugstr.append(classname).append("\r\n");
if (debug) {
debugstr.append(classname).append("\r\n");
}
for (final ClassFilter filter : filters) {
if (filter != null) filter.filter(null, classname, url);
if (filter != null) {
filter.filter(null, classname, url);
}
}
}
}
@@ -546,7 +641,9 @@ public final class ClassFilter<T> {
} else {
for (String classname : classes) {
for (final ClassFilter filter : filters) {
if (filter != null) filter.filter(null, classname, url);
if (filter != null) {
filter.filter(null, classname, url);
}
}
}
}
@@ -556,7 +653,9 @@ public final class ClassFilter<T> {
if (classes == null) {
classes = new LinkedHashSet<>();
final Set<String> cs = classes;
if (url == RedkaleClassLoader.URL_NONE) loader.forEachCacheClass(v -> cs.add(v));
if (url == RedkaleClassLoader.URL_NONE) {
loader.forEachCacheClass(v -> cs.add(v));
}
if (cs.isEmpty()) {
files.clear();
File root = new File(url.getFile());
@@ -564,17 +663,25 @@ public final class ClassFilter<T> {
loadClassFiles(excludeFile, root, files);
for (File f : files) {
String classname = f.getPath().substring(rootpath.length() + 1, f.getPath().length() - 6).replace(File.separatorChar, '.');
if (classname.startsWith("javax.") || classname.startsWith("com.sun.")) continue;
if (classname.startsWith("javax.") || classname.startsWith("com.sun.")) {
continue;
}
classes.add(classname);
if (debug) debugstr.append(classname).append("\r\n");
if (debug) {
debugstr.append(classname).append("\r\n");
}
for (final ClassFilter filter : filters) {
if (filter != null) filter.filter(null, classname, url);
if (filter != null) {
filter.filter(null, classname, url);
}
}
}
} else {
for (String classname : classes) {
for (final ClassFilter filter : filters) {
if (filter != null) filter.filter(null, classname, url);
if (filter != null) {
filter.filter(null, classname, url);
}
}
}
}
@@ -582,23 +689,28 @@ public final class ClassFilter<T> {
} else {
for (String classname : classes) {
for (final ClassFilter filter : filters) {
if (filter != null) filter.filter(null, classname, url);
if (filter != null) {
filter.filter(null, classname, url);
}
}
}
}
}
//if (debug) logger.log(Level.INFO, "scan classes: \r\n{0}", debugstr);
//if (debug) logger.log(Level.INFO, "Scan classes: \r\n{0}", debugstr);
}
private static void loadClassFiles(File exclude, File root, List<File> files) {
if (root.isFile() && root.getName().endsWith(".class")) {
files.add(root);
} else if (root.isDirectory()) {
if (exclude != null && exclude.equals(root)) return;
if (exclude != null && exclude.equals(root)) {
return;
}
File[] lfs = root.listFiles();
if (lfs == null) throw new RuntimeException("File(" + root + ") cannot listFiles()");
for (File f : lfs) {
loadClassFiles(exclude, f, files);
if (lfs != null) {
for (File f : lfs) {
loadClassFiles(exclude, f, files);
}
}
}
}

View File

@@ -0,0 +1,135 @@
/*
*/
package org.redkale.boot;
import java.io.*;
import java.util.logging.*;
import org.redkale.util.Traces;
/**
* Handler基类
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
* @since 2.7.0
*/
public abstract class LoggingBaseHandler extends Handler {
//public static final String FORMATTER_FORMAT = "%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS.%tL %4$s %2$s%n%5$s%6$s%n";
//无threadName、TID
public static final String FORMATTER_FORMAT = "[%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS.%tL] %4$s %2$s\r\n%5$s%6$s\r\n";
//有threadName
public static final String FORMATTER_FORMAT2 = "[%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS.%tL] [%7$s] %4$s %2$s\r\n%5$s%6$s\r\n";
//有threadName、TID
public static final String FORMATTER_FORMAT3 = "[%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS.%tL] [%7$s] %8$s %4$s %2$s\r\n%5$s%6$s\r\n";
/**
* 默认的日志时间格式化类
* 与SimpleFormatter的区别在于level不使用本地化
*
*/
public static class LoggingFormater extends Formatter {
@Override
public String format(LogRecord log) {
if (log.getThrown() == null && log.getMessage() != null && log.getMessage().startsWith("------")) {
return formatMessage(log) + "\r\n";
}
String source;
if (log.getSourceClassName() != null) {
source = log.getSourceClassName();
if (log.getSourceMethodName() != null) {
source += " " + log.getSourceMethodName();
}
} else {
source = log.getLoggerName();
}
String message = formatMessage(log);
String throwable = "";
if (log.getThrown() != null) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw) {
@Override
public void println() {
super.print("\r\n");
}
};
pw.println();
log.getThrown().printStackTrace(pw);
pw.close();
throwable = sw.toString();
}
Object[] params = log.getParameters();
if (params != null) {
if (params.length == 1) {
return String.format(FORMATTER_FORMAT2,
log.getInstant().toEpochMilli(),
source,
log.getLoggerName(),
log.getLevel().getName(),
message,
throwable,
params[0]);
} else if (params.length == 2) {
return String.format(FORMATTER_FORMAT3,
log.getInstant().toEpochMilli(),
source,
log.getLoggerName(),
log.getLevel().getName(),
message,
throwable,
params[0],
params[1]);
}
}
return String.format(FORMATTER_FORMAT,
log.getInstant().toEpochMilli(),
source,
log.getLoggerName(),
log.getLevel().getName(),
message,
throwable);
}
}
static boolean traceFlag = false; //防止设置system.property前调用Traces类导致enable提前初始化
protected static void fillLogRecord(LogRecord log) {
String traceid = null;
if (traceFlag && Traces.enable()) {
traceid = Traces.currTraceid();
if (traceid == null || traceid.isEmpty()) {
traceid = "[TID:N/A] ";
} else {
traceid = "[TID:" + traceid + "] ";
}
}
if (traceid == null) {
log.setParameters(new String[]{Thread.currentThread().getName()});
} else {
log.setParameters(new String[]{Thread.currentThread().getName(), traceid});
}
}
public static void initDebugLogConfig() {
try {
ByteArrayOutputStream out = new ByteArrayOutputStream();
final PrintStream ps = new PrintStream(out);
final String handlerName = LoggingFileHandler.LoggingConsoleHandler.class.getName(); //java.util.logging.ConsoleHandler
ps.println("handlers = " + handlerName);
ps.println(".level = FINEST");
ps.println("jdk.level = INFO");
ps.println("sun.level = INFO");
ps.println("com.sun.level = INFO");
ps.println("javax.level = INFO");
ps.println(handlerName + ".level = FINEST");
ps.println(handlerName + ".formatter = " + LoggingFormater.class.getName());
LogManager.getLogManager().readConfiguration(new ByteArrayInputStream(out.toByteArray()));
} catch (Exception e) {
}
}
}

View File

@@ -5,18 +5,15 @@
*/
package org.redkale.boot;
import org.redkale.util.RedkaleClassLoader;
import java.io.*;
import java.nio.file.*;
import java.nio.file.Files;
import static java.nio.file.StandardCopyOption.*;
import java.time.*;
import java.util.*;
import java.util.concurrent.*;
import java.util.Calendar;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.atomic.*;
import java.util.logging.*;
import java.util.logging.Formatter;
import java.util.regex.Pattern;
import org.redkale.util.*;
/**
* 自定义的日志输出类
@@ -26,10 +23,7 @@ import java.util.regex.Pattern;
* @author zhangjx
*/
@SuppressWarnings("unchecked")
public class LoggingFileHandler extends Handler {
//public static final String FORMATTER_FORMAT = "%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS.%tL %4$s %2$s%n%5$s%6$s%n";
public static final String FORMATTER_FORMAT = "%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS.%tL %4$s %2$s\r\n%5$s%6$s\r\n";
public class LoggingFileHandler extends LoggingBaseHandler {
/**
* SNCP的日志输出Handler
@@ -42,71 +36,49 @@ public class LoggingFileHandler extends Handler {
}
}
/**
* 默认的日志时间格式化类
* 与SimpleFormatter的区别在于level不使用本地化
*
*/
public static class LoggingFormater extends Formatter {
public static class LoggingConsoleHandler extends ConsoleHandler {
private Pattern denyRegx;
public LoggingConsoleHandler() {
super();
setFormatter(new LoggingFormater());
configure();
}
private void configure() {
LogManager manager = LogManager.getLogManager();
String denyregxstr = manager.getProperty(LoggingConsoleHandler.class.getName() + ".denyregx");
if (denyregxstr == null) {
denyregxstr = manager.getProperty("java.util.logging.ConsoleHandler.denyregx");
}
try {
if (denyregxstr != null && !denyregxstr.trim().isEmpty()) {
this.denyRegx = Pattern.compile(denyregxstr);
}
} catch (Exception e) {
}
}
@Override
public String format(LogRecord log) {
String source;
if (log.getSourceClassName() != null) {
source = log.getSourceClassName();
if (log.getSourceMethodName() != null) {
source += " " + log.getSourceMethodName();
}
} else {
source = log.getLoggerName();
public void publish(LogRecord log) {
if (denyRegx != null && denyRegx.matcher(log.getMessage()).find()) {
return;
}
String message = formatMessage(log);
String throwable = "";
if (log.getThrown() != null) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw) {
@Override
public void println() {
super.print("\r\n");
}
};
pw.println();
log.getThrown().printStackTrace(pw);
pw.close();
throwable = sw.toString();
}
return String.format(FORMATTER_FORMAT,
System.currentTimeMillis(),
source,
log.getLoggerName(),
log.getLevel().getName(),
message,
throwable);
}
}
public static void initDebugLogConfig() {
try {
ByteArrayOutputStream out = new ByteArrayOutputStream();
final PrintStream ps = new PrintStream(out);
ps.println("handlers = java.util.logging.ConsoleHandler");
ps.println(".level = FINEST");
ps.println("jdk.level = INFO");
ps.println("sun.level = INFO");
ps.println("com.sun.level = INFO");
ps.println("javax.level = INFO");
ps.println("java.util.logging.ConsoleHandler.level = FINEST");
ps.println("java.util.logging.ConsoleHandler.formatter = " + LoggingFileHandler.LoggingFormater.class.getName());
LogManager.getLogManager().readConfiguration(new ByteArrayInputStream(out.toByteArray()));
} catch (Exception e) {
fillLogRecord(log);
super.publish(log);
}
}
protected final LinkedBlockingQueue<LogRecord> logqueue = new LinkedBlockingQueue();
private String pattern;
protected String pattern;
private String unusual; //不为null表示将 WARNING、SEVERE 级别的日志写入单独的文件中
protected String patternDateFormat; //需要时间格式化
protected String unusual; //不为null表示将 WARNING、SEVERE 级别的日志写入单独的文件中
protected String unusualDateFormat; //需要时间格式化
private int limit; //文件大小限制
@@ -118,13 +90,13 @@ public class LoggingFileHandler extends Handler {
private long tomorrow;
private boolean append;
protected boolean append;
private Pattern denyreg;
protected Pattern denyregx;
private final AtomicLong loglength = new AtomicLong();
private final AtomicLong logLength = new AtomicLong();
private final AtomicLong logunusuallength = new AtomicLong();
private final AtomicLong logUnusualLength = new AtomicLong();
private File logfile;
@@ -148,12 +120,14 @@ public class LoggingFileHandler extends Handler {
cal.set(Calendar.MILLISECOND, 0);
cal.add(Calendar.DAY_OF_YEAR, 1);
long t = cal.getTimeInMillis();
if (this.tomorrow != t) logindex.set(0);
if (this.tomorrow != t) {
logindex.set(0);
}
this.tomorrow = t;
}
private void open() {
final String name = "Redkale-Logging-" + getClass().getSimpleName() + "-Thread";
final String name = "Redkale-Logging-" + getClass().getSimpleName().replace("Logging", "") + "-Thread";
new Thread() {
{
setName(name);
@@ -165,7 +139,7 @@ public class LoggingFileHandler extends Handler {
while (true) {
try {
LogRecord log = logqueue.take();
final boolean bigger = (limit > 0 && limit <= loglength.get());
final boolean bigger = (limit > 0 && limit <= logLength.get());
final boolean changeday = tomorrow <= log.getMillis();
if (bigger || changeday) {
updateTomorrow();
@@ -174,42 +148,48 @@ public class LoggingFileHandler extends Handler {
if (bigger) {
for (int i = Math.min(count - 2, logindex.get() - 1); i > 0; i--) {
File greater = new File(logfile.getPath() + "." + i);
if (greater.exists()) Files.move(greater.toPath(), new File(logfile.getPath() + "." + (i + 1)).toPath(), REPLACE_EXISTING, ATOMIC_MOVE);
if (greater.exists()) {
Files.move(greater.toPath(), new File(logfile.getPath() + "." + (i + 1)).toPath(), REPLACE_EXISTING, ATOMIC_MOVE);
}
}
Files.move(logfile.toPath(), new File(logfile.getPath() + ".1").toPath(), REPLACE_EXISTING, ATOMIC_MOVE);
} else {
if (logfile.exists() && logfile.length() < 1) logfile.delete();
if (logfile.exists() && logfile.length() < 1) {
logfile.delete();
}
}
logstream = null;
}
}
if (unusual != null && changeday && logunusualstream != null) {
logunusualstream.close();
if (limit > 0 && limit <= logunusuallength.get()) {
if (limit > 0 && limit <= logUnusualLength.get()) {
for (int i = Math.min(count - 2, logunusualindex.get() - 1); i > 0; i--) {
File greater = new File(logunusualfile.getPath() + "." + i);
if (greater.exists()) Files.move(greater.toPath(), new File(logunusualfile.getPath() + "." + (i + 1)).toPath(), REPLACE_EXISTING, ATOMIC_MOVE);
if (greater.exists()) {
Files.move(greater.toPath(), new File(logunusualfile.getPath() + "." + (i + 1)).toPath(), REPLACE_EXISTING, ATOMIC_MOVE);
}
}
Files.move(logunusualfile.toPath(), new File(logunusualfile.getPath() + ".1").toPath(), REPLACE_EXISTING, ATOMIC_MOVE);
} else {
if (logunusualfile.exists() && logunusualfile.length() < 1) logunusualfile.delete();
if (logunusualfile.exists() && logunusualfile.length() < 1) {
logunusualfile.delete();
}
}
logunusualstream = null;
}
if (logstream == null) {
logindex.incrementAndGet();
java.time.LocalDate date = LocalDate.now();
logfile = new File(pattern.replace("%m", String.valueOf((date.getYear() * 100 + date.getMonthValue()))).replace("%d", String.valueOf((date.getYear() * 10000 + date.getMonthValue() * 100 + date.getDayOfMonth()))));
logfile = new File(patternDateFormat == null ? pattern : Utility.formatTime(patternDateFormat, -1, System.currentTimeMillis()));
logfile.getParentFile().mkdirs();
loglength.set(logfile.length());
logLength.set(logfile.length());
logstream = new FileOutputStream(logfile, append);
}
if (unusual != null && logunusualstream == null) {
logunusualindex.incrementAndGet();
java.time.LocalDate date = LocalDate.now();
logunusualfile = new File(unusual.replace("%m", String.valueOf((date.getYear() * 100 + date.getMonthValue()))).replace("%d", String.valueOf((date.getYear() * 10000 + date.getMonthValue() * 100 + date.getDayOfMonth()))));
logunusualfile = new File(unusualDateFormat == null ? unusual : Utility.formatTime(unusualDateFormat, -1, System.currentTimeMillis()));
logunusualfile.getParentFile().mkdirs();
logunusuallength.set(logunusualfile.length());
logUnusualLength.set(logunusualfile.length());
logunusualstream = new FileOutputStream(logunusualfile, append);
}
//----------------------写日志-------------------------
@@ -217,14 +197,16 @@ public class LoggingFileHandler extends Handler {
String encoding = getEncoding();
byte[] bytes = encoding == null ? message.getBytes() : message.getBytes(encoding);
logstream.write(bytes);
loglength.addAndGet(bytes.length);
logLength.addAndGet(bytes.length);
if (unusual != null && (log.getLevel() == Level.WARNING || log.getLevel() == Level.SEVERE)) {
logunusualstream.write(bytes);
logunusuallength.addAndGet(bytes.length);
logUnusualLength.addAndGet(bytes.length);
}
} catch (Exception e) {
ErrorManager err = getErrorManager();
if (err != null) err.error(null, e, ErrorManager.WRITE_FAILURE);
if (err != null) {
err.error(null, e, ErrorManager.WRITE_FAILURE);
}
}
}
@@ -241,7 +223,7 @@ public class LoggingFileHandler extends Handler {
String cname = LoggingFileHandler.class.getName();
this.pattern = manager.getProperty(cname + ".pattern");
if (this.pattern == null) {
this.pattern = "logs-%m/" + getPrefix() + "log-%d.log";
this.pattern = "logs-%tm/" + getPrefix() + "log-%td.log";
} else {
int pos = this.pattern.lastIndexOf('/');
if (pos > 0) {
@@ -250,6 +232,10 @@ public class LoggingFileHandler extends Handler {
this.pattern = getPrefix() + this.pattern;
}
}
if (this.pattern != null && this.pattern.contains("%")) { //需要时间格式化
this.patternDateFormat = this.pattern;
Utility.formatTime(this.patternDateFormat, -1, System.currentTimeMillis()); //测试时间格式是否正确
}
String unusualstr = manager.getProperty(cname + ".unusual");
if (unusualstr != null) {
int pos = unusualstr.lastIndexOf('/');
@@ -259,6 +245,10 @@ public class LoggingFileHandler extends Handler {
this.unusual = getPrefix() + unusualstr;
}
}
if (this.unusual != null && this.unusual.contains("%")) { //需要时间格式化
this.unusualDateFormat = this.unusual;
Utility.formatTime(this.unusualDateFormat, -1, System.currentTimeMillis()); //测试时间格式是否正确
}
String limitstr = manager.getProperty(cname + ".limit");
try {
if (limitstr != null) {
@@ -280,12 +270,16 @@ public class LoggingFileHandler extends Handler {
}
String countstr = manager.getProperty(cname + ".count");
try {
if (countstr != null) this.count = Math.max(1, Math.abs(Integer.decode(countstr)));
if (countstr != null) {
this.count = Math.max(1, Math.abs(Integer.decode(countstr)));
}
} catch (Exception e) {
}
String appendstr = manager.getProperty(cname + ".append");
try {
if (appendstr != null) this.append = "true".equalsIgnoreCase(appendstr) || "1".equals(appendstr);
if (appendstr != null) {
this.append = "true".equalsIgnoreCase(appendstr) || "1".equals(appendstr);
}
} catch (Exception e) {
}
String levelstr = manager.getProperty(cname + ".level");
@@ -314,18 +308,22 @@ public class LoggingFileHandler extends Handler {
}
} catch (Exception e) {
}
if (getFormatter() == null) setFormatter(new SimpleFormatter());
if (getFormatter() == null) {
setFormatter(new SimpleFormatter());
}
String encodingstr = manager.getProperty(cname + ".encoding");
try {
if (encodingstr != null) setEncoding(encodingstr);
if (encodingstr != null) {
setEncoding(encodingstr);
}
} catch (Exception e) {
}
String denyregstr = manager.getProperty(cname + ".denyreg");
String denyregxstr = manager.getProperty(cname + ".denyregx");
try {
if (denyregstr != null && !denyregstr.trim().isEmpty()) {
denyreg = Pattern.compile(denyregstr);
if (denyregxstr != null && !denyregxstr.trim().isEmpty()) {
denyregx = Pattern.compile(denyregxstr);
}
} catch (Exception e) {
}
@@ -333,39 +331,41 @@ public class LoggingFileHandler extends Handler {
@Override
public void publish(LogRecord log) {
final String sourceClassName = log.getSourceClassName();
if (sourceClassName == null || true) {
StackTraceElement[] ses = new Throwable().getStackTrace();
for (int i = 2; i < ses.length; i++) {
if (ses[i].getClassName().startsWith("java.util.logging")) continue;
log.setSourceClassName('[' + Thread.currentThread().getName() + "] " + ses[i].getClassName());
log.setSourceMethodName(ses[i].getMethodName());
break;
}
} else {
log.setSourceClassName('[' + Thread.currentThread().getName() + "] " + sourceClassName);
if (!isLoggable(log)) {
return;
}
if (denyreg != null && denyreg.matcher(log.getMessage()).find()) return;
if (denyregx != null && denyregx.matcher(log.getMessage()).find()) {
return;
}
fillLogRecord(log);
logqueue.offer(log);
}
@Override
public void flush() {
try {
if (logstream != null) logstream.flush();
if (logstream != null) {
logstream.flush();
}
} catch (Exception e) {
ErrorManager err = getErrorManager();
if (err != null) err.error(null, e, ErrorManager.FLUSH_FAILURE);
if (err != null) {
err.error(null, e, ErrorManager.FLUSH_FAILURE);
}
}
}
@Override
public void close() throws SecurityException {
try {
if (logstream != null) logstream.close();
if (logstream != null) {
logstream.close();
}
} catch (Exception e) {
ErrorManager err = getErrorManager();
if (err != null) err.error(null, e, ErrorManager.CLOSE_FAILURE);
if (err != null) {
err.error(null, e, ErrorManager.CLOSE_FAILURE);
}
}
}

View File

@@ -0,0 +1,345 @@
/*
*/
package org.redkale.boot;
import java.io.*;
import java.util.*;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Formatter;
import java.util.logging.*;
import java.util.regex.Pattern;
import static org.redkale.boot.Application.RESNAME_APP_NAME;
import org.redkale.convert.*;
import org.redkale.convert.json.JsonConvert;
import org.redkale.persistence.SearchColumn;
import org.redkale.persistence.*;
import org.redkale.source.*;
import org.redkale.util.*;
/**
* 基于SearchSource的日志输出类
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
* @since 2.7.0
*/
public class LoggingSearchHandler extends LoggingBaseHandler {
protected static final String DEFAULT_TABLE_NAME = "log-record";
protected final LinkedBlockingQueue<SearchLogRecord> logqueue = new LinkedBlockingQueue();
protected final AtomicInteger retryCount = new AtomicInteger(3);
protected String tag = DEFAULT_TABLE_NAME; //用于表前缀, 默认是
protected String tagDateFormat; //需要时间格式化
protected String pattern;
protected Pattern denyRegx;
protected String sourceResourceName;
protected SearchSource source;
//在LogManager.getLogManager().readConfiguration执行完后通过反射注入Application
protected Application application;
public LoggingSearchHandler() {
configure();
open();
}
private void open() {
final String name = "Redkale-Logging-" + getClass().getSimpleName().replace("Logging", "") + "-Thread";
final int batchSize = 100; //批量最多100条
final List<SearchLogRecord> logList = new ArrayList<>();
final SimpleFormatter formatter = new SimpleFormatter();
final PrintStream outStream = System.out;
new Thread() {
{
setName(name);
setDaemon(true);
}
@Override
public void run() {
while (true) {
try {
SearchLogRecord log = logqueue.take();
while (source == null && retryCount.get() > 0) initSource();
//----------------------写日志-------------------------
if (source == null) { //source加载失败
outStream.print(formatter.format(log.rawLog));
} else {
logList.add(log);
int size = batchSize;
while (--size > 0) {
log = logqueue.poll();
if (log == null) {
break;
}
logList.add(log);
}
source.insert(logList);
}
} catch (Exception e) {
ErrorManager err = getErrorManager();
if (err != null) {
err.error(null, e, ErrorManager.WRITE_FAILURE);
}
} finally {
logList.clear();
}
}
}
}.start();
}
private void initSource() {
if (retryCount.get() < 1) {
return;
}
try {
Utility.sleep(3000); //如果SearchSource自身在打印日志需要停顿一点时间让SearchSource初始化完成
if (application == null) {
Utility.sleep(3000);
}
if (application == null) {
return;
}
this.source = (SearchSource) application.loadDataSource(sourceResourceName, false);
if (retryCount.get() == 1 && this.source == null) {
System.err.println("ERROR: not load logging.source(" + sourceResourceName + ")");
}
} catch (Exception t) {
ErrorManager err = getErrorManager();
if (err != null) {
err.error(null, t, ErrorManager.WRITE_FAILURE);
}
} finally {
retryCount.decrementAndGet();
}
}
private static boolean checkTagName(String name) { //只能是字母、数字、短横、点、%、$和下划线
if (name.isEmpty()) {
return false;
}
for (char ch : name.toCharArray()) {
if (ch >= '0' && ch <= '9') {
continue;
}
if (ch >= 'a' && ch <= 'z') {
continue;
}
if (ch >= 'A' && ch <= 'Z') {
continue;
}
if (ch == '_' || ch == '-' || ch == '%' || ch == '$' || ch == '.') {
continue;
}
return false;
}
return true;
}
private void configure() {
LogManager manager = LogManager.getLogManager();
String cname = getClass().getName();
this.sourceResourceName = manager.getProperty(cname + ".source");
if (this.sourceResourceName == null || this.sourceResourceName.isEmpty()) {
throw new RedkaleException("not found logging.property " + cname + ".source");
}
String tagstr = manager.getProperty(cname + ".tag");
if (tagstr != null && !tagstr.isEmpty()) {
if (!checkTagName(tagstr.replaceAll("\\$\\{.+\\}", ""))) {
throw new RedkaleException("found illegal logging.property " + cname + ".tag = " + tagstr);
}
this.tag = tagstr.replace("${" + RESNAME_APP_NAME + "}", System.getProperty(RESNAME_APP_NAME, ""));
if (this.tag.contains("%")) {
this.tagDateFormat = this.tag;
Utility.formatTime(this.tagDateFormat, -1, System.currentTimeMillis()); //测试时间格式是否正确
}
}
String levelstr = manager.getProperty(cname + ".level");
try {
if (levelstr != null) {
Level l = Level.parse(levelstr);
setLevel(l != null ? l : Level.ALL);
}
} catch (Exception e) {
}
String filterstr = manager.getProperty(cname + ".filter");
try {
if (filterstr != null) {
Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(filterstr);
RedkaleClassLoader.putReflectionDeclaredConstructors(clz, clz.getName());
setFilter((Filter) clz.getDeclaredConstructor().newInstance());
}
} catch (Exception e) {
}
String formatterstr = manager.getProperty(cname + ".formatter");
try {
if (formatterstr != null) {
Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(formatterstr);
RedkaleClassLoader.putReflectionDeclaredConstructors(clz, clz.getName());
setFormatter((Formatter) clz.getDeclaredConstructor().newInstance());
}
} catch (Exception e) {
}
if (getFormatter() == null) {
setFormatter(new SimpleFormatter());
}
String encodingstr = manager.getProperty(cname + ".encoding");
try {
if (encodingstr != null) {
setEncoding(encodingstr);
}
} catch (Exception e) {
}
String denyregxstr = manager.getProperty(cname + ".denyregx");
try {
if (denyregxstr != null && !denyregxstr.trim().isEmpty()) {
denyRegx = Pattern.compile(denyregxstr);
}
} catch (Exception e) {
}
}
@Override
public void publish(LogRecord log) {
if (!isLoggable(log)) {
return;
}
if (denyRegx != null && denyRegx.matcher(log.getMessage()).find()) {
return;
}
if (log.getSourceClassName() != null) {
StackTraceElement[] ses = new Throwable().getStackTrace();
for (int i = 2; i < ses.length; i++) {
if (ses[i].getClassName().startsWith("java.util.logging")) {
continue;
}
log.setSourceClassName(ses[i].getClassName());
log.setSourceMethodName(ses[i].getMethodName());
break;
}
}
String rawTag = tagDateFormat == null ? tag : Utility.formatTime(tagDateFormat, -1, log.getInstant().toEpochMilli());
fillLogRecord(log);
logqueue.offer(new SearchLogRecord(rawTag, log));
}
@Override
public void flush() {
}
@Override
public void close() throws SecurityException {
}
@Entity
@Table(name = DEFAULT_TABLE_NAME)
@DistributeTable(strategy = SearchLogRecord.TableStrategy.class)
public static class SearchLogRecord {
@Id
@ConvertColumn(index = 1)
@SearchColumn(options = "false")
public String logid;
@ConvertColumn(index = 2)
@SearchColumn(options = "false")
public String level;
@ConvertColumn(index = 3)
@SearchColumn(date = true)
public long timestamp;
@ConvertColumn(index = 4)
@SearchColumn(options = "false")
public String traceid;
@ConvertColumn(index = 5)
public String threadName;
@ConvertColumn(index = 6)
@SearchColumn(text = true, options = "offsets")
public String loggerName;
@ConvertColumn(index = 7)
@SearchColumn(text = true, options = "offsets")
public String methodName;
@ConvertColumn(index = 8)
@SearchColumn(text = true, options = "offsets") //, analyzer = "ik_max_word"
public String message; //log.message +"\r\n"+ log.thrown
@Transient
@ConvertDisabled
LogRecord rawLog;
@Transient
@ConvertDisabled
String rawTag;
public SearchLogRecord() {
}
protected SearchLogRecord(String tag, LogRecord log) {
this.rawLog = log;
this.rawTag = tag;
this.threadName = Thread.currentThread().getName();
this.traceid = LoggingBaseHandler.traceFlag ? Traces.currTraceid() : null;
String msg = log.getMessage();
if (log.getThrown() != null) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
pw.println();
log.getThrown().printStackTrace(pw);
pw.close();
String throwable = sw.toString();
this.message = (msg != null && !msg.isEmpty()) ? (msg + "\r\n" + throwable) : throwable;
} else {
this.message = msg;
}
this.level = log.getLevel().toString();
this.loggerName = log.getLoggerName();
this.methodName = log.getSourceClassName() + " " + log.getSourceMethodName();
this.timestamp = log.getInstant().toEpochMilli();
this.logid = Utility.format36time(timestamp) + "_" + Utility.uuid();
}
@Override
public String toString() {
return JsonConvert.root().convertTo(this);
}
public static class TableStrategy implements DistributeTableStrategy<SearchLogRecord> {
@Override
public String getTable(String table, SearchLogRecord bean) {
return bean.rawTag;
}
@Override
public String getTable(String table, Serializable primary) {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public String[] getTables(String table, FilterNode node) {
throw new UnsupportedOperationException("Not supported yet.");
}
}
}
}

View File

@@ -9,18 +9,19 @@ import java.lang.annotation.Annotation;
import java.lang.reflect.*;
import java.net.*;
import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.*;
import java.util.concurrent.locks.ReentrantLock;
import java.util.logging.Level;
import java.util.stream.Stream;
import javax.annotation.*;
import static org.redkale.boot.Application.RESNAME_SNCP_ADDR;
import org.redkale.annotation.*;
import static org.redkale.boot.Application.RESNAME_SNCP_ADDRESS;
import org.redkale.boot.ClassFilter.FilterEntry;
import org.redkale.cluster.ClusterAgent;
import org.redkale.mq.MessageAgent;
import org.redkale.net.*;
import org.redkale.net.http.*;
import org.redkale.net.sncp.Sncp;
import org.redkale.service.*;
import org.redkale.service.Service;
import org.redkale.util.AnyValue.DefaultAnyValue;
import org.redkale.util.*;
import org.redkale.watch.*;
@@ -40,10 +41,13 @@ public class NodeHttpServer extends NodeServer {
protected final HttpServer httpServer;
protected ClassFilter<? extends WebSocket> webSocketFilter;
public NodeHttpServer(Application application, AnyValue serconf) {
super(application, createServer(application, serconf));
this.httpServer = (HttpServer) server;
this.rest = serconf == null ? false : serconf.getAnyValue("rest") != null;
}
private static Server createServer(Application application, AnyValue serconf) {
@@ -78,102 +82,148 @@ public class NodeHttpServer extends NodeServer {
}
@Override
protected ClassFilter createOtherClassFilter() {
return createClassFilter(null, RestWebSocket.class, WebSocket.class, null, null, "rest", "websocket");
protected List<ClassFilter> createOtherClassFilters() {
this.webSocketFilter = createClassFilter(null, RestWebSocket.class, WebSocket.class, null, null, "rest", "websocket");
List<ClassFilter> filters = super.createOtherClassFilters();
if (filters == null) {
filters = new ArrayList<>();
}
filters.add(webSocketFilter);
return filters;
}
@Override
protected void loadService(ClassFilter<? extends Service> serviceFilter, ClassFilter otherFilter) throws Exception {
super.loadService(serviceFilter, otherFilter);
protected void loadOthers(List<ClassFilter> otherFilters) throws Exception {
List<ClassFilter> filters = otherFilters;
if (filters != null) {
filters.remove(this.webSocketFilter); //webSocketFilter会在loadHttpFilter中处理先剔除
}
super.loadOthers(filters);
}
@Override
protected void loadService(ClassFilter<? extends Service> serviceFilter) throws Exception {
super.loadService(serviceFilter);
initWebSocketService();
}
@Override
protected void loadFilter(ClassFilter<? extends Filter> filterFilter, ClassFilter otherFilter) throws Exception {
if (httpServer != null) loadHttpFilter(this.serverConf.getAnyValue("filters"), filterFilter);
protected void loadFilter(ClassFilter<? extends Filter> filterFilter) throws Exception {
if (httpServer != null) {
loadHttpFilter(filterFilter);
}
}
@Override
@SuppressWarnings("unchecked")
protected void loadServlet(ClassFilter<? extends Servlet> servletFilter, ClassFilter otherFilter) throws Exception {
if (httpServer != null) loadHttpServlet(servletFilter, otherFilter);
protected void loadServlet(ClassFilter<? extends Servlet> servletFilter) throws Exception {
if (httpServer != null) {
loadHttpServlet(servletFilter);
}
}
private void initWebSocketService() {
final NodeServer self = this;
final ResourceFactory regFactory = application.getResourceFactory();
resourceFactory.register((ResourceFactory rf, final Object src, final String resourceName, Field field, Object attachment) -> { //主要用于单点的服务
resourceFactory.register((ResourceFactory rf, String srcResourceName, final Object srcObj, final String resourceName, Field field, Object attachment) -> { //主要用于单点的服务
try {
if (field.getAnnotation(Resource.class) == null) return;
if (!(src instanceof WebSocketServlet)) return;
ResourceFactory.ResourceLoader loader = null;
if (field.getAnnotation(Resource.class) == null && field.getAnnotation(javax.annotation.Resource.class) == null) {
return null;
}
if (!(srcObj instanceof WebSocketServlet)) {
return null;
}
ResourceTypeLoader loader = null;
ResourceFactory sncpResFactory = null;
for (NodeServer ns : application.servers) {
if (!ns.isSNCP()) continue;
if (!ns.isSNCP()) {
continue;
}
sncpResFactory = ns.resourceFactory;
loader = sncpResFactory.findLoader(WebSocketNode.class, field);
if (loader != null) break;
loader = sncpResFactory.findTypeLoader(WebSocketNode.class, field);
if (loader != null) {
break;
}
}
if (loader != null) loader.load(sncpResFactory, src, resourceName, field, attachment);
synchronized (regFactory) {
Service nodeService = (Service) rf.find(resourceName, WebSocketNode.class);
if (sncpResFactory != null && resourceFactory.find(RESNAME_SNCP_ADDR, String.class) == null) {
resourceFactory.register(RESNAME_SNCP_ADDR, InetSocketAddress.class, sncpResFactory.find(RESNAME_SNCP_ADDR, InetSocketAddress.class));
resourceFactory.register(RESNAME_SNCP_ADDR, SocketAddress.class, sncpResFactory.find(RESNAME_SNCP_ADDR, SocketAddress.class));
resourceFactory.register(RESNAME_SNCP_ADDR, String.class, sncpResFactory.find(RESNAME_SNCP_ADDR, String.class));
Service nodeService = null;
if (loader != null) {
nodeService = (Service) loader.load(sncpResFactory, srcResourceName, srcObj, resourceName, field, attachment);
}
regFactory.lock();
try {
if (nodeService == null) {
nodeService = (Service) rf.find(resourceName, WebSocketNode.class);
}
if (sncpResFactory != null && resourceFactory.find(RESNAME_SNCP_ADDRESS, String.class) == null) {
resourceFactory.register(RESNAME_SNCP_ADDRESS, InetSocketAddress.class, sncpResFactory.find(RESNAME_SNCP_ADDRESS, InetSocketAddress.class));
resourceFactory.register(RESNAME_SNCP_ADDRESS, SocketAddress.class, sncpResFactory.find(RESNAME_SNCP_ADDRESS, SocketAddress.class));
resourceFactory.register(RESNAME_SNCP_ADDRESS, String.class, sncpResFactory.find(RESNAME_SNCP_ADDRESS, String.class));
}
if (nodeService == null) {
MessageAgent messageAgent = null;
try {
Field c = WebSocketServlet.class.getDeclaredField("messageAgent");
RedkaleClassLoader.putReflectionField("messageAgent", c);
c.setAccessible(true);
messageAgent = (MessageAgent) c.get(src);
messageAgent = (MessageAgent) c.get(srcObj);
} catch (Exception ex) {
logger.log(Level.WARNING, "WebSocketServlet getMessageAgent error", ex);
}
nodeService = Sncp.createLocalService(serverClassLoader, resourceName, org.redkale.net.http.WebSocketNodeService.class, messageAgent, application.getResourceFactory(), application.getSncpTransportFactory(), (InetSocketAddress) null, (Set<String>) null, (AnyValue) null);
nodeService = Sncp.createLocalService(serverClassLoader, resourceName, org.redkale.net.http.WebSocketNodeService.class, application.getResourceFactory(), application.getSncpRpcGroups(), sncpClient, messageAgent, (String) null, (AnyValue) null);
regFactory.register(resourceName, WebSocketNode.class, nodeService);
}
resourceFactory.inject(nodeService, self);
field.set(src, nodeService);
logger.fine("[" + Thread.currentThread().getName() + "] Load Service " + nodeService);
resourceFactory.inject(resourceName, nodeService, self);
field.set(srcObj, nodeService);
logger.fine("Load Service " + nodeService);
return nodeService;
} finally {
regFactory.unlock();
}
} catch (Exception e) {
logger.log(Level.SEVERE, "WebSocketNode inject error", e);
return null;
}
}, WebSocketNode.class);
}
@SuppressWarnings("unchecked")
protected void loadHttpFilter(final AnyValue filtersConf, final ClassFilter<? extends Filter> classFilter) throws Exception {
protected void loadHttpFilter(final ClassFilter<? extends Filter> classFilter) throws Exception {
final StringBuilder sb = logger.isLoggable(Level.INFO) ? new StringBuilder() : null;
final String localThreadName = "[" + Thread.currentThread().getName() + "] ";
List<FilterEntry<? extends Filter>> list = new ArrayList(classFilter.getFilterEntrys());
for (FilterEntry<? extends Filter> en : list) {
Class<HttpFilter> clazz = (Class<HttpFilter>) en.getType();
if (Modifier.isAbstract(clazz.getModifiers())) continue;
if (Modifier.isAbstract(clazz.getModifiers())) {
continue;
}
RedkaleClassLoader.putReflectionDeclaredConstructors(clazz, clazz.getName());
final HttpFilter filter = clazz.getDeclaredConstructor().newInstance();
resourceFactory.inject(filter, this);
DefaultAnyValue filterConf = (DefaultAnyValue) en.getProperty();
this.httpServer.addHttpFilter(filter, filterConf);
if (sb != null) sb.append(localThreadName).append(" Load ").append(clazz.getName()).append(LINE_SEPARATOR);
if (sb != null) {
sb.append("Load ").append(clazz.getName()).append(LINE_SEPARATOR);
}
}
if (sb != null && sb.length() > 0) {
logger.log(Level.INFO, sb.toString());
}
if (sb != null && sb.length() > 0) logger.log(Level.INFO, sb.toString());
}
@SuppressWarnings("unchecked")
protected void loadHttpServlet(final ClassFilter<? extends Servlet> servletFilter, ClassFilter<? extends WebSocket> webSocketFilter) throws Exception {
protected void loadHttpServlet(final ClassFilter<? extends Servlet> servletFilter) throws Exception {
RedkaleClassLoader.putReflectionPublicClasses(HttpServlet.class.getName());
RedkaleClassLoader.putReflectionPublicClasses(HttpPrepareServlet.class.getName());
RedkaleClassLoader.putReflectionPublicClasses(HttpDispatcherServlet.class.getName());
RedkaleClassLoader.putReflectionDeclaredConstructors(HttpResourceServlet.class, HttpResourceServlet.class.getName());
final AnyValue servletsConf = this.serverConf.getAnyValue("servlets");
final StringBuilder sb = logger.isLoggable(Level.INFO) ? new StringBuilder() : null;
String prefix0 = servletsConf == null ? "" : servletsConf.getValue("path", "");
if (!prefix0.isEmpty() && prefix0.charAt(prefix0.length() - 1) == '/') prefix0 = prefix0.substring(0, prefix0.length() - 1);
if (!prefix0.isEmpty() && prefix0.charAt(0) != '/') prefix0 = '/' + prefix0;
if (!prefix0.isEmpty() && prefix0.charAt(prefix0.length() - 1) == '/') {
prefix0 = prefix0.substring(0, prefix0.length() - 1);
}
if (!prefix0.isEmpty() && prefix0.charAt(0) != '/') {
prefix0 = '/' + prefix0;
}
final String prefix = prefix0;
final String localThreadName = "[" + Thread.currentThread().getName() + "] ";
List<FilterEntry<? extends Servlet>> list = new ArrayList(servletFilter.getFilterEntrys());
list.sort((FilterEntry<? extends Servlet> o1, FilterEntry<? extends Servlet> o2) -> { //必须保证WebSocketServlet优先加载 因为要确保其他的HttpServlet可以注入本地模式的WebSocketNode
boolean ws1 = WebSocketServlet.class.isAssignableFrom(o1.getType());
@@ -190,12 +240,18 @@ public class NodeHttpServer extends NodeServer {
final List<AbstractMap.SimpleEntry<String, String[]>> ss = sb == null ? null : new ArrayList<>();
for (FilterEntry<? extends Servlet> en : list) {
Class<HttpServlet> clazz = (Class<HttpServlet>) en.getType();
if (Modifier.isAbstract(clazz.getModifiers())) continue;
if (clazz.getAnnotation(Rest.RestDyn.class) != null) continue; //动态生成的跳过
if (Modifier.isAbstract(clazz.getModifiers())) {
continue;
}
if (clazz.getAnnotation(Rest.RestDyn.class) != null) {
continue; //动态生成的跳过
}
WebServlet ws = clazz.getAnnotation(WebServlet.class);
if (ws == null) continue;
if (ws == null) {
continue;
}
if (ws.value().length == 0) {
logger.log(Level.INFO, "not found @WebServlet.value in " + clazz.getName());
logger.log(Level.INFO, "Not found @WebServlet.value in " + clazz.getName());
continue;
}
RedkaleClassLoader.putReflectionDeclaredConstructors(clazz, clazz.getName());
@@ -209,16 +265,18 @@ public class NodeHttpServer extends NodeServer {
for (int i = 0; i < mappings.length; i++) {
mappings[i] = pref + mappings[i];
}
ss.add(new AbstractMap.SimpleEntry<>("HttpServlet (type=" + clazz.getName() + ")", mappings));
ss.add(new AbstractMap.SimpleEntry<>("HttpServlet (type=" + clazz.getName() + ")", mappings));
}
}
final List<AbstractMap.SimpleEntry<String, String[]>> rests = sb == null ? null : new ArrayList<>();
final List<AbstractMap.SimpleEntry<String, String[]>> webss = sb == null ? null : new ArrayList<>();
final CopyOnWriteArrayList<AbstractMap.SimpleEntry<String, String[]>> rests = sb == null ? null : new CopyOnWriteArrayList<>();
final CopyOnWriteArrayList<AbstractMap.SimpleEntry<String, String[]>> webss = sb == null ? null : new CopyOnWriteArrayList<>();
if (rest && serverConf != null) {
final List<Object> restedObjects = new ArrayList<>();
final ReentrantLock restedLock = new ReentrantLock();
for (AnyValue restConf : serverConf.getAnyValues("rest")) {
loadRestServlet(webSocketFilter, restConf, restedObjects, sb, rests, webss);
loadRestServlet(webSocketFilter, restConf, restedObjects, restedLock, sb, rests, webss);
}
this.webSocketFilter = null;
}
int max = 0;
if (ss != null && sb != null) {
@@ -226,87 +284,114 @@ public class NodeHttpServer extends NodeServer {
int maxNameLength = 0;
if (rests != null) {
for (AbstractMap.SimpleEntry<String, String[]> en : rests) {
int pos = en.getKey().indexOf('#');
if (pos > maxTypeLength) maxTypeLength = pos;
int pos = en.getKey().indexOf(':');
if (pos > maxTypeLength) {
maxTypeLength = pos;
}
int len = en.getKey().length() - pos - 1;
if (len > maxNameLength) maxNameLength = len;
if (len > maxNameLength) {
maxNameLength = len;
}
}
}
if (webss != null) {
for (AbstractMap.SimpleEntry<String, String[]> en : webss) {
int pos = en.getKey().indexOf('#');
if (pos > maxTypeLength) maxTypeLength = pos;
int pos = en.getKey().indexOf(':');
if (pos > maxTypeLength) {
maxTypeLength = pos;
}
int len = en.getKey().length() - pos - 1;
if (len > maxNameLength) maxNameLength = len;
if (len > maxNameLength) {
maxNameLength = len;
}
}
}
if (rests != null) {
for (AbstractMap.SimpleEntry<String, String[]> en : rests) {
StringBuilder sub = new StringBuilder();
int pos = en.getKey().indexOf('#');
sub.append("RestDynServlet (type=").append(en.getKey().substring(0, pos));
int pos = en.getKey().indexOf(':');
sub.append("RestServlet (type=").append(en.getKey().substring(0, pos));
for (int i = 0; i < maxTypeLength - pos; i++) {
sub.append(' ');
}
sub.append(", name='").append(en.getKey().substring(pos + 1));
for (int i = 0; i < maxNameLength - pos; i++) {
String n = en.getKey().substring(pos + 1);
sub.append(", name='").append(n).append("'");
for (int i = 0; i < maxNameLength - n.length(); i++) {
sub.append(' ');
}
sub.append("')");
sub.append(")");
ss.add(new AbstractMap.SimpleEntry<>(sub.toString(), en.getValue()));
}
}
if (webss != null) {
for (AbstractMap.SimpleEntry<String, String[]> en : webss) {
StringBuilder sub = new StringBuilder();
int pos = en.getKey().indexOf('#');
int pos = en.getKey().indexOf(':');
sub.append("RestWebSocket (type=").append(en.getKey().substring(0, pos));
for (int i = 0; i < maxTypeLength - pos; i++) {
sub.append(' ');
}
sub.append(", name='").append(en.getKey().substring(pos + 1));
for (int i = 0; i < maxNameLength - pos; i++) {
String n = en.getKey().substring(pos + 1);
sub.append(", name='").append(n).append("'");
for (int i = 0; i < maxNameLength - n.length(); i++) {
sub.append(' ');
}
sub.append("')");
sub.append(")");
ss.add(new AbstractMap.SimpleEntry<>(sub.toString(), en.getValue()));
}
}
ss.sort((AbstractMap.SimpleEntry<String, String[]> o1, AbstractMap.SimpleEntry<String, String[]> o2) -> o1.getKey().compareTo(o2.getKey()));
for (AbstractMap.SimpleEntry<String, String[]> as : ss) {
if (as.getKey().length() > max) max = as.getKey().length();
if (as.getKey().length() > max) {
max = as.getKey().length();
}
}
for (AbstractMap.SimpleEntry<String, String[]> as : ss) {
sb.append(localThreadName).append("Load ").append(as.getKey());
sb.append("Load ").append(as.getKey());
for (int i = 0; i < max - as.getKey().length(); i++) {
sb.append(' ');
}
sb.append(" mapping to ").append(Arrays.toString(as.getValue())).append(LINE_SEPARATOR);
}
sb.append(localThreadName).append("All HttpServlets load cost ").append(System.currentTimeMillis() - starts).append(" ms").append(LINE_SEPARATOR);
sb.append("All HttpServlets load in ").append(System.currentTimeMillis() - starts).append(" ms").append(LINE_SEPARATOR);
}
if (sb != null && sb.length() > 0) {
logger.log(Level.INFO, sb.toString().trim());
}
if (sb != null && sb.length() > 0) logger.log(Level.INFO, sb.toString().trim());
}
@SuppressWarnings("unchecked")
protected void loadRestServlet(final ClassFilter<? extends WebSocket> webSocketFilter, final AnyValue restConf, final List<Object> restedObjects, final StringBuilder sb,
final List<AbstractMap.SimpleEntry<String, String[]>> rests, final List<AbstractMap.SimpleEntry<String, String[]>> webss) throws Exception {
if (!rest) return;
if (restConf == null) return; //不存在REST服务
protected void loadRestServlet(final ClassFilter<? extends WebSocket> webSocketFilter,
final AnyValue restConf, final List<Object> restedObjects,
final ReentrantLock restedLock, final StringBuilder sb,
final CopyOnWriteArrayList<AbstractMap.SimpleEntry<String, String[]>> rests,
final CopyOnWriteArrayList<AbstractMap.SimpleEntry<String, String[]>> webss) throws Exception {
if (!rest) {
return;
}
if (restConf == null) {
return; //不存在REST服务
}
String prefix0 = restConf.getValue("path", "");
if (!prefix0.isEmpty() && prefix0.charAt(prefix0.length() - 1) == '/') prefix0 = prefix0.substring(0, prefix0.length() - 1);
if (!prefix0.isEmpty() && prefix0.charAt(0) != '/') prefix0 = '/' + prefix0;
if (!prefix0.isEmpty() && prefix0.charAt(prefix0.length() - 1) == '/') {
prefix0 = prefix0.substring(0, prefix0.length() - 1);
}
if (!prefix0.isEmpty() && prefix0.charAt(0) != '/') {
prefix0 = '/' + prefix0;
}
final String localThreadName = "[" + Thread.currentThread().getName() + "] ";
String mqname = restConf.getValue("mq");
MessageAgent agent0 = null;
if (mqname != null) {
agent0 = application.getMessageAgent(mqname);
if (agent0 == null) throw new RuntimeException("not found " + MessageAgent.class.getSimpleName() + " config for (name=" + mqname + ")");
if (agent0 == null) {
throw new RedkaleException("not found " + MessageAgent.class.getSimpleName() + " config for (name=" + mqname + ")");
}
}
final MessageAgent messageAgent = agent0;
if (messageAgent != null) prefix0 = ""; //开启MQ时,prefix字段失效
if (messageAgent != null) {
prefix0 = ""; //开启MQ时,prefix字段失效
}
final String prefix = prefix0;
final boolean autoload = restConf.getBoolValue("autoload", true);
{ //加载RestService
@@ -325,43 +410,58 @@ public class NodeHttpServer extends NodeServer {
}
final ClassFilter restFilter = ClassFilter.create(serverClassLoader, null, application.isCompileMode() ? "" : restConf.getValue("includes", ""), application.isCompileMode() ? "" : restConf.getValue("excludes", ""), includeValues, excludeValues);
final CountDownLatch scdl = new CountDownLatch(super.interceptorServices.size());
Stream<Service> stream = super.interceptorServices.stream();
if (!application.isCompileMode()) stream = stream.parallel(); //不能并行否则在maven plugin运行环境下ClassLoader不对
final CountDownLatch scdl = new CountDownLatch(super.servletServices.size());
Stream<Service> stream = super.servletServices.stream();
if (!application.isCompileMode()) {
stream = stream.parallel(); //不能并行否则在maven plugin运行环境下ClassLoader不对
}
stream.forEach((service) -> {
try {
final Class stype = Sncp.getServiceType(service);
final Class stype = Sncp.getResourceType(service);
final String name = Sncp.getResourceName(service);
RestService rs = (RestService) stype.getAnnotation(RestService.class);
if (rs == null || rs.ignore()) return;
if (rs == null || rs.ignore()) {
return;
}
final String stypename = stype.getName();
if (!autoload && !includeValues.contains(stypename)) return;
if (!restFilter.accept(stypename)) return;
synchronized (restedObjects) {
if (!autoload && !includeValues.contains(stypename)) {
return;
}
if (!restFilter.accept(stypename)) {
return;
}
restedLock.lock();
try {
if (restedObjects.contains(service)) {
logger.log(Level.WARNING, stype.getName() + " repeat create rest servlet, so ignore");
return;
}
restedObjects.add(service); //避免重复创建Rest对象
} finally {
restedLock.unlock();
}
HttpServlet servlet = httpServer.addRestServlet(serverClassLoader, service, userType, baseServletType, prefix);
if (servlet == null) return; //没有HttpMapping方法的HttpServlet调用Rest.createRestServlet就会返回null
if (servlet == null) {
return; //没有HttpMapping方法的HttpServlet调用Rest.createRestServlet就会返回null
}
String prefix2 = prefix;
WebServlet ws = servlet.getClass().getAnnotation(WebServlet.class);
if (ws != null && !ws.repair()) prefix2 = "";
if (ws != null && !ws.repair()) {
prefix2 = "";
}
resourceFactory.inject(servlet, NodeHttpServer.this);
dynServletMap.put(service, servlet);
if (messageAgent != null) messageAgent.putService(this, service, servlet);
//if (finest) logger.finest(localThreadName + " Create RestServlet(resource.name='" + name + "') = " + servlet);
if (messageAgent != null) {
messageAgent.putService(this, service, servlet);
}
//if (finest) logger.finest("Create RestServlet(resource.name='" + name + "') = " + servlet);
if (rests != null) {
String[] mappings = servlet.getClass().getAnnotation(WebServlet.class).value();
for (int i = 0; i < mappings.length; i++) {
mappings[i] = prefix2 + mappings[i];
}
synchronized (rests) {
rests.add(new AbstractMap.SimpleEntry<>(Sncp.getServiceType(service).getName() + "#" + name, mappings));
}
rests.add(new AbstractMap.SimpleEntry<>(Sncp.getResourceType(service).getName() + ":" + name, mappings));
}
} finally {
scdl.countDown();
@@ -380,7 +480,6 @@ public class NodeHttpServer extends NodeServer {
}
}
final ClassFilter restFilter = ClassFilter.create(serverClassLoader, null, application.isCompileMode() ? "" : restConf.getValue("includes", ""), application.isCompileMode() ? "" : restConf.getValue("excludes", ""), includeValues, excludeValues);
final boolean finest = logger.isLoggable(Level.FINEST);
List<FilterEntry<? extends WebSocket>> list = new ArrayList(webSocketFilter.getFilterEntrys());
for (FilterEntry<? extends WebSocket> en : list) {
@@ -394,47 +493,65 @@ public class NodeHttpServer extends NodeServer {
continue;
}
final Class<? extends WebSocket> stype = en.getType();
if (stype.getAnnotation(Rest.RestDyn.class) != null) continue;
if (stype.getAnnotation(Rest.RestDyn.class) != null) {
continue;
}
RestWebSocket rs = stype.getAnnotation(RestWebSocket.class);
if (rs == null || rs.ignore()) continue;
if (rs == null || rs.ignore()) {
continue;
}
final String stypename = stype.getName();
if (!autoload && !includeValues.contains(stypename)) continue;
if (!restFilter.accept(stypename)) continue;
if (!autoload && !includeValues.contains(stypename)) {
continue;
}
if (!restFilter.accept(stypename)) {
continue;
}
if (restedObjects.contains(stype)) {
logger.log(Level.WARNING, stype.getName() + " repeat create rest websocket, so ignore");
continue;
}
restedObjects.add(stype); //避免重复创建Rest对象
WebSocketServlet servlet = httpServer.addRestWebSocketServlet(serverClassLoader, stype, messageAgent, prefix, en.getProperty());
if (servlet == null) continue; //没有RestOnMessage方法的HttpServlet调用Rest.createRestWebSocketServlet就会返回null
if (servlet == null) {
continue; //没有RestOnMessage方法的HttpServlet调用Rest.createRestWebSocketServlet就会返回null
}
String prefix2 = prefix;
WebServlet ws = servlet.getClass().getAnnotation(WebServlet.class);
if (ws != null && !ws.repair()) prefix2 = "";
if (ws != null && !ws.repair()) {
prefix2 = "";
}
resourceFactory.inject(servlet, NodeHttpServer.this);
if (finest) logger.finest(localThreadName + " " + stype.getName() + " create a RestWebSocketServlet");
if (logger.isLoggable(Level.FINEST)) {
logger.finest(stype.getName() + " create a RestWebSocketServlet");
}
if (webss != null) {
String[] mappings = servlet.getClass().getAnnotation(WebServlet.class).value();
for (int i = 0; i < mappings.length; i++) {
mappings[i] = prefix2 + mappings[i];
}
synchronized (webss) {
webss.add(new AbstractMap.SimpleEntry<>(stype.getName() + "#" + rs.name(), mappings));
}
webss.add(new AbstractMap.SimpleEntry<>(stype.getName() + ":" + rs.name(), mappings));
}
}
}
if (messageAgent != null) this.messageAgents.put(messageAgent.getName(), messageAgent);
if (messageAgent != null) {
this.messageAgents.put(messageAgent.getName(), messageAgent);
}
}
@Override //loadServlet执行之后调用
protected void postLoadServlets() {
final ClusterAgent cluster = application.clusterAgent;
final ClusterAgent cluster = application.getClusterAgent();
if (!application.isCompileMode() && cluster != null) {
NodeProtocol pros = getClass().getAnnotation(NodeProtocol.class);
String protocol = pros.value().toUpperCase();
if (!cluster.containsProtocol(protocol)) return;
if (!cluster.containsPort(server.getSocketAddress().getPort())) return;
if (!cluster.containsProtocol(protocol)) {
return;
}
if (!cluster.containsPort(server.getSocketAddress().getPort())) {
return;
}
cluster.register(this, protocol, dynServletMap.keySet(), new HashSet<>());
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -5,17 +5,16 @@
*/
package org.redkale.boot;
import java.lang.reflect.Modifier;
import java.net.*;
import java.net.InetSocketAddress;
import java.util.*;
import java.util.logging.Level;
import org.redkale.boot.ClassFilter.FilterEntry;
import org.redkale.mq.MessageAgent;
import org.redkale.net.*;
import org.redkale.net.sncp.*;
import org.redkale.service.*;
import org.redkale.util.*;
import org.redkale.service.Local;
import org.redkale.util.AnyValue.DefaultAnyValue;
import org.redkale.util.*;
/**
* SNCP Server节点的配置Server
@@ -33,12 +32,6 @@ public class NodeSncpServer extends NodeServer {
private NodeSncpServer(Application application, AnyValue serconf) {
super(application, createServer(application, serconf));
this.sncpServer = (SncpServer) this.server;
this.consumer = sncpServer == null || application.isSingletonMode() ? null : (agent, x) -> {//singleton模式下不生成SncpServlet
if (x.getClass().getAnnotation(Local.class) != null) return; //本地模式的Service不生成SncpServlet
SncpDynServlet servlet = sncpServer.addSncpServlet(x);
dynServletMap.put(x, servlet);
if (agent != null) agent.putService(this, x, servlet);
};
}
public static NodeServer createNodeServer(Application application, AnyValue serconf) {
@@ -54,23 +47,49 @@ public class NodeSncpServer extends NodeServer {
return sncpServer == null ? null : sncpServer.getSocketAddress();
}
public void consumerAccept(MessageAgent messageAgent, Service service) {
if (this.consumer != null) this.consumer.accept(messageAgent, service);
}
@Override
public void init(AnyValue config) throws Exception {
super.init(config);
//-------------------------------------------------------------------
if (sncpServer == null) return; //调试时server才可能为null
if (sncpServer == null) {
return; //调试时server才可能为null
}
final StringBuilder sb = logger.isLoggable(Level.FINE) ? new StringBuilder() : null;
final String localThreadName = "[" + Thread.currentThread().getName() + "] ";
List<SncpServlet> servlets = sncpServer.getSncpServlets();
Collections.sort(servlets);
int maxTypeLength = 0;
int maxNameLength = 0;
for (SncpServlet en : servlets) {
if (sb != null) sb.append(localThreadName).append(" Load ").append(en).append(LINE_SEPARATOR);
maxNameLength = Math.max(maxNameLength, en.getResourceName().length() + 1);
maxTypeLength = Math.max(maxTypeLength, en.getResourceType().getName().length());
}
if (sb != null && sb.length() > 0) logger.log(Level.FINE, sb.toString());
for (SncpServlet en : servlets) {
if (sb != null) {
sb.append("Load ").append(toSimpleString(en, maxTypeLength, maxNameLength)).append(LINE_SEPARATOR);
}
}
if (sb != null && sb.length() > 0) {
logger.log(Level.FINE, sb.toString());
}
}
private StringBuilder toSimpleString(SncpServlet servlet, int maxTypeLength, int maxNameLength) {
StringBuilder sb = new StringBuilder();
Class serviceType = servlet.getResourceType();
String serviceName = servlet.getResourceName();
int size = servlet.getActionSize();
sb.append(SncpServlet.class.getSimpleName()).append(" (type=").append(serviceType.getName());
int len = maxTypeLength - serviceType.getName().length();
for (int i = 0; i < len; i++) {
sb.append(' ');
}
sb.append(", serviceid=").append(servlet.getServiceid()).append(", name='").append(serviceName).append("'");
for (int i = 0; i < maxNameLength - serviceName.length(); i++) {
sb.append(' ');
}
sb.append(", actions.size=").append(size > 9 ? "" : " ").append(size).append(")");
return sb;
}
@Override
@@ -83,32 +102,51 @@ public class NodeSncpServer extends NodeServer {
}
@Override
protected void loadFilter(ClassFilter<? extends Filter> filterFilter, ClassFilter otherFilter) throws Exception {
if (sncpServer != null) loadSncpFilter(this.serverConf.getAnyValue("fliters"), filterFilter);
protected void loadFilter(ClassFilter<? extends Filter> filterFilter) throws Exception {
if (sncpServer != null) {
loadSncpFilter(this.serverConf.getAnyValue("fliters"), filterFilter);
}
}
@SuppressWarnings("unchecked")
protected void loadSncpFilter(final AnyValue servletsConf, final ClassFilter<? extends Filter> classFilter) throws Exception {
final StringBuilder sb = logger.isLoggable(Level.INFO) ? new StringBuilder() : null;
final String localThreadName = "[" + Thread.currentThread().getName() + "] ";
List<FilterEntry<? extends Filter>> list = new ArrayList(classFilter.getFilterEntrys());
for (FilterEntry<? extends Filter> en : list) {
Class<SncpFilter> clazz = (Class<SncpFilter>) en.getType();
if (Modifier.isAbstract(clazz.getModifiers())) continue;
if (Utility.isAbstractOrInterface(clazz)) {
continue;
}
RedkaleClassLoader.putReflectionDeclaredConstructors(clazz, clazz.getName());
final SncpFilter filter = clazz.getDeclaredConstructor().newInstance();
resourceFactory.inject(filter, this);
DefaultAnyValue filterConf = (DefaultAnyValue) en.getProperty();
this.sncpServer.addSncpFilter(filter, filterConf);
if (sb != null) sb.append(localThreadName).append(" Load ").append(clazz.getName()).append(LINE_SEPARATOR);
if (sb != null) {
sb.append("Load ").append(clazz.getName()).append(LINE_SEPARATOR);
}
}
if (sb != null && sb.length() > 0) {
logger.log(Level.INFO, sb.toString());
}
if (sb != null && sb.length() > 0) logger.log(Level.INFO, sb.toString());
}
@Override
protected void loadServlet(ClassFilter<? extends Servlet> servletFilter, ClassFilter otherFilter) throws Exception {
protected void loadServlet(ClassFilter<? extends Servlet> servletFilter) throws Exception {
RedkaleClassLoader.putReflectionPublicClasses(SncpServlet.class.getName());
RedkaleClassLoader.putReflectionPublicClasses(SncpDynServlet.class.getName());
if (!application.isSingletonMode()) {
this.servletServices.stream()
.filter(x -> x.getClass().getAnnotation(Local.class) == null) //Local模式的Service不生成SncpServlet
.forEach(x -> {
SncpServlet servlet = sncpServer.addSncpServlet(x);
dynServletMap.put(x, servlet);
String mq = Sncp.getResourceMQ(x);
if (mq != null) {
MessageAgent agent = application.getMessageAgent(mq);
agent.putService(this, x, servlet);
}
});
}
}
@Override

View File

@@ -6,8 +6,9 @@
package org.redkale.boot;
import java.lang.annotation.Annotation;
import java.util.List;
import org.redkale.net.*;
import org.redkale.net.http.*;
import org.redkale.net.http.WebServlet;
import org.redkale.service.Service;
import org.redkale.util.AnyValue;
import org.redkale.watch.*;
@@ -42,8 +43,8 @@ public class NodeWatchServer extends NodeHttpServer {
}
@Override
protected ClassFilter createOtherClassFilter() {
return null;
protected List<ClassFilter> createOtherClassFilters() {
return null; //不调用 super.createOtherClassFilters()
}
@Override

View File

@@ -5,14 +5,14 @@
*/
package org.redkale.boot;
import java.lang.reflect.Modifier;
import javax.persistence.Entity;
import org.redkale.annotation.Bean;
import org.redkale.boot.ClassFilter.FilterEntry;
import org.redkale.convert.Decodeable;
import org.redkale.convert.bson.BsonFactory;
import org.redkale.convert.json.*;
import org.redkale.persistence.Entity;
import org.redkale.source.*;
import org.redkale.util.*;
import org.redkale.util.Utility;
/**
* 执行一次Application.run提前获取所有动态类
@@ -26,6 +26,9 @@ public class PrepareCompiler {
// new PrepareCompiler().run();
// }
public Application run() throws Exception {
//必须设置redkale.resource.skip.check=true
//因redkale-maven-plugin的maven-core依赖jsr250会覆盖redkale的javax.annotation.Resource导致无法识别Resource.required方法
System.setProperty("redkale.resource.skip.check", "true");
final Application application = new Application(false, true, Application.loadAppConfig());
application.init();
for (ApplicationListener listener : application.listeners) {
@@ -39,39 +42,92 @@ public class PrepareCompiler {
final String[] exlibs = (application.excludelibs != null ? (application.excludelibs + ";") : "").split(";");
final ClassFilter<?> entityFilter = new ClassFilter(application.getClassLoader(), Entity.class, Object.class, (Class[]) null);
final ClassFilter<?> entityFilter2 = new ClassFilter(application.getClassLoader(), javax.persistence.Entity.class, Object.class, (Class[]) null);
final ClassFilter<?> beanFilter = new ClassFilter(application.getClassLoader(), Bean.class, Object.class, (Class[]) null);
final ClassFilter<?> beanFilter2 = new ClassFilter(application.getClassLoader(), org.redkale.util.Bean.class, Object.class, (Class[]) null);
final ClassFilter<?> filterFilter = new ClassFilter(application.getClassLoader(), null, FilterBean.class, (Class[]) null);
ClassFilter.Loader.load(application.getHome(), application.getClassLoader(), exlibs, entityFilter, beanFilter, filterFilter);
for (FilterEntry en : entityFilter.getFilterEntrys()) {
Class clz = en.getType();
if (clz.isInterface() || Modifier.isAbstract(clz.getModifiers())) continue;
if (Utility.isAbstractOrInterface(clz)) {
continue;
}
try {
application.dataSources.forEach(source -> source.compile(clz));
JsonFactory.root().loadEncoder(clz);
if (hasSncp) BsonFactory.root().loadEncoder(clz);
if (hasSncp) {
BsonFactory.root().loadEncoder(clz);
}
Decodeable decoder = JsonFactory.root().loadDecoder(clz);
if (hasSncp) BsonFactory.root().loadDecoder(clz);
if (hasSncp) {
BsonFactory.root().loadDecoder(clz);
}
decoder.convertFrom(new JsonReader("{}"));
} catch (Exception e) { //JsonFactory.loadDecoder可能会失败因为class可能包含抽象类字段,如ColumnValue.value字段
}
}
for (FilterEntry en : entityFilter2.getFilterEntrys()) {
Class clz = en.getType();
if (Utility.isAbstractOrInterface(clz)) {
continue;
}
try {
application.dataSources.forEach(source -> source.compile(clz));
JsonFactory.root().loadEncoder(clz);
if (hasSncp) {
BsonFactory.root().loadEncoder(clz);
}
Decodeable decoder = JsonFactory.root().loadDecoder(clz);
if (hasSncp) {
BsonFactory.root().loadDecoder(clz);
}
decoder.convertFrom(new JsonReader("{}"));
} catch (Exception e) { //JsonFactory.loadDecoder可能会失败因为class可能包含抽象类字段,如ColumnValue.value字段
}
}
for (FilterEntry en : beanFilter.getFilterEntrys()) {
Class clz = en.getType();
if (clz.isInterface() || Modifier.isAbstract(clz.getModifiers())) continue;
if (Utility.isAbstractOrInterface(clz)) {
continue;
}
try {
JsonFactory.root().loadEncoder(clz);
if (hasSncp) BsonFactory.root().loadEncoder(clz);
if (hasSncp) {
BsonFactory.root().loadEncoder(clz);
}
Decodeable decoder = JsonFactory.root().loadDecoder(clz);
if (hasSncp) BsonFactory.root().loadDecoder(clz);
if (hasSncp) {
BsonFactory.root().loadDecoder(clz);
}
decoder.convertFrom(new JsonReader("{}"));
} catch (Exception e) { //JsonFactory.loadDecoder可能会失败因为class可能包含抽象类字段,如ColumnValue.value字段
}
}
for (FilterEntry en : beanFilter2.getFilterEntrys()) {
Class clz = en.getType();
if (Utility.isAbstractOrInterface(clz)) {
continue;
}
try {
JsonFactory.root().loadEncoder(clz);
if (hasSncp) {
BsonFactory.root().loadEncoder(clz);
}
Decodeable decoder = JsonFactory.root().loadDecoder(clz);
if (hasSncp) {
BsonFactory.root().loadDecoder(clz);
}
decoder.convertFrom(new JsonReader("{}"));
} catch (Exception e) { //JsonFactory.loadDecoder可能会失败因为class可能包含抽象类字段,如ColumnValue.value字段
}
}
for (FilterEntry en : filterFilter.getFilterEntrys()) {
Class clz = en.getType();
if (clz.isInterface() || Modifier.isAbstract(clz.getModifiers())) continue;
if (Utility.isAbstractOrInterface(clz)) {
continue;
}
try {
FilterNodeBean.load(clz);
} catch (Exception e) {

View File

@@ -0,0 +1,67 @@
/*
*/
package org.redkale.boot;
import java.util.*;
import java.util.logging.Logger;
import org.redkale.util.*;
/**
* 配置源Agent, 在init方法内需要实现读取配置信息如果支持配置更改通知也需要在init里实现监听
*
* 配置项优先级: 本地配置 &#60; 配置中心 &#60; 环境变量
*
*
* 详情见: https://redkale.org
*
* @author zhangjx
*
* @since 2.7.0
*/
public abstract class PropertiesAgent {
protected final Logger logger = Logger.getLogger(this.getClass().getSimpleName());
/**
* 编译时进行的操作
*
* @param conf 节点配置
*/
public void compile(AnyValue conf) {
}
/**
* ServiceLoader时判断配置是否符合当前实现类
*
* @param config 节点配置
*
* @return boolean
*/
public abstract boolean acceptsConf(AnyValue config);
/**
* 初始化配置源配置项需要写入envProperties并监听配置项的变化
*
* @param application Application
* @param conf 节点配置
*
* @return 加载的配置项, key:namespace
*/
public abstract Map<String, Properties> init(Application application, AnyValue conf);
/**
* 销毁动作
*
* @param conf 节点配置
*/
public abstract void destroy(AnyValue conf);
protected void updateEnvironmentProperties(Application application, String namespace, List<ResourceEvent> events) {
if (events == null || events.isEmpty()) return;
application.updateEnvironmentProperties(namespace, events);
}
protected void reconfigLogging(Application application, Properties loggingProperties) {
application.reconfigLogging(loggingProperties);
}
}

View File

@@ -0,0 +1,19 @@
/*
*/
package org.redkale.boot;
import org.redkale.util.*;
/**
* 自定义的PropertiesAgent加载器
*
*
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
* @since 2.8.0
*/
public interface PropertiesAgentProvider extends InstanceProvider<PropertiesAgent> {
}

View File

@@ -6,7 +6,7 @@
package org.redkale.boot.watch;
import org.redkale.service.AbstractService;
import org.redkale.util.Comment;
import org.redkale.annotation.Comment;
import org.redkale.watch.WatchService;
/**

View File

@@ -7,11 +7,10 @@ package org.redkale.boot.watch;
import java.io.IOException;
import java.util.List;
import javax.annotation.Resource;
import org.redkale.annotation.*;
import org.redkale.boot.*;
import org.redkale.net.http.*;
import org.redkale.service.RetResult;
import org.redkale.util.Comment;
/**
*
@@ -36,14 +35,20 @@ public class FilterWatchService extends AbstractWatchService {
protected Application application;
@RestMapping(name = "addFilter", auth = false, comment = "动态增加Filter")
public RetResult addFilter(@RestUploadFile(maxLength = 10 * 1024 * 1024, fileNameReg = "\\.jar$") byte[] jar,
public RetResult addFilter(@RestUploadFile(maxLength = 10 * 1024 * 1024, fileNameRegx = "\\.jar$") byte[] jar,
@RestParam(name = "server", comment = "Server节点名") final String serverName,
@RestParam(name = "type", comment = "Filter类名") final String filterType) throws IOException {
if (filterType == null) return new RetResult(RET_FILTER_TYPE_NOT_EXISTS, "Not found Filter Type (" + filterType + ")");
if (jar == null) return new RetResult(RET_FILTER_JAR_ILLEGAL, "Not found jar file");
if (filterType == null) {
return new RetResult(RET_FILTER_TYPE_NOT_EXISTS, "Not found Filter Type (" + filterType + ")");
}
if (jar == null) {
return new RetResult(RET_FILTER_JAR_ILLEGAL, "Not found jar file");
}
List<NodeServer> nodes = application.getNodeServers();
for (NodeServer node : nodes) {
if (node.getServer().containsFilter(filterType)) return new RetResult(RET_FILTER_EXISTS, "Filter(" + filterType + ") exists");
if (node.getServer().containsFilter(filterType)) {
return new RetResult(RET_FILTER_EXISTS, "Filter(" + filterType + ") exists");
}
}
return RetResult.success();
}

View File

@@ -9,12 +9,11 @@ import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.*;
import java.util.stream.Stream;
import javax.annotation.Resource;
import org.redkale.annotation.*;
import org.redkale.boot.*;
import org.redkale.net.Server;
import org.redkale.net.http.*;
import org.redkale.service.RetResult;
import org.redkale.util.Comment;
/**
*
@@ -36,7 +35,9 @@ public class ServerWatchService extends AbstractWatchService {
public RetResult info(@RestParam(name = "#port:") final int port) {
Stream<NodeServer> stream = application.getNodeServers().stream();
NodeServer node = stream.filter(ns -> ns.getServer().getSocketAddress().getPort() == port).findFirst().orElse(null);
if (node == null) return new RetResult(RET_SERVER_NOT_EXISTS, "Server(port=" + port + ") not found");
if (node == null) {
return new RetResult(RET_SERVER_NOT_EXISTS, "Server(port=" + port + ") not found");
}
return new RetResult(formatToMap(node));
}
@@ -53,18 +54,24 @@ public class ServerWatchService extends AbstractWatchService {
@RestMapping(name = "changeAddress", comment = "更改Server的监听地址和端口")
public RetResult changeAddress(@RestParam(name = "#port:") final int oldport,
@RestParam(name = "#newhost:") final String newhost, @RestParam(name = "#newport:") final int newport) {
if (oldport < 1) return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `oldport`");
if (newport < 1) return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `newport`");
if (oldport < 1) {
return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `oldport`");
}
if (newport < 1) {
return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `newport`");
}
Stream<NodeServer> stream = application.getNodeServers().stream();
NodeServer node = stream.filter(ns -> ns.getServer().getSocketAddress().getPort() == oldport).findFirst().orElse(null);
if (node == null) return new RetResult(RET_SERVER_NOT_EXISTS, "Server(port=" + oldport + ") not found");
if (node == null) {
return new RetResult(RET_SERVER_NOT_EXISTS, "Server(port=" + oldport + ") not found");
}
final Server server = node.getServer();
InetSocketAddress newAddr = new InetSocketAddress(newhost == null || newhost.isEmpty() ? server.getSocketAddress().getHostString() : newhost, newport);
try {
server.changeAddress(application, newAddr);
} catch (IOException e) {
e.printStackTrace();
return new RetResult(RET_SERVER_CHANGEPORT_ERROR, "changeaddress error");
return new RetResult(RET_SERVER_CHANGEPORT_ERROR, "changeAddress error");
}
return RetResult.success();
}
@@ -90,8 +97,8 @@ public class ServerWatchService extends AbstractWatchService {
rs.put("bufferCapacity", server.getBufferCapacity());
rs.put("bufferPoolSize", server.getBufferPoolSize());
rs.put("charset", server.getCharset() == null ? "UTF-8" : server.getCharset().name());
rs.put("maxbody", server.getMaxbody());
rs.put("maxconns", server.getMaxconns());
rs.put("maxbody", server.getMaxBody());
rs.put("maxconns", server.getMaxConns());
rs.put("serverStartTime", server.getServerStartTime());
rs.put("responsePoolSize", server.getResponsePoolSize());
rs.put("readTimeoutSeconds", server.getReadTimeoutSeconds());

View File

@@ -6,13 +6,14 @@
package org.redkale.boot.watch;
import java.lang.reflect.*;
import java.util.*;
import javax.annotation.Resource;
import java.util.List;
import org.redkale.annotation.Comment;
import org.redkale.annotation.*;
import org.redkale.boot.*;
import org.redkale.convert.json.JsonConvert;
import org.redkale.net.http.*;
import org.redkale.service.RetResult;
import org.redkale.util.*;
import org.redkale.util.ResourceFactory;
/**
* <p>
@@ -35,13 +36,23 @@ public class ServiceWatchService extends AbstractWatchService {
@RestParam(name = "type", comment = "Service的类名") String type,
@RestParam(name = "field", comment = "字段名") String field,
@RestParam(name = "value", comment = "字段值") String value) {
if (name == null) name = "";
if (type == null) type = "";
if (field == null) field = "";
if (name == null) {
name = "";
}
if (type == null) {
type = "";
}
if (field == null) {
field = "";
}
type = type.trim();
field = field.trim();
if (type.isEmpty()) return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `type`");
if (field.isEmpty()) return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `field`");
if (type.isEmpty()) {
return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `type`");
}
if (field.isEmpty()) {
return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `field`");
}
Object dest = findService(name, type);
Class clazz = dest.getClass();
Throwable t = null;
@@ -52,10 +63,14 @@ public class ServiceWatchService extends AbstractWatchService {
fieldObj = clazz.getDeclaredField(field);
break;
} catch (Exception e) {
if (t == null) t = e;
if (t == null) {
t = e;
}
}
} while ((clazz = clazz.getSuperclass()) != Object.class);
if (fieldObj == null) return new RetResult(RET_WATCH_RUN_EXCEPTION, "run exception (" + String.valueOf(t) + ")");
if (fieldObj == null) {
return new RetResult(RET_WATCH_RUN_EXCEPTION, "run exception (" + String.valueOf(t) + ")");
}
fieldObj.setAccessible(true);
fieldObj.set(dest, JsonConvert.root().convertFrom(fieldObj.getGenericType(), value));
return RetResult.success();
@@ -69,13 +84,23 @@ public class ServiceWatchService extends AbstractWatchService {
public RetResult getField(@RestParam(name = "name", comment = "Service的资源名") String name,
@RestParam(name = "type", comment = "Service的类名") String type,
@RestParam(name = "field", comment = "字段名") String field) {
if (name == null) name = "";
if (type == null) type = "";
if (field == null) field = "";
if (name == null) {
name = "";
}
if (type == null) {
type = "";
}
if (field == null) {
field = "";
}
type = type.trim();
field = field.trim();
if (type.isEmpty()) return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `type`");
if (field.isEmpty()) return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `field`");
if (type.isEmpty()) {
return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `type`");
}
if (field.isEmpty()) {
return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `field`");
}
Object dest = findService(name, type);
Class clazz = dest.getClass();
Throwable t = null;
@@ -86,10 +111,14 @@ public class ServiceWatchService extends AbstractWatchService {
fieldObj = clazz.getDeclaredField(field);
break;
} catch (Exception e) {
if (t == null) t = e;
if (t == null) {
t = e;
}
}
} while ((clazz = clazz.getSuperclass()) != Object.class);
if (fieldObj == null) return new RetResult(RET_WATCH_RUN_EXCEPTION, "run exception (" + String.valueOf(t) + ")");
if (fieldObj == null) {
return new RetResult(RET_WATCH_RUN_EXCEPTION, "run exception (" + String.valueOf(t) + ")");
}
fieldObj.setAccessible(true);
return new RetResult(fieldObj.get(dest));
} catch (Throwable t2) {
@@ -104,18 +133,30 @@ public class ServiceWatchService extends AbstractWatchService {
@RestParam(name = "method", comment = "Service的方法名") String method,
@RestParam(name = "params", comment = "方法的参数值") List<String> params,
@RestParam(name = "paramtypes", comment = "方法的参数数据类型") List<String> paramtypes) {
if (name == null) name = "";
if (type == null) type = "";
if (method == null) method = "";
if (name == null) {
name = "";
}
if (type == null) {
type = "";
}
if (method == null) {
method = "";
}
type = type.trim();
method = method.trim();
if (type.isEmpty()) return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `type`");
if (method.isEmpty()) return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `method`");
if (type.isEmpty()) {
return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `type`");
}
if (method.isEmpty()) {
return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "not found param `method`");
}
Object dest = findService(name, type);
Class clazz = dest.getClass();
Throwable t = null;
final int paramcount = params == null ? 0 : params.size();
if (paramtypes != null && paramcount != paramtypes.size()) return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "params.size not equals to paramtypes.size");
if (paramtypes != null && paramcount != paramtypes.size()) {
return new RetResult(RET_WATCH_PARAMS_ILLEGAL, "params.size not equals to paramtypes.size");
}
try {
Method methodObj = null;
do {
@@ -138,14 +179,22 @@ public class ServiceWatchService extends AbstractWatchService {
}
}
}
if (methodObj != null) break;
if (methodObj != null) {
break;
}
} catch (Exception e) {
if (t == null) t = e;
if (t == null) {
t = e;
}
}
} while ((clazz = clazz.getSuperclass()) != Object.class);
if (methodObj == null) return new RetResult(RET_WATCH_RUN_EXCEPTION, "run exception (" + (t == null ? ("not found method(" + method + ")") : String.valueOf(t)) + ")");
if (methodObj == null) {
return new RetResult(RET_WATCH_RUN_EXCEPTION, "run exception (" + (t == null ? ("not found method(" + method + ")") : String.valueOf(t)) + ")");
}
methodObj.setAccessible(true);
if (paramcount < 1) return new RetResult(methodObj.invoke(dest));
if (paramcount < 1) {
return new RetResult(methodObj.invoke(dest));
}
Object[] paramObjs = new Object[paramcount];
Type[] pts = methodObj.getGenericParameterTypes();
for (int i = 0; i < paramObjs.length; i++) {
@@ -162,16 +211,20 @@ public class ServiceWatchService extends AbstractWatchService {
for (NodeServer ns : application.getNodeServers()) {
ResourceFactory resFactory = ns.getResourceFactory();
List list = resFactory.query((n, s) -> name.equals(n) && s != null && s.getClass().getName().endsWith(type));
if (list == null || list.isEmpty()) continue;
if (list == null || list.isEmpty()) {
continue;
}
dest = list.get(0);
}
if (dest == null) return new RetResult(RET_SERVICE_DEST_NOT_EXISTS, "not found servie (name=" + name + ", type=" + type + ")");
if (dest == null) {
return new RetResult(RET_SERVICE_DEST_NOT_EXISTS, "not found servie (name=" + name + ", type=" + type + ")");
}
return dest;
}
@RestMapping(name = "loadService", auth = false, comment = "动态增加Service")
public RetResult loadService(@RestParam(name = "type", comment = "Service的类名") String type,
@RestUploadFile(maxLength = 10 * 1024 * 1024, fileNameReg = "\\.jar$") byte[] jar) {
@RestUploadFile(maxLength = 10 * 1024 * 1024, fileNameRegx = "\\.jar$") byte[] jar) {
//待开发
return RetResult.success();
}

View File

@@ -1,39 +0,0 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.boot.watch;
import javax.annotation.Resource;
import org.redkale.boot.Application;
import org.redkale.net.TransportFactory;
import org.redkale.net.http.*;
/**
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
*/
@RestService(name = "servlet", catalog = "watch", repair = false)
public class ServletWatchService extends AbstractWatchService {
@Resource
protected Application application;
@Resource
protected TransportFactory transportFactory;
//
// @RestMapping(name = "loadServlet", auth = false, comment = "动态增加Servlet")
// public RetResult loadServlet(String type, @RestUploadFile(maxLength = 10 * 1024 * 1024, fileNameReg = "\\.jar$") byte[] jar) {
// //待开发
// return RetResult.success();
// }
//
// @RestMapping(name = "stopServlet", auth = false, comment = "动态停止Servlet")
// public RetResult stopServlet(String type) {
// //待开发
// return RetResult.success();
// }
}

View File

@@ -1,140 +0,0 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.redkale.boot.watch;
import java.io.IOException;
import java.net.*;
import java.nio.channels.AsynchronousSocketChannel;
import java.util.List;
import java.util.concurrent.TimeUnit;
import javax.annotation.Resource;
import org.redkale.boot.Application;
import org.redkale.net.*;
import org.redkale.net.http.*;
import org.redkale.net.sncp.*;
import org.redkale.service.*;
import org.redkale.util.*;
import org.redkale.util.AnyValue.DefaultAnyValue;
/**
*
* @author zhangjx
*/
@RestService(name = "transport", catalog = "watch", repair = false)
public class TransportWatchService extends AbstractWatchService {
@Comment("不存在的Group节点")
public static final int RET_TRANSPORT_GROUP_NOT_EXISTS = 1606_0001;
@Comment("非法的Node节点IP地址")
public static final int RET_TRANSPORT_ADDR_ILLEGAL = 1606_0002;
@Comment("Node节点IP地址已存在")
public static final int RET_TRANSPORT_ADDR_EXISTS = 1606_0003;
@Resource
protected Application application;
@Resource
protected TransportFactory transportFactory;
@RestMapping(name = "listnodes", auth = false, comment = "获取所有Node节点")
public List<TransportGroupInfo> listNodes() {
return transportFactory.getGroupInfos();
}
@RestMapping(name = "addnode", auth = false, comment = "动态增加指定Group的Node节点")
public RetResult addNode(@RestParam(name = "group", comment = "Group节点名") final String group,
@RestParam(name = "addr", comment = "节点IP") final String addr,
@RestParam(name = "port", comment = "节点端口") final int port) throws IOException {
InetSocketAddress address;
try {
address = new InetSocketAddress(addr, port);
AsynchronousSocketChannel channel = AsynchronousSocketChannel.open();
channel.connect(address).get(2, TimeUnit.SECONDS); //连接超时2秒
channel.close();
} catch (Exception e) {
return new RetResult(RET_TRANSPORT_ADDR_ILLEGAL, "InetSocketAddress(addr=" + addr + ", port=" + port + ") is illegal or cannot connect");
}
if (transportFactory.findGroupName(address) != null) return new RetResult(RET_TRANSPORT_ADDR_ILLEGAL, "InetSocketAddress(addr=" + addr + ", port=" + port + ") is exists");
synchronized (this) {
if (transportFactory.findGroupInfo(group) == null) {
return new RetResult(RET_TRANSPORT_GROUP_NOT_EXISTS, "not found group (" + group + ")");
}
transportFactory.addGroupInfo(group, address);
for (Service service : transportFactory.getServices()) {
if (!Sncp.isSncpDyn(service)) continue;
SncpClient client = Sncp.getSncpClient(service);
if (Sncp.isRemote(service)) {
if (client.getRemoteGroups() != null && client.getRemoteGroups().contains(group)) {
client.getRemoteGroupTransport().addRemoteAddresses(address);
}
}
}
DefaultAnyValue node = DefaultAnyValue.create("addr", addr).addValue("port", port);
for (AnyValue groupconf : application.getAppConfig().getAnyValue("resources").getAnyValues("group")) {
if (group.equals(groupconf.getValue("name"))) {
((DefaultAnyValue) groupconf).addValue("node", node);
break;
}
}
//application.restoreConfig();
}
return RetResult.success();
}
@RestMapping(name = "removenode", auth = false, comment = "动态删除指定Group的Node节点")
public RetResult removeNode(@RestParam(name = "group", comment = "Group节点名") final String group,
@RestParam(name = "addr", comment = "节点IP") final String addr,
@RestParam(name = "port", comment = "节点端口") final int port) throws IOException {
if (group == null) return new RetResult(RET_TRANSPORT_GROUP_NOT_EXISTS, "not found group (" + group + ")");
final InetSocketAddress address = new InetSocketAddress(addr, port);
if (!group.equals(transportFactory.findGroupName(address))) return new RetResult(RET_TRANSPORT_ADDR_ILLEGAL, "InetSocketAddress(addr=" + addr + ", port=" + port + ") not belong to group(" + group + ")");
synchronized (this) {
if (transportFactory.findGroupInfo(group) == null) {
return new RetResult(RET_TRANSPORT_GROUP_NOT_EXISTS, "not found group (" + group + ")");
}
transportFactory.removeGroupInfo(group, address);
for (Service service : transportFactory.getServices()) {
if (!Sncp.isSncpDyn(service)) continue;
SncpClient client = Sncp.getSncpClient(service);
if (Sncp.isRemote(service)) {
if (client.getRemoteGroups() != null && client.getRemoteGroups().contains(group)) {
client.getRemoteGroupTransport().removeRemoteAddresses(address);
}
}
}
for (AnyValue groupconf : application.getAppConfig().getAnyValue("resources").getAnyValues("group")) {
if (group.equals(groupconf.getValue("name"))) {
((DefaultAnyValue) groupconf).removeValue("node", DefaultAnyValue.create("addr", addr).addValue("port", port));
break;
}
}
//application.restoreConfig();
}
return RetResult.success();
}
@RestMapping(name = "test1", auth = false, comment = "预留")
public RetResult test1() {
return RetResult.success();
}
@RestMapping(name = "test2", auth = false, comment = "预留")
public RetResult test2() {
return RetResult.success();
}
@RestMapping(name = "test3", auth = false, comment = "预留")
public RetResult test3() {
return RetResult.success();
}
@RestMapping(name = "test4", auth = false, comment = "预留")
public RetResult test4() {
return RetResult.success();
}
}

View File

@@ -0,0 +1,4 @@
/**
* 提供系统默认监控包
*/
package org.redkale.boot.watch;

View File

@@ -5,11 +5,13 @@
*/
package org.redkale.cluster;
import java.net.*;
import java.net.InetSocketAddress;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
import javax.annotation.Resource;
import org.redkale.annotation.*;
import org.redkale.annotation.ResourceListener;
import org.redkale.boot.*;
import org.redkale.convert.json.JsonConvert;
import org.redkale.service.Service;
@@ -37,41 +39,68 @@ public class CacheClusterAgent extends ClusterAgent implements Resourcable {
protected ScheduledThreadPoolExecutor scheduler;
//可能被HttpMessageClient用到的服务 key: servicename
protected final ConcurrentHashMap<String, Collection<InetSocketAddress>> httpAddressMap = new ConcurrentHashMap<>();
protected ScheduledFuture taskFuture;
//可能被mqtp用到的服务 key: servicename
protected final ConcurrentHashMap<String, Collection<InetSocketAddress>> mqtpAddressMap = new ConcurrentHashMap<>();
//可能被HttpMessageClient用到的服务 key: serviceName
protected final ConcurrentHashMap<String, Set<InetSocketAddress>> httpAddressMap = new ConcurrentHashMap<>();
//可能被sncp用到的服务 key: serviceName
protected final ConcurrentHashMap<String, Set<InetSocketAddress>> sncpAddressMap = new ConcurrentHashMap<>();
//可能被mqtp用到的服务 key: serviceName
protected final ConcurrentHashMap<String, Set<InetSocketAddress>> mqtpAddressMap = new ConcurrentHashMap<>();
@Override
public void init(AnyValue config) {
super.init(config);
this.sourceName = getSourceName();
AnyValue[] properties = config.getAnyValues("property");
for (AnyValue property : properties) {
if ("ttls".equalsIgnoreCase(property.getValue("name"))) {
this.ttls = Integer.parseInt(property.getValue("value", "").trim());
if (this.ttls < 5) this.ttls = 10;
}
this.ttls = config.getIntValue("ttls", 10);
if (this.ttls < 5) {
this.ttls = 10;
}
}
@Override
@ResourceListener
public void onResourceChange(ResourceEvent[] events) {
StringBuilder sb = new StringBuilder();
int newTtls = this.ttls;
for (ResourceEvent event : events) {
if ("ttls".equals(event.name())) {
newTtls = Integer.parseInt(event.newValue().toString());
if (newTtls < 5) {
sb.append(CacheClusterAgent.class.getSimpleName()).append("(name=").append(resourceName()).append(") cannot change '").append(event.name()).append("' to '").append(event.coverNewValue()).append("'\r\n");
} else {
sb.append(CacheClusterAgent.class.getSimpleName()).append("(name=").append(resourceName()).append(") change '").append(event.name()).append("' to '").append(event.coverNewValue()).append("'\r\n");
}
} else {
sb.append(CacheClusterAgent.class.getSimpleName()).append("(name=").append(resourceName()).append(") skip change '").append(event.name()).append("' to '").append(event.coverNewValue()).append("'\r\n");
}
}
if (newTtls != this.ttls) {
this.ttls = newTtls;
start();
}
if (sb.length() > 0) {
logger.log(Level.INFO, sb.toString());
}
}
@Override
public void setConfig(AnyValue config) {
super.setConfig(config);
this.sourceName = getSourceName();
}
@Override
public void destroy(AnyValue config) {
if (scheduler != null) scheduler.shutdownNow();
if (scheduler != null) {
scheduler.shutdownNow();
}
}
public String getSourceName() {
AnyValue[] properties = config.getAnyValues("property");
for (AnyValue property : properties) {
if ("source".equalsIgnoreCase(property.getValue("name"))
&& property.getValue("value") != null) {
this.sourceName = property.getValue("value");
return this.sourceName;
}
}
return null;
return config.getValue("source");
}
@Override
@@ -81,61 +110,76 @@ public class CacheClusterAgent extends ClusterAgent implements Resourcable {
@Override //ServiceLoader时判断配置是否符合当前实现类
public boolean acceptsConf(AnyValue config) {
if (config == null) return false;
AnyValue[] properties = config.getAnyValues("property");
if (properties == null || properties.length == 0) return false;
for (AnyValue property : properties) {
if ("source".equalsIgnoreCase(property.getValue("name"))
&& property.getValue("value") != null) return true;
if (config == null) {
return false;
}
return false;
return config.getValue("source") != null;
}
@Override
public void start() {
if (this.scheduler == null) {
this.scheduler = new ScheduledThreadPoolExecutor(4, (Runnable r) -> {
final Thread t = new Thread(r, "Redkale-" + CacheClusterAgent.class.getSimpleName() + "-Task-Thread");
AtomicInteger counter = new AtomicInteger();
this.scheduler = new ScheduledThreadPoolExecutor(1, (Runnable r) -> {
final Thread t = new Thread(r, "Redkale-" + CacheClusterAgent.class.getSimpleName() + "-Check-Thread-" + counter.incrementAndGet());
t.setDaemon(true);
return t;
});
this.scheduler.scheduleAtFixedRate(() -> {
try {
checkApplicationHealth();
checkHttpAddressHealth();
loadMqtpAddressHealth();
localEntrys.values().stream().filter(e -> !e.canceled).forEach(entry -> {
checkLocalHealth(entry);
});
remoteEntrys.values().stream().filter(entry -> "SNCP".equalsIgnoreCase(entry.protocol)).forEach(entry -> {
updateSncpTransport(entry);
});
} catch (Exception e) {
logger.log(Level.SEVERE, "scheduleAtFixedRate check error", e instanceof CompletionException ? ((CompletionException) e).getCause() : e);
}
}, Math.max(2000, ttls * 1000), Math.max(2000, ttls * 1000), TimeUnit.MILLISECONDS);
}
if (this.taskFuture != null) {
this.taskFuture.cancel(true);
}
this.taskFuture = this.scheduler.scheduleAtFixedRate(newTask(), Math.max(2000, ttls * 1000), Math.max(2000, ttls * 1000), TimeUnit.MILLISECONDS);
}
private Runnable newTask() {
return () -> {
try {
checkApplicationHealth();
checkHttpAddressHealth();
loadSncpAddressHealth();
loadMqtpAddressHealth();
localEntrys.values().stream().filter(e -> !e.canceled).forEach(entry -> {
checkLocalHealth(entry);
});
remoteEntrys.values().stream().filter(entry -> "SNCP".equalsIgnoreCase(entry.protocol)).forEach(entry -> {
updateSncpAddress(entry);
});
} catch (Exception e) {
logger.log(Level.SEVERE, "scheduleAtFixedRate check error", e instanceof CompletionException ? ((CompletionException) e).getCause() : e);
}
};
}
protected void loadSncpAddressHealth() {
List<String> keys = source.keysStartsWith("cluster.sncp:");
keys.forEach(serviceName -> {
try {
this.sncpAddressMap.put(serviceName, queryAddress(serviceName).get(3, TimeUnit.SECONDS));
} catch (Exception e) {
logger.log(Level.SEVERE, "loadSncpAddressHealth check " + serviceName + " error", e);
}
});
}
protected void loadMqtpAddressHealth() {
List<String> keys = source.queryKeysStartsWith("cluster.mqtp:");
keys.forEach(servicename -> {
List<String> keys = source.keysStartsWith("cluster.mqtp:");
keys.forEach(serviceName -> {
try {
this.mqtpAddressMap.put(servicename, queryAddress(servicename).get(3, TimeUnit.SECONDS));
this.mqtpAddressMap.put(serviceName, queryAddress(serviceName).get(3, TimeUnit.SECONDS));
} catch (Exception e) {
logger.log(Level.SEVERE, "loadMqtpAddressHealth check " + servicename + " error", e);
logger.log(Level.SEVERE, "loadMqtpAddressHealth check " + serviceName + " error", e);
}
});
}
protected void checkHttpAddressHealth() {
try {
this.httpAddressMap.keySet().stream().forEach(servicename -> {
this.httpAddressMap.keySet().stream().forEach(serviceName -> {
try {
this.httpAddressMap.put(servicename, queryAddress(servicename).get(3, TimeUnit.SECONDS));
this.httpAddressMap.put(serviceName, queryAddress(serviceName).get(3, TimeUnit.SECONDS));
} catch (Exception e) {
logger.log(Level.SEVERE, "checkHttpAddressHealth check " + servicename + " error", e);
logger.log(Level.SEVERE, "checkHttpAddressHealth check " + serviceName + " error", e);
}
});
} catch (Exception ex) {
@@ -146,14 +190,28 @@ public class CacheClusterAgent extends ClusterAgent implements Resourcable {
protected void checkLocalHealth(final ClusterEntry entry) {
AddressEntry newaddr = new AddressEntry();
newaddr.addr = entry.address;
newaddr.resname = entry.resourceName;
newaddr.nodeid = this.nodeid;
newaddr.time = System.currentTimeMillis();
source.hset(entry.checkname, entry.checkid, AddressEntry.class, newaddr);
source.hset(entry.checkName, entry.checkid, AddressEntry.class, newaddr);
}
@Override //获取MQTP的HTTP远程服务的可用ip列表, key = servicename的后半段
public CompletableFuture<Map<String, Collection<InetSocketAddress>>> queryMqtpAddress(String protocol, String module, String resname) {
final Map<String, Collection<InetSocketAddress>> rsmap = new ConcurrentHashMap<>();
@Override //获取SNCP远程服务的可用ip列表
public CompletableFuture<Set<InetSocketAddress>> querySncpAddress(String protocol, String module, String resname) {
final String serviceName = generateSncpServiceName(protocol, module, resname);
Set<InetSocketAddress> rs = sncpAddressMap.get(serviceName);
if (rs != null) {
return CompletableFuture.completedFuture(rs);
}
return queryAddress(serviceName).thenApply(t -> {
sncpAddressMap.put(serviceName, t);
return t;
});
}
@Override //获取MQTP的HTTP远程服务的可用ip列表, key = serviceName的后半段
public CompletableFuture<Map<String, Set<InetSocketAddress>>> queryMqtpAddress(String protocol, String module, String resname) {
final Map<String, Set<InetSocketAddress>> rsmap = new ConcurrentHashMap<>();
final String servicenamprefix = generateHttpServiceName(protocol, module, null) + ":";
mqtpAddressMap.keySet().stream().filter(k -> k.startsWith(servicenamprefix))
.forEach(sn -> rsmap.put(sn.substring(servicenamprefix.length()), mqtpAddressMap.get(sn)));
@@ -161,36 +219,40 @@ public class CacheClusterAgent extends ClusterAgent implements Resourcable {
}
@Override //获取HTTP远程服务的可用ip列表
public CompletableFuture<Collection<InetSocketAddress>> queryHttpAddress(String protocol, String module, String resname) {
final String servicename = generateHttpServiceName(protocol, module, resname);
Collection<InetSocketAddress> rs = httpAddressMap.get(servicename);
if (rs != null) return CompletableFuture.completedFuture(rs);
return queryAddress(servicename).thenApply(t -> {
httpAddressMap.put(servicename, t);
public CompletableFuture<Set<InetSocketAddress>> queryHttpAddress(String protocol, String module, String resname) {
final String serviceName = generateHttpServiceName(protocol, module, resname);
Set<InetSocketAddress> rs = httpAddressMap.get(serviceName);
if (rs != null) {
return CompletableFuture.completedFuture(rs);
}
return queryAddress(serviceName).thenApply(t -> {
httpAddressMap.put(serviceName, t);
return t;
});
}
@Override
protected CompletableFuture<Collection<InetSocketAddress>> queryAddress(final ClusterEntry entry) {
return queryAddress(entry.servicename);
protected CompletableFuture<Set<InetSocketAddress>> queryAddress(final ClusterEntry entry) {
return queryAddress(entry.serviceName);
}
private CompletableFuture<Collection<InetSocketAddress>> queryAddress(final String servicename) {
final CompletableFuture<Map<String, AddressEntry>> future = source.hmapAsync(servicename, AddressEntry.class, 0, 10000);
private CompletableFuture<Set<InetSocketAddress>> queryAddress(final String serviceName) {
final CompletableFuture<Map<String, AddressEntry>> future = source.hmapAsync(serviceName, AddressEntry.class, 0, 10000);
return future.thenApply(map -> {
final Set<InetSocketAddress> set = new HashSet<>();
map.forEach((n, v) -> {
if (v != null && (System.currentTimeMillis() - v.time) / 1000 < ttls) set.add(v.addr);
if (v != null && (System.currentTimeMillis() - v.time) / 1000 < ttls) {
set.add(v.addr);
}
});
return set;
});
}
protected boolean isApplicationHealth() {
String servicename = generateApplicationServiceName();
String serviceName = generateApplicationServiceName();
String serviceid = generateApplicationServiceId();
AddressEntry entry = (AddressEntry) source.hget(servicename, serviceid, AddressEntry.class);
AddressEntry entry = (AddressEntry) source.hget(serviceName, serviceid, AddressEntry.class);
return entry != null && (System.currentTimeMillis() - entry.time) / 1000 < ttls;
}
@@ -206,22 +268,24 @@ public class CacheClusterAgent extends ClusterAgent implements Resourcable {
@Override
public void register(Application application) {
if (isApplicationHealth()) throw new RuntimeException("application.nodeid=" + nodeid + " exists in cluster");
if (isApplicationHealth()) {
throw new RedkaleException("application.nodeid=" + nodeid + " exists in cluster");
}
deregister(application);
String serviceid = generateApplicationServiceId();
String servicename = generateApplicationServiceName();
String serviceName = generateApplicationServiceName();
AddressEntry entry = new AddressEntry();
entry.addr = this.appAddress;
entry.nodeid = this.nodeid;
entry.time = System.currentTimeMillis();
source.hset(servicename, serviceid, AddressEntry.class, entry);
source.hset(serviceName, serviceid, AddressEntry.class, entry);
}
@Override
public void deregister(Application application) {
String servicename = generateApplicationServiceName();
source.remove(servicename);
String serviceName = generateApplicationServiceName();
source.del(serviceName);
}
@Override
@@ -231,9 +295,10 @@ public class CacheClusterAgent extends ClusterAgent implements Resourcable {
ClusterEntry clusterEntry = new ClusterEntry(ns, protocol, service);
AddressEntry entry = new AddressEntry();
entry.addr = clusterEntry.address;
entry.resname = clusterEntry.resourceName;
entry.nodeid = this.nodeid;
entry.time = System.currentTimeMillis();
source.hset(clusterEntry.servicename, clusterEntry.serviceid, AddressEntry.class, entry);
source.hset(clusterEntry.serviceName, clusterEntry.serviceid, AddressEntry.class, entry);
return clusterEntry;
}
@@ -243,25 +308,27 @@ public class CacheClusterAgent extends ClusterAgent implements Resourcable {
}
protected void deregister(NodeServer ns, String protocol, Service service, boolean realcanceled) {
String servicename = generateServiceName(ns, protocol, service);
String serviceName = generateServiceName(ns, protocol, service);
String serviceid = generateServiceId(ns, protocol, service);
ClusterEntry currEntry = null;
for (final ClusterEntry entry : localEntrys.values()) {
if (entry.servicename.equals(servicename) && entry.serviceid.equals(serviceid)) {
if (entry.serviceName.equals(serviceName) && entry.serviceid.equals(serviceid)) {
currEntry = entry;
break;
}
}
if (currEntry == null) {
for (final ClusterEntry entry : remoteEntrys.values()) {
if (entry.servicename.equals(servicename) && entry.serviceid.equals(serviceid)) {
if (entry.serviceName.equals(serviceName) && entry.serviceid.equals(serviceid)) {
currEntry = entry;
break;
}
}
}
source.hremove(servicename, serviceid);
if (realcanceled && currEntry != null) currEntry.canceled = true;
source.hdel(serviceName, serviceid);
if (realcanceled && currEntry != null) {
currEntry.canceled = true;
}
if (!"mqtp".equals(protocol) && currEntry != null && currEntry.submqtp) {
deregister(ns, "mqtp", service, realcanceled);
}
@@ -282,6 +349,11 @@ public class CacheClusterAgent extends ClusterAgent implements Resourcable {
return "cluster." + super.generateHttpServiceName(protocol, module, resname);
}
@Override
public String generateSncpServiceName(String protocol, String restype, String resname) {
return "cluster." + super.generateSncpServiceName(protocol, restype, resname);
}
@Override
protected String generateApplicationCheckName() {
return generateApplicationServiceName();
@@ -310,6 +382,8 @@ public class CacheClusterAgent extends ClusterAgent implements Resourcable {
public long time;
public String resname;
public AddressEntry() {
}

View File

@@ -6,23 +6,27 @@
package org.redkale.cluster;
import java.lang.ref.WeakReference;
import java.net.InetSocketAddress;
import java.net.*;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.*;
import java.util.logging.Logger;
import javax.annotation.Resource;
import java.util.logging.*;
import org.redkale.annotation.AutoLoad;
import org.redkale.annotation.*;
import org.redkale.annotation.ResourceListener;
import org.redkale.boot.*;
import static org.redkale.boot.Application.*;
import org.redkale.convert.ConvertDisabled;
import org.redkale.convert.json.JsonConvert;
import org.redkale.mq.MessageMultiConsumer;
import org.redkale.net.*;
import org.redkale.net.Server;
import org.redkale.net.http.*;
import org.redkale.net.sncp.*;
import org.redkale.service.*;
import org.redkale.util.*;
/**
* 第三方服务发现管理接口cluster
* 服务注册中心管理类cluster
*
*
* 详情见: https://redkale.org
@@ -44,6 +48,9 @@ public abstract class ClusterAgent {
@Resource(name = RESNAME_APP_ADDR)
protected InetSocketAddress appAddress;
@Resource(required = false)
protected Application application;
protected String name;
protected boolean waits;
@@ -54,7 +61,7 @@ public abstract class ClusterAgent {
protected AnyValue config;
protected TransportFactory transportFactory;
protected Set<String> tags;
protected final ConcurrentHashMap<String, ClusterEntry> localEntrys = new ConcurrentHashMap<>();
@@ -66,7 +73,9 @@ public abstract class ClusterAgent {
this.waits = config.getBoolValue("waits", false);
{
String ps = config.getValue("protocols", "").toUpperCase();
if (ps == null || ps.isEmpty()) ps = "SNCP;HTTP";
if (ps == null || ps.isEmpty()) {
ps = "SNCP;HTTP";
}
this.protocols = ps.split(";");
}
String ts = config.getValue("ports", "");
@@ -74,26 +83,52 @@ public abstract class ClusterAgent {
String[] its = ts.split(";");
List<Integer> list = new ArrayList<>();
for (String str : its) {
if (str.trim().isEmpty()) continue;
if (str.trim().isEmpty()) {
continue;
}
list.add(Integer.parseInt(str.trim()));
}
if (!list.isEmpty()) this.ports = list.stream().mapToInt(x -> x).toArray();
if (!list.isEmpty()) {
this.ports = list.stream().mapToInt(x -> x).toArray();
}
}
Set<String> tags0 = new HashSet<>();
for (String str : config.getValue("tags", "").split(";|,")) {
if (!str.trim().isEmpty()) {
tags0.add(str.trim());
}
}
if (!tags0.isEmpty()) {
this.tags = tags0;
}
}
@ResourceListener
public abstract void onResourceChange(ResourceEvent[] events);
public void destroy(AnyValue config) {
}
//ServiceLoader时判断配置是否符合当前实现类
/**
* ServiceLoader时判断配置是否符合当前实现类
*
* @param config 节点配置
*
* @return boolean
*/
public abstract boolean acceptsConf(AnyValue config);
public boolean containsProtocol(String protocol) {
if (protocol == null || protocol.isEmpty()) return false;
if (protocol == null || protocol.isEmpty()) {
return false;
}
return protocols == null || Utility.contains(protocols, protocol.toUpperCase());
}
public boolean containsPort(int port) {
if (ports == null || ports.length == 0) return true;
if (ports == null || ports.length == 0) {
return true;
}
return Utility.contains(ports, port);
}
@@ -103,10 +138,14 @@ public abstract class ClusterAgent {
//注册服务, 在NodeService调用Service.init方法之前调用
public void register(NodeServer ns, String protocol, Set<Service> localServices, Set<Service> remoteServices) {
if (localServices.isEmpty()) return;
if (localServices.isEmpty()) {
return;
}
//注册本地模式
for (Service service : localServices) {
if (!canRegister(protocol, service)) continue;
if (!canRegister(ns, protocol, service)) {
continue;
}
ClusterEntry htentry = register(ns, protocol, service);
localEntrys.put(htentry.serviceid, htentry);
if (protocol.toLowerCase().startsWith("http")) {
@@ -122,7 +161,7 @@ public abstract class ClusterAgent {
if (ns.isSNCP()) {
for (Service service : remoteServices) {
ClusterEntry entry = new ClusterEntry(ns, protocol, service);
updateSncpTransport(entry);
updateSncpAddress(entry);
remoteEntrys.put(entry.serviceid, entry);
}
}
@@ -132,18 +171,34 @@ public abstract class ClusterAgent {
public void deregister(NodeServer ns, String protocol, Set<Service> localServices, Set<Service> remoteServices) {
//注销本地模式 远程模式不注册
for (Service service : localServices) {
if (!canRegister(protocol, service)) continue;
if (!canRegister(ns, protocol, service)) {
continue;
}
deregister(ns, protocol, service);
}
afterDeregister(ns, protocol);
}
protected boolean canRegister(String protocol, Service service) {
if ("SNCP".equalsIgnoreCase(protocol) && service.getClass().getAnnotation(Local.class) != null) return false;
protected boolean canRegister(NodeServer ns, String protocol, Service service) {
if ("SNCP".equalsIgnoreCase(protocol) && service.getClass().getAnnotation(Local.class) != null) {
return false;
}
AutoLoad al = service.getClass().getAnnotation(AutoLoad.class);
if (al != null && !al.value() && service.getClass().getAnnotation(Local.class) != null) return false;
if (al != null && !al.value() && service.getClass().getAnnotation(Local.class) != null) {
return false;
}
org.redkale.util.AutoLoad al2 = service.getClass().getAnnotation(org.redkale.util.AutoLoad.class);
if (al2 != null && !al2.value() && service.getClass().getAnnotation(Local.class) != null) {
return false;
}
if (service instanceof WebSocketNode) {
if (((WebSocketNode) service).getLocalWebSocketEngine() == null) return false;
if (((WebSocketNode) service).getLocalWebSocketEngine() == null) {
return false;
}
}
ClusterEntry entry = new ClusterEntry(ns, protocol, service);
if (entry.serviceName.trim().endsWith(serviceSeparator())) {
return false;
}
return true;
}
@@ -152,7 +207,9 @@ public abstract class ClusterAgent {
}
protected void afterDeregister(NodeServer ns, String protocol) {
if (!this.waits) return;
if (!this.waits) {
return;
}
int s = intervalCheckSeconds();
if (s > 0) { //暂停,弥补其他依赖本进程服务的周期偏差
try {
@@ -167,14 +224,17 @@ public abstract class ClusterAgent {
return 10;
}
//获取MQTP的HTTP远程服务的可用ip列表, key = servicename的后半段
public abstract CompletableFuture<Map<String, Collection<InetSocketAddress>>> queryMqtpAddress(String protocol, String module, String resname);
//获取MQTP的HTTP远程服务的可用ip列表, key = serviceName的后半段
public abstract CompletableFuture<Map<String, Set<InetSocketAddress>>> queryMqtpAddress(String protocol, String module, String resname);
//获取HTTP远程服务的可用ip列表
public abstract CompletableFuture<Collection<InetSocketAddress>> queryHttpAddress(String protocol, String module, String resname);
public abstract CompletableFuture<Set<InetSocketAddress>> queryHttpAddress(String protocol, String module, String resname);
//获取SNCP远程服务的可用ip列表 restype: resourceType.getName()
public abstract CompletableFuture<Set<InetSocketAddress>> querySncpAddress(String protocol, String restype, String resname);
//获取远程服务的可用ip列表
protected abstract CompletableFuture<Collection<InetSocketAddress>> queryAddress(ClusterEntry entry);
protected abstract CompletableFuture<Set<InetSocketAddress>> queryAddress(ClusterEntry entry);
//注册服务
protected abstract ClusterEntry register(NodeServer ns, String protocol, Service service);
@@ -183,19 +243,37 @@ public abstract class ClusterAgent {
protected abstract void deregister(NodeServer ns, String protocol, Service service);
//格式: protocol:classtype-resourcename
protected void updateSncpTransport(ClusterEntry entry) {
Service service = entry.serviceref.get();
if (service == null) return;
Collection<InetSocketAddress> addrs = ClusterAgent.this.queryAddress(entry).join();
Sncp.updateTransport(service, transportFactory, Sncp.getResourceType(service).getName() + "-" + Sncp.getResourceName(service), entry.netprotocol, entry.address, null, addrs);
protected void updateSncpAddress(ClusterEntry entry) {
if (application == null) {
return;
}
Service service = entry.serviceRef.get();
if (service == null) {
return;
}
try {
Set<InetSocketAddress> addrs = ClusterAgent.this.queryAddress(entry).join();
SncpRpcGroups rpcGroups = application.getSncpRpcGroups();
rpcGroups.putClusterAddress(entry.resourceid, addrs);
} catch (Exception e) {
logger.log(Level.SEVERE, entry + " updateSncpAddress error", e);
}
}
protected String urlEncode(String value) {
return value == null ? null : URLEncoder.encode(value, StandardCharsets.UTF_8);
}
protected String generateApplicationServiceName() {
return "application" + (appName == null || appName.isEmpty() ? "" : ("." + appName)) + ".node" + this.nodeid;
return "application.node" + (appName == null || appName.isEmpty() ? "" : ("." + appName));
}
protected String generateApplicationServiceId() { //与servicename相同
return generateApplicationServiceName();
protected String generateApplicationServiceType() {
return "application.nodes";
}
protected String generateApplicationServiceId() {
return generateApplicationServiceName() + "." + this.nodeid;
}
protected String generateApplicationCheckName() {
@@ -206,9 +284,25 @@ public abstract class ClusterAgent {
return "check-" + generateApplicationServiceId();
}
protected String generateApplicationHost() {
return this.appAddress.getHostString();
}
protected int generateApplicationPort() {
return this.appAddress.getPort();
}
protected String serviceSeparator() {
return "-";
}
public String generateSncpServiceName(String protocol, String restype, String resname) {
return protocol.toLowerCase() + serviceSeparator() + restype + (resname == null || resname.isEmpty() ? "" : ("-" + resname));
}
//也会提供给HttpMessageClusterAgent适用
public String generateHttpServiceName(String protocol, String module, String resname) {
return protocol.toLowerCase() + ":" + module + (resname == null || resname.isEmpty() ? "" : ("-" + resname));
return protocol.toLowerCase() + serviceSeparator() + module + (resname == null || resname.isEmpty() ? "" : ("-" + resname));
}
//格式: protocol:classtype-resourcename
@@ -216,21 +310,23 @@ public abstract class ClusterAgent {
if (protocol.toLowerCase().startsWith("http")) { //HTTP使用RestService.name方式是为了与MessageClient中的module保持一致, 因为HTTP依靠的url中的module无法知道Service类名
String resname = Sncp.getResourceName(service);
String module = Rest.getRestModule(service).toLowerCase();
return protocol.toLowerCase() + ":" + module + (resname.isEmpty() ? "" : ("-" + resname));
return protocol.toLowerCase() + serviceSeparator() + module + (resname.isEmpty() ? "" : ("-" + resname));
}
if ("mqtp".equalsIgnoreCase(protocol)) {
MessageMultiConsumer mmc = service.getClass().getAnnotation(MessageMultiConsumer.class);
String selfmodule = Rest.getRestModule(service).toLowerCase();
return protocol.toLowerCase() + ":" + mmc.module() + ":" + selfmodule;
return protocol.toLowerCase() + serviceSeparator() + mmc.module() + serviceSeparator() + selfmodule;
}
if (!Sncp.isSncpDyn(service)) {
return protocol.toLowerCase() + serviceSeparator() + service.getClass().getName();
}
if (!Sncp.isSncpDyn(service)) return protocol.toLowerCase() + ":" + service.getClass().getName();
String resname = Sncp.getResourceName(service);
return protocol.toLowerCase() + ":" + Sncp.getResourceType(service).getName() + (resname.isEmpty() ? "" : ("-" + resname));
return protocol.toLowerCase() + serviceSeparator() + Sncp.getResourceType(service).getName() + (resname.isEmpty() ? "" : ("-" + resname));
}
//格式: protocol:classtype-resourcename:nodeid
protected String generateServiceId(NodeServer ns, String protocol, Service service) {
return generateServiceName(ns, protocol, service) + ":" + this.nodeid;
return generateServiceName(ns, protocol, service) + serviceSeparator() + this.nodeid;
}
protected String generateCheckName(NodeServer ns, String protocol, Service service) {
@@ -249,19 +345,6 @@ public abstract class ClusterAgent {
return remoteEntrys;
}
@Override
public String toString() {
return JsonConvert.root().convertTo(this);
}
public TransportFactory getTransportFactory() {
return transportFactory;
}
public void setTransportFactory(TransportFactory transportFactory) {
this.transportFactory = transportFactory;
}
public String getName() {
return name;
}
@@ -296,19 +379,30 @@ public abstract class ClusterAgent {
public class ClusterEntry {
//serviceName+nodeid为主 服务的单个实例
public String serviceid;
public String servicename;
//以协议+Rest资源名为主 服务类名
public String serviceName;
public final String resourceType;
public final String resourceName;
public final String resourceid;
public String checkid;
public String checkname;
public String checkName;
//http or sncp or mqtp
public String protocol;
public String netprotocol;
//TCP or UDP
public String netProtocol;
public WeakReference<Service> serviceref;
@ConvertDisabled
public WeakReference<Service> serviceRef;
public InetSocketAddress address;
@@ -318,9 +412,13 @@ public abstract class ClusterAgent {
public ClusterEntry(NodeServer ns, String protocol, Service service) {
this.serviceid = generateServiceId(ns, protocol, service);
this.servicename = generateServiceName(ns, protocol, service);
this.serviceName = generateServiceName(ns, protocol, service);
this.checkid = generateCheckId(ns, protocol, service);
this.checkname = generateCheckName(ns, protocol, service);
this.checkName = generateCheckName(ns, protocol, service);
Class restype = Sncp.getResourceType(service);
this.resourceType = restype.getName();
this.resourceName = Sncp.getResourceName(service);
this.resourceid = Sncp.resourceid(resourceName, restype);
this.protocol = protocol;
InetSocketAddress addr = ns.getSocketAddress();
String host = addr.getHostString();
@@ -329,9 +427,9 @@ public abstract class ClusterAgent {
addr = new InetSocketAddress(host, addr.getPort());
}
this.address = addr;
this.serviceref = new WeakReference(service);
this.serviceRef = new WeakReference(service);
Server server = ns.getServer();
this.netprotocol = server instanceof SncpServer ? ((SncpServer) server).getNetprotocol() : Transport.DEFAULT_NETPROTOCOL;
this.netProtocol = server instanceof SncpServer ? ((SncpServer) server).getNetprotocol() : "TCP";
}
@Override

View File

@@ -5,7 +5,7 @@
*/
package org.redkale.cluster;
import org.redkale.util.AnyValue;
import org.redkale.util.*;
/**
* 自定义的ClusterAgent加载器
@@ -17,9 +17,6 @@ import org.redkale.util.AnyValue;
* @author zhangjx
* @since 2.5.0
*/
public interface ClusterAgentProvider {
public interface ClusterAgentProvider extends InstanceProvider<ClusterAgent> {
public boolean acceptsConf(AnyValue config);
public Class<? extends ClusterAgent> agentClass();
}

View File

@@ -0,0 +1,4 @@
/**
* 提供注册服务与发现服务包
*/
package org.redkale.cluster;

View File

@@ -7,9 +7,9 @@ package org.redkale.convert;
import java.lang.reflect.Type;
import java.util.*;
import org.redkale.util.*;
import org.redkale.convert.Reader.ValueType;
import static org.redkale.convert.Reader.ValueType.MAP;
import org.redkale.util.*;
/**
* 对不明类型的对象进行反序列化。 <br>
@@ -51,7 +51,9 @@ public class AnyDecoder implements Decodeable<Reader, Object> {
@Override
public Object convertFrom(Reader in) {
ValueType vt = in.readType();
if (vt == null) return null;
if (vt == null) {
return null;
}
switch (vt) {
case ARRAY:
return this.collectionDecoder.convertFrom(in);

View File

@@ -9,7 +9,7 @@ import java.lang.reflect.Type;
/**
* 对不明类型的对象进行序列化; BSON序列化时将对象的类名写入WriterJSON则不写入。
*
*
* 详情见: https://redkale.org
*
* @author zhangjx
@@ -36,7 +36,9 @@ public final class AnyEncoder<T> implements Encodeable<Writer, T> {
out.writeObjectE(value);
return;
}
if (out.needWriteClassName()) out.writeClassName(factory.getEntityAlias(clazz));
if (out.needWriteClassName()) {
out.writeClassName(factory.getEntityAlias(clazz));
}
factory.loadEncoder(clazz).convertTo(out, value);
}
}
@@ -46,4 +48,8 @@ public final class AnyEncoder<T> implements Encodeable<Writer, T> {
return Object.class;
}
@Override
public boolean specifyable() {
return false;
}
}

View File

@@ -7,6 +7,9 @@ package org.redkale.convert;
import java.lang.reflect.*;
import java.util.*;
import java.util.concurrent.locks.*;
import java.util.function.IntFunction;
import org.redkale.util.Creator;
/**
* 数组的反序列化操作类 <br>
@@ -30,9 +33,13 @@ public class ArrayDecoder<T> implements Decodeable<Reader, T[]> {
protected final Decodeable<Reader, T> componentDecoder;
protected final IntFunction<T[]> componentArrayFunction;
protected volatile boolean inited = false;
protected final Object lock = new Object();
private final ReentrantLock lock = new ReentrantLock();
private final Condition condition = lock.newCondition();
public ArrayDecoder(final ConvertFactory factory, final Type type) {
this.type = type;
@@ -52,10 +59,14 @@ public class ArrayDecoder<T> implements Decodeable<Reader, T[]> {
}
factory.register(type, this);
this.componentDecoder = factory.loadDecoder(this.componentType);
this.componentArrayFunction = Creator.arrayFunction(this.componentClass);
} finally {
inited = true;
synchronized (lock) {
lock.notifyAll();
lock.lock();
try {
condition.signalAll();
} finally {
lock.unlock();
}
}
}
@@ -69,19 +80,21 @@ public class ArrayDecoder<T> implements Decodeable<Reader, T[]> {
byte[] typevals = new byte[1];
int len = in.readArrayB(member, typevals, componentDecoder);
int contentLength = -1;
if (len == Reader.SIGN_NULL) return null;
if (len == Reader.SIGN_NULL) {
return null;
}
if (len == Reader.SIGN_NOLENBUTBYTES) {
contentLength = in.readMemberContentLength(member, componentDecoder);
len = Reader.SIGN_NOLENGTH;
}
if (this.componentDecoder == null) {
if (!this.inited) {
synchronized (lock) {
try {
lock.wait();
} catch (Exception e) {
e.printStackTrace();
}
lock.lock();
try {
condition.await();
} catch (Exception e) {
} finally {
lock.unlock();
}
}
}
@@ -92,7 +105,9 @@ public class ArrayDecoder<T> implements Decodeable<Reader, T[]> {
int startPosition = in.position();
while (hasNext(in, member, startPosition, contentLength, first)) {
Reader itemReader = getItemReader(in, member, first);
if (itemReader == null) break;
if (itemReader == null) {
break;
}
result.add(readMemberValue(itemReader, member, localdecoder, first));
first = false;
}
@@ -102,7 +117,7 @@ public class ArrayDecoder<T> implements Decodeable<Reader, T[]> {
}
}
in.readArrayE();
T[] rs = (T[]) Array.newInstance((Class) this.componentClass, result.size());
T[] rs = this.componentArrayFunction.apply(result.size());
return result.toArray(rs);
}
@@ -119,7 +134,9 @@ public class ArrayDecoder<T> implements Decodeable<Reader, T[]> {
}
protected T readMemberValue(Reader in, DeMember member, Decodeable<Reader, T> decoder, boolean first) {
if (in == null) return null;
if (in == null) {
return null;
}
return decoder.convertFrom(in);
}

View File

@@ -6,6 +6,7 @@
package org.redkale.convert;
import java.lang.reflect.*;
import java.util.concurrent.locks.*;
/**
* 数组的序列化操作类 <br>
@@ -29,11 +30,13 @@ public class ArrayEncoder<T> implements Encodeable<Writer, T[]> {
protected final Encodeable<Writer, Object> componentEncoder;
protected final boolean subtypefinal;
protected final boolean subTypeFinal;
protected volatile boolean inited = false;
protected final Object lock = new Object();
private final ReentrantLock lock = new ReentrantLock();
private final Condition condition = lock.newCondition();
public ArrayEncoder(final ConvertFactory factory, final Type type) {
this.type = type;
@@ -48,12 +51,18 @@ public class ArrayEncoder<T> implements Encodeable<Writer, T[]> {
}
factory.register(type, this);
this.componentEncoder = factory.loadEncoder(this.componentType);
if (componentEncoder == null) {
throw new ConvertException("ArrayEncoder init componentEncoder error, componentType = " + this.componentType);
}
this.anyEncoder = factory.getAnyEncoder();
this.subtypefinal = (this.componentType instanceof Class) && Modifier.isFinal(((Class) this.componentType).getModifiers());
this.subTypeFinal = (this.componentType instanceof Class) && Modifier.isFinal(((Class) this.componentType).getModifiers());
} finally {
inited = true;
synchronized (lock) {
lock.notifyAll();
lock.lock();
try {
condition.signalAll();
} finally {
lock.unlock();
}
}
}
@@ -74,23 +83,26 @@ public class ArrayEncoder<T> implements Encodeable<Writer, T[]> {
out.writeArrayE();
return;
}
if (this.componentEncoder == null) {
Encodeable<Writer, Object> itemEncoder = this.componentEncoder;
if (itemEncoder == null) {
if (!this.inited) {
synchronized (lock) {
try {
lock.wait();
} catch (Exception e) {
e.printStackTrace();
}
lock.lock();
try {
condition.await();
} catch (Exception e) {
} finally {
lock.unlock();
}
itemEncoder = this.componentEncoder;
}
}
Encodeable<Writer, Object> itemEncoder = this.componentEncoder;
if (subtypefinal) {
if (subTypeFinal) {
if (out.writeArrayB(value.length, this, itemEncoder, value) < 0) {
for (int i = 0;; i++) {
writeMemberValue(out, member, itemEncoder, value[i], i);
if (i == iMax) break;
if (i == iMax) {
break;
}
out.writeArrayMark();
}
}
@@ -99,8 +111,10 @@ public class ArrayEncoder<T> implements Encodeable<Writer, T[]> {
final Type comp = this.componentType;
for (int i = 0;; i++) {
Object v = value[i];
writeMemberValue(out, member, ((v != null && (v.getClass() == comp || out.specify() == comp)) ? itemEncoder : anyEncoder), v, i);
if (i == iMax) break;
writeMemberValue(out, member, ((v != null && (v.getClass() == comp || out.specificObjectType() == comp)) ? itemEncoder : anyEncoder), v, i);
if (i == iMax) {
break;
}
out.writeArrayMark();
}
}
@@ -122,6 +136,11 @@ public class ArrayEncoder<T> implements Encodeable<Writer, T[]> {
return type;
}
@Override
public boolean specifyable() {
return false;
}
public Type getComponentType() {
return componentType;
}
@@ -129,5 +148,4 @@ public class ArrayEncoder<T> implements Encodeable<Writer, T[]> {
public Encodeable<Writer, Object> getComponentEncoder() {
return componentEncoder;
}
}

View File

@@ -5,10 +5,10 @@
*/
package org.redkale.convert;
import org.redkale.util.Creator;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.*;
import java.util.*;
import java.util.concurrent.locks.*;
import org.redkale.util.Creator;
/**
* Collection的反序列化操作类 <br>
@@ -33,7 +33,9 @@ public class CollectionDecoder<T> implements Decodeable<Reader, Collection<T>> {
protected volatile boolean inited = false;
protected final Object lock = new Object();
private final ReentrantLock lock = new ReentrantLock();
private final Condition condition = lock.newCondition();
public CollectionDecoder(final ConvertFactory factory, final Type type) {
this.type = type;
@@ -54,8 +56,11 @@ public class CollectionDecoder<T> implements Decodeable<Reader, Collection<T>> {
}
} finally {
inited = true;
synchronized (lock) {
lock.notifyAll();
lock.lock();
try {
condition.signalAll();
} finally {
lock.unlock();
}
}
}
@@ -80,19 +85,21 @@ public class CollectionDecoder<T> implements Decodeable<Reader, Collection<T>> {
byte[] typevals = new byte[1];
int len = in.readArrayB(member, typevals, componentDecoder);
int contentLength = -1;
if (len == Reader.SIGN_NULL) return null;
if (len == Reader.SIGN_NULL) {
return null;
}
if (len == Reader.SIGN_NOLENBUTBYTES) {
contentLength = in.readMemberContentLength(member, componentDecoder);
len = Reader.SIGN_NOLENGTH;
}
if (this.componentDecoder == null) {
if (!this.inited) {
synchronized (lock) {
try {
lock.wait();
} catch (Exception e) {
e.printStackTrace();
}
lock.lock();
try {
condition.await();
} catch (Exception e) {
} finally {
lock.unlock();
}
}
}
@@ -103,7 +110,9 @@ public class CollectionDecoder<T> implements Decodeable<Reader, Collection<T>> {
int startPosition = in.position();
while (hasNext(in, member, startPosition, contentLength, first)) {
Reader itemReader = getItemReader(in, member, first);
if (itemReader == null) break;
if (itemReader == null) {
break;
}
result.add(readMemberValue(itemReader, member, localdecoder, first));
first = false;
}
@@ -129,7 +138,9 @@ public class CollectionDecoder<T> implements Decodeable<Reader, Collection<T>> {
}
protected T readMemberValue(Reader in, DeMember member, Decodeable<Reader, T> decoder, boolean first) {
if (in == null) return null;
if (in == null) {
return null;
}
return decoder.convertFrom(in);
}

View File

@@ -7,6 +7,7 @@ package org.redkale.convert;
import java.lang.reflect.*;
import java.util.Collection;
import java.util.concurrent.locks.*;
/**
* Collection的序列化操作类 <br>
@@ -27,7 +28,9 @@ public class CollectionEncoder<T> implements Encodeable<Writer, Collection<T>> {
protected volatile boolean inited = false;
protected final Object lock = new Object();
private final ReentrantLock lock = new ReentrantLock();
private final Condition condition = lock.newCondition();
public CollectionEncoder(final ConvertFactory factory, final Type type) {
this.type = type;
@@ -44,8 +47,11 @@ public class CollectionEncoder<T> implements Encodeable<Writer, Collection<T>> {
}
} finally {
inited = true;
synchronized (lock) {
lock.notifyAll();
lock.lock();
try {
condition.signalAll();
} finally {
lock.unlock();
}
}
}
@@ -67,21 +73,25 @@ public class CollectionEncoder<T> implements Encodeable<Writer, Collection<T>> {
}
if (this.componentEncoder == null) {
if (!this.inited) {
synchronized (lock) {
try {
lock.wait();
} catch (Exception e) {
e.printStackTrace();
}
lock.lock();
try {
condition.await();
} catch (Exception e) {
} finally {
lock.unlock();
}
}
}
if (out.writeArrayB(value.size(), this, componentEncoder, value) < 0) {
boolean first = true;
for (Object v : value) {
if (!first) out.writeArrayMark();
if (!first) {
out.writeArrayMark();
}
writeMemberValue(out, member, v, first);
if (first) first = false;
if (first) {
first = false;
}
}
}
out.writeArrayE();
@@ -96,6 +106,11 @@ public class CollectionEncoder<T> implements Encodeable<Writer, Collection<T>> {
return type;
}
@Override
public boolean specifyable() {
return false;
}
@Override
public String toString() {
return this.getClass().getSimpleName() + "{componentType:" + this.type + ", encoder:" + this.componentEncoder + "}";

View File

@@ -36,20 +36,42 @@ public abstract class Convert<R extends Reader, W extends Writer> {
return writer;
}
protected <S extends W> S fieldFunc(S writer, BiFunction<Attribute, Object, Object> objFieldFunc, Function<Object, ConvertField[]> objExtFunc) {
protected <S extends W> S fieldFunc(S writer, BiFunction<Attribute, Object, Object> objFieldFunc, BiFunction<Object, Object, Object> mapFieldFunc, Function<Object, ConvertField[]> objExtFunc) {
writer.mapFieldFunc = mapFieldFunc;
writer.objFieldFunc = objFieldFunc;
writer.objExtFunc = objExtFunc;
return writer;
}
public abstract Convert<R, W> newConvert(final BiFunction<Attribute, Object, Object> objFieldFunc);
public Convert<R, W> newConvert(BiFunction<Attribute, Object, Object> objFieldFunc) {
return newConvert(objFieldFunc, null, null);
}
public abstract Convert<R, W> newConvert(final BiFunction<Attribute, Object, Object> objFieldFunc, Function<Object, ConvertField[]> objExtFunc);
public Convert<R, W> newConvert(BiFunction<Attribute, Object, Object> objFieldFunc, BiFunction<Object, Object, Object> mapFieldFunc) {
return newConvert(objFieldFunc, mapFieldFunc, null);
}
public Convert<R, W> newConvert(BiFunction<Attribute, Object, Object> objFieldFunc, Function<Object, ConvertField[]> objExtFunc) {
return newConvert(objFieldFunc, null, objExtFunc);
}
public abstract Convert<R, W> newConvert(BiFunction<Attribute, Object, Object> objFieldFunc, BiFunction<Object, Object, Object> mapFieldFunc, Function<Object, ConvertField[]> objExtFunc);
public abstract boolean isBinary();
public abstract R pollReader();
public abstract void offerReader(final R reader);
//返回的Writer子类必须实现ByteTuple接口
public abstract W pollWriter();
public abstract void offerWriter(final W write);
public abstract <T> T convertFrom(final Type type, final byte[] bytes);
public abstract <T> T convertFrom(final Type type, final R reader);
//@since 2.2.0
public abstract <T> T convertFrom(final Type type, final byte[] bytes, final int offset, final int length);

View File

@@ -0,0 +1,70 @@
/*
*/
package org.redkale.convert;
import java.lang.annotation.*;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.*;
/**
* 依附在setter、getter方法、字段进行简单的配置 <br>
* 优先使用coder字段
*
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
* @since 2.7.0
*/
@Inherited
@Documented
@Target({METHOD, FIELD})
@Retention(RUNTIME)
@Repeatable(ConvertCoder.ConvertCoders.class)
public @interface ConvertCoder {
/**
* 需要指定的字段类型指定了coder字段值则可以不设置此字段
*
* @return 字段类名
*/
Class column() default Object.class;
/**
* 序列化定制化的 Encodeable
*
* @return Encodeable 类
*/
Class<? extends Encodeable> encoder() default Encodeable.class;
/**
* 反序列化定制化的 Decodeable
*
* @return Decodeable 类
*/
Class<? extends Decodeable> decoder() default Decodeable.class;
/**
* 解析/序列化定制化的TYPE
*
* @return JSON or BSON or ALL
*/
ConvertType type() default ConvertType.ALL;
/**
* ConvertCoder 的多用类
*
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
*/
@Inherited
@Documented
@Target({METHOD, FIELD})
@Retention(RUNTIME)
public static @interface ConvertCoders {
ConvertCoder[] value();
}
}

View File

@@ -0,0 +1,28 @@
/*
* Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
* Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
*/
package org.redkale.convert;
import java.lang.annotation.*;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* 用于枚举类序列化的字段名<br>
*
*
* <p>
* 详情见: https://redkale.org
*
* @author zhangjx
* @since 2.8.0
*/
@Inherited
@Documented
@Target({TYPE})
@Retention(RUNTIME)
public @interface ConvertEnumValue {
String value();
}

View File

@@ -4,6 +4,8 @@
*/
package org.redkale.convert;
import org.redkale.util.RedkaleException;
/**
* 序列化自定义异常类
*
@@ -12,7 +14,7 @@ package org.redkale.convert;
*
* @author zhangjx
*/
public class ConvertException extends RuntimeException {
public class ConvertException extends RedkaleException {
public ConvertException() {
super();

File diff suppressed because it is too large Load Diff

View File

@@ -19,18 +19,18 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
* public String getName();
* }
*
*
*
* public class OneImpl implements OneEntity {
* private String name;
* public String getName(){return name;}
* public void setName(String name){this.name=name;}
* }
*
*
*
* String json = "{'name':'hello'}";
* OneEntity one = JsonConvert.root.convertFrom(OneEntity.class, json);
* OneEntity one = JsonConvert.root().convertFrom(OneEntity.class, json);
* //one instanceof OneImpl
*
*
* </pre></blockquote>
* <p>
* 详情见: https://redkale.org
@@ -38,7 +38,7 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
* @author zhangjx
* @since 2.5.0
*/
@Inherited
//一定不能标记Inherited
@Documented
@Target({TYPE})
@Retention(RUNTIME)
@@ -49,5 +49,12 @@ public @interface ConvertImpl {
*
* @return String
*/
Class value();
Class value() default Object.class;
/**
* 实现类的集合
*
* @return Class[]
*/
Class[] types() default {};
}

View File

@@ -19,6 +19,7 @@ public enum ConvertType {
BSON(2),
PROTOBUF(64),
PROTOBUF_JSON(64 + 1),
PROTOBUF_BSON(64 + 2),
DIY(256),
ALL(1023);

View File

@@ -6,9 +6,10 @@
package org.redkale.convert;
import java.lang.reflect.*;
import javax.persistence.Column;
import org.redkale.annotation.Comment;
import org.redkale.persistence.Column;
import org.redkale.source.FilterColumn;
import org.redkale.util.*;
import org.redkale.util.Attribute;
/**
* 字段的反序列化操作类
@@ -88,26 +89,26 @@ public final class DeMember<R extends Reader, T, F> {
this.decoder = decoder;
}
public static <R extends Reader, T, F> DeMember<R, T, F> create(final ConvertFactory factory, final Class<T> clazz, final String fieldname) {
public static <R extends Reader, T, F> DeMember<R, T, F> create(final ConvertFactory factory, final Class<T> clazz, final String fieldName) {
try {
Field field = clazz.getDeclaredField(fieldname);
Field field = clazz.getDeclaredField(fieldName);
return new DeMember<>(Attribute.create(field), factory.loadDecoder(field.getGenericType()), field, null);
} catch (Exception e) {
throw new RuntimeException(e);
throw new ConvertException(e);
}
}
public static <R extends Reader, T, F> DeMember<R, T, F> create(final ConvertFactory factory, final Class<T> clazz, final String fieldname, final Class<F> fieldtype) {
public static <R extends Reader, T, F> DeMember<R, T, F> create(final ConvertFactory factory, final Class<T> clazz, final String fieldName, final Class<F> fieldType) {
try {
Field field = clazz.getDeclaredField(fieldname);
return new DeMember<>(Attribute.create(clazz, fieldname, fieldtype), factory.loadDecoder(fieldtype), field, null);
Field field = clazz.getDeclaredField(fieldName);
return new DeMember<>(Attribute.create(clazz, fieldName, fieldType), factory.loadDecoder(fieldType), field, null);
} catch (Exception e) {
throw new RuntimeException(e);
throw new ConvertException(e);
}
}
public static <R extends Reader, T, F> DeMember<R, T, F> create(final Attribute<T, F> attribute, final ConvertFactory factory, final Class<F> fieldtype) {
return new DeMember<>(attribute, factory.loadDecoder(fieldtype), null, null);
public static <R extends Reader, T, F> DeMember<R, T, F> create(final Attribute<T, F> attribute, final ConvertFactory factory, final Class<F> fieldType) {
return new DeMember<>(attribute, factory.loadDecoder(fieldType), null, null);
}
public final boolean accepts(String name) {
@@ -155,17 +156,29 @@ public final class DeMember<R extends Reader, T, F> {
}
public int compareTo(boolean fieldSort, DeMember<R, T, F> o) {
if (o == null) return -1;
if (this.position != o.position) return (this.position == 0 ? Integer.MAX_VALUE : this.position) - (o.position == 0 ? Integer.MAX_VALUE : o.position);
if (this.index != o.index) return (this.index == 0 ? Integer.MAX_VALUE : this.index) - (o.index == 0 ? Integer.MAX_VALUE : o.index);
if (this.index != 0) throw new RuntimeException("fields (" + attribute.field() + ", " + o.attribute.field() + ") have same ConvertColumn.index(" + this.index + ") in " + attribute.declaringClass());
if (o == null) {
return -1;
}
if (this.position != o.position) {
return (this.position == 0 ? Integer.MAX_VALUE : this.position) - (o.position == 0 ? Integer.MAX_VALUE : o.position);
}
if (this.index != o.index) {
return (this.index == 0 ? Integer.MAX_VALUE : this.index) - (o.index == 0 ? Integer.MAX_VALUE : o.index);
}
if (this.index != 0) {
throw new ConvertException("fields (" + attribute.field() + ", " + o.attribute.field() + ") have same ConvertColumn.index(" + this.index + ") in " + attribute.declaringClass());
}
return fieldSort ? this.attribute.field().compareTo(o.attribute.field()) : 0;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (!(obj instanceof DeMember)) return false;
if (this == obj) {
return true;
}
if (!(obj instanceof DeMember)) {
return false;
}
DeMember other = (DeMember) obj;
return compareTo(true, other) == 0;
}

View File

@@ -6,9 +6,10 @@
package org.redkale.convert;
import java.lang.reflect.*;
import javax.persistence.Column;
import org.redkale.annotation.Comment;
import org.redkale.persistence.Column;
import org.redkale.source.FilterColumn;
import org.redkale.util.*;
import org.redkale.util.Attribute;
/**
* 字段的序列化操作类
@@ -104,7 +105,7 @@ public final class EnMember<W extends Writer, T, F> {
Field field = clazz.getDeclaredField(fieldname);
return new EnMember<>(Attribute.create(field), factory.loadEncoder(field.getGenericType()), field, null);
} catch (Exception e) {
throw new RuntimeException(e);
throw new ConvertException(e);
}
}
@@ -113,7 +114,7 @@ public final class EnMember<W extends Writer, T, F> {
Field field = clazz.getDeclaredField(fieldname);
return new EnMember<>(Attribute.create(clazz, fieldname, fieldtype), factory.loadEncoder(fieldtype), field, null);
} catch (Exception e) {
throw new RuntimeException(e);
throw new ConvertException(e);
}
}
@@ -174,17 +175,29 @@ public final class EnMember<W extends Writer, T, F> {
}
public int compareTo(boolean fieldSort, EnMember<W, T, F> o) {
if (o == null) return -1;
if (this.position != o.position) return (this.position == 0 ? Integer.MAX_VALUE : this.position) - (o.position == 0 ? Integer.MAX_VALUE : o.position);
if (this.index != o.index) return (this.index == 0 ? Integer.MAX_VALUE : this.index) - (o.index == 0 ? Integer.MAX_VALUE : o.index);
if (this.index != 0) throw new RuntimeException("fields (" + attribute.field() + ", " + o.attribute.field() + ") have same ConvertColumn.index(" + this.index + ") in " + attribute.declaringClass());
if (o == null) {
return -1;
}
if (this.position != o.position) {
return (this.position == 0 ? Integer.MAX_VALUE : this.position) - (o.position == 0 ? Integer.MAX_VALUE : o.position);
}
if (this.index != o.index) {
return (this.index == 0 ? Integer.MAX_VALUE : this.index) - (o.index == 0 ? Integer.MAX_VALUE : o.index);
}
if (this.index != 0) {
throw new ConvertException("fields (" + attribute.field() + ", " + o.attribute.field() + ") have same ConvertColumn.index(" + this.index + ") in " + attribute.declaringClass());
}
return fieldSort ? this.attribute.field().compareTo(o.attribute.field()) : 0;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (!(obj instanceof EnMember)) return false;
if (this == obj) {
return true;
}
if (!(obj instanceof EnMember)) {
return false;
}
EnMember other = (EnMember) obj;
return compareTo(true, other) == 0;
}

View File

@@ -5,10 +5,10 @@
*/
package org.redkale.convert;
import org.redkale.util.Creator;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.*;
import java.util.*;
import java.util.concurrent.locks.*;
import org.redkale.util.Creator;
/**
* Map的反序列化操作类 <br>
@@ -37,7 +37,9 @@ public class MapDecoder<K, V> implements Decodeable<Reader, Map<K, V>> {
protected volatile boolean inited = false;
protected final Object lock = new Object();
private final ReentrantLock lock = new ReentrantLock();
private final Condition condition = lock.newCondition();
public MapDecoder(final ConvertFactory factory, final Type type) {
this.type = type;
@@ -68,8 +70,11 @@ public class MapDecoder<K, V> implements Decodeable<Reader, Map<K, V>> {
}
} finally {
inited = true;
synchronized (lock) {
lock.notifyAll();
lock.lock();
try {
condition.signalAll();
} finally {
lock.unlock();
}
}
}
@@ -96,19 +101,21 @@ public class MapDecoder<K, V> implements Decodeable<Reader, Map<K, V>> {
public Map<K, V> convertFrom(Reader in, DeMember member) {
if (this.keyDecoder == null || this.valueDecoder == null) {
if (!this.inited) {
synchronized (lock) {
try {
lock.wait();
} catch (Exception e) {
e.printStackTrace();
}
lock.lock();
try {
condition.await();
} catch (Exception e) {
} finally {
lock.unlock();
}
}
}
byte[] typevals = new byte[2];
int len = in.readMapB(member, typevals, this.keyDecoder, this.valueDecoder);
int contentLength = -1;
if (len == Reader.SIGN_NULL) return null;
if (len == Reader.SIGN_NULL) {
return null;
}
if (len == Reader.SIGN_NOLENBUTBYTES) {
contentLength = in.readMemberContentLength(member, null);
len = Reader.SIGN_NOLENGTH;
@@ -121,7 +128,9 @@ public class MapDecoder<K, V> implements Decodeable<Reader, Map<K, V>> {
int startPosition = in.position();
while (hasNext(in, member, startPosition, contentLength, first)) {
Reader entryReader = getEntryReader(in, member, first);
if (entryReader == null) break;
if (entryReader == null) {
break;
}
K key = readKeyMember(entryReader, member, kdecoder, first);
entryReader.readBlank();
V value = readValueMember(entryReader, member, vdecoder, first);

View File

@@ -5,9 +5,10 @@
*/
package org.redkale.convert;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Map;
import java.lang.reflect.*;
import java.util.*;
import java.util.concurrent.locks.*;
import java.util.function.BiFunction;
/**
* Map的序列化操作类
@@ -30,7 +31,11 @@ public class MapEncoder<K, V> implements Encodeable<Writer, Map<K, V>> {
protected volatile boolean inited = false;
protected final Object lock = new Object();
private final ReentrantLock lock = new ReentrantLock();
private final Condition condition = lock.newCondition();
protected final Set<String> ignoreMapColumns;
public MapEncoder(final ConvertFactory factory, final Type type) {
this.type = type;
@@ -43,10 +48,19 @@ public class MapEncoder<K, V> implements Encodeable<Writer, Map<K, V>> {
this.keyEncoder = factory.getAnyEncoder();
this.valueEncoder = factory.getAnyEncoder();
}
factory.ignoreMapColumnLock.lock();
try {
this.ignoreMapColumns = factory.ignoreMapColumns.isEmpty() ? null : new HashSet<>(factory.ignoreMapColumns);
} finally {
factory.ignoreMapColumnLock.unlock();
}
} finally {
inited = true;
synchronized (lock) {
lock.notifyAll();
lock.lock();
try {
condition.signalAll();
} finally {
lock.unlock();
}
}
}
@@ -65,21 +79,31 @@ public class MapEncoder<K, V> implements Encodeable<Writer, Map<K, V>> {
if (this.keyEncoder == null || this.valueEncoder == null) {
if (!this.inited) {
synchronized (lock) {
try {
lock.wait();
} catch (Exception e) {
e.printStackTrace();
}
lock.lock();
try {
condition.await();
} catch (Exception e) {
} finally {
lock.unlock();
}
}
}
Set<String> ignoreColumns = this.ignoreMapColumns;
BiFunction<K, V, V> mapFieldFunc = (BiFunction) out.mapFieldFunc;
if (out.writeMapB(values.size(), (Encodeable) keyEncoder, (Encodeable) valueEncoder, value) < 0) {
boolean first = true;
for (Map.Entry<K, V> en : values.entrySet()) {
if (!first) out.writeArrayMark();
writeMemberValue(out, member, en.getKey(), en.getValue(), first);
if (first) first = false;
if (ignoreColumns != null && ignoreColumns.contains(en.getKey())) {
continue;
}
V v = mapFieldFunc == null ? en.getValue() : mapFieldFunc.apply(en.getKey(), en.getValue());
if (!first) {
out.writeArrayMark();
}
writeMemberValue(out, member, en.getKey(), v, first);
if (first) {
first = false;
}
}
}
out.writeMapE();
@@ -96,6 +120,11 @@ public class MapEncoder<K, V> implements Encodeable<Writer, Map<K, V>> {
return type;
}
@Override
public boolean specifyable() {
return false;
}
public Type getKeyType() {
return keyEncoder == null ? null : keyEncoder.getType();
}

View File

@@ -5,9 +5,9 @@
*/
package org.redkale.convert;
import org.redkale.util.Creator;
import java.lang.reflect.*;
import java.util.*;
import java.util.concurrent.locks.*;
import org.redkale.convert.ext.StringSimpledCoder;
import org.redkale.util.*;
@@ -34,11 +34,17 @@ public class ObjectDecoder<R extends Reader, T> implements Decodeable<R, T> {
protected DeMember[] members;
protected Map<String, DeMember> memberFieldMap;
protected Map<Integer, DeMember> memberTagMap;
protected ConvertFactory factory;
protected volatile boolean inited = false;
protected final Object lock = new Object();
private final ReentrantLock lock = new ReentrantLock();
private final Condition condition = lock.newCondition();
protected ObjectDecoder(Type type) {
this.type = ((type instanceof Class) && ((Class) type).isInterface()) ? Object.class : type;
@@ -86,49 +92,80 @@ public class ObjectDecoder<R extends Reader, T> implements Decodeable<R, T> {
}
if (!clazz.isInterface() && !Modifier.isAbstract(clazz.getModifiers())) {
this.creator = factory.loadCreator(clazz);
if (this.creator == null) throw new ConvertException("Cannot create a creator for " + clazz);
if (this.creator == null) {
throw new ConvertException("Cannot create a creator for " + clazz);
}
}
final Set<DeMember> list = new LinkedHashSet();
final String[] cps = ObjectEncoder.findConstructorProperties(this.creator);
try {
ConvertColumnEntry ref;
ConvertFactory colFactory;
RedkaleClassLoader.putReflectionPublicFields(clazz.getName());
for (final Field field : clazz.getFields()) {
if (Modifier.isStatic(field.getModifiers())) continue;
if (factory.isConvertDisabled(field)) continue;
if (Modifier.isStatic(field.getModifiers())) {
continue;
}
if (factory.isConvertDisabled(field)) {
continue;
}
ref = factory.findRef(clazz, field);
if (ref != null && ref.ignore()) continue;
if (ref != null && ref.ignore()) {
continue;
}
ConvertSmallString small = field.getAnnotation(ConvertSmallString.class);
colFactory = factory.columnFactory(field.getType(), field.getAnnotationsByType(ConvertCoder.class), false);
Decodeable<R, ?> fieldCoder;
if (small != null && field.getType() == String.class) {
fieldCoder = StringSimpledCoder.SmallStringSimpledCoder.instance;
} else {
fieldCoder = factory.findFieldCoder(clazz, field.getName());
fieldCoder = colFactory.findFieldCoder(clazz, field.getName());
}
if (fieldCoder == null) {
Type t = TypeToken.createClassType(TypeToken.getGenericType(field.getGenericType(), this.type), this.type);
fieldCoder = factory.loadDecoder(t);
fieldCoder = colFactory.loadDecoder(t);
}
DeMember member = new DeMember(ObjectEncoder.createAttribute(colFactory, type, clazz, field, null, null), fieldCoder, field, null);
if (ref != null) {
member.index = ref.getIndex();
}
DeMember member = new DeMember(ObjectEncoder.createAttribute(factory, type, clazz, field, null, null), fieldCoder, field, null);
if (ref != null) member.index = ref.getIndex();
list.add(member);
}
final boolean reversible = factory.isReversible();
RedkaleClassLoader.putReflectionPublicMethods(clazz.getName());
for (final Method method : clazz.getMethods()) {
if (Modifier.isStatic(method.getModifiers())) continue;
if (Modifier.isAbstract(method.getModifiers())) continue;
if (method.isSynthetic()) continue;
if (method.getReturnType() != void.class) continue;
if (method.getParameterCount() != 1) continue;
if (method.getName().length() < 4) continue;
if (!method.getName().startsWith("set")) continue;
if (factory.isConvertDisabled(method)) continue;
if (Modifier.isStatic(method.getModifiers())) {
continue;
}
if (Modifier.isAbstract(method.getModifiers())) {
continue;
}
if (method.isSynthetic()) {
continue;
}
if (method.getParameterCount() != 1) {
continue;
}
if (method.getName().length() < 4) {
continue;
}
if (!method.getName().startsWith("set")) {
continue;
}
//setter不再限制要求void返回类型
// if (method.getReturnType() != void.class && method.getReturnType() != clazz) {
// continue;
// }
if (factory.isConvertDisabled(method)) {
continue;
}
if (reversible && (cps == null || !ObjectEncoder.contains(cps, ConvertFactory.readGetSetFieldName(method)))) {
boolean is = method.getParameterTypes()[0] == boolean.class || method.getParameterTypes()[0] == Boolean.class;
try {
Method getter = clazz.getMethod(method.getName().replaceFirst("set", is ? "is" : "get"));
if (getter.getReturnType() != method.getParameterTypes()[0]) continue;
if (getter.getReturnType() != method.getParameterTypes()[0]) {
continue;
}
} catch (Exception e) {
continue;
}
@@ -137,34 +174,47 @@ public class ObjectDecoder<R extends Reader, T> implements Decodeable<R, T> {
Field f = null;
try {
f = clazz.getDeclaredField(fieldname);
if (f.getType() != method.getParameterTypes()[0]) continue;
if (f.getType() != method.getParameterTypes()[0]) {
continue;
}
} catch (Exception e) {
}
if (f == null) {
boolean is = method.getParameterTypes()[0] == boolean.class || method.getParameterTypes()[0] == Boolean.class;
try {
Method getter = clazz.getMethod(method.getName().replaceFirst("set", is ? "is" : "get"));
if (getter.getReturnType() != method.getParameterTypes()[0]) continue;
if (getter.getReturnType() != method.getParameterTypes()[0]) {
continue;
}
} catch (Exception e) {
}
}
}
ref = factory.findRef(clazz, method);
if (ref != null && ref.ignore()) continue;
if (ref != null && ref.ignore()) {
continue;
}
ConvertSmallString small = method.getAnnotation(ConvertSmallString.class);
Field maybeField = ConvertFactory.readGetSetField(method);
colFactory = factory.columnFactory(method.getParameterTypes()[0], method.getAnnotationsByType(ConvertCoder.class), false);
if (maybeField != null && colFactory == factory) {
colFactory = factory.columnFactory(maybeField.getType(), maybeField.getAnnotationsByType(ConvertCoder.class), false);
}
Decodeable<R, ?> fieldCoder;
if (small != null && method.getReturnType() == String.class) {
if (small != null && method.getParameterTypes()[0] == String.class) {
fieldCoder = StringSimpledCoder.SmallStringSimpledCoder.instance;
} else {
fieldCoder = factory.findFieldCoder(clazz, ConvertFactory.readGetSetFieldName(method));
fieldCoder = colFactory.findFieldCoder(clazz, ConvertFactory.readGetSetFieldName(method));
}
if (fieldCoder == null) {
Type t = TypeToken.createClassType(TypeToken.getGenericType(method.getGenericParameterTypes()[0], this.type), this.type);
fieldCoder = factory.loadDecoder(t);
fieldCoder = colFactory.loadDecoder(t);
}
DeMember member = new DeMember(ObjectEncoder.createAttribute(colFactory, type, clazz, null, null, method), fieldCoder, maybeField, method);
if (ref != null) {
member.index = ref.getIndex();
}
DeMember member = new DeMember(ObjectEncoder.createAttribute(factory, type, clazz, null, null, method), fieldCoder, ConvertFactory.readGetSetField(method), method);
if (ref != null) member.index = ref.getIndex();
list.add(member);
}
if (cps != null) { //可能存在某些构造函数中的字段名不存在setter方法
@@ -176,7 +226,9 @@ public class ObjectDecoder<R extends Reader, T> implements Decodeable<R, T> {
break;
}
}
if (flag) continue;
if (flag) {
continue;
}
//不存在setter方法
try {
Field f = clazz.getDeclaredField(constructorField);
@@ -202,7 +254,9 @@ public class ObjectDecoder<R extends Reader, T> implements Decodeable<R, T> {
Collections.sort(sorts, (a, b) -> a.compareTo(factory.isFieldSort(), b));
Set<Integer> pos = new HashSet<>();
for (DeMember member : sorts) {
if (member.index > 0) pos.add(member.index);
if (member.index > 0) {
pos.add(member.index);
}
}
int pidx = 0;
for (DeMember member : sorts) {
@@ -217,6 +271,12 @@ public class ObjectDecoder<R extends Reader, T> implements Decodeable<R, T> {
this.members = list.toArray(new DeMember[list.size()]);
Arrays.sort(this.members, (a, b) -> a.compareTo(factory.isFieldSort(), b));
this.memberFieldMap = new HashMap<>(this.members.length);
this.memberTagMap = new HashMap<>(this.members.length);
for (DeMember member : this.members) {
this.memberFieldMap.put(member.getAttribute().field(), member);
this.memberTagMap.put(member.getTag(), member);
}
if (cps != null) {
final String[] fields = cps;
@@ -231,24 +291,22 @@ public class ObjectDecoder<R extends Reader, T> implements Decodeable<R, T> {
}
this.creatorConstructorMembers = ms;
}
afterInitDeMember(factory);
} catch (Exception ex) {
throw new ConvertException(ex);
}
} finally {
inited = true;
synchronized (lock) {
lock.notifyAll();
lock.lock();
try {
condition.signalAll();
} finally {
lock.unlock();
}
}
}
protected void initForEachDeMember(ConvertFactory factory, DeMember member) {
}
protected void setTag(DeMember member, int tag) {
member.tag = tag;
}
/**
* 对象格式: [0x1][short字段个数][字段名][字段值]...[0x2]
*
@@ -260,15 +318,19 @@ public class ObjectDecoder<R extends Reader, T> implements Decodeable<R, T> {
public T convertFrom(final R in) {
R objin = objectReader(in);
final String clazz = objin.readObjectB(typeClass);
if (clazz == null) return null;
if (!clazz.isEmpty()) return (T) factory.loadDecoder(factory.getEntityAlias(clazz)).convertFrom(objin);
if (clazz == null) {
return null;
}
if (!clazz.isEmpty()) {
return (T) factory.loadDecoder(factory.getEntityAlias(clazz)).convertFrom(objin);
}
if (!this.inited) {
synchronized (lock) {
try {
lock.wait();
} catch (Exception e) {
e.printStackTrace();
}
lock.lock();
try {
condition.await();
} catch (Exception e) {
} finally {
lock.unlock();
}
}
if (this.creator == null) {
@@ -276,49 +338,57 @@ public class ObjectDecoder<R extends Reader, T> implements Decodeable<R, T> {
throw new ConvertException("[" + typeClass + "] is a interface or abstract class, cannot create it's Creator.");
}
}
DeMember[] memberArray = this.members;
Map<String, DeMember> fieldMap = this.memberFieldMap;
Map<Integer, DeMember> tagMap = this.memberTagMap;
if (this.creatorConstructorMembers == null) { //空构造函数
final T result = this.creator == null ? null : this.creator.create();
boolean first = true;
while (hasNext(objin, first)) {
DeMember member = objin.readFieldName(members);
while (objin.hasNext()) {
DeMember member = objin.readFieldName(memberArray, fieldMap, tagMap);
objin.readBlank();
if (member == null) {
objin.skipValue(); //跳过不存在的属性的值
} else {
readMemberValue(objin, member, result, first);
readDeMemberValue(objin, member, result, first);
}
first = false;
}
objin.readObjectE(typeClass);
return result;
} else { //带参数的构造函数
final DeMember<R, T, ?>[] fields = this.creatorConstructorMembers;
final Object[] constructorParams = new Object[fields.length];
final DeMember<R, T, ?>[] constructorFields = this.creatorConstructorMembers;
final Object[] constructorParams = new Object[constructorFields.length];
final Object[][] otherParams = new Object[this.members.length][2];
int oc = 0;
boolean first = true;
while (hasNext(objin, first)) {
DeMember member = objin.readFieldName(members);
while (objin.hasNext()) {
DeMember member = objin.readFieldName(memberArray, fieldMap, tagMap);
objin.readBlank();
if (member == null) {
objin.skipValue(); //跳过不存在的属性的值
} else {
Object val = readMemberValue(objin, member, first);
Object val = readDeMemberValue(objin, member, first);
boolean flag = true;
for (int i = 0; i < fields.length; i++) {
if (member == fields[i]) {
for (int i = 0; i < constructorFields.length; i++) {
if (member == constructorFields[i]) {
constructorParams[i] = val;
flag = false;
break;
}
}
if (flag) otherParams[oc++] = new Object[]{member.attribute, val};
if (flag) {
otherParams[oc++] = new Object[]{member.attribute, val};
}
}
first = false;
}
objin.readObjectE(typeClass);
if (this.creator == null) return null;
if (this.creator == null) {
return null;
}
final T result = this.creator.create(constructorParams);
for (int i = 0; i < oc; i++) {
((Attribute) otherParams[i][0]).set(result, otherParams[i][1]);
@@ -327,29 +397,69 @@ public class ObjectDecoder<R extends Reader, T> implements Decodeable<R, T> {
}
}
protected R objectReader(R in) {
return in;
//---------------------------------- 可定制方法 ----------------------------------
protected void initForEachDeMember(ConvertFactory factory, DeMember member) {
}
protected void afterInitDeMember(ConvertFactory factory) {
}
protected boolean hasNext(R in, boolean first) {
return in.hasNext();
}
protected Object readMemberValue(R in, DeMember member, boolean first) {
protected R objectReader(R in) {
return in;
}
protected Object readDeMemberValue(R in, DeMember member, boolean first) {
return member.read(in);
}
protected void readMemberValue(R in, DeMember member, T result, boolean first) {
protected void readDeMemberValue(R in, DeMember member, T result, boolean first) {
member.read(in, result);
}
//---------------------------------------------------------------------------------
protected void setTag(DeMember member, int tag) {
member.tag = tag;
}
protected void setIndex(DeMember member, int index) {
member.index = index;
}
protected void setPosition(DeMember member, int position) {
member.position = position;
}
@Override
public Type getType() {
return this.type;
}
public DeMember[] getMembers() {
return Arrays.copyOf(members, members.length);
return members;
}
public DeMember getMember(String fieldName) {
return memberFieldMap.get(fieldName);
}
public Map<String, DeMember> getMemberFieldMap() {
return memberFieldMap;
}
public Map<Integer, DeMember> getMemberTagMap() {
return memberTagMap;
}
public DeMember<R, T, ?>[] getConstructorMembers() {
return creatorConstructorMembers;
}
public Creator<T> getCreator() {
return creator;
}
@Override

View File

@@ -7,6 +7,8 @@ package org.redkale.convert;
import java.lang.reflect.*;
import java.util.*;
import java.util.concurrent.locks.*;
import org.redkale.annotation.ConstructorParameters;
import org.redkale.convert.ext.StringSimpledCoder;
import org.redkale.util.*;
@@ -35,7 +37,9 @@ public class ObjectEncoder<W extends Writer, T> implements Encodeable<W, T> {
protected volatile boolean inited = false;
protected final Object lock = new Object();
private final ReentrantLock lock = new ReentrantLock();
private final Condition condition = lock.newCondition();
protected ObjectEncoder(Type type) {
this.type = type;
@@ -59,7 +63,9 @@ public class ObjectEncoder<W extends Writer, T> implements Encodeable<W, T> {
public void init(final ConvertFactory factory) {
this.factory = factory;
try {
if (type == Object.class) return;
if (type == Object.class) {
return;
}
//if (!(type instanceof Class)) throw new ConvertException("[" + type + "] is no a class");
final Class clazz = this.typeClass;
final Set<EnMember> list = new LinkedHashSet();
@@ -68,44 +74,73 @@ public class ObjectEncoder<W extends Writer, T> implements Encodeable<W, T> {
try {
creator = factory.loadCreator(this.typeClass);
} catch (RuntimeException e) {
if (reversible && !Modifier.isAbstract(this.typeClass.getModifiers())) throw e;
if (reversible && !Modifier.isAbstract(this.typeClass.getModifiers())) {
throw e;
}
}
final String[] cps = creator == null ? null : ObjectEncoder.findConstructorProperties(creator);
try {
ConvertColumnEntry ref;
ConvertFactory colFactory;
RedkaleClassLoader.putReflectionPublicFields(clazz.getName());
for (final Field field : clazz.getFields()) {
if (Modifier.isStatic(field.getModifiers())) continue;
if (factory.isConvertDisabled(field)) continue;
if (Modifier.isStatic(field.getModifiers())) {
continue;
}
if (factory.isConvertDisabled(field)) {
continue;
}
ref = factory.findRef(clazz, field);
if (ref != null && ref.ignore()) continue;
if (ref != null && ref.ignore()) {
continue;
}
ConvertSmallString small = field.getAnnotation(ConvertSmallString.class);
colFactory = factory.columnFactory(field.getType(), field.getAnnotationsByType(ConvertCoder.class), true);
Encodeable<W, ?> fieldCoder;
if (small != null && field.getType() == String.class) {
fieldCoder = StringSimpledCoder.SmallStringSimpledCoder.instance;
} else {
fieldCoder = factory.findFieldCoder(clazz, field.getName());
fieldCoder = colFactory.findFieldCoder(clazz, field.getName());
}
if (fieldCoder == null) {
Type t = TypeToken.createClassType(TypeToken.getGenericType(field.getGenericType(), this.type), this.type);
fieldCoder = factory.loadEncoder(t);
fieldCoder = colFactory.loadEncoder(t);
}
EnMember member = new EnMember(createAttribute(colFactory, type, clazz, field, null, null), fieldCoder, field, null);
if (ref != null) {
member.index = ref.getIndex();
}
EnMember member = new EnMember(createAttribute(factory, type, clazz, field, null, null), fieldCoder, field, null);
if (ref != null) member.index = ref.getIndex();
list.add(member);
}
RedkaleClassLoader.putReflectionPublicMethods(clazz.getName());
for (final Method method : clazz.getMethods()) {
if (Modifier.isStatic(method.getModifiers())) continue;
if (Modifier.isAbstract(method.getModifiers())) continue;
if (method.isSynthetic()) continue;
if (method.getName().equals("getClass")) continue;
if (method.getReturnType() == void.class) continue;
if (method.getParameterCount() != 0) continue;
if (!method.getName().startsWith("is") && !method.getName().startsWith("get") && !Utility.isRecordGetter(clazz, method)) continue;
if (factory.isConvertDisabled(method)) continue;
if (Modifier.isStatic(method.getModifiers())) {
continue;
}
if (Modifier.isAbstract(method.getModifiers())) {
continue;
}
if (method.isSynthetic()) {
continue;
}
if (method.getName().equals("getClass")) {
continue;
}
if (method.getReturnType() == void.class) {
continue;
}
if (method.getParameterCount() != 0) {
continue;
}
if (!(method.getName().startsWith("is") && method.getName().length() > 2)
&& !(method.getName().startsWith("get") && method.getName().length() > 3)
&& !Utility.isRecordGetter(clazz, method)) {
continue;
}
if (factory.isConvertDisabled(method)) {
continue;
}
String convertname = ConvertFactory.readGetSetFieldName(method);
if (reversible && (cps == null || !contains(cps, convertname))) {
boolean is = method.getName().startsWith("is");
@@ -116,27 +151,38 @@ public class ObjectEncoder<W extends Writer, T> implements Encodeable<W, T> {
}
}
ref = factory.findRef(clazz, method);
if (ref != null && ref.ignore()) continue;
if (ref != null && ref.ignore()) {
continue;
}
ConvertSmallString small = method.getAnnotation(ConvertSmallString.class);
if (small == null) {
try {
Field f = clazz.getDeclaredField(convertname);
if (f != null) small = f.getAnnotation(ConvertSmallString.class);
if (f != null) {
small = f.getAnnotation(ConvertSmallString.class);
}
} catch (Exception e) {
}
}
Field maybeField = ConvertFactory.readGetSetField(method);
colFactory = factory.columnFactory(method.getReturnType(), method.getAnnotationsByType(ConvertCoder.class), true);
if (maybeField != null && colFactory == factory) {
colFactory = factory.columnFactory(maybeField.getType(), maybeField.getAnnotationsByType(ConvertCoder.class), true);
}
Encodeable<W, ?> fieldCoder;
if (small != null && method.getReturnType() == String.class) {
fieldCoder = StringSimpledCoder.SmallStringSimpledCoder.instance;
} else {
fieldCoder = factory.findFieldCoder(clazz, ConvertFactory.readGetSetFieldName(method));
fieldCoder = colFactory.findFieldCoder(clazz, ConvertFactory.readGetSetFieldName(method));
}
if (fieldCoder == null) {
Type t = TypeToken.createClassType(TypeToken.getGenericType(method.getGenericReturnType(), this.type), this.type);
fieldCoder = factory.loadEncoder(t);
fieldCoder = colFactory.loadEncoder(t);
}
EnMember member = new EnMember(createAttribute(colFactory, type, clazz, null, method, null), fieldCoder, maybeField, method);
if (ref != null) {
member.index = ref.getIndex();
}
EnMember member = new EnMember(createAttribute(factory, type, clazz, null, method, null), fieldCoder, ConvertFactory.readGetSetField(method), method);
if (ref != null) member.index = ref.getIndex();
list.add(member);
}
List<EnMember> sorts = new ArrayList<>(list);
@@ -150,7 +196,9 @@ public class ObjectEncoder<W extends Writer, T> implements Encodeable<W, T> {
break;
}
}
if (flag) continue;
if (flag) {
continue;
}
//不存在setter方法
try {
Field f = clazz.getDeclaredField(constructorField);
@@ -176,12 +224,16 @@ public class ObjectEncoder<W extends Writer, T> implements Encodeable<W, T> {
}
}
}
if (dissorts.size() != list.size()) sorts = new ArrayList<>(dissorts);
if (dissorts.size() != list.size()) {
sorts = new ArrayList<>(dissorts);
}
}
Collections.sort(sorts, (a, b) -> a.compareTo(factory.isFieldSort(), b));
Set<Integer> pos = new HashSet<>();
for (EnMember member : sorts) {
if (member.index > 0) pos.add(member.index);
if (member.index > 0) {
pos.add(member.index);
}
}
int pidx = 0;
for (EnMember member : sorts) {
@@ -197,24 +249,21 @@ public class ObjectEncoder<W extends Writer, T> implements Encodeable<W, T> {
this.members = list.toArray(new EnMember[list.size()]);
Arrays.sort(this.members, (a, b) -> a.compareTo(factory.isFieldSort(), b));
afterInitEnMember(factory);
} catch (Exception ex) {
throw new ConvertException("ObjectEncoder init type=" + this.type + " error", ex);
}
} finally {
inited = true;
synchronized (lock) {
lock.notifyAll();
lock.lock();
try {
condition.signalAll();
} finally {
lock.unlock();
}
}
}
protected void initForEachEnMember(ConvertFactory factory, EnMember member) {
}
protected void setTag(EnMember member, int tag) {
member.tag = tag;
}
@Override
public void convertTo(W out, T value) {
if (value == null) {
@@ -222,17 +271,19 @@ public class ObjectEncoder<W extends Writer, T> implements Encodeable<W, T> {
return;
}
if (!this.inited) {
synchronized (lock) {
try {
lock.wait();
} catch (Exception e) {
e.printStackTrace();
}
lock.lock();
try {
condition.await();
} catch (Exception e) {
} finally {
lock.unlock();
}
}
if (value.getClass() != this.typeClass && !this.type.equals(out.specify())) {
if (value.getClass() != this.typeClass && !this.type.equals(out.specificObjectType())) {
final Class clz = value.getClass();
if (out.needWriteClassName()) out.writeClassName(factory.getEntityAlias(clz));
if (out.needWriteClassName()) {
out.writeClassName(factory.getEntityAlias(clz));
}
factory.loadEncoder(clz).convertTo(out, value);
return;
}
@@ -248,7 +299,9 @@ public class ObjectEncoder<W extends Writer, T> implements Encodeable<W, T> {
if (extFields != null) {
Encodeable<W, ?> anyEncoder = factory.getAnyEncoder();
for (ConvertField en : extFields) {
if (en == null) continue;
if (en == null) {
continue;
}
maxPosition++;
objout.writeObjectField(en.getName(), en.getType(), Math.max(en.getPosition(), maxPosition), anyEncoder, en.getValue());
}
@@ -258,10 +311,30 @@ public class ObjectEncoder<W extends Writer, T> implements Encodeable<W, T> {
objout.writeObjectE(value);
}
//---------------------------------- 可定制方法 ----------------------------------
protected void initForEachEnMember(ConvertFactory factory, EnMember member) {
}
protected void afterInitEnMember(ConvertFactory factory) {
}
protected W objectWriter(W out, T value) {
return out;
}
//---------------------------------------------------------------------------------
protected void setTag(EnMember member, int tag) {
member.tag = tag;
}
protected void setIndex(EnMember member, int index) {
member.index = index;
}
protected void setPosition(EnMember member, int position) {
member.position = position;
}
@Override
public Type getType() {
return this.type;
@@ -272,7 +345,7 @@ public class ObjectEncoder<W extends Writer, T> implements Encodeable<W, T> {
}
public EnMember[] getMembers() {
return Arrays.copyOf(members, members.length);
return members;
}
@Override
@@ -280,66 +353,32 @@ public class ObjectEncoder<W extends Writer, T> implements Encodeable<W, T> {
return "ObjectEncoder{" + "type=" + type + ", members=" + Arrays.toString(members) + '}';
}
//
// static Type makeGenericType(final Type type, final Type[] virGenericTypes, final Type[] realGenericTypes) {
// if (type instanceof Class) { //e.g. String
// return type;
// } else if (type instanceof ParameterizedType) { //e.g. Map<String, String>
// final ParameterizedType pt = (ParameterizedType) type;
// Type[] paramTypes = pt.getActualTypeArguments();
// final Type[] newTypes = new Type[paramTypes.length];
// int count = 0;
// for (int i = 0; i < newTypes.length; i++) {
// newTypes[i] = makeGenericType(paramTypes[i], virGenericTypes, realGenericTypes);
// if (paramTypes[i] == newTypes[i]) count++;
// }
// if (count == paramTypes.length) return pt;
// return new ParameterizedType() {
//
// @Override
// public Type[] getActualTypeArguments() {
// return newTypes;
// }
//
// @Override
// public Type getRawType() {
// return pt.getRawType();
// }
//
// @Override
// public Type getOwnerType() {
// return pt.getOwnerType();
// }
//
// };
// }
// if (realGenericTypes == null) return type;
// if (type instanceof WildcardType) { // e.g. <? extends Serializable>
// final WildcardType wt = (WildcardType) type;
// for (Type f : wt.getUpperBounds()) {
// for (int i = 0; i < virGenericTypes.length; i++) {
// if (virGenericTypes[i] == f) return realGenericTypes.length == 0 ? Object.class : realGenericTypes[i];
// }
// }
// } else if (type instanceof TypeVariable) { // e.g. <? extends E>
// for (int i = 0; i < virGenericTypes.length; i++) {
// if (virGenericTypes[i] == type) return i >= realGenericTypes.length ? Object.class : realGenericTypes[i];
// }
// }
// return type;
// }
static boolean contains(String[] values, String value) {
for (String str : values) {
if (str.equals(value)) return true;
if (str.equals(value)) {
return true;
}
}
return false;
}
static String[] findConstructorProperties(Creator creator) {
if (creator == null) return null;
if (creator == null) {
return null;
}
try {
ConstructorParameters cps = creator.getClass().getMethod("create", Object[].class).getAnnotation(ConstructorParameters.class);
return cps == null ? null : cps.value();
Method method = creator.getClass().getMethod("create", Object[].class);
ConstructorParameters cps = method.getAnnotation(ConstructorParameters.class);
String[] vals = null;
if (cps != null) {
vals = cps.value();
} else {
org.redkale.util.ConstructorParameters cps2 = method.getAnnotation(org.redkale.util.ConstructorParameters.class);
if (cps2 != null) {
vals = cps2.value();
}
}
return vals;
} catch (Exception e) {
return null;
}
@@ -371,8 +410,12 @@ public class ObjectEncoder<W extends Writer, T> implements Encodeable<W, T> {
}
fieldalias = ref == null || ref.name().isEmpty() ? mfieldname : ref.name();
}
return Attribute.create(realType, clazz, fieldalias, null, field, getter, setter, null);
Type subclass = realType;
if ((realType instanceof Class) && field != null && getter == null && setter == null) {
//修复父类含public fieldsubclass不传父类会导致java.lang.NoSuchFieldError的bug
subclass = field.getDeclaringClass();
}
return Attribute.create(subclass, clazz, fieldalias, null, field, getter, setter, null);
}
}

View File

@@ -6,7 +6,8 @@
package org.redkale.convert;
import java.lang.reflect.*;
import java.util.*;
import java.util.Optional;
import java.util.concurrent.locks.*;
/**
* Optional 的SimpledCoder实现
@@ -30,7 +31,9 @@ public class OptionalCoder<R extends Reader, W extends Writer, T> extends Simple
protected volatile boolean inited = false;
private final Object lock = new Object();
private final ReentrantLock lock = new ReentrantLock();
private final Condition condition = lock.newCondition();
@SuppressWarnings("unchecked")
public OptionalCoder(final ConvertFactory factory, final Type type) {
@@ -61,8 +64,11 @@ public class OptionalCoder<R extends Reader, W extends Writer, T> extends Simple
}
} finally {
inited = true;
synchronized (lock) {
lock.notifyAll();
lock.lock();
try {
condition.signalAll();
} finally {
lock.unlock();
}
}
}
@@ -75,12 +81,12 @@ public class OptionalCoder<R extends Reader, W extends Writer, T> extends Simple
}
if (this.encoder == null) {
if (!this.inited) {
synchronized (lock) {
try {
lock.wait();
} catch (Exception e) {
e.printStackTrace();
}
lock.lock();
try {
condition.await();
} catch (Exception e) {
} finally {
lock.unlock();
}
}
}
@@ -91,12 +97,12 @@ public class OptionalCoder<R extends Reader, W extends Writer, T> extends Simple
public Optional<T> convertFrom(R in) {
if (this.decoder == null) {
if (!this.inited) {
synchronized (lock) {
try {
lock.wait();
} catch (Exception e) {
e.printStackTrace();
}
lock.lock();
try {
condition.await();
} catch (Exception e) {
} finally {
lock.unlock();
}
}
}

View File

@@ -5,6 +5,8 @@
*/
package org.redkale.convert;
import java.util.Map;
/**
* 反序列化的数据读取流
*
@@ -28,6 +30,13 @@ public abstract class Reader {
public static final short SIGN_NOLENBUTBYTES = -3; //目前只适合于protobuf的boolean[]...double[]类型
/**
* 设置Reader的内容通常结合对象池使用
*
* @param content 内容
*/
public abstract void prepare(byte[] content);
/**
* 是否还存在下个元素或字段 <br>
* 注意: 主要用于Array、Collection、Stream或Map等集合对象
@@ -141,11 +150,13 @@ public abstract class Reader {
/**
* 根据字段读取字段对应的DeMember
*
* @param members DeMember的全量集合
* @param members DeMember的全量集合
* @param memberFieldMap DeMember的字段名map
* @param memberTagMap DeMember的tag map
*
* @return 匹配的DeMember
*/
public abstract DeMember readFieldName(final DeMember[] members);
public abstract DeMember readFieldName(final DeMember[] members, Map<String, DeMember> memberFieldMap, Map<Integer, DeMember> memberTagMap);
/**
* 读取一个boolean值

View File

@@ -5,10 +5,9 @@
*/
package org.redkale.convert;
import org.redkale.util.Creator;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.*;
import java.util.*;
import java.util.concurrent.locks.*;
import java.util.stream.Stream;
/**
@@ -32,7 +31,9 @@ public class StreamDecoder<T> implements Decodeable<Reader, Stream<T>> {
protected volatile boolean inited = false;
protected final Object lock = new Object();
private final ReentrantLock lock = new ReentrantLock();
private final Condition condition = lock.newCondition();
public StreamDecoder(final ConvertFactory factory, final Type type) {
this.type = type;
@@ -47,8 +48,11 @@ public class StreamDecoder<T> implements Decodeable<Reader, Stream<T>> {
}
} finally {
inited = true;
synchronized (lock) {
lock.notifyAll();
lock.lock();
try {
condition.signalAll();
} finally {
lock.unlock();
}
}
}
@@ -69,12 +73,12 @@ public class StreamDecoder<T> implements Decodeable<Reader, Stream<T>> {
}
if (this.componentDecoder == null) {
if (!this.inited) {
synchronized (lock) {
try {
lock.wait();
} catch (Exception e) {
e.printStackTrace();
}
lock.lock();
try {
condition.await();
} catch (Exception e) {
} finally {
lock.unlock();
}
}
}

Some files were not shown because too many files have changed in this diff Show More