Compare commits

...

210 Commits

Author SHA1 Message Date
W ce41f4d407
修复项目启动注入属性为null的空指针问题 (#357) 2025-06-09 19:59:46 +08:00
胡俊 bede11a7e2
update version 2.1.1 (#348) 2024-08-01 14:43:27 +08:00
abin 9388aa7f65
use nacos-spring-context self AbstractAnnotationBeanPostProcessor (#345) (#346) 2024-07-27 16:36:45 +08:00
Jefferson Chern 4b106fb992
resolve javadoc error. (#344)
* resolve javadoc error.

* add maven-war-plugin
2024-06-14 19:31:29 +08:00
胡俊 9b61ef68d2
update version 2.1.1-RC (#343) 2024-06-04 22:17:35 +08:00
Jefferson Chern 0a75c0b8c0
# 1.add guava in nacos-spring-context; (#342)
# 2.refactor dependency version.
2024-06-04 22:08:24 +08:00
W eb8b10f3f3
[ISSUE #285] Fix 服务端配置修改后,不支持@Value值的动态变更 #285 (#286)
* fix the thread-safety problem in NacosConfigurationPropertiesBinder (#268)

* 新增服务端配置更改后spring注解@Value值动态变更功能

---------

Co-authored-by: realJackSun <sjtusl@163.com>
Co-authored-by: 胡俊 <510830970@qq.com>
2024-05-09 23:27:48 +08:00
codestagea b209b291c2
修复 配置项value $符号异常 #293 (#317)
Co-authored-by: huijun.xu <huijun.xu@urbanic.com>
Co-authored-by: 胡俊 <510830970@qq.com>
2024-05-09 23:20:00 +08:00
pdkst fcf008405b
improve snakeyml compatibility for 2.2 (#336) 2024-05-09 23:11:27 +08:00
jsbxyyx 1ada9f4e88
fix: empty yaml npe (#332) 2023-12-18 20:55:36 +08:00
SuperZ1999 b1351d7f88
Summer (#331)
* [ISSUE #321] Support spring 6.x (#324)

* [ISSUE #315] Support spring 6.x

* Update document (#325)

* Modify version

---------

Co-authored-by: hujun3 <hujun3@xiaomi.com>
2023-12-03 13:05:31 +08:00
SuperZ1999 96d08e679d
Summer ospp#10375 (#330)
[ISSUE #321] Support spring 6.x (#324)
2023-12-03 11:50:51 +08:00
阿魁 5f0eb0b0d9
[ISSUE #314]Fix the RCE caused by the vulnerability in YAML deseriali… (#328)
* [ISSUE #314]Fix the RCE caused by the vulnerability in YAML deserialization.

* [ISSUE #314]Add YAML_ALLOW_OBJECT.

* [ISSUE #314]Add README.md.

* update style.

* Update.

* Update README.md
2023-11-22 14:32:17 +08:00
SuperZ1999 0e660eb3ab
Update document (#323) 2023-09-30 20:09:37 +08:00
SuperZ1999 d4543ecb97
[ISSUE #321] Support spring 6.x and native-image (#322)
* [ISSUE #315] Support spring 6.x

* Support native-image
2023-09-30 20:09:02 +08:00
zhanghong e8cae2c501
修改nacos-client 2.2.1版本,适配 (#307) 2023-05-10 11:40:20 +08:00
Akitata 9591915028
fixbug: error default field name (#303)
Co-authored-by: akitata <akitata@akitata>
2023-03-24 16:54:46 +08:00
qxo 4a99227a88
[ISSUE #269]去除每次构建时不必要的warning信息, 增加构建稳定性和性能 (#270)
指定构建依赖plugin的具体版本号
目的增加构建稳定性和性能
2022-09-30 21:42:30 +08:00
胡俊 13f14239ea
Merge pull request #295 from hujun-w-2/fix_code_merge
[ISSUE#296]develop branch merge
2022-09-30 21:30:37 +08:00
hujun3 1118b4bf2c Merge remote-tracking branch 'upstream/release1.1.1' into fix_code_merge 2022-09-30 15:40:53 +08:00
Oliver 4854adbe89
update README (#282) 2022-04-24 09:45:31 +08:00
胡俊 00072db454
Code optimization (#279)
* fix #7546

* Code optimization

* Code optimization
2022-02-10 10:20:48 +08:00
胡俊 26fee8ca46
Json parse bug (#280)
* fix #7546

* json parse bug
2022-01-24 16:09:47 +08:00
胡俊 31507dbf3f
fix #7546 (#276) 2022-01-11 17:40:46 +08:00
realJackSun 72f20b8f91 Release 1.1.1, fix the thread-safety problem in NacosConfigurationPropertiesBinder 2021-07-15 01:59:15 +08:00
brotherlu-xcq 3f0a06d6db
[ISSUE #238] optimize the property printout (#257)
* don't print the password in log file

* optimize the symbol

Co-authored-by: chenglu <tingqiu@qunhemail.com>
2021-06-21 11:37:24 +08:00
realJackSun 88741f1750
Merge pull request #263 from horizonzy/262-patch
Patch #262, add unit case.
2021-06-17 17:02:43 +08:00
horizonzy bd3b9652f3 patch for #262: append unit test. 2021-06-16 21:34:20 +08:00
zxn-git 8bfd91ff28
json默认值解析失败修复 (#262)
* json默认值解析失败修复

* json默认值解析失败修复 #262
2021-06-16 20:55:24 +08:00
邪影oO 01308b6b1b
Upgrade version number to 1.1.0 (#255) 2021-04-15 15:29:53 +08:00
邪影oO f906491e0a
增加 UT 时的文件编码(解决UT中有中文会乱码的问题) (#254) 2021-04-15 10:15:25 +08:00
小水牛 458517f414
issue#271 (#251)
NacosUtils.readFromEnvironment 支持基于 Environment 的 SeEL 表达式解析
同时增加 NacosUtils.readFromBeanFactory 方法支持基于 BeanFactory 的 SpEL 表达式解析
2021-04-14 11:26:35 +08:00
邪影oO 6a72c2966f
fix #5316 (#253) 2021-04-13 18:10:04 +08:00
邪影oO 400b3480f8
Merge pull request #250 from dmsolr/patch-1
fix delegate to the wrong method
2021-03-29 11:35:27 +08:00
Daming f791545562
fix typo 2021-03-24 15:07:08 +08:00
邪影oO d61ba1761b
Fix read type from data (#248)
* fix #247

* 默认配制类型改为 properties, test全部跑通

* 修改 license

* 修改CI问题
2021-03-05 09:49:29 +08:00
onewe 478e043739
[ISSUE-#243] fix weblogic classloader leak (#244)
* fix(AbstractNacosPropertySourceBuilder): 修复weblogic中classloader泄漏问题

- AbstractNacosPropertySourceBuilder增加销毁方法,关闭nacos相关线程池

* fix(AbstractNacosPropertySourceBuilder): 格式化代码

* fix(AbstractNacosPropertySourceBuilder): 格式化代码
2021-01-06 15:16:53 +08:00
Mercy Ma cddc2a329a
Merge pull request #237 from horizonzy/fix-236
[ISSUE-#236] Support spel expression
2020-10-28 13:54:22 +08:00
horizonzy a320f02179 support spel expression 2020-10-25 21:24:32 +08:00
Mercy Ma 0126b26cc8
Merge pull request #229 from mercyblitz/master
1.0.0
2020-10-14 16:00:22 +08:00
mercyblitz c6dba51cf3 Merge remote-tracking branch 'upstream/master'
# Conflicts:
#	nacos-spring-context/src/main/java/com/alibaba/nacos/spring/context/annotation/config/NacosValueAnnotationBeanPostProcessor.java
#	nacos-spring-context/src/main/java/com/alibaba/nacos/spring/context/event/config/EventPublishingConfigService.java
2020-10-14 15:57:31 +08:00
mercyblitz ec35969e68 Polish nacos-group/nacos-spring-project#228 : [Enhancement] Supporting the lifcycle on Nacos ConfigSerivice and NamingService when @NacosInjected is used 2020-10-14 14:49:22 +08:00
mercyblitz cc2f2ca276 Polish nacos-group/nacos-spring-project#227 : [Enhancement] Refactoring NacosValueAnnotationBeanPostProcessor based on the latest spring-context-support 2020-10-14 10:48:15 +08:00
Mercy Ma 8265710c77
Merge pull request #223 from JayUpadhyay-8/master
Update Docs
2020-10-14 10:28:45 +08:00
Mercy Ma c060f8631e
1.0.0 Release (#226)
* Polish nacos-group/nacos-spring-project#116 : Upgrade the infrastructure

* Polish nacos-group/nacos-spring-project#177 : [Dependency] degrade the dependency of spring-context-support to be 3.2.18.REELEASE

* Upgrade the version to be 0.3.7-SNAPSHOT

* Update 1.0.0

* Code Format using Spring Boot Conventions
2020-10-13 18:22:58 +08:00
mercyblitz c24e721fe5 Code Format using Spring Boot Conventions 2020-10-13 17:50:29 +08:00
mercyblitz bfe6d58d9b Update 1.0.0 2020-10-13 16:05:35 +08:00
Mercy Ma ca3f04e0fe
Merge pull request #219 from nacos-group/develop
upgradt nacos-client version to 1.3.2
2020-10-10 16:00:24 +08:00
mercyblitz b90ab50ac0 Merge remote-tracking branch 'upstream/develop'
# Conflicts:
#	nacos-spring-context/pom.xml
#	nacos-spring-samples/nacos-embedded-webserver/pom.xml
#	nacos-spring-samples/nacos-spring-webmvc-sample/pom.xml
#	nacos-spring-samples/pom.xml
#	pom.xml
2020-10-10 15:26:55 +08:00
mercyblitz 20897e41c8 Upgrade the version to be 0.3.7-SNAPSHOT 2020-10-10 15:16:12 +08:00
mercyblitz 466852c25f Merge remote-tracking branch 'upstream/master' 2020-10-09 10:48:57 +08:00
Jay Upadhyay 12883bbd2a
Update README.md 2020-10-01 22:32:19 +05:30
liaochuntao 6d88d451df
Merge branch 'master' into develop 2020-08-24 19:35:44 +08:00
邪影oO 4d26367bda
升级nacos-client 到 1.3.2 及相应修改 (#218)
* 升级nacos-client 到 1.3.2 及相应修改

* 调整代码格式

* 增加 commons-lang3 的引入,避免将来 nacos-api中移除 commons-lang3 而出问题
2020-08-24 19:31:30 +08:00
liaochuntao 42203532ca
Refactor config type gain (#211)
* Update README.md

* refactor: removes dataId determines configuration type logic

* fix: fix ut

* fix: fix ut

* fix: fix ut

* refactor: the JDK was demoted to 6
2020-07-19 11:33:41 +08:00
liaochuntao 21f0ad8c02
Merge pull request #205 from Maijh97/develop
Fix #179 Support bind multi-level YAML to javabean
2020-04-20 00:10:05 +08:00
mai.jh 7e73ba6228 fix #179 2020-04-15 22:58:51 +08:00
mai.jh 3e52fa8341 fix #179 2020-04-15 14:45:34 +08:00
liaochuntao 542a5d433e
Update README.md 2020-03-09 20:37:36 +08:00
liaochuntao 190225477d
Merge pull request #198 from nacos-group/develop
Format code style
2020-03-09 16:51:58 +08:00
liaochuntao a36e45ba0c
Merge pull request #197 from chuntaojun/develop
style: code format
2020-03-09 16:45:58 +08:00
chuntaojun 81da8f6d94 style: code format 2020-03-09 16:41:21 +08:00
liaochuntao b55a0c86d4
Merge pull request #196 from nacos-group/develop
Update spring-context-support version to 1.0.5
2020-03-05 17:16:27 +08:00
liaochuntao 72f0aa4104
Merge pull request #195 from chuntaojun/develop
refactor: update spring-context-support to 1.0.5
2020-03-05 17:11:39 +08:00
chuntaojun b10a9603ed refactor: update spring-context-support to 1.0.5 2020-03-05 17:07:09 +08:00
liaochuntao 811a83e8b0
Merge pull request #194 from nacos-group/develop
Update version to 0.3.6
2020-03-05 16:10:29 +08:00
liaochuntao 5bf4d37470
Merge pull request #193 from chuntaojun/develop
docs: update nacos-client version to 1.2.0
2020-03-05 16:07:06 +08:00
chuntaojun ac31f73e22 docs: update nacos-client version to 1.2.0 2020-03-05 16:00:26 +08:00
liaochuntao fd3d649d03
Merge pull request #192 from chuntaojun/develop
feat: issue #189
2020-03-05 15:50:30 +08:00
chuntaojun 866288c544 style: remove unuse dir 2020-03-05 15:35:12 +08:00
chuntaojun d6aea36f33 docs: update version to 0.3.6 2020-03-05 15:18:36 +08:00
chuntaojun bb3627a24e fix: Fix missing XML configuration information 2020-03-04 21:55:58 +08:00
chuntaojun 4e4a53acb4 refactor: remove nacos.xsd about data-ids setting 2020-03-04 16:24:25 +08:00
chuntaojun 380581985b feat: issue #189 2020-03-02 17:16:15 +08:00
liaochuntao 5ca43068d4
Merge pull request #186 from ZShUn/develop
1.添加username password参数
2020-02-24 22:35:09 +08:00
ZShUn 5a7a5f38a1 1.config.xml GlobalNacosPropertiesBeanDefinitionParser 增加username,password属性
2.EnableNacosDiscovery 导包
2020-02-24 22:36:46 +08:00
ZShUn e90852a08d Merge remote-tracking branch 'upstream/develop' into develop 2020-02-23 11:39:47 +08:00
liaochuntao a5caed05b8
Merge pull request #188 from chuntaojun/develop
Upgrade nacos-client to 1.2.0-beta.1
2020-02-21 20:36:07 +08:00
chuntaojun 4b9655943e feat: update nacos-client to 1.2.0-beta.1 2020-02-21 18:43:35 +08:00
ZShUn 38d8661ef4 1.格式化代码 2020-02-11 15:02:03 +08:00
ZShUn 3ff6fc076f 1.修复username password 未导包问题
2.修复注释描述错误
2020-02-11 13:12:42 +08:00
ZShUn fad3f9ce84 1.修复username password 未导包问题 2020-02-11 13:03:49 +08:00
ZShUn d59e4e98ae 1.添加username password参数 2020-02-10 23:54:06 +08:00
liaochuntao 83a9f58ff0
Merge pull request #184 from nacos-group/develop
hotfix/getBeanOfType
2020-01-13 11:59:08 +08:00
liaochuntao 9e402e2f4a
Merge pull request #183 from chuntaojun/hotfix/getBeanOfType
update verion 0.3.4 => 0.3.5
2020-01-13 11:20:21 +08:00
chuntaojun d2c24f4532 fix: fix pom version 2020-01-13 11:14:51 +08:00
chuntaojun ca217ac3d8 docs: update version 0.3.4 => 0.3.5 2020-01-13 10:46:48 +08:00
Mercy Ma 0a4cdeef4d
Merge pull request #182 from chuntaojun/hotfix/getBeanOfType
Hotfix/get bean of type
2020-01-13 10:19:39 +08:00
liaochuntao f9efd43b96 fix: fix map bind 2020-01-12 16:10:13 +08:00
liaochuntao 552876db54 fix: fix refresh can't clean map 2020-01-11 20:56:14 +08:00
liaochuntao d9aa35bf13 fix: fix getBeanOfType 2020-01-11 11:12:33 +08:00
mercyblitz 19809b04d1 Polish nacos-group/nacos-spring-project#177 : [Dependency] degrade the dependency of spring-context-support to be 3.2.18.REELEASE 2019-12-24 17:53:54 +08:00
mercyblitz 684c2e446a Merge remote-tracking branch 'upstream/master' 2019-12-24 17:34:13 +08:00
liaochuntao c50f681d05
Merge pull request #173 from chuntaojun/develop
fix: remove error code
2019-12-14 13:23:33 +08:00
liaochuntao 35dee7faf7 fix: remove error code 2019-12-13 13:16:13 +08:00
liaochuntao 392f7513da
Merge pull request #172 from nacos-group/develop
remove @value auto refresh
2019-12-12 15:02:23 +08:00
mercyblitz 38f80c37c5 Merge remote-tracking branch 'upstream/master'
# Conflicts:
#	nacos-spring-context/src/main/java/com/alibaba/nacos/spring/context/event/DeferredApplicationEventPublisher.java
2019-12-09 10:12:44 +08:00
liaochuntao c9412f949f
Merge pull request #170 from chuntaojun/develop
Delete @Value auto refresh logic
2019-12-09 09:15:18 +08:00
liaochuntao 0f7256fa78 refactor: remove @Value auto refresh logic 2019-12-08 08:38:10 +08:00
liaochuntao 8d063fce72 refactor: delete @value automatically refreshes 2019-12-07 23:12:09 +08:00
liaochuntao 779b8b948c
Merge pull request #167 from nacos-group/develop
release 0.3.4
2019-10-24 22:56:35 +08:00
liaochuntao 28d39ff702
Merge pull request #166 from chuntaojun/develop
fix: update nacos
2019-10-24 22:51:20 +08:00
chuntaojun 88620ec0a1 fix: update nacos 2019-10-24 22:49:26 +08:00
liaochuntao be8b587a31
Merge pull request #165 from nacos-group/develop
Release 0.3.4 version
2019-10-21 13:43:44 +08:00
liaochuntao 671903979e
Merge pull request #164 from chuntaojun/feat_issue_160
refactor: Correct part code implementation
2019-10-21 13:38:12 +08:00
chuntaojun d75bdb35b7 refactor: Correct part code implementation 2019-10-21 13:37:09 +08:00
liaochuntao d005acac91
Merge pull request #161 from chuntaojun/feat_issue_160
feature issue #160
2019-10-17 22:08:41 +08:00
chuntaojun f620468662 refactor: 2019-10-17 14:04:07 +08:00
chuntaojun 49f3a99cc0 refactor: 2019-10-17 10:35:47 +08:00
chuntaojun 2439515a45 docs: 2019-10-16 14:44:10 +08:00
chuntaojun 8bed91cfe8 feat: Support @Value autor-efresh 2019-10-16 14:42:06 +08:00
liaochuntao d60abcb134
Merge pull request #159 from rushsky518/develop
#144 NamingMaintainServiceBean 属性注入
2019-10-16 08:13:56 +08:00
liaochuntao 4e2612079f
Merge pull request #158 from coderDylan/master
fix issue#157 1.完善demo,从properties文件中读取nacos.server-addr等属性,避免修改JVM -D 启动参数
2019-10-16 08:13:28 +08:00
rushsky518 7fe41a4f03 #144 NamingMaintainServiceBean 属性注入 2019-10-15 11:27:06 +08:00
mercyblitz f41de89b52 Merge remote-tracking branch 'upstream/master' 2019-10-11 16:23:08 +08:00
coderDylan 0446a1150b 1.完善demo,从properties文件中读取nacos.server-addr等属性,避免修改JVM -D 启动参数
2.创建propertySourcesPlaceholderConfigurer bean时新增了容错处理,避免老项目中的配置文件缺失或者配置项缺失导致应用启动或容器初始化bean失败
2019-10-10 14:31:07 +08:00
coder_dylan b58cce0dff 1.完善demo,从properties文件中读取nacos.server-addr等属性,避免修改JVM -D 启动参数
2.创建propertySourcesPlaceholderConfigurer bean时新增了容错处理,避免老项目中的配置文件缺失或者配置项缺失导致应用启动或容器初始化bean失败
2019-09-30 21:11:41 +08:00
liaochuntao b64cc9ff44
Merge pull request #150 from nacos-group/develop
Develop
2019-09-15 09:14:32 +08:00
liaochuntao 885950508b
Merge pull request #149 from chuntaojun/refactor_create
Refactor create
2019-09-15 08:42:27 +08:00
chuntaojun d85993a812 refactor(test): To optimize the test code 2019-09-15 08:37:54 +08:00
chuntaojun 58e935e5cb refactor(all): 2019-09-14 18:54:41 +08:00
liaochuntao 2313afac8c
Merge pull request #148 from chuntaojun/refactor_create
refactor(config): Optimized to create the Service logic, add delay cr…
2019-09-13 21:30:54 +08:00
chuntaojun c24907b92b refactor(all): follower new code 2019-09-13 21:02:47 +08:00
chuntaojun 53578cfdfa refactor(config): Optimized to create the Service logic, add delay create function 2019-09-13 20:27:38 +08:00
liaochuntao c6b0439088
Merge pull request #146 from chuntaojun/fix_issue_142
Fix issue 142
2019-09-07 09:17:58 +08:00
chuntaojun d392140053 nonooe 2019-09-06 13:44:35 +08:00
chuntaojun 3750669d37 docs: 2019-09-06 13:25:32 +08:00
chuntaojun 3dda125957 fix: fix issue 142 2019-09-03 19:55:23 +08:00
chuntaojun fd1ad803cd refactor: 2019-08-26 18:56:14 +08:00
chuntaojun 0a611c943c feat: 2019-08-26 18:55:07 +08:00
liaochuntao e412be2973
Merge pull request #140 from nacos-group/develop
Develop
2019-08-14 18:01:59 +08:00
liaochuntao 03b9f4bee1
Merge pull request #139 from chuntaojun/develop
refactor: Configuration parsing code optimization
2019-08-14 17:46:05 +08:00
chuntaojun 08f48d0bf0 refactor: Configuration parsing code optimization 2019-08-14 17:43:01 +08:00
liaochuntao 7bfee49517
Merge pull request #138 from chuntaojun/feature
refactor: update version to 0.3.3
2019-08-14 15:54:15 +08:00
liaochuntao 25b0f034a3
Merge pull request #136 from nacos-group/develop
support read data-id from environment
2019-08-14 15:51:51 +08:00
chuntaojun 4482679bb0 refactor: update version to 0.3.3 2019-08-13 22:20:31 +08:00
liaochuntao 2bd3ffcba0
Merge pull request #137 from chuntaojun/feature
update nacos version to 1.1.3
2019-08-06 20:22:16 +08:00
chuntaojun 9c73caaced chore: Change depend on the version 2019-08-06 20:10:32 +08:00
chuntaojun 745e909744 refactor: update nacos-client version to 0.3.2 2019-08-06 19:58:13 +08:00
chuntaojun 05a9c2e240 Merge branch 'master' of https://github.com/nacos-group/nacos-spring-project into feature 2019-08-05 16:05:32 +08:00
liaochuntao b2d3ba6a00
Merge pull request #135 from chuntaojun/feature
support read data-id from environment
2019-08-05 16:05:02 +08:00
chuntaojun bc2dc92a8f fix: fix read config type from data-id bug 2019-08-05 09:56:56 +08:00
liaochuntao d30d206229
Merge pull request #88 from ddatsh/master
refactor
2019-08-05 09:36:43 +08:00
chuntaojun aa39b3c969 refactor: Optimization of part of the code 2019-08-02 16:50:16 +08:00
chuntaojun 06ad02b506 feat(config): Loading from the Environment to support dataId and groupId 2019-07-27 11:25:25 +08:00
liaochuntao 688a61be1f
Update README.md 2019-07-22 16:14:53 +08:00
liaochuntao c0275b713b
Update README.md 2019-07-22 15:52:53 +08:00
liaochuntao d7b28788e1
Update README.md 2019-07-22 11:24:47 +08:00
liaochuntao 78def0ee6d
Merge pull request #134 from nacos-group/develop
Develop
2019-07-17 10:02:46 +08:00
liaochuntao d18505b5f9
Merge pull request #133 from chuntaojun/develop
refactor: change @NacosPropertySources type paramType from string to …
2019-07-17 09:04:03 +08:00
chuntaojun 939be89960 refactor: 2019-07-16 22:39:58 +08:00
chuntaojun 0b9c3a7609 refactor: change @NacosPropertySources type paramType from string to ConfigType 2019-07-16 22:16:57 +08:00
liaochuntao 0eedaf7c04
Merge pull request #132 from nacos-group/develop
Merge pull request #131 from chuntaojun/develop
2019-07-16 17:27:21 +08:00
liaochuntao 370ffa46c7
Merge pull request #131 from chuntaojun/develop
merge develop
2019-07-16 17:17:44 +08:00
liaochuntao 5e1d24dc64
Merge pull request #130 from chuntaojun/fix_issue_129
fix issue #129
2019-07-16 16:58:40 +08:00
chuntaojun 4208139256 fix: fix issue #129 2019-07-16 16:54:32 +08:00
liaochuntao 3cda73453c
Merge pull request #127 from nacos-group/develop
Modify class and method modifiers
2019-07-15 13:41:46 +08:00
liaochuntao 9a8a68fda9
Merge pull request #126 from chuntaojun/develop
Modify class and method modifiers
2019-07-13 00:18:29 +08:00
chuntaojun 00d3bcc556 refactor: 2019-07-12 17:52:08 +08:00
liaochuntao 5ebf1d177f
Merge pull request #125 from nacos-group/develop
update version to 0.3.0 and modify test example
2019-07-12 14:41:54 +08:00
liaochuntao 3683a568cd
Merge pull request #124 from chuntaojun/develop
refactor: update version to 0.3.0 and modify test example
2019-07-12 14:04:29 +08:00
chuntaojun c4454cc110 refactor: update version to 0.3.0 and modify test example 2019-07-12 13:01:33 +08:00
liaochuntao 67bb064014
Merge pull request #121 from nacos-group/develop
merge develop
2019-07-11 00:08:31 +08:00
liaochuntao e8461e6c09
Merge pull request #122 from chuntaojun/develop
refactor: Resolve code review issues
2019-07-11 00:02:28 +08:00
chuntaojun 9601e87653 refactor: Resolve code review issues 2019-07-10 23:51:50 +08:00
liaochuntao 927c718fd6
Merge pull request #120 from chuntaojun/fix_issue_119
fix: fix issue #119
2019-07-07 13:22:25 +08:00
chuntaojun 7d6e6a75da fix: fix issue #1119 2019-07-07 11:43:01 +08:00
liaochuntao 511d611539
Merge pull request #118 from chuntaojun/develop
feat: upgrade nacos dependence to 1.1.0
2019-07-07 11:02:02 +08:00
chuntaojun ef2c4d85e3 refactor: 2019-07-07 10:53:31 +08:00
chuntaojun 7bd1bd2276 feat: upgrade nacos dependence to 1.1.0 2019-07-07 10:44:24 +08:00
mercyblitz 0e0f603ca0 Polish nacos-group/nacos-spring-project#116 : Upgrade the infrastructure 2019-07-04 15:42:37 +08:00
liaochuntao a9cdcdc9d3
Merge pull request #113 from nacos-group/develop
develop
2019-07-03 11:02:36 +08:00
liaochuntao 58e0782107
Merge pull request #114 from chuntaojun/develop
chore: update version to 0.3.0-RC1
2019-07-03 10:54:10 +08:00
chuntaojun 8a54619085 fix: add javax.annotation-api 2019-07-03 10:41:12 +08:00
chuntaojun 28e035b49f chore: update version to 0.3.0-RC1 2019-07-03 10:23:59 +08:00
liaochuntao fb936c871e
Merge pull request #112 from chuntaojun/fix_issue_33
Fix issue 33
2019-07-03 10:11:53 +08:00
chuntaojun 95dacfcb84 fix: Fix configuration file parser error calling custom 2019-07-01 10:13:51 +08:00
chuntaojun 82f5edc02c fix: fix ConfigParseUtils can't register user-defined ConfigParse 2019-07-01 09:53:53 +08:00
chuntaojun 9bc59ad2c2 test: Refine unit test cases 2019-07-01 09:16:34 +08:00
chuntaojun 6d248d79bd Merge branch 'master' of https://github.com/nacos-group/nacos-spring-project into develop 2019-07-01 09:14:36 +08:00
liaochuntao c94eed0818
Merge pull request #111 from chuntaojun/master
Add issue and pr template
2019-06-30 13:43:12 +08:00
liaochuntao 5dca5b4918
Merge pull request #110 from chuntaojun/fix_issue_109
fix issue #109
2019-06-30 13:41:39 +08:00
chuntaojun 388ca01cd7 refactor: remove .DS_Store 2019-06-30 13:38:25 +08:00
chuntaojun c8bfbf159a docs(.github): add issue and pull request template 2019-06-30 13:37:12 +08:00
chuntaojun 610ba0a896 docs(.github): add issue and pr template 2019-06-30 13:35:27 +08:00
chuntaojun 1f2cbc68d2 fix: fix issue #109 2019-06-30 13:11:43 +08:00
chuntaojun f8fbadafa8 refactor: refactor NacosUtils.resolvePropertyValues func 2019-06-30 11:26:29 +08:00
liaochuntao a7bb73caa2
Merge pull request #105 from chuntaojun/fix_issue_91
[#ISSUE 91] Fix
2019-06-30 10:42:23 +08:00
chuntaojun f5a28752f5 style: 2019-06-30 10:40:24 +08:00
chuntaojun 7c98a68da2 feat: 2019-06-30 10:28:09 +08:00
Fury Zhu f170cb3add
Merge pull request #104 from chuntaojun/feature
Optimized singleton management for NacosServiceFactory
2019-06-30 10:12:05 +08:00
chuntaojun 0f073495ee refactor: Modify the exception handling logic 2019-06-25 18:10:13 +08:00
chuntaojun b3dba11f67 fix: fix issue #91 2019-06-24 15:30:58 +08:00
chuntaojun d48c081382 Merge branch 'master' of https://github.com/nacos-group/nacos-spring-project into fix_issue_33 2019-06-24 14:24:11 +08:00
chuntaojun 445886730e fix: fix code conflict errors 2019-06-24 14:22:00 +08:00
Fury Zhu 1499392faa
Merge pull request #103 from chuntaojun/follow_nacos_version
support nacos-client v1.0.1 feature
2019-06-24 14:03:07 +08:00
Fury Zhu 1a1f930734
Merge pull request #102 from chuntaojun/fix_issue_89
fix issue #89
2019-06-24 14:01:39 +08:00
Fury Zhu f092502a1d
Merge pull request #101 from chuntaojun/fix_issue_85
fix issue #85
2019-06-24 14:00:48 +08:00
chuntaojun 56a7e34118 fix: Fix code errors found during review 2019-06-22 21:43:46 +08:00
chuntaojun 79f22d1d01 chore: add yaml dependency 2019-06-22 21:29:11 +08:00
chuntaojun bfd3c6e8c2 feat: support nacos-client v1.0.1 feature 2019-06-20 14:53:17 +08:00
chuntaojun 5d764d3660 refactor: Optimized singleton management for NacosServiceFactory 2019-06-20 13:43:22 +08:00
chuntaojun 0c0fbff71d fix: fix issue #89 2019-06-20 00:00:54 +08:00
chuntaojun c9e9b1ee9e fix: fix issue #85 2019-06-19 23:57:43 +08:00
peter zhang 824250b248 refactor
new Date().getTime() > System.currentTimeMillis()
2019-05-07 10:36:54 +08:00
Keep 4f6c351dc2
Merge pull request #81 from hxy1991/master
Change the version to 0.2.3-RC1
2019-02-19 19:51:40 +08:00
hxy1991 450319c860 Change the version to 0.2.3-RC1 2019-02-19 17:06:19 +08:00
Mercy Ma ef402cf718
Merge pull request #80 from hxy1991/master
Support Spring 5+
2019-02-19 11:11:14 +08:00
hxy1991 240df444b5 Merge branch 'upstream' 2019-02-18 14:51:33 +08:00
hxy1991 132de0596c Fixes #79 2019-02-18 14:50:38 +08:00
165 changed files with 14279 additions and 5735 deletions

20
.github/ISSUE_TEMPLATE.md vendored Normal file
View File

@ -0,0 +1,20 @@
## Issue Description
Type: *bug report* or *feature request*
### Describe what happened (or what feature you want)
### Describe what you expected to happen
### How to reproduce it (as minimally and precisely as possible)
1.
2.
3.
### Tell us your environment
### Anything else we need to know?

22
.github/PULL_REQUEST_TEMPLATE.md vendored Normal file
View File

@ -0,0 +1,22 @@
Please do not create a Pull Request without creating an issue first.
## What is the purpose of the change
XXXXX
## Brief changelog
XX
## Verifying this change
XXXX
Follow this checklist to help us incorporate your contribution quickly and easily:
* [ ] Make sure there is a Github issue filed for the change (usually before you start working on it). Trivial changes like typos do not require a Github issue. Your pull request should address just this issue, without pulling in other changes - one PR resolves one issue.
* [ ] Format the pull request title like `[ISSUE #123] Fix UnknownException when host config not exist`. Each commit in the pull request should have a meaningful subject line and body.
* [ ] Write a pull request description that is detailed enough to understand what the pull request does, how, and why.
* [ ] Write necessary unit-test to verify your logic correction, more mock a little better when cross module dependency exist. If the new feature or significant change is committed, please remember to add integration-test in [test module](https://github.com/alibaba/nacos/tree/master/test).
* [ ] Run `mvn -B clean package apache-rat:check findbugs:findbugs -Dmaven.test.skip=true` to make sure basic checks pass. Run `mvn clean install -DskipITs` to make sure unit-test pass. Run `mvn clean test-compile failsafe:integration-test` to make sure integration-test pass.

2
.gitignore vendored
View File

@ -23,6 +23,7 @@
hs_err_pid* hs_err_pid*
target target
classes
.project .project
.classpath .classpath
.settings/ .settings/
@ -35,3 +36,4 @@ target
*.prefs *.prefs
*~ *~
.extract .extract
.flattened-pom.xml

View File

@ -9,8 +9,7 @@ notifications:
language: java language: java
jdk: jdk:
- openjdk10 - openjdk11
- openjdk9
- openjdk8 - openjdk8
script: script:

View File

@ -41,6 +41,7 @@ Content
- [4.1.1. Enable Nacos](#411-enable-nacos) - [4.1.1. Enable Nacos](#411-enable-nacos)
- [4.1.2. Configure Change Listener method](#412-configure-change-listener-method) - [4.1.2. Configure Change Listener method](#412-configure-change-listener-method)
- [4.1.2.1. Type Conversion](#4121-type-conversion) - [4.1.2.1. Type Conversion](#4121-type-conversion)
- [4.1.2.1.1. Type Conversion during YAML Parsing](#41211-Type Conversion during YAML Parsing)
- [4.1.2.2. Timeout of Execution](#4122-timeout-of-execution) - [4.1.2.2. Timeout of Execution](#4122-timeout-of-execution)
- [4.1.3. Global and Special Nacos Properties](#413-global-and-special-nacos-properties) - [4.1.3. Global and Special Nacos Properties](#413-global-and-special-nacos-properties)
- [4.1.4. `@NacosProperties`](#414-nacosproperties) - [4.1.4. `@NacosProperties`](#414-nacosproperties)
@ -95,10 +96,10 @@ The following table shows the dependencies and compatabilities of Nacos Spring P
| Dependencies | Compatibility | | Dependencies | Compatibility |
| -------------- | ------------- | | -------------- | ------------- |
| Java | 1.6+ | | Java | 1.8+ |
| Spring Context | 3.2+ | | Spring Context | 3.2+ |
| [Alibaba Spring Context Support](https://github.com/alibaba/spring-context-support) | 1.0.1+ | | [Alibaba Spring Context Support](https://github.com/alibaba/spring-context-support) | 1.0.1+ |
| [Alibaba Nacos](https://github.com/alibaba/nacos) | 0.2.1+ | | [Alibaba Nacos](https://github.com/alibaba/nacos) | 1.1.1+ |
@ -123,13 +124,15 @@ Complete the following steps to enable Nacos for your Spring project.
<dependency> <dependency>
<groupId>com.alibaba.nacos</groupId> <groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-spring-context</artifactId> <artifactId>nacos-spring-context</artifactId>
<version>0.2.2-RC1</version> <version>1.1.0</version>
</dependency> </dependency>
... ...
</dependencies> </dependencies>
``` ```
**Note:** Support Spring 5 from version 0.2.3-RC1, support Spring 6 from version 2.1.0.
2. Add the `@EnableNacos` annotation in the `@Configuration` class of Spring and specify "\${host}:${port}" of your Nacos server in the `serverAddr` attribute: 2. Add the `@EnableNacos` annotation in the `@Configuration` class of Spring and specify "\${host}:${port}" of your Nacos server in the `serverAddr` attribute:
```java ```java
@ -313,8 +316,33 @@ The `UserNacosConfigConverter` class binds the `@NacosConfigListener.converter()
} }
``` ```
##### 4.1.2.1.1. Type Conversion during YAML Parsing
By default, starting from version 1.1.2, this library uses `SafeConstructor` for type conversion during YAML parsing. This is done to ensure that potentially unsafe code is not executed during the parsing process. `SafeConstructor` provides a secure construction logic for mapping YAML structures to Java objects.
**System Property Toggle**
To maintain compatibility with versions prior to 1.1.2, we have introduced a system property toggle named `yamlAllowComplexObject`. Prior to version 1.1.2, the library defaulted to using `Constructor`, another constructor in the SnakeYAML library that supports more complex object mapping. Starting from version 1.1.2, the default is switched to `SafeConstructor`.
**Potential Risks**
It's important to note that enabling `Constructor` introduces some potential risks, particularly the risk of Remote Code Execution (`RCE`). This is because `Constructor` allows more flexible object construction, but it also increases the risk of handling malicious YAML input.
**Recommendations**
- We recommend using the `NacosConfigConverter` for custom conversions.
**If You Must Use `Constructor`**
- Ensure that the source of the YAML data is secure.
**How to Disable `SafeConstructor`**
You can set the toggle by adding a JVM system property when starting your application. For example, in the command line:
```bash
java -DyamlAllowComplexObject=true -jar your-application.jar
```
- See [Type Conversion Sample of `@NacosConfigListener`](https://github.com/nacos-group/nacos-spring-project/blob/master/nacos-spring-samples/nacos-spring-webmvc-sample/src/main/java/com/alibaba/nacos/samples/spring/listener/PojoNacosConfigListener.java) - See [Type Conversion Sample of `@NacosConfigListener`](https://github.com/nacos-group/nacos-spring-project/blob/master/nacos-spring-samples/nacos-spring-webmvc-sample/src/main/java/com/alibaba/nacos/samples/spring/listener/PojoNacosConfigListener.java)
@ -399,7 +427,7 @@ try to retrieve properities from `@EnableNacosConfig.globalProperties()` or `@En
### 4.1.4. `@NacosProperties` ### 4.1.4. `Nacos Properties`
`@NacosProperties` is a uniform annotation for global and special Nacos properties. It serves as a mediator between Java `Properties` and `NacosFactory` class. `NacosFactory` is responsible for creating `ConfigService` or `NamingService` instances. `@NacosProperties` is a uniform annotation for global and special Nacos properties. It serves as a mediator between Java `Properties` and `NacosFactory` class. `NacosFactory` is responsible for creating `ConfigService` or `NamingService` instances.

View File

@ -0,0 +1,755 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<profiles version="12">
<profile kind="CodeFormatterProfile" name="Spring Boot Java Conventions" version="12">
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_ellipsis"
value="insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations"
value="insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration"
value="insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression"
value="do not insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration"
value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries"
value="true"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters"
value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter"
value="do not insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package"
value="insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant"
value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_imports" value="1"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while"
value="do not insert"/>
<setting
id="org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags"
value="do not insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration"
value="do not insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws"
value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_javadoc_comments"
value="true"/>
<setting id="org.eclipse.jdt.core.formatter.indentation.size" value="8"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator"
value="do not insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments"
value="insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments"
value="insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits"
value="do not insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration"
value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for"
value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.disabling_tag"
value="@formatter:off"/>
<setting id="org.eclipse.jdt.core.formatter.continuation_indentation" value="2"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_enum_constants"
value="0"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_imports"
value="1"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_package" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_binary_operator"
value="insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations"
value="insert"/>
<setting
id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant"
value="16"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference"
value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.indent_root_tags"
value="false"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch"
value="true"/>
<setting id="org.eclipse.jdt.core.formatter.enabling_tag" value="@formatter:on"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block"
value="insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return"
value="insert"/>
<setting
id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration"
value="16"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter"
value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line"
value="false"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field"
value="insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments"
value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block"
value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator"
value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations"
value="1"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer"
value="insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for"
value="do not insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch"
value="do not insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments"
value="do not insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method"
value="insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch"
value="do not insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration"
value="insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression"
value="do not insert"/>
<setting
id="org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column"
value="false"/>
<setting id="org.eclipse.jdt.core.compiler.problem.enumIdentifier" value="error"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter"
value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits"
value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_block"
value="true"/>
<setting
id="org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration"
value="end_of_line"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard"
value="do not insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation"
value="do not insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments"
value="do not insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch"
value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.line_length" value="90"/>
<setting id="org.eclipse.jdt.core.formatter.disabling_tag"
value="@formatter:off"/>
<setting id="org.eclipse.jdt.core.formatter.use_on_off_tags" value="true"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression"
value="do not insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant"
value="insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation"
value="do not insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator"
value="insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration"
value="insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for"
value="do not insert"/>
<setting
id="org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments"
value="false"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable"
value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_method_declaration"
value="end_of_line"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation"
value="do not insert"/>
<setting
id="org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch"
value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for"
value="insert"/>
<setting
id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body"
value="0"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments"
value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line"
value="false"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_binary_expression"
value="16"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference"
value="insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer"
value="do not insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations"
value="insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation"
value="do not insert"/>
<setting
id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call"
value="16"/>
<setting
id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header"
value="true"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces"
value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default"
value="do not insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional"
value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block"
value="end_of_line"/>
<setting
id="org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration"
value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_lambda_body"
value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.compact_else_if" value="true"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters"
value="do not insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch"
value="insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation"
value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line"
value="true"/>
<setting
id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration"
value="16"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments"
value="insert"/>
<setting
id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation"
value="16"/>
<setting
id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration"
value="16"/>
<setting id="org.eclipse.jdt.core.compiler.problem.assertIdentifier"
value="error"/>
<setting
id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment"
value="false"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement"
value="insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try"
value="insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing"
value="do not insert"/>
<setting
id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment"
value="false"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer"
value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_binary_operator"
value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_unary_operator"
value="do not insert"/>
<setting
id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer"
value="16"/>
<setting
id="org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column"
value="true"/>
<setting id="org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve"
value="1"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case"
value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_ellipsis"
value="do not insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources"
value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert"
value="insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if"
value="do not insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments"
value="do not insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter"
value="insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration"
value="insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression"
value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_line_comments"
value="true"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement"
value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.align_type_members_on_columns"
value="false"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_assignment" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body"
value="insert"/>
<setting
id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header"
value="true"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration"
value="do not insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant"
value="do not insert"/>
<setting
id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration"
value="16"/>
<setting
id="org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration"
value="0"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_conditional_expression"
value="80"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer"
value="do not insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters"
value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line"
value="false"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if"
value="insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type"
value="insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block"
value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration"
value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block_in_case"
value="end_of_line"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration"
value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_header" value="false"/>
<setting
id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression"
value="16"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation"
value="do not insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while"
value="insert"/>
<setting id="org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode"
value="enabled"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch"
value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_method_declaration"
value="0"/>
<setting id="org.eclipse.jdt.core.formatter.join_wrapped_lines" value="true"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration"
value="do not insert"/>
<setting
id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases"
value="true"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression"
value="do not insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized"
value="do not insert"/>
<setting
id="org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries"
value="true"/>
<setting
id="org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration"
value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for"
value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_resources_in_try"
value="80"/>
<setting
id="org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations"
value="false"/>
<setting
id="org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation"
value="16"/>
<setting
id="org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column"
value="false"/>
<setting id="org.eclipse.jdt.core.compiler.source" value="1.8"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized"
value="do not insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws"
value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.tabulation.size" value="4"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant"
value="insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression"
value="insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference"
value="do not insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional"
value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_source_code"
value="true"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer"
value="insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try"
value="do not insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources"
value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_field" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation"
value="do not insert"/>
<setting
id="org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer"
value="2"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard"
value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_method" value="1"/>
<setting
id="org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration"
value="16"/>
<setting
id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration"
value="16"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw"
value="insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement"
value="do not insert"/>
<setting id="org.eclipse.jdt.core.compiler.codegen.targetPlatform" value="1.8"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_switch"
value="end_of_line"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces"
value="do not insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters"
value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation"
value="do not insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer"
value="insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression"
value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_html" value="true"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration"
value="do not insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters"
value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_compact_if" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.indent_empty_lines" value="false"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference"
value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_unary_operator"
value="do not insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant"
value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation"
value="0"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations"
value="do not insert"/>
<setting
id="org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line"
value="false"/>
<setting
id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch"
value="false"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement"
value="insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator"
value="insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration"
value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk"
value="1"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_label"
value="do not insert"/>
<setting
id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header"
value="true"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression"
value="do not insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration"
value="do not insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional"
value="insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference"
value="do not insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters"
value="do not insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments"
value="do not insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast"
value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert"
value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_member_type"
value="1"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement"
value="insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference"
value="do not insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference"
value="do not insert"/>
<setting
id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression"
value="16"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer"
value="do not insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration"
value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases"
value="true"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration"
value="do not insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if"
value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon"
value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator"
value="do not insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try"
value="do not insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments"
value="do not insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast"
value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_block_comments"
value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow"
value="insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration"
value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line"
value="false"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration"
value="insert"/>
<setting
id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration"
value="16"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference"
value="do not insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters"
value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for"
value="do not insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws"
value="insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression"
value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_body"
value="true"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_multiple_fields"
value="16"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments"
value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator"
value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_array_initializer"
value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_binary_operator"
value="true"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration"
value="insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters"
value="insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch"
value="do not insert"/>
<setting id="org.eclipse.jdt.core.compiler.compliance" value="1.8"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference"
value="do not insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation"
value="insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments"
value="do not insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer"
value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case"
value="do not insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations"
value="do not insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration"
value="insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference"
value="do not insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration"
value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested"
value="true"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast"
value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_constant"
value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_type_declaration"
value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_package"
value="0"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for"
value="insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized"
value="insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments"
value="do not insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration"
value="do not insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while"
value="do not insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant"
value="do not insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments"
value="do not insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation"
value="do not insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters"
value="do not insert"/>
<setting
id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header"
value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow"
value="insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration"
value="insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws"
value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.join_lines_in_comments" value="true"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters"
value="do not insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional"
value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.indent_parameter_description"
value="true"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement"
value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.tabulation.char" value="tab"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations"
value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_import_groups"
value="1"/>
<setting id="org.eclipse.jdt.core.formatter.lineSplit" value="90"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation"
value="do not insert"/>
<setting
id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch"
value="insert"/>
</profile>
</profiles>

View File

@ -0,0 +1,36 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-spring-parent</artifactId>
<version>${revision}</version>
<relativePath>../pom.xml</relativePath>
</parent>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-spring-context-aot</artifactId>
<version>${revision}</version>
<name>Alibaba Nacos :: Spring :: Context :: Aot</name>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring6.framework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring6.framework.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-spring-context</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,76 @@
/*
*
* * 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 com.alibaba.nacos.spring.aot;
import com.alibaba.nacos.api.annotation.NacosInjected;
import com.alibaba.nacos.api.config.annotation.NacosValue;
import org.springframework.aot.generate.GenerationContext;
import org.springframework.beans.factory.aot.BeanRegistrationAotContribution;
import org.springframework.beans.factory.aot.BeanRegistrationAotProcessor;
import org.springframework.beans.factory.aot.BeanRegistrationCode;
import org.springframework.beans.factory.support.RegisteredBean;
import org.springframework.util.ReflectionUtils;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
/**
* {@link NacosInjected} and {@link NacosValue} AotProcessor
* The fields annotated with {@link NacosInjected} or {@link NacosValue} must be added to the reflect-config.json
* @author SuperZ1999
*/
public class NacosAnnotationBeanRegistrationAotProcessor implements BeanRegistrationAotProcessor {
@Override
public BeanRegistrationAotContribution processAheadOfTime(RegisteredBean registeredBean) {
Class<?> beanClass = registeredBean.getBeanClass();
List<Field> fields = new ArrayList<>();
ReflectionUtils.doWithFields(beanClass, field -> {
NacosInjected injectedAnnotation = field.getDeclaredAnnotation(NacosInjected.class);
NacosValue nacosValueAnnotation = field.getDeclaredAnnotation(NacosValue.class);
if (injectedAnnotation != null || nacosValueAnnotation != null) {
fields.add(field);
}
});
if (fields.isEmpty()) {
return null;
}
return new AotContribution(fields);
}
private static class AotContribution implements BeanRegistrationAotContribution {
private final List<Field> fields;
public AotContribution() {
this.fields = new ArrayList<>();
}
public AotContribution(List<Field> fields) {
this.fields = fields;
}
@Override
public void applyTo(GenerationContext generationContext, BeanRegistrationCode beanRegistrationCode) {
for (Field field : fields) {
generationContext.getRuntimeHints().reflection().registerField(field);
}
}
}
}

View File

@ -0,0 +1,15 @@
{
"resources": {
"includes": [
{
"pattern": "\\QMETA-INF/spring.handlers\\E"
},
{
"pattern": "\\QMETA-INF/spring.schemas\\E"
},
{
"pattern": "\\QMETA-INF/schemas/nacos.xsd\\E"
}
]
}
}

View File

@ -0,0 +1,2 @@
org.springframework.beans.factory.aot.BeanRegistrationAotProcessor=\
com.alibaba.nacos.spring.aot.NacosAnnotationBeanRegistrationAotProcessor

View File

@ -1,42 +1,66 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" <project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent> <parent>
<artifactId>nacos-spring-parent</artifactId> <artifactId>nacos-spring-parent</artifactId>
<groupId>com.alibaba.nacos</groupId> <groupId>com.alibaba.nacos</groupId>
<version>0.2.2-RC1</version> <version>${revision}</version>
<relativePath>../pom.xml</relativePath> <relativePath>../pom.xml</relativePath>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<groupId>com.alibaba.nacos</groupId> <groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-spring-context</artifactId> <artifactId>nacos-spring-context</artifactId>
<version>0.2.2-RC1</version> <version>${revision}</version>
<name>Alibaba Nacos :: Spring :: Context</name> <name>Alibaba Nacos :: Spring :: Context</name>
<packaging>jar</packaging> <packaging>jar</packaging>
<dependencies> <dependencies>
<!-- java-->
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
</dependency>
<!-- Nacos --> <!-- Nacos -->
<dependency> <dependency>
<groupId>com.alibaba.nacos</groupId> <groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId> <artifactId>nacos-client</artifactId>
<version>${nacos.version}</version> <exclusions>
<exclusion>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
</exclusion>
<exclusion>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
</dependency>
<!--yaml-->
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
</dependency> </dependency>
<!-- Spring Framework --> <!-- Spring Framework -->
<dependency> <dependency>
<groupId>org.springframework</groupId> <groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId> <artifactId>spring-context</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency> </dependency>
<!-- Spring Context Extras --> <!-- Spring Context Extras -->
<dependency> <dependency>
<groupId>com.alibaba.spring</groupId> <groupId>com.alibaba.spring</groupId>
<artifactId>spring-context-support</artifactId> <artifactId>spring-context-support</artifactId>
<version>1.0.1</version>
</dependency> </dependency>
<!-- Testing --> <!-- Testing -->
<dependency> <dependency>
<groupId>${project.groupId}</groupId> <groupId>${project.groupId}</groupId>
@ -44,21 +68,27 @@
<version>${project.version}</version> <version>${project.version}</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>junit</groupId> <groupId>junit</groupId>
<artifactId>junit</artifactId> <artifactId>junit</artifactId>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.springframework</groupId> <groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId> <artifactId>spring-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.mockito</groupId> <groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId> <artifactId>mockito-core</artifactId>
</dependency> </dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
</dependencies> </dependencies>
</project> </project>

View File

@ -0,0 +1,644 @@
/*
* 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 com.alibaba.nacos.spring.beans.factory.annotation;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor;
import org.springframework.beans.factory.annotation.InjectionMetadata;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
import org.springframework.beans.factory.support.MergedBeanDefinitionPostProcessor;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.EnvironmentAware;
import org.springframework.core.Ordered;
import org.springframework.core.PriorityOrdered;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.env.Environment;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;
import java.beans.PropertyDescriptor;
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import static com.alibaba.spring.util.AnnotationUtils.getAnnotationAttributes;
import static java.util.Collections.unmodifiableMap;
import static org.springframework.aop.support.AopUtils.getTargetClass;
import static org.springframework.core.BridgeMethodResolver.findBridgedMethod;
import static org.springframework.core.BridgeMethodResolver.isVisibilityBridgeMethodPair;
import static org.springframework.core.GenericTypeResolver.resolveTypeArgument;
/**
* Abstract common {@link BeanPostProcessor} implementation for customized annotation that annotated injected-object.
*
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
* @since 1.0.3
*/
@SuppressWarnings("unchecked")
public abstract class AbstractAnnotationBeanPostProcessor implements InstantiationAwareBeanPostProcessor, MergedBeanDefinitionPostProcessor, PriorityOrdered,
BeanFactoryAware, BeanClassLoaderAware, EnvironmentAware, DisposableBean {
private final static int CACHE_SIZE = Integer.getInteger("", 32);
private final Log logger = LogFactory.getLog(getClass());
private final Class<? extends Annotation>[] annotationTypes;
private final ConcurrentMap<String, AnnotatedInjectionMetadata> injectionMetadataCache =
new ConcurrentHashMap<String, AnnotatedInjectionMetadata>(CACHE_SIZE);
private final ConcurrentMap<String, Object> injectedObjectsCache = new ConcurrentHashMap<String, Object>(CACHE_SIZE);
private ConfigurableListableBeanFactory beanFactory;
private Environment environment;
private ClassLoader classLoader;
/**
* make sure higher priority than {@link AutowiredAnnotationBeanPostProcessor}
*/
private int order = Ordered.LOWEST_PRECEDENCE - 3;
/**
* whether to turn Class references into Strings (for
* compatibility with {@link org.springframework.core.type.AnnotationMetadata} or to
* preserve them as Class references
*
* @since 1.0.11
*/
private boolean classValuesAsString = true;
/**
* whether to turn nested Annotation instances into
* {@link AnnotationAttributes} maps (for compatibility with
* {@link org.springframework.core.type.AnnotationMetadata} or to preserve them as
* Annotation instances
*
* @since 1.0.11
*/
private boolean nestedAnnotationsAsMap = true;
/**
* whether ignore default value or not
*
* @since 1.0.11
*/
private boolean ignoreDefaultValue = true;
/**
* whether try merged annotation or not
*
* @since 1.0.11
*/
private boolean tryMergedAnnotation = true;
/**
* @param annotationTypes the multiple types of {@link Annotation annotations}
*/
public AbstractAnnotationBeanPostProcessor(Class<? extends Annotation>... annotationTypes) {
Assert.notEmpty(annotationTypes, "The argument of annotations' types must not empty");
this.annotationTypes = annotationTypes;
}
private static <T> Collection<T> combine(Collection<? extends T>... elements) {
List<T> allElements = new ArrayList<T>();
for (Collection<? extends T> e : elements) {
allElements.addAll(e);
}
return allElements;
}
/**
* Annotation type
*
* @return non-null
* @deprecated 2.7.3, uses {@link #getAnnotationTypes()}
*/
@Deprecated
public final Class<? extends Annotation> getAnnotationType() {
return annotationTypes[0];
}
protected final Class<? extends Annotation>[] getAnnotationTypes() {
return annotationTypes;
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
Assert.isInstanceOf(ConfigurableListableBeanFactory.class, beanFactory,
"AnnotationInjectedBeanPostProcessor requires a ConfigurableListableBeanFactory");
this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
}
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeanCreationException {
InjectionMetadata metadata = findInjectionMetadata(beanName, bean.getClass(), pvs);
try {
metadata.inject(bean, beanName, pvs);
} catch (BeanCreationException ex) {
throw ex;
} catch (Throwable ex) {
throw new BeanCreationException(beanName, "Injection of @" + getAnnotationType().getSimpleName()
+ " dependencies is failed", ex);
}
return pvs;
}
/**
* Finds {@link InjectionMetadata.InjectedElement} Metadata from annotated fields
*
* @param beanClass The {@link Class} of Bean
* @return non-null {@link List}
*/
private List<AnnotatedFieldElement> findFieldAnnotationMetadata(final Class<?> beanClass) {
final List<AnnotatedFieldElement> elements = new LinkedList<AnnotatedFieldElement>();
ReflectionUtils.doWithFields(beanClass, new ReflectionUtils.FieldCallback() {
@Override
public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException {
for (Class<? extends Annotation> annotationType : getAnnotationTypes()) {
AnnotationAttributes attributes = doGetAnnotationAttributes(field, annotationType);
if (attributes != null) {
if (Modifier.isStatic(field.getModifiers())) {
if (logger.isWarnEnabled()) {
logger.warn("@" + annotationType.getName() + " is not supported on static fields: " + field);
}
return;
}
elements.add(new AnnotatedFieldElement(field, attributes));
}
}
}
});
return elements;
}
/**
* Finds {@link InjectionMetadata.InjectedElement} Metadata from annotated methods
*
* @param beanClass The {@link Class} of Bean
* @return non-null {@link List}
*/
private List<AnnotatedMethodElement> findAnnotatedMethodMetadata(final Class<?> beanClass) {
final List<AnnotatedMethodElement> elements = new LinkedList<AnnotatedMethodElement>();
ReflectionUtils.doWithMethods(beanClass, new ReflectionUtils.MethodCallback() {
@Override
public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
Method bridgedMethod = findBridgedMethod(method);
if (!isVisibilityBridgeMethodPair(method, bridgedMethod)) {
return;
}
for (Class<? extends Annotation> annotationType : getAnnotationTypes()) {
AnnotationAttributes attributes = doGetAnnotationAttributes(bridgedMethod, annotationType);
if (attributes != null && method.equals(ClassUtils.getMostSpecificMethod(method, beanClass))) {
if (Modifier.isStatic(method.getModifiers())) {
if (logger.isWarnEnabled()) {
logger.warn("@" + annotationType.getName() + " annotation is not supported on static methods: " + method);
}
return;
}
if (method.getParameterTypes().length == 0) {
if (logger.isWarnEnabled()) {
logger.warn("@" + annotationType.getName() + " annotation should only be used on methods with parameters: " +
method);
}
}
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, beanClass);
elements.add(new AnnotatedMethodElement(method, pd, attributes));
}
}
}
});
return elements;
}
/**
* Get {@link AnnotationAttributes}
*
* @param annotatedElement {@link AnnotatedElement the annotated element}
* @param annotationType the {@link Class tyoe} pf {@link Annotation annotation}
* @return if <code>annotatedElement</code> can't be found in <code>annotatedElement</code>, return <code>null</code>
* @since 1.0.11
*/
protected AnnotationAttributes doGetAnnotationAttributes(AnnotatedElement annotatedElement,
Class<? extends Annotation> annotationType) {
return getAnnotationAttributes(annotatedElement, annotationType, getEnvironment(),
classValuesAsString, nestedAnnotationsAsMap, ignoreDefaultValue, tryMergedAnnotation);
}
private AnnotatedInjectionMetadata buildAnnotatedMetadata(final Class<?> beanClass) {
Collection<AnnotatedFieldElement> fieldElements = findFieldAnnotationMetadata(beanClass);
Collection<AnnotatedMethodElement> methodElements = findAnnotatedMethodMetadata(beanClass);
return new AnnotatedInjectionMetadata(beanClass, fieldElements, methodElements);
}
private InjectionMetadata findInjectionMetadata(String beanName, Class<?> clazz, PropertyValues pvs) {
// Fall back to class name as cache key, for backwards compatibility with custom callers.
String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
// Quick check on the concurrent map first, with minimal locking.
AnnotatedInjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
synchronized (this.injectionMetadataCache) {
metadata = this.injectionMetadataCache.get(cacheKey);
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
if (metadata != null) {
metadata.clear(pvs);
}
try {
metadata = buildAnnotatedMetadata(clazz);
this.injectionMetadataCache.put(cacheKey, metadata);
} catch (NoClassDefFoundError err) {
throw new IllegalStateException("Failed to introspect object class [" + clazz.getName() +
"] for annotation metadata: could not find class that it depends on", err);
}
}
}
}
return metadata;
}
@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
if (beanType != null) {
InjectionMetadata metadata = findInjectionMetadata(beanName, beanType, null);
metadata.checkConfigMembers(beanDefinition);
}
}
@Override
public int getOrder() {
return order;
}
public void setOrder(int order) {
this.order = order;
}
@Override
public void destroy() throws Exception {
for (Object object : injectedObjectsCache.values()) {
if (logger.isInfoEnabled()) {
logger.info(object + " was destroying!");
}
if (object instanceof DisposableBean) {
((DisposableBean) object).destroy();
}
}
injectionMetadataCache.clear();
injectedObjectsCache.clear();
if (logger.isInfoEnabled()) {
logger.info(getClass() + " was destroying!");
}
}
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
this.classLoader = classLoader;
}
@Override
public void setEnvironment(Environment environment) {
this.environment = environment;
}
protected Environment getEnvironment() {
return environment;
}
protected ClassLoader getClassLoader() {
return classLoader;
}
protected ConfigurableListableBeanFactory getBeanFactory() {
return beanFactory;
}
/**
* Gets all injected-objects.
*
* @return non-null {@link Collection}
*/
protected Collection<Object> getInjectedObjects() {
return this.injectedObjectsCache.values();
}
/**
* Get injected-object from specified {@link AnnotationAttributes annotation attributes} and Bean Class
*
* @param attributes {@link AnnotationAttributes the annotation attributes}
* @param bean Current bean that will be injected
* @param beanName Current bean name that will be injected
* @param injectedType the type of injected-object
* @param injectedElement {@link InjectionMetadata.InjectedElement}
* @return An injected object
* @throws Exception If getting is failed
*/
protected Object getInjectedObject(AnnotationAttributes attributes, Object bean, String beanName, Class<?> injectedType,
InjectionMetadata.InjectedElement injectedElement) throws Exception {
String cacheKey = buildInjectedObjectCacheKey(attributes, bean, beanName, injectedType, injectedElement);
Object injectedObject = injectedObjectsCache.get(cacheKey);
if (injectedObject == null) {
injectedObject = doGetInjectedBean(attributes, bean, beanName, injectedType, injectedElement);
if (injectedObject != null) {
// Customized inject-object if necessary
injectedObjectsCache.putIfAbsent(cacheKey, injectedObject);
}
}
return injectedObject;
}
/**
* Subclass must implement this method to get injected-object. The context objects could help this method if
* necessary :
* <ul>
* <li>{@link #getBeanFactory() BeanFactory}</li>
* <li>{@link #getClassLoader() ClassLoader}</li>
* <li>{@link #getEnvironment() Environment}</li>
* </ul>
*
* @param attributes {@link AnnotationAttributes the annotation attributes}
* @param bean Current bean that will be injected
* @param beanName Current bean name that will be injected
* @param injectedType the type of injected-object
* @param injectedElement {@link InjectionMetadata.InjectedElement}
* @return The injected object
* @throws Exception If resolving an injected object is failed.
*/
protected abstract Object doGetInjectedBean(AnnotationAttributes attributes, Object bean, String beanName, Class<?> injectedType,
InjectionMetadata.InjectedElement injectedElement) throws Exception;
/**
* Build a cache key for injected-object. The context objects could help this method if
* necessary :
* <ul>
* <li>{@link #getBeanFactory() BeanFactory}</li>
* <li>{@link #getClassLoader() ClassLoader}</li>
* <li>{@link #getEnvironment() Environment}</li>
* </ul>
*
* @param attributes {@link AnnotationAttributes the annotation attributes}
* @param bean Current bean that will be injected
* @param beanName Current bean name that will be injected
* @param injectedType the type of injected-object
* @param injectedElement {@link InjectionMetadata.InjectedElement}
* @return Bean cache key
*/
protected abstract String buildInjectedObjectCacheKey(AnnotationAttributes attributes, Object bean, String beanName,
Class<?> injectedType,
InjectionMetadata.InjectedElement injectedElement);
/**
* Get {@link Map} in injected field.
*
* @return non-null ready-only {@link Map}
*/
protected Map<InjectionMetadata.InjectedElement, Object> getInjectedFieldObjectsMap() {
Map<InjectionMetadata.InjectedElement, Object> injectedElementBeanMap =
new LinkedHashMap<InjectionMetadata.InjectedElement, Object>();
for (AnnotatedInjectionMetadata metadata : injectionMetadataCache.values()) {
Collection<AnnotatedFieldElement> fieldElements = metadata.getFieldElements();
for (AnnotatedFieldElement fieldElement : fieldElements) {
injectedElementBeanMap.put(fieldElement, fieldElement.bean);
}
}
return unmodifiableMap(injectedElementBeanMap);
}
/**
* Get {@link Map} in injected method.
*
* @return non-null {@link Map}
*/
protected Map<InjectionMetadata.InjectedElement, Object> getInjectedMethodObjectsMap() {
Map<InjectionMetadata.InjectedElement, Object> injectedElementBeanMap =
new LinkedHashMap<InjectionMetadata.InjectedElement, Object>();
for (AnnotatedInjectionMetadata metadata : injectionMetadataCache.values()) {
Collection<AnnotatedMethodElement> methodElements = metadata.getMethodElements();
for (AnnotatedMethodElement methodElement : methodElements) {
injectedElementBeanMap.put(methodElement, methodElement.object);
}
}
return unmodifiableMap(injectedElementBeanMap);
}
/**
* @param classValuesAsString whether to turn Class references into Strings (for
* compatibility with {@link org.springframework.core.type.AnnotationMetadata} or to
* preserve them as Class references
* @since 1.0.11
*/
public void setClassValuesAsString(boolean classValuesAsString) {
this.classValuesAsString = classValuesAsString;
}
/**
* @param nestedAnnotationsAsMap whether to turn nested Annotation instances into
* {@link AnnotationAttributes} maps (for compatibility with
* {@link org.springframework.core.type.AnnotationMetadata} or to preserve them as
* Annotation instances
* @since 1.0.11
*/
public void setNestedAnnotationsAsMap(boolean nestedAnnotationsAsMap) {
this.nestedAnnotationsAsMap = nestedAnnotationsAsMap;
}
/**
* @param ignoreDefaultValue whether ignore default value or not
* @since 1.0.11
*/
public void setIgnoreDefaultValue(boolean ignoreDefaultValue) {
this.ignoreDefaultValue = ignoreDefaultValue;
}
/**
* @param tryMergedAnnotation whether try merged annotation or not
* @since 1.0.11
*/
public void setTryMergedAnnotation(boolean tryMergedAnnotation) {
this.tryMergedAnnotation = tryMergedAnnotation;
}
/**
* {@link Annotation Annotated} {@link InjectionMetadata} implementation
*/
private class AnnotatedInjectionMetadata extends InjectionMetadata {
private final Collection<AnnotatedFieldElement> fieldElements;
private final Collection<AnnotatedMethodElement> methodElements;
public AnnotatedInjectionMetadata(Class<?> targetClass, Collection<AnnotatedFieldElement> fieldElements,
Collection<AnnotatedMethodElement> methodElements) {
super(targetClass, combine(fieldElements, methodElements));
this.fieldElements = fieldElements;
this.methodElements = methodElements;
}
public Collection<AnnotatedFieldElement> getFieldElements() {
return fieldElements;
}
public Collection<AnnotatedMethodElement> getMethodElements() {
return methodElements;
}
}
/**
* {@link Annotation Annotated} {@link Method} {@link InjectionMetadata.InjectedElement}
*/
private class AnnotatedMethodElement extends InjectionMetadata.InjectedElement {
private final Method method;
private final AnnotationAttributes attributes;
private volatile Object object;
protected AnnotatedMethodElement(Method method, PropertyDescriptor pd, AnnotationAttributes attributes) {
super(method, pd);
this.method = method;
this.attributes = attributes;
}
@Override
protected void inject(Object bean, String beanName, PropertyValues pvs) throws Throwable {
Class<?> injectedType = pd.getPropertyType();
Object injectedObject = getInjectedObject(attributes, bean, beanName, injectedType, this);
ReflectionUtils.makeAccessible(method);
method.invoke(bean, injectedObject);
}
}
/**
* {@link Annotation Annotated} {@link Field} {@link InjectionMetadata.InjectedElement}
*/
public class AnnotatedFieldElement extends InjectionMetadata.InjectedElement {
private final Field field;
private final AnnotationAttributes attributes;
private volatile Object bean;
protected AnnotatedFieldElement(Field field, AnnotationAttributes attributes) {
super(field, null);
this.field = field;
this.attributes = attributes;
}
@Override
protected void inject(Object bean, String beanName, PropertyValues pvs) throws Throwable {
Class<?> injectedType = resolveInjectedType(bean, field);
Object injectedObject = getInjectedObject(attributes, bean, beanName, injectedType, this);
ReflectionUtils.makeAccessible(field);
field.set(bean, injectedObject);
}
private Class<?> resolveInjectedType(Object bean, Field field) {
Type genericType = field.getGenericType();
if (genericType instanceof Class) { // Just a normal Class
return field.getType();
} else { // GenericType
return resolveTypeArgument(getTargetClass(bean), field.getDeclaringClass());
}
}
}
}

View File

@ -16,24 +16,25 @@
*/ */
package com.alibaba.nacos.spring.beans.factory.annotation; package com.alibaba.nacos.spring.beans.factory.annotation;
import com.alibaba.nacos.api.annotation.NacosProperties; import static com.alibaba.nacos.spring.util.NacosBeanUtils.getNacosServiceFactoryBean;
import com.alibaba.nacos.api.exception.NacosException; import static com.alibaba.spring.util.ClassUtils.resolveGenericType;
import com.alibaba.nacos.spring.factory.NacosServiceFactory; import static java.lang.String.format;
import com.alibaba.nacos.spring.util.GlobalNacosPropertiesSource; import static org.springframework.core.annotation.AnnotationUtils.getAnnotationAttributes;
import com.alibaba.nacos.spring.util.NacosUtils;
import java.util.Map;
import java.util.Properties;
import org.springframework.beans.factory.BeanCreationException; import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.context.EnvironmentAware; import org.springframework.context.EnvironmentAware;
import org.springframework.core.env.Environment; import org.springframework.core.env.Environment;
import java.util.Map; import com.alibaba.nacos.api.annotation.NacosProperties;
import java.util.Properties; import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.spring.factory.NacosServiceFactory;
import static com.alibaba.nacos.spring.util.NacosBeanUtils.getNacosServiceFactoryBean; import com.alibaba.nacos.spring.util.GlobalNacosPropertiesSource;
import static com.alibaba.spring.util.ClassUtils.resolveGenericType; import com.alibaba.nacos.spring.util.NacosUtils;
import static java.lang.String.format;
import static org.springframework.core.annotation.AnnotationUtils.getAnnotationAttributes;
/** /**
* Abstract Nacos Service Bean Builder * Abstract Nacos Service Bean Builder
@ -42,15 +43,13 @@ import static org.springframework.core.annotation.AnnotationUtils.getAnnotationA
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a> * @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
* @since 0.1.0 * @since 0.1.0
*/ */
public abstract class AbstractNacosServiceBeanBuilder<S> implements BeanFactoryAware, EnvironmentAware { public abstract class AbstractNacosServiceBeanBuilder<S>
implements BeanFactoryAware, EnvironmentAware {
private BeanFactory beanFactory;
private Environment environment;
private final Class<?> type; private final Class<?> type;
private final GlobalNacosPropertiesSource source; private final GlobalNacosPropertiesSource source;
private BeanFactory beanFactory;
private Environment environment;
protected AbstractNacosServiceBeanBuilder(GlobalNacosPropertiesSource source) { protected AbstractNacosServiceBeanBuilder(GlobalNacosPropertiesSource source) {
type = resolveGenericType(getClass()); type = resolveGenericType(getClass());
@ -74,7 +73,8 @@ public abstract class AbstractNacosServiceBeanBuilder<S> implements BeanFactoryA
try { try {
return createService(nacosServiceFactory, properties); return createService(nacosServiceFactory, properties);
} catch (NacosException e) { }
catch (NacosException e) {
throw new BeanCreationException(e.getErrMsg(), e); throw new BeanCreationException(e.getErrMsg(), e);
} }
} }
@ -87,7 +87,8 @@ public abstract class AbstractNacosServiceBeanBuilder<S> implements BeanFactoryA
* @return target Nacos Service instance * @return target Nacos Service instance
* @throws NacosException When Nacos Service creation is failed * @throws NacosException When Nacos Service creation is failed
*/ */
protected abstract S createService(NacosServiceFactory nacosServiceFactory, Properties properties) throws NacosException; protected abstract S createService(NacosServiceFactory nacosServiceFactory,
Properties properties) throws NacosException;
/** /**
* Resolve Nacos {@link Properties} from {@link NacosProperties @NacosProperties} * Resolve Nacos {@link Properties} from {@link NacosProperties @NacosProperties}
@ -97,25 +98,28 @@ public abstract class AbstractNacosServiceBeanBuilder<S> implements BeanFactoryA
*/ */
public final Properties resolveProperties(NacosProperties nacosProperties) { public final Properties resolveProperties(NacosProperties nacosProperties) {
Properties globalNacosProperties = resolveGlobalNacosProperties(); Properties globalNacosProperties = resolveGlobalNacosProperties();
return NacosUtils.resolveProperties(nacosProperties, environment, globalNacosProperties); return NacosUtils.resolveProperties(nacosProperties, environment,
globalNacosProperties);
} }
/** /**
* Resolve Nacos {@link Properties} from {@link NacosProperties @NacosProperties} * Resolve Nacos {@link Properties} from {@link NacosProperties @NacosProperties}
* *
* @param nacosPropertiesAttributes {@link NacosProperties Nacos Properties}'s attributes * @param nacosPropertiesAttributes {@link NacosProperties Nacos Properties}'s
* attributes
* @return non-null * @return non-null
*/ */
public final Properties resolveProperties(Map<String, Object> nacosPropertiesAttributes) { public final Properties resolveProperties(
Map<String, Object> nacosPropertiesAttributes) {
Properties globalNacosProperties = resolveGlobalNacosProperties(); Properties globalNacosProperties = resolveGlobalNacosProperties();
return NacosUtils.resolveProperties(nacosPropertiesAttributes, environment, globalNacosProperties); return NacosUtils.resolveProperties(nacosPropertiesAttributes, environment,
globalNacosProperties);
} }
private Properties resolveGlobalNacosProperties() { private Properties resolveGlobalNacosProperties() {
return source.getMergedGlobalProperties(beanFactory); return source.getMergedGlobalProperties(beanFactory);
} }
final Class<?> getType() { final Class<?> getType() {
return type; return type;
} }

View File

@ -16,15 +16,8 @@
*/ */
package com.alibaba.nacos.spring.beans.factory.annotation; package com.alibaba.nacos.spring.beans.factory.annotation;
import com.alibaba.nacos.api.annotation.NacosInjected; import static java.lang.String.format;
import com.alibaba.nacos.api.config.ConfigService; import static java.util.Collections.unmodifiableMap;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.spring.beans.factory.annotation.AnnotationInjectedBeanPostProcessor;
import com.alibaba.spring.util.BeanUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.annotation.InjectionMetadata;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
@ -32,19 +25,28 @@ import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Properties; import java.util.Properties;
import static java.lang.String.format; import org.springframework.beans.factory.InitializingBean;
import static java.util.Collections.unmodifiableMap; import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.annotation.InjectionMetadata;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.core.annotation.AnnotationAttributes;
import com.alibaba.nacos.api.annotation.NacosInjected;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.spring.beans.factory.annotation.AnnotationInjectedBeanPostProcessor;
import com.alibaba.spring.util.BeanUtils;
/** /**
* {@link AnnotationInjectedBeanPostProcessor} implementation is used to * {@link AnnotationInjectedBeanPostProcessor} implementation is used to inject
* inject {@link ConfigService} or {@link NamingService} instance into a Spring Bean If it's attributes or properties annotated * {@link ConfigService} or {@link NamingService} instance into a Spring Bean If it's
* {@link NacosInjected @NacosInjected}. * attributes or properties annotated {@link NacosInjected @NacosInjected}.
* *
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a> * @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
* @since 0.1.0 * @since 0.1.0
*/ */
public class AnnotationNacosInjectedBeanPostProcessor extends AnnotationInjectedBeanPostProcessor<NacosInjected> public class AnnotationNacosInjectedBeanPostProcessor
implements InitializingBean { extends AbstractAnnotationBeanPostProcessor implements InitializingBean {
/** /**
* The name of {@link AnnotationNacosInjectedBeanPostProcessor} * The name of {@link AnnotationNacosInjectedBeanPostProcessor}
@ -53,6 +55,10 @@ public class AnnotationNacosInjectedBeanPostProcessor extends AnnotationInjected
private Map<Class<?>, AbstractNacosServiceBeanBuilder> nacosServiceBeanBuilderMap; private Map<Class<?>, AbstractNacosServiceBeanBuilder> nacosServiceBeanBuilderMap;
public AnnotationNacosInjectedBeanPostProcessor() {
super(NacosInjected.class);
}
@Override @Override
public final void afterPropertiesSet() { public final void afterPropertiesSet() {
// Get beanFactory from super // Get beanFactory from super
@ -61,29 +67,32 @@ public class AnnotationNacosInjectedBeanPostProcessor extends AnnotationInjected
initNacosServiceBeanBuilderMap(beanFactory); initNacosServiceBeanBuilderMap(beanFactory);
} }
private void initNacosServiceBeanBuilderMap(ConfigurableListableBeanFactory beanFactory) { private void initNacosServiceBeanBuilderMap(
ConfigurableListableBeanFactory beanFactory) {
Class<AbstractNacosServiceBeanBuilder> builderClass = AbstractNacosServiceBeanBuilder.class; Class<AbstractNacosServiceBeanBuilder> builderClass = AbstractNacosServiceBeanBuilder.class;
String[] beanNames = BeanUtils.getBeanNames(beanFactory, builderClass); String[] beanNames = BeanUtils.getBeanNames(beanFactory, builderClass);
if (beanNames.length == 0) { if (beanNames.length == 0) {
throw new NoSuchBeanDefinitionException(builderClass, throw new NoSuchBeanDefinitionException(builderClass,
format("Please check the BeanDefinition of %s in Spring BeanFactory", builderClass)); format("Please check the BeanDefinition of %s in Spring BeanFactory",
builderClass));
} }
Collection<AbstractNacosServiceBeanBuilder> serviceBeanBuilders Collection<AbstractNacosServiceBeanBuilder> serviceBeanBuilders = new ArrayList<AbstractNacosServiceBeanBuilder>(
= new ArrayList<AbstractNacosServiceBeanBuilder>(beanNames.length); beanNames.length);
for (String beanName : beanNames) { for (String beanName : beanNames) {
serviceBeanBuilders.add(beanFactory.getBean(beanName, builderClass)); serviceBeanBuilders.add(beanFactory.getBean(beanName, builderClass));
} }
if (serviceBeanBuilders.isEmpty()) { if (serviceBeanBuilders.isEmpty()) {
throw new NoSuchBeanDefinitionException(builderClass, throw new NoSuchBeanDefinitionException(builderClass,
format("Please check the BeanDefinition of %s in Spring BeanFactory", builderClass)); format("Please check the BeanDefinition of %s in Spring BeanFactory",
builderClass));
} }
Map<Class<?>, AbstractNacosServiceBeanBuilder> builderMap = Map<Class<?>, AbstractNacosServiceBeanBuilder> builderMap = new HashMap<Class<?>, AbstractNacosServiceBeanBuilder>(
new HashMap<Class<?>, AbstractNacosServiceBeanBuilder>(serviceBeanBuilders.size()); serviceBeanBuilders.size());
for (AbstractNacosServiceBeanBuilder serviceBeanBuilder : serviceBeanBuilders) { for (AbstractNacosServiceBeanBuilder serviceBeanBuilder : serviceBeanBuilders) {
Class<?> type = serviceBeanBuilder.getType(); Class<?> type = serviceBeanBuilder.getType();
@ -95,34 +104,43 @@ public class AnnotationNacosInjectedBeanPostProcessor extends AnnotationInjected
} }
@Override @Override
protected Object doGetInjectedBean(NacosInjected annotation, Object bean, String beanName, Class<?> injectedType, protected Object doGetInjectedBean(AnnotationAttributes attributes, Object bean,
InjectionMetadata.InjectedElement injectedElement) { String beanName, Class<?> injectedType,
InjectionMetadata.InjectedElement injectedElement) throws Exception {
AbstractNacosServiceBeanBuilder serviceBeanBuilder = nacosServiceBeanBuilderMap
.get(injectedType);
AbstractNacosServiceBeanBuilder serviceBeanBuilder = nacosServiceBeanBuilderMap.get(injectedType); Map<String, Object> nacosProperties = getNacosProperties(attributes);
return serviceBeanBuilder.build(annotation.properties());
return serviceBeanBuilder.build(nacosProperties);
} }
@Override @Override
protected String buildInjectedObjectCacheKey(NacosInjected annotation, Object bean, String beanName, protected String buildInjectedObjectCacheKey(AnnotationAttributes attributes,
Class<?> injectedType, InjectionMetadata.InjectedElement injectedElement) { Object bean, String beanName, Class<?> injectedType,
InjectionMetadata.InjectedElement injectedElement) {
StringBuilder keyBuilder = new StringBuilder(injectedType.getSimpleName()); StringBuilder keyBuilder = new StringBuilder(injectedType.getSimpleName());
AbstractNacosServiceBeanBuilder serviceBeanBuilder = nacosServiceBeanBuilderMap.get(injectedType); AbstractNacosServiceBeanBuilder serviceBeanBuilder = nacosServiceBeanBuilderMap
.get(injectedType);
if (serviceBeanBuilder == null) { if (serviceBeanBuilder == null) {
throw new UnsupportedOperationException( throw new UnsupportedOperationException(format(
format("Only support to inject types[%s] instance , however actual injected type [%s] in member[%s]", "Only support to inject types[%s] instance , however actual injected type [%s] in member[%s]",
nacosServiceBeanBuilderMap.keySet(), injectedType, injectedElement.getMember())); nacosServiceBeanBuilderMap.keySet(), injectedType,
injectedElement.getMember()));
} }
Properties properties = serviceBeanBuilder.resolveProperties(annotation.properties()); Map<String, Object> nacosProperties = getNacosProperties(attributes);
Properties properties = serviceBeanBuilder.resolveProperties(nacosProperties);
keyBuilder.append(properties); keyBuilder.append(properties);
return keyBuilder.toString(); return keyBuilder.toString();
}
private Map<String, Object> getNacosProperties(AnnotationAttributes attributes) {
return (Map<String, Object>) attributes.get("properties");
} }
} }

View File

@ -16,20 +16,21 @@
*/ */
package com.alibaba.nacos.spring.beans.factory.annotation; package com.alibaba.nacos.spring.beans.factory.annotation;
import java.util.Properties;
import com.alibaba.nacos.api.config.ConfigService; import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.exception.NacosException; import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.spring.factory.NacosServiceFactory; import com.alibaba.nacos.spring.factory.NacosServiceFactory;
import com.alibaba.nacos.spring.util.GlobalNacosPropertiesSource; import com.alibaba.nacos.spring.util.GlobalNacosPropertiesSource;
import java.util.Properties;
/** /**
* {@link ConfigService} Bean Builder * {@link ConfigService} Bean Builder
* *
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a> * @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
* @since 0.1.0 * @since 0.1.0
*/ */
public class ConfigServiceBeanBuilder extends AbstractNacosServiceBeanBuilder<ConfigService> { public class ConfigServiceBeanBuilder
extends AbstractNacosServiceBeanBuilder<ConfigService> {
/** /**
* The bean name of {@link ConfigServiceBeanBuilder} * The bean name of {@link ConfigServiceBeanBuilder}
@ -41,8 +42,8 @@ public class ConfigServiceBeanBuilder extends AbstractNacosServiceBeanBuilder<Co
} }
@Override @Override
protected ConfigService createService(NacosServiceFactory nacosServiceFactory, Properties properties) protected ConfigService createService(NacosServiceFactory nacosServiceFactory,
throws NacosException { Properties properties) throws NacosException {
return nacosServiceFactory.createConfigService(properties); return nacosServiceFactory.createConfigService(properties);
} }
} }

View File

@ -0,0 +1,46 @@
/*
* 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 com.alibaba.nacos.spring.beans.factory.annotation;
import java.util.Properties;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.NamingMaintainService;
import com.alibaba.nacos.spring.factory.NacosServiceFactory;
import com.alibaba.nacos.spring.util.GlobalNacosPropertiesSource;
/**
* @author <a href="mailto:liaochunyhm@live.com">liaochuntao</a>
*/
public class NamingMaintainServiceBeanBuilder
extends AbstractNacosServiceBeanBuilder<NamingMaintainService> {
/**
* The bean name of {@link NamingServiceBeanBuilder}
*/
public static final String BEAN_NAME = "namingMaintainServiceBeanBuilder";
public NamingMaintainServiceBeanBuilder() {
super(GlobalNacosPropertiesSource.MAINTAIN);
}
@Override
protected NamingMaintainService createService(NacosServiceFactory nacosServiceFactory,
Properties properties) throws NacosException {
return nacosServiceFactory.createNamingMaintainService(properties);
}
}

View File

@ -16,20 +16,21 @@
*/ */
package com.alibaba.nacos.spring.beans.factory.annotation; package com.alibaba.nacos.spring.beans.factory.annotation;
import java.util.Properties;
import com.alibaba.nacos.api.exception.NacosException; import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.NamingService; import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.spring.factory.NacosServiceFactory; import com.alibaba.nacos.spring.factory.NacosServiceFactory;
import com.alibaba.nacos.spring.util.GlobalNacosPropertiesSource; import com.alibaba.nacos.spring.util.GlobalNacosPropertiesSource;
import java.util.Properties;
/** /**
* {@link NamingService} Bean Builder * {@link NamingService} Bean Builder
* *
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a> * @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
* @since 0.1.0 * @since 0.1.0
*/ */
public class NamingServiceBeanBuilder extends AbstractNacosServiceBeanBuilder<NamingService> { public class NamingServiceBeanBuilder
extends AbstractNacosServiceBeanBuilder<NamingService> {
/** /**
* The bean name of {@link NamingServiceBeanBuilder} * The bean name of {@link NamingServiceBeanBuilder}
@ -41,8 +42,8 @@ public class NamingServiceBeanBuilder extends AbstractNacosServiceBeanBuilder<Na
} }
@Override @Override
protected NamingService createService(NacosServiceFactory nacosServiceFactory, Properties properties) protected NamingService createService(NacosServiceFactory nacosServiceFactory,
throws NacosException { Properties properties) throws NacosException {
return nacosServiceFactory.createNamingService(properties); return nacosServiceFactory.createNamingService(properties);
} }
} }

View File

@ -16,13 +16,18 @@
*/ */
package com.alibaba.nacos.spring.context.annotation; package com.alibaba.nacos.spring.context.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.context.annotation.Import;
import com.alibaba.nacos.api.annotation.NacosInjected; import com.alibaba.nacos.api.annotation.NacosInjected;
import com.alibaba.nacos.api.annotation.NacosProperties; import com.alibaba.nacos.api.annotation.NacosProperties;
import com.alibaba.nacos.api.config.annotation.NacosConfigListener; import com.alibaba.nacos.api.config.annotation.NacosConfigListener;
import com.alibaba.nacos.api.config.annotation.NacosConfigurationProperties; import com.alibaba.nacos.api.config.annotation.NacosConfigurationProperties;
import org.springframework.context.annotation.Import;
import java.lang.annotation.*;
/** /**
* Annotation for enabling Nacos features. * Annotation for enabling Nacos features.
@ -34,7 +39,7 @@ import java.lang.annotation.*;
@Target({ ElementType.TYPE, ElementType.ANNOTATION_TYPE }) @Target({ ElementType.TYPE, ElementType.ANNOTATION_TYPE })
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Documented @Documented
@Import(NacosBeanDefinitionRegistrar.class) @Import({NacosBeanDefinitionRegistrar.class, EnableNacosAotProcessor.class})
public @interface EnableNacos { public @interface EnableNacos {
/** /**

View File

@ -0,0 +1,96 @@
/*
*
* * 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 com.alibaba.nacos.spring.context.annotation;
import com.alibaba.nacos.spring.util.aot.AotDetector;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.EnvironmentAware;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotationMetadata;
import java.util.Collection;
import java.util.Map;
import static com.alibaba.nacos.spring.util.NacosBeanUtils.*;
/**
* {@link EnableNacos} AotProcessor
* Except for the operation of registering BeanDefinition, all other operations in {@link NacosBeanDefinitionRegistrar} must be done here
* because spring will not call {@link NacosBeanDefinitionRegistrar#registerBeanDefinitions} in AOT.
* @author SuperZ1999
*/
public class EnableNacosAotProcessor implements BeanDefinitionRegistryPostProcessor, EnvironmentAware, BeanFactoryAware {
private Environment environment;
private BeanFactory beanFactory;
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
if (!AotDetector.useGeneratedArtifacts()) {
return;
}
DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) this.beanFactory;
Map<String, Object> beansWithAnnotation = beanFactory.getBeansWithAnnotation(EnableNacos.class);
Object[] beans = beansWithAnnotation.values().toArray();
if (beans.length != 0) {
// only handle the first one
Class<?> aClass = beans[0].getClass();
if (aClass.getAnnotation(EnableNacos.class) == null) {
// cglib proxy object
aClass = aClass.getSuperclass();
}
AnnotationMetadata annotationMetadata = AnnotationMetadata.introspect(aClass);
AnnotationAttributes attributes = AnnotationAttributes
.fromMap(annotationMetadata
.getAnnotationAttributes(EnableNacos.class.getName()));
// Register Global Nacos Properties Bean
registerGlobalNacosProperties(attributes, registry, environment,
GLOBAL_NACOS_PROPERTIES_BEAN_NAME);
}
registerNacosConfigListenerExecutor(registry, environment);
// Invoke NacosPropertySourcePostProcessor immediately
// in order to enhance the precedence of @NacosPropertySource process
invokeNacosPropertySourcePostProcessor(this.beanFactory);
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
}
@Override
public void setEnvironment(Environment environment) {
this.environment = environment;
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
}

View File

@ -16,6 +16,13 @@
*/ */
package com.alibaba.nacos.spring.context.annotation; package com.alibaba.nacos.spring.context.annotation;
import static com.alibaba.nacos.spring.util.NacosBeanUtils.GLOBAL_NACOS_PROPERTIES_BEAN_NAME;
import static com.alibaba.nacos.spring.util.NacosBeanUtils.invokeNacosPropertySourcePostProcessor;
import static com.alibaba.nacos.spring.util.NacosBeanUtils.registerGlobalNacosProperties;
import static com.alibaba.nacos.spring.util.NacosBeanUtils.registerNacosCommonBeans;
import static com.alibaba.nacos.spring.util.NacosBeanUtils.registerNacosConfigBeans;
import static com.alibaba.nacos.spring.util.NacosBeanUtils.registerNacosDiscoveryBeans;
import org.springframework.beans.BeansException; import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.beans.factory.BeanFactoryAware;
@ -29,13 +36,6 @@ import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.env.Environment; import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotationMetadata; import org.springframework.core.type.AnnotationMetadata;
import static com.alibaba.nacos.spring.util.NacosBeanUtils.GLOBAL_NACOS_PROPERTIES_BEAN_NAME;
import static com.alibaba.nacos.spring.util.NacosBeanUtils.invokeNacosPropertySourcePostProcessor;
import static com.alibaba.nacos.spring.util.NacosBeanUtils.registerGlobalNacosProperties;
import static com.alibaba.nacos.spring.util.NacosBeanUtils.registerNacosCommonBeans;
import static com.alibaba.nacos.spring.util.NacosBeanUtils.registerNacosConfigBeans;
import static com.alibaba.nacos.spring.util.NacosBeanUtils.registerNacosDiscoveryBeans;
/** /**
* Nacos Properties {@link ImportBeanDefinitionRegistrar BeanDefinition Registrar} * Nacos Properties {@link ImportBeanDefinitionRegistrar BeanDefinition Registrar}
* *
@ -43,23 +43,30 @@ import static com.alibaba.nacos.spring.util.NacosBeanUtils.registerNacosDiscover
* @see EnableNacos * @see EnableNacos
* @since 0.1.0 * @since 0.1.0
*/ */
public class NacosBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar, EnvironmentAware, BeanFactoryAware { public class NacosBeanDefinitionRegistrar
implements ImportBeanDefinitionRegistrar, EnvironmentAware, BeanFactoryAware {
private Environment environment; private Environment environment;
private BeanFactory beanFactory; private BeanFactory beanFactory;
@Override @Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
BeanDefinition annotationProcessor = BeanDefinitionBuilder.genericBeanDefinition( BeanDefinitionRegistry registry) {
PropertySourcesPlaceholderConfigurer.class).getBeanDefinition(); BeanDefinition annotationProcessor = BeanDefinitionBuilder
registry.registerBeanDefinition(PropertySourcesPlaceholderConfigurer.class.getName(), annotationProcessor); .genericBeanDefinition(PropertySourcesPlaceholderConfigurer.class)
.getBeanDefinition();
registry.registerBeanDefinition(
PropertySourcesPlaceholderConfigurer.class.getName(),
annotationProcessor);
AnnotationAttributes attributes = AnnotationAttributes.fromMap( AnnotationAttributes attributes = AnnotationAttributes
importingClassMetadata.getAnnotationAttributes(EnableNacos.class.getName())); .fromMap(importingClassMetadata
.getAnnotationAttributes(EnableNacos.class.getName()));
// Register Global Nacos Properties Bean // Register Global Nacos Properties Bean
registerGlobalNacosProperties(attributes, registry, environment, GLOBAL_NACOS_PROPERTIES_BEAN_NAME); registerGlobalNacosProperties(attributes, registry, environment,
GLOBAL_NACOS_PROPERTIES_BEAN_NAME);
// Register Nacos Annotation Beans // Register Nacos Annotation Beans
registerNacosAnnotationBeans(registry); registerNacosAnnotationBeans(registry);
// Invoke NacosPropertySourcePostProcessor immediately // Invoke NacosPropertySourcePostProcessor immediately
@ -74,7 +81,7 @@ public class NacosBeanDefinitionRegistrar implements ImportBeanDefinitionRegistr
public void registerNacosAnnotationBeans(BeanDefinitionRegistry registry) { public void registerNacosAnnotationBeans(BeanDefinitionRegistry registry) {
registerNacosCommonBeans(registry); registerNacosCommonBeans(registry);
registerNacosConfigBeans(registry, environment); registerNacosConfigBeans(registry, environment, beanFactory);
registerNacosDiscoveryBeans(registry); registerNacosDiscoveryBeans(registry);
} }

View File

@ -16,16 +16,33 @@
*/ */
package com.alibaba.nacos.spring.context.annotation.config; package com.alibaba.nacos.spring.context.annotation.config;
import static com.alibaba.nacos.api.annotation.NacosProperties.ACCESS_KEY;
import static com.alibaba.nacos.api.annotation.NacosProperties.CLUSTER_NAME;
import static com.alibaba.nacos.api.annotation.NacosProperties.CONFIG_LONG_POLL_TIMEOUT;
import static com.alibaba.nacos.api.annotation.NacosProperties.CONFIG_RETRY_TIME;
import static com.alibaba.nacos.api.annotation.NacosProperties.CONTEXT_PATH;
import static com.alibaba.nacos.api.annotation.NacosProperties.ENCODE;
import static com.alibaba.nacos.api.annotation.NacosProperties.ENDPOINT;
import static com.alibaba.nacos.api.annotation.NacosProperties.MAX_RETRY;
import static com.alibaba.nacos.api.annotation.NacosProperties.NAMESPACE;
import static com.alibaba.nacos.api.annotation.NacosProperties.PASSWORD;
import static com.alibaba.nacos.api.annotation.NacosProperties.SECRET_KEY;
import static com.alibaba.nacos.api.annotation.NacosProperties.SERVER_ADDR;
import static com.alibaba.nacos.api.annotation.NacosProperties.USERNAME;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.context.annotation.Import;
import com.alibaba.nacos.api.annotation.NacosInjected; import com.alibaba.nacos.api.annotation.NacosInjected;
import com.alibaba.nacos.api.annotation.NacosProperties; import com.alibaba.nacos.api.annotation.NacosProperties;
import com.alibaba.nacos.api.config.annotation.NacosConfigListener; import com.alibaba.nacos.api.config.annotation.NacosConfigListener;
import com.alibaba.nacos.api.config.annotation.NacosConfigurationProperties; import com.alibaba.nacos.api.config.annotation.NacosConfigurationProperties;
import com.alibaba.nacos.spring.context.annotation.NacosBeanDefinitionRegistrar; import com.alibaba.nacos.spring.context.annotation.NacosBeanDefinitionRegistrar;
import org.springframework.context.annotation.Import;
import java.lang.annotation.*;
import static com.alibaba.nacos.api.annotation.NacosProperties.*;
/** /**
* Annotation for enabling Nacos Config features. * Annotation for enabling Nacos Config features.
@ -37,61 +54,92 @@ import static com.alibaba.nacos.api.annotation.NacosProperties.*;
@Target({ ElementType.TYPE, ElementType.ANNOTATION_TYPE }) @Target({ ElementType.TYPE, ElementType.ANNOTATION_TYPE })
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Documented @Documented
@Import(NacosConfigBeanDefinitionRegistrar.class) @Import({NacosConfigBeanDefinitionRegistrar.class, EnableNacosConfigAotProcessor.class})
public @interface EnableNacosConfig { public @interface EnableNacosConfig {
/** /**
* The prefix of property name of Nacos Config * The prefix of property name of Nacos Config
*/ */
String CONFIG_PREFIX = NacosProperties.PREFIX + "config."; String CONFIG_PREFIX = NacosProperties.PREFIX + "config.";
/** /**
* The placeholder of endpoint, the value is * The placeholder of endpoint, the value is
* <code>"${nacos.config.endpoint:${nacos.endpoint:}}"</code> * <code>"${nacos.config.endpoint:${nacos.endpoint:}}"</code>
*/ */
String ENDPOINT_PLACEHOLDER = "${" + CONFIG_PREFIX + ENDPOINT + ":" + NacosProperties.ENDPOINT_PLACEHOLDER + "}"; String ENDPOINT_PLACEHOLDER = "${" + CONFIG_PREFIX + ENDPOINT + ":"
+ NacosProperties.ENDPOINT_PLACEHOLDER + "}";
/** /**
* The placeholder of endpoint, the value is * The placeholder of endpoint, the value is
* <code>"${nacos.config.namespace:${nacos.namespace:}}"</code> * <code>"${nacos.config.namespace:${nacos.namespace:}}"</code>
*/ */
String NAMESPACE_PLACEHOLDER = "${" + CONFIG_PREFIX + NAMESPACE + ":" + NacosProperties.NAMESPACE_PLACEHOLDER + "}"; String NAMESPACE_PLACEHOLDER = "${" + CONFIG_PREFIX + NAMESPACE + ":"
+ NacosProperties.NAMESPACE_PLACEHOLDER + "}";
/** /**
* The placeholder of endpoint, the value is * The placeholder of endpoint, the value is
* <code>"${nacos.config.access-key:${nacos.access-key:}}"</code> * <code>"${nacos.config.access-key:${nacos.access-key:}}"</code>
*/ */
String ACCESS_KEY_PLACEHOLDER = "${" + CONFIG_PREFIX + ACCESS_KEY + ":" + NacosProperties.ACCESS_KEY_PLACEHOLDER + "}"; String ACCESS_KEY_PLACEHOLDER = "${" + CONFIG_PREFIX + ACCESS_KEY + ":"
+ NacosProperties.ACCESS_KEY_PLACEHOLDER + "}";
/** /**
* The placeholder of endpoint, the value is * The placeholder of endpoint, the value is
* <code>"${nacos.config.secret-key:${nacos.secret-key:}}"</code> * <code>"${nacos.config.secret-key:${nacos.secret-key:}}"</code>
*/ */
String SECRET_KEY_PLACEHOLDER = "${" + CONFIG_PREFIX + SECRET_KEY + ":" + NacosProperties.SECRET_KEY_PLACEHOLDER + "}"; String SECRET_KEY_PLACEHOLDER = "${" + CONFIG_PREFIX + SECRET_KEY + ":"
+ NacosProperties.SECRET_KEY_PLACEHOLDER + "}";
/** /**
* The placeholder of endpoint, the value is * The placeholder of endpoint, the value is
* <code>"${nacos.config.server-addr:${nacos.server-addr:}}"</code> * <code>"${nacos.config.server-addr:${nacos.server-addr:}}"</code>
*/ */
String SERVER_ADDR_PLACEHOLDER = "${" + CONFIG_PREFIX + SERVER_ADDR + ":" + NacosProperties.SERVER_ADDR_PLACEHOLDER + "}"; String SERVER_ADDR_PLACEHOLDER = "${" + CONFIG_PREFIX + SERVER_ADDR + ":"
+ NacosProperties.SERVER_ADDR_PLACEHOLDER + "}";
/** /**
* The placeholder of endpoint, the value is * The placeholder of endpoint, the value is
* <code>"${nacos.config.context-path:${nacos.context-path:}}"</code> * <code>"${nacos.config.context-path:${nacos.context-path:}}"</code>
*/ */
String CONTEXT_PATH_PLACEHOLDER = "${" + CONFIG_PREFIX + CONTEXT_PATH + ":" + NacosProperties.CONTEXT_PATH_PLACEHOLDER + "}"; String CONTEXT_PATH_PLACEHOLDER = "${" + CONFIG_PREFIX + CONTEXT_PATH + ":"
+ NacosProperties.CONTEXT_PATH_PLACEHOLDER + "}";
/** /**
* The placeholder of endpoint, the value is * The placeholder of endpoint, the value is
* <code>"${nacos.config.cluster-name:${nacos.cluster-name:}}"</code> * <code>"${nacos.config.cluster-name:${nacos.cluster-name:}}"</code>
*/ */
String CLUSTER_NAME_PLACEHOLDER = "${" + CONFIG_PREFIX + CLUSTER_NAME + ":" + NacosProperties.CLUSTER_NAME_PLACEHOLDER + "}"; String CLUSTER_NAME_PLACEHOLDER = "${" + CONFIG_PREFIX + CLUSTER_NAME + ":"
+ NacosProperties.CLUSTER_NAME_PLACEHOLDER + "}";
/** /**
* The placeholder of {@link NacosProperties#ENCODE encode}, the value is * The placeholder of {@link NacosProperties#ENCODE encode}, the value is
* <code>"${nacos.config.encode:${nacos.encode:UTF-8}}"</code> * <code>"${nacos.config.encode:${nacos.encode:UTF-8}}"</code>
*/ */
String ENCODE_PLACEHOLDER = "${" + CONFIG_PREFIX + ENCODE + ":" + NacosProperties.ENCODE_PLACEHOLDER + "}"; String ENCODE_PLACEHOLDER = "${" + CONFIG_PREFIX + ENCODE + ":"
+ NacosProperties.ENCODE_PLACEHOLDER + "}";
/**
* The placeholder of {@link NacosProperties#CONFIG_LONG_POLL_TIMEOUT
* configLongPollTimeout}, the value is <code>"${nacos.configLongPollTimeout:}"</code>
*/
String CONFIG_LONG_POLL_TIMEOUT_PLACEHOLDER = "${" + CONFIG_PREFIX
+ CONFIG_LONG_POLL_TIMEOUT + ":"
+ NacosProperties.CONFIG_LONG_POLL_TIMEOUT_PLACEHOLDER + "}";
/**
* The placeholder of {@link NacosProperties#CONFIG_RETRY_TIME configRetryTime}, the
* value is <code>"${nacos.configRetryTime:}"</code>
*/
String CONFIG_RETRY_TIME_PLACEHOLDER = "${" + CONFIG_PREFIX + CONFIG_RETRY_TIME + ":"
+ NacosProperties.CONFIG_RETRY_TIME_PLACEHOLDER + "}";
/**
* The placeholder of {@link NacosProperties#MAX_RETRY maxRetry}, the value is
* <code>"${nacos.maxRetry:}"</code>
*/
String MAX_RETRY_PLACEHOLDER = "${" + CONFIG_PREFIX + MAX_RETRY + ":"
+ NacosProperties.MAX_RETRY_PLACEHOLDER + "}";
/**
* The placeholder of endpoint, the value is
* <code>"${nacos.config.username:${nacos.username:}}"</code>
*/
String USERNAME_PLACEHOLDER = "${" + CONFIG_PREFIX + USERNAME + ":"
+ NacosProperties.USERNAME_PLACEHOLDER + "}";
/**
* The placeholder of endpoint, the value is
* <code>"${nacos.config.password:${nacos.password:}}"</code>
*/
String PASSWORD_PLACEHOLDER = "${" + CONFIG_PREFIX + PASSWORD + ":"
+ NacosProperties.PASSWORD_PLACEHOLDER + "}";
/** /**
* Global {@link NacosProperties Nacos Properties} * Global {@link NacosProperties Nacos Properties}
@ -101,15 +149,5 @@ public @interface EnableNacosConfig {
* @see NacosConfigListener#properties() * @see NacosConfigListener#properties()
* @see NacosConfigurationProperties#properties() * @see NacosConfigurationProperties#properties()
*/ */
NacosProperties globalProperties() default NacosProperties globalProperties() default @NacosProperties(username = USERNAME_PLACEHOLDER, password = PASSWORD_PLACEHOLDER, endpoint = ENDPOINT_PLACEHOLDER, namespace = NAMESPACE_PLACEHOLDER, accessKey = ACCESS_KEY_PLACEHOLDER, secretKey = SECRET_KEY_PLACEHOLDER, serverAddr = SERVER_ADDR_PLACEHOLDER, contextPath = CONTEXT_PATH_PLACEHOLDER, clusterName = CLUSTER_NAME_PLACEHOLDER, encode = ENCODE_PLACEHOLDER, configLongPollTimeout = CONFIG_LONG_POLL_TIMEOUT_PLACEHOLDER, configRetryTime = CONFIG_RETRY_TIME_PLACEHOLDER, maxRetry = MAX_RETRY_PLACEHOLDER);
@NacosProperties(
endpoint = ENDPOINT_PLACEHOLDER,
namespace = NAMESPACE_PLACEHOLDER,
accessKey = ACCESS_KEY_PLACEHOLDER,
secretKey = SECRET_KEY_PLACEHOLDER,
serverAddr = SERVER_ADDR_PLACEHOLDER,
contextPath = CONTEXT_PATH_PLACEHOLDER,
clusterName = CLUSTER_NAME_PLACEHOLDER,
encode = ENCODE_PLACEHOLDER
);
} }

View File

@ -0,0 +1,95 @@
/*
*
* * 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 com.alibaba.nacos.spring.context.annotation.config;
import com.alibaba.nacos.spring.util.aot.AotDetector;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.EnvironmentAware;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotationMetadata;
import java.util.Map;
import static com.alibaba.nacos.spring.util.NacosBeanUtils.*;
/**
* {@link EnableNacosConfig} AotProcessor
* Except for the operation of registering BeanDefinition, all other operations in {@link NacosConfigBeanDefinitionRegistrar} must be done here
* because spring will not call {@link NacosConfigBeanDefinitionRegistrar#registerBeanDefinitions} in AOT.
* @author SuperZ1999
*/
public class EnableNacosConfigAotProcessor implements BeanDefinitionRegistryPostProcessor, EnvironmentAware, BeanFactoryAware {
private Environment environment;
private BeanFactory beanFactory;
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
if (!AotDetector.useGeneratedArtifacts()) {
return;
}
DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) this.beanFactory;
Map<String, Object> beansWithAnnotation = beanFactory.getBeansWithAnnotation(EnableNacosConfig.class);
Object[] beans = beansWithAnnotation.values().toArray();
if (beans.length != 0) {
// only handle the first one
Class<?> aClass = beans[0].getClass();
if (aClass.getAnnotation(EnableNacosConfig.class) == null) {
// cglib proxy object
aClass = aClass.getSuperclass();
}
AnnotationMetadata annotationMetadata = AnnotationMetadata.introspect(aClass);
AnnotationAttributes attributes = AnnotationAttributes
.fromMap(annotationMetadata
.getAnnotationAttributes(EnableNacosConfig.class.getName()));
// Register Global Nacos Properties Bean
registerGlobalNacosProperties(attributes, registry, environment,
CONFIG_GLOBAL_NACOS_PROPERTIES_BEAN_NAME);
}
registerNacosConfigListenerExecutor(registry, environment);
// Invoke NacosPropertySourcePostProcessor immediately
// in order to enhance the precedence of @NacosPropertySource process
invokeNacosPropertySourcePostProcessor(this.beanFactory);
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
}
@Override
public void setEnvironment(Environment environment) {
this.environment = environment;
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
}

View File

@ -16,7 +16,12 @@
*/ */
package com.alibaba.nacos.spring.context.annotation.config; package com.alibaba.nacos.spring.context.annotation.config;
import com.alibaba.nacos.spring.util.NacosBeanUtils; import static com.alibaba.nacos.spring.util.NacosBeanUtils.CONFIG_GLOBAL_NACOS_PROPERTIES_BEAN_NAME;
import static com.alibaba.nacos.spring.util.NacosBeanUtils.invokeNacosPropertySourcePostProcessor;
import static com.alibaba.nacos.spring.util.NacosBeanUtils.registerGlobalNacosProperties;
import static com.alibaba.nacos.spring.util.NacosBeanUtils.registerNacosCommonBeans;
import static com.alibaba.nacos.spring.util.NacosBeanUtils.registerNacosConfigBeans;
import static org.springframework.core.annotation.AnnotationAttributes.fromMap;
import org.springframework.beans.BeansException; import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactory;
@ -29,41 +34,43 @@ import org.springframework.core.env.Environment;
import org.springframework.core.env.PropertyResolver; import org.springframework.core.env.PropertyResolver;
import org.springframework.core.type.AnnotationMetadata; import org.springframework.core.type.AnnotationMetadata;
import static com.alibaba.nacos.spring.util.NacosBeanUtils.CONFIG_GLOBAL_NACOS_PROPERTIES_BEAN_NAME; import com.alibaba.nacos.spring.util.NacosBeanUtils;
import static com.alibaba.nacos.spring.util.NacosBeanUtils.invokeNacosPropertySourcePostProcessor;
import static com.alibaba.nacos.spring.util.NacosBeanUtils.registerGlobalNacosProperties;
import static com.alibaba.nacos.spring.util.NacosBeanUtils.registerNacosCommonBeans;
import static com.alibaba.nacos.spring.util.NacosBeanUtils.registerNacosConfigBeans;
import static org.springframework.core.annotation.AnnotationAttributes.fromMap;
/** /**
* Nacos Config {@link ImportBeanDefinitionRegistrar BeanDefinition Registrar} * Nacos Config {@link ImportBeanDefinitionRegistrar BeanDefinition Registrar}
* *
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a> * @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
* @see EnableNacosConfig * @see EnableNacosConfig
* @see NacosBeanUtils#registerGlobalNacosProperties(AnnotationAttributes, BeanDefinitionRegistry, PropertyResolver, String) * @see NacosBeanUtils#registerGlobalNacosProperties(AnnotationAttributes,
* BeanDefinitionRegistry, PropertyResolver, String)
* @see NacosBeanUtils#registerNacosCommonBeans(BeanDefinitionRegistry) * @see NacosBeanUtils#registerNacosCommonBeans(BeanDefinitionRegistry)
* @see NacosBeanUtils#registerNacosConfigBeans(BeanDefinitionRegistry, Environment) * @see NacosBeanUtils#registerNacosConfigBeans(BeanDefinitionRegistry,
* Environment,BeanFactory)
* @since 0.1.0 * @since 0.1.0
*/ */
public class NacosConfigBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar, EnvironmentAware, public class NacosConfigBeanDefinitionRegistrar
BeanFactoryAware { implements ImportBeanDefinitionRegistrar, EnvironmentAware, BeanFactoryAware {
private Environment environment; private Environment environment;
private BeanFactory beanFactory; private BeanFactory beanFactory;
@Override @Override
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) { public void registerBeanDefinitions(AnnotationMetadata metadata,
AnnotationAttributes attributes = fromMap(metadata.getAnnotationAttributes(EnableNacosConfig.class.getName())); BeanDefinitionRegistry registry) {
AnnotationAttributes attributes = fromMap(
metadata.getAnnotationAttributes(EnableNacosConfig.class.getName()));
// Register Global Nacos Properties Bean // Register Global Nacos Properties Bean
registerGlobalNacosProperties(attributes, registry, environment, CONFIG_GLOBAL_NACOS_PROPERTIES_BEAN_NAME); registerGlobalNacosProperties(attributes, registry, environment,
CONFIG_GLOBAL_NACOS_PROPERTIES_BEAN_NAME);
// Register Nacos Common Beans // Register Nacos Common Beans
registerNacosCommonBeans(registry); registerNacosCommonBeans(registry);
// Register Nacos Config Beans // Register Nacos Config Beans
registerNacosConfigBeans(registry, environment); registerNacosConfigBeans(registry, environment, beanFactory);
// Invoke NacosPropertySourcePostProcessor immediately // Invoke NacosPropertySourcePostProcessor immediately
// in order to enhance the precedence of @NacosPropertySource process // in order to enhance the precedence of @NacosPropertySource process
invokeNacosPropertySourcePostProcessor(beanFactory); invokeNacosPropertySourcePostProcessor(beanFactory);
} }

View File

@ -16,6 +16,31 @@
*/ */
package com.alibaba.nacos.spring.context.annotation.config; package com.alibaba.nacos.spring.context.annotation.config;
import static com.alibaba.nacos.spring.util.GlobalNacosPropertiesSource.CONFIG;
import static com.alibaba.nacos.spring.util.NacosBeanUtils.getConfigServiceBeanBuilder;
import static com.alibaba.nacos.spring.util.NacosBeanUtils.getNacosServiceFactoryBean;
import static org.springframework.beans.BeanUtils.instantiateClass;
import static org.springframework.core.annotation.AnnotationUtils.getAnnotationAttributes;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.Properties;
import com.alibaba.nacos.api.config.ConfigType;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.context.EnvironmentAware;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.env.Environment;
import org.springframework.format.support.DefaultFormattingConversionService;
import org.springframework.util.Assert;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;
import com.alibaba.nacos.api.annotation.NacosProperties; import com.alibaba.nacos.api.annotation.NacosProperties;
import com.alibaba.nacos.api.config.ConfigService; import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.annotation.NacosConfigListener; import com.alibaba.nacos.api.config.annotation.NacosConfigListener;
@ -27,25 +52,7 @@ import com.alibaba.nacos.spring.context.event.config.NacosConfigMetadataEvent;
import com.alibaba.nacos.spring.context.event.config.TimeoutNacosConfigListener; import com.alibaba.nacos.spring.context.event.config.TimeoutNacosConfigListener;
import com.alibaba.nacos.spring.convert.converter.config.DefaultNacosConfigConverter; import com.alibaba.nacos.spring.convert.converter.config.DefaultNacosConfigConverter;
import com.alibaba.nacos.spring.factory.NacosServiceFactory; import com.alibaba.nacos.spring.factory.NacosServiceFactory;
import org.springframework.beans.BeansException; import com.alibaba.nacos.spring.util.NacosUtils;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.context.*;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.env.Environment;
import org.springframework.format.support.DefaultFormattingConversionService;
import org.springframework.util.Assert;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.Properties;
import static com.alibaba.nacos.spring.util.GlobalNacosPropertiesSource.CONFIG;
import static com.alibaba.nacos.spring.util.NacosBeanUtils.getConfigServiceBeanBuilder;
import static com.alibaba.nacos.spring.util.NacosBeanUtils.getNacosServiceFactoryBean;
import static org.springframework.beans.BeanUtils.instantiateClass;
import static org.springframework.core.annotation.AnnotationUtils.getAnnotationAttributes;
/** /**
* {@link NacosConfigListener @NacosConfigListener} {@link Method method} Processor * {@link NacosConfigListener @NacosConfigListener} {@link Method method} Processor
@ -56,8 +63,9 @@ import static org.springframework.core.annotation.AnnotationUtils.getAnnotationA
* @see Method * @see Method
* @since 0.1.0 * @since 0.1.0
*/ */
public class NacosConfigListenerMethodProcessor extends AnnotationListenerMethodProcessor<NacosConfigListener> public class NacosConfigListenerMethodProcessor
implements ApplicationContextAware, ApplicationEventPublisherAware, EnvironmentAware { extends AnnotationListenerMethodProcessor<NacosConfigListener> implements
ApplicationContextAware, ApplicationEventPublisherAware, EnvironmentAware {
/** /**
* The bean name of {@link NacosConfigListenerMethodProcessor} * The bean name of {@link NacosConfigListenerMethodProcessor}
@ -82,49 +90,65 @@ public class NacosConfigListenerMethodProcessor extends AnnotationListenerMethod
private ApplicationEventPublisher applicationEventPublisher; private ApplicationEventPublisher applicationEventPublisher;
@Override @Override
protected void processListenerMethod(String beanName, final Object bean, Class<?> beanClass, protected void processListenerMethod(String beanName, final Object bean,
final NacosConfigListener listener, final Method method, Class<?> beanClass, final NacosConfigListener listener, final Method method,
ApplicationContext applicationContext) { ApplicationContext applicationContext) {
String dataId = listener.dataId(); final String dataId = NacosUtils.readFromEnvironment(listener.dataId(),
String groupId = listener.groupId(); environment);
final String groupId = NacosUtils.readFromEnvironment(listener.groupId(),
environment);
final String type;
ConfigType typeEnum = listener.type();
if (ConfigType.UNSET.equals(typeEnum)) {
type = NacosUtils.readFileExtension(dataId);
}
else {
type = typeEnum.getType();
}
long timeout = listener.timeout(); long timeout = listener.timeout();
Assert.isTrue(StringUtils.hasText(dataId), "dataId must have content"); Assert.isTrue(StringUtils.hasText(dataId), "dataId must have content");
Assert.isTrue(StringUtils.hasText(groupId), "groupId must have content"); Assert.isTrue(StringUtils.hasText(groupId), "groupId must have content");
Assert.isTrue(timeout > 0, "timeout must be greater than zero"); Assert.isTrue(timeout > 0, "timeout must be greater than zero");
ConfigService configService = configServiceBeanBuilder.build(listener.properties()); ConfigService configService = configServiceBeanBuilder
.build(listener.properties());
try { try {
configService.addListener(dataId, groupId,
configService.addListener(dataId, groupId, new TimeoutNacosConfigListener(dataId, groupId, timeout) { new TimeoutNacosConfigListener(dataId, groupId, timeout) {
@Override @Override
protected void onReceived(String config) { protected void onReceived(String config) {
Class<?> targetType = method.getParameterTypes()[0]; Class<?> targetType = method.getParameterTypes()[0];
NacosConfigConverter configConverter = determineNacosConfigConverter(targetType, listener); NacosConfigConverter configConverter = determineNacosConfigConverter(
targetType, listener, type);
Object parameterValue = configConverter.convert(config); Object parameterValue = configConverter.convert(config);
// Execute target method // Execute target method
ReflectionUtils.invokeMethod(method, bean, parameterValue); ReflectionUtils.invokeMethod(method, bean, parameterValue);
} }
}); });
} catch (NacosException e) {
if (logger.isErrorEnabled()) {
logger.error("ConfigService can't add Listener for dataId : " + dataId + " , groupId : " + groupId, e);
} }
catch (NacosException e) {
logger.error("ConfigService can't add Listener for dataId : " + dataId
+ " , groupId : " + groupId, e);
} }
publishMetadataEvent(beanName, bean, beanClass, dataId, groupId, listener, method); publishMetadataEvent(beanName, bean, beanClass, dataId, groupId, listener,
method);
} }
private void publishMetadataEvent(String beanName, Object bean, Class<?> beanClass, String dataId, String groupId, private void publishMetadataEvent(String beanName, Object bean, Class<?> beanClass,
NacosConfigListener listener, Method method) { String dataId, String groupId, NacosConfigListener listener, Method method) {
NacosProperties nacosProperties = listener.properties(); NacosProperties nacosProperties = listener.properties();
Properties resolvedNacosProperties = configServiceBeanBuilder.resolveProperties(nacosProperties); Properties resolvedNacosProperties = configServiceBeanBuilder
.resolveProperties(nacosProperties);
NacosConfigMetadataEvent metadataEvent = new NacosConfigMetadataEvent(listener); NacosConfigMetadataEvent metadataEvent = new NacosConfigMetadataEvent(listener);
@ -132,7 +156,8 @@ public class NacosConfigListenerMethodProcessor extends AnnotationListenerMethod
metadataEvent.setDataId(dataId); metadataEvent.setDataId(dataId);
metadataEvent.setGroupId(groupId); metadataEvent.setGroupId(groupId);
Map<String, Object> nacosPropertiesAttributes = getAnnotationAttributes(nacosProperties); Map<String, Object> nacosPropertiesAttributes = getAnnotationAttributes(
nacosProperties);
metadataEvent.setNacosPropertiesAttributes(nacosPropertiesAttributes); metadataEvent.setNacosPropertiesAttributes(nacosPropertiesAttributes);
metadataEvent.setNacosProperties(resolvedNacosProperties); metadataEvent.setNacosProperties(resolvedNacosProperties);
@ -146,40 +171,30 @@ public class NacosConfigListenerMethodProcessor extends AnnotationListenerMethod
applicationEventPublisher.publishEvent(metadataEvent); applicationEventPublisher.publishEvent(metadataEvent);
} }
private ConfigService resolveConfigService(Properties nacosProperties, ApplicationContext applicationContext)
throws BeansException {
ConfigService configService = null;
try {
configService = nacosServiceFactory.createConfigService(nacosProperties);
} catch (NacosException e) {
throw new BeanCreationException(e.getErrMsg(), e);
}
return configService;
}
@Override @Override
protected boolean isCandidateMethod(Object bean, Class<?> beanClass, NacosConfigListener listener, Method method, protected boolean isCandidateMethod(Object bean, Class<?> beanClass,
NacosConfigListener listener, Method method,
ApplicationContext applicationContext) { ApplicationContext applicationContext) {
Class<?>[] parameterTypes = method.getParameterTypes(); Class<?>[] parameterTypes = method.getParameterTypes();
if (parameterTypes.length != 1) { // Only one argument on method if (parameterTypes.length != 1) { // Only one argument on method
if (logger.isWarnEnabled()) { if (logger.isWarnEnabled()) {
logger.warn("Listener method [" + method + "] parameters' count must be one !"); logger.warn("Listener method [" + method
+ "] parameters' count must be one !");
} }
return false; return false;
} }
Class<?> targetType = parameterTypes[0]; Class<?> targetType = parameterTypes[0];
NacosConfigConverter configConverter = determineNacosConfigConverter(targetType, listener); NacosConfigConverter configConverter = determineNacosConfigConverter(targetType,
listener, listener.type().getType());
if (!configConverter.canConvert(targetType)) { if (!configConverter.canConvert(targetType)) {
if (logger.isWarnEnabled()) { if (logger.isWarnEnabled()) {
logger.warn("Listener method [" + method + "] is not a candidate , thus its parameter type [" logger.warn("Listener method [" + method
+ targetType + "] can't be converted , please check NacosConfigConverter implementation : " + "] is not a candidate , thus its parameter type [" + targetType
+ "] can't be converted , please check NacosConfigConverter implementation : "
+ configConverter.getClass().getName()); + configConverter.getClass().getName());
} }
} }
@ -187,18 +202,21 @@ public class NacosConfigListenerMethodProcessor extends AnnotationListenerMethod
return true; return true;
} }
private NacosConfigConverter determineNacosConfigConverter(Class<?> targetType, NacosConfigListener listener) { private NacosConfigConverter determineNacosConfigConverter(Class<?> targetType,
NacosConfigListener listener, String type) {
Class<?> converterClass = listener.converter(); Class<?> converterClass = listener.converter();
NacosConfigConverter configConverter = null; NacosConfigConverter configConverter = null;
if (NacosConfigConverter.class.equals(converterClass)) { // Use default implementation // Use default implementation
if (NacosConfigConverter.class.equals(converterClass)) {
configConverter = new DefaultNacosConfigConverter(targetType, conversionService); configConverter = new DefaultNacosConfigConverter(targetType,
conversionService, type);
} else { // Use customized implementation
}
else {
// Use customized implementation
configConverter = (NacosConfigConverter) instantiateClass(converterClass); configConverter = (NacosConfigConverter) instantiateClass(converterClass);
} }
@ -207,19 +225,22 @@ public class NacosConfigListenerMethodProcessor extends AnnotationListenerMethod
} }
@Override @Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
globalNacosProperties = CONFIG.getMergedGlobalProperties(applicationContext); globalNacosProperties = CONFIG.getMergedGlobalProperties(applicationContext);
nacosServiceFactory = getNacosServiceFactoryBean(applicationContext); nacosServiceFactory = getNacosServiceFactoryBean(applicationContext);
conversionService = determineConversionService(applicationContext); conversionService = determineConversionService(applicationContext);
configServiceBeanBuilder = getConfigServiceBeanBuilder(applicationContext); configServiceBeanBuilder = getConfigServiceBeanBuilder(applicationContext);
} }
private ConversionService determineConversionService(ApplicationContext applicationContext) { private ConversionService determineConversionService(
ApplicationContext applicationContext) {
String beanName = NACOS_CONFIG_CONVERSION_SERVICE_BEAN_NAME; String beanName = NACOS_CONFIG_CONVERSION_SERVICE_BEAN_NAME;
ConversionService conversionService = applicationContext.containsBean(beanName) ? ConversionService conversionService = applicationContext.containsBean(beanName)
applicationContext.getBean(beanName, ConversionService.class) : null; ? applicationContext.getBean(beanName, ConversionService.class)
: null;
if (conversionService == null) { if (conversionService == null) {
conversionService = new DefaultFormattingConversionService(); conversionService = new DefaultFormattingConversionService();
@ -229,7 +250,8 @@ public class NacosConfigListenerMethodProcessor extends AnnotationListenerMethod
} }
@Override @Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) { public void setApplicationEventPublisher(
ApplicationEventPublisher applicationEventPublisher) {
this.applicationEventPublisher = applicationEventPublisher; this.applicationEventPublisher = applicationEventPublisher;
} }

View File

@ -16,19 +16,26 @@
*/ */
package com.alibaba.nacos.spring.context.annotation.config; package com.alibaba.nacos.spring.context.annotation.config;
import com.alibaba.nacos.api.annotation.NacosProperties;
import com.alibaba.nacos.api.common.Constants;
import com.alibaba.nacos.spring.context.annotation.EnableNacos;
import com.alibaba.nacos.spring.util.NacosUtils;
import org.springframework.core.env.PropertySource;
import java.lang.annotation.*;
import java.util.Map;
import static com.alibaba.nacos.api.common.Constants.DEFAULT_GROUP; import static com.alibaba.nacos.api.common.Constants.DEFAULT_GROUP;
import static com.alibaba.nacos.spring.util.NacosUtils.DEFAULT_BOOLEAN_ATTRIBUTE_VALUE; import static com.alibaba.nacos.spring.util.NacosUtils.DEFAULT_BOOLEAN_ATTRIBUTE_VALUE;
import static com.alibaba.nacos.spring.util.NacosUtils.DEFAULT_STRING_ATTRIBUTE_VALUE; import static com.alibaba.nacos.spring.util.NacosUtils.DEFAULT_STRING_ATTRIBUTE_VALUE;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.Map;
import org.springframework.core.env.PropertySource;
import com.alibaba.nacos.api.annotation.NacosProperties;
import com.alibaba.nacos.api.common.Constants;
import com.alibaba.nacos.api.config.ConfigType;
import com.alibaba.nacos.spring.context.annotation.EnableNacos;
import com.alibaba.nacos.spring.util.NacosUtils;
/** /**
* An annotation for Nacos {@link PropertySource} * An annotation for Nacos {@link PropertySource}
* *
@ -84,9 +91,14 @@ public @interface NacosPropertySource {
String PROPERTIES_ATTRIBUTE_NAME = "properties"; String PROPERTIES_ATTRIBUTE_NAME = "properties";
/** /**
* The name of Nacos {@link PropertySource} * The attribute name of {@link NacosPropertySource#type()} ()}
* If absent , the default name will be built from */
* {@link #dataId() dataId}, {@link #groupId() groupid} and {@link #properties() properties} by String CONFIG_TYPE_ATTRIBUTE_NAME = "type";
/**
* The name of Nacos {@link PropertySource} If absent , the default name will be built
* from {@link #dataId() dataId}, {@link #groupId() groupid} and {@link #properties()
* properties} by
* {@link NacosUtils#buildDefaultPropertySourceName(String, String, Map)} method * {@link NacosUtils#buildDefaultPropertySourceName(String, String, Map)} method
* *
* @return default value is "" * @return default value is ""
@ -108,16 +120,16 @@ public @interface NacosPropertySource {
String dataId(); String dataId();
/** /**
* It indicates the property source is auto-refreshed when Nacos configuration is changed. * It indicates the property source is auto-refreshed when Nacos configuration is
* changed.
* *
* @return default value is <code>false</code> * @return default value is <code>false</code>
*/ */
boolean autoRefreshed() default DEFAULT_BOOLEAN_ATTRIBUTE_VALUE; boolean autoRefreshed() default DEFAULT_BOOLEAN_ATTRIBUTE_VALUE;
/** /**
* Indicates current Nacos {@link PropertySource} is first order or not * Indicates current Nacos {@link PropertySource} is first order or not If specified ,
* If specified , {@link #before()} and {@link #after()} will be ignored, or * {@link #before()} and {@link #after()} will be ignored, or last order.
* last order.
* *
* @return default value is <code>false</code> * @return default value is <code>false</code>
*/ */
@ -145,6 +157,13 @@ public @interface NacosPropertySource {
*/ */
String after() default DEFAULT_STRING_ATTRIBUTE_VALUE; String after() default DEFAULT_STRING_ATTRIBUTE_VALUE;
/**
* The type of config
*
* @return the type of config
*/
ConfigType type() default ConfigType.UNSET;
/** /**
* The {@link NacosProperties} attribute, If not specified, it will use * The {@link NacosProperties} attribute, If not specified, it will use
* {@link EnableNacos#globalProperties() global Nacos Properties}. * {@link EnableNacos#globalProperties() global Nacos Properties}.
@ -154,5 +173,4 @@ public @interface NacosPropertySource {
*/ */
NacosProperties properties() default @NacosProperties; NacosProperties properties() default @NacosProperties;
} }

View File

@ -16,23 +16,25 @@
*/ */
package com.alibaba.nacos.spring.context.annotation.config; package com.alibaba.nacos.spring.context.annotation.config;
import com.alibaba.nacos.spring.factory.NacosServiceFactory;
import com.alibaba.nacos.spring.util.config.NacosConfigLoader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.PropertiesPropertySource;
import org.springframework.core.env.PropertySource;
import org.springframework.util.StringUtils;
import java.util.Properties;
import static com.alibaba.nacos.spring.util.NacosBeanUtils.getNacosServiceFactoryBean; import static com.alibaba.nacos.spring.util.NacosBeanUtils.getNacosServiceFactoryBean;
import static com.alibaba.nacos.spring.util.NacosUtils.buildDefaultPropertySourceName; import static com.alibaba.nacos.spring.util.NacosUtils.buildDefaultPropertySourceName;
import static com.alibaba.nacos.spring.util.NacosUtils.toProperties; import static com.alibaba.nacos.spring.util.NacosUtils.toProperties;
import static java.lang.String.format; import static java.lang.String.format;
import java.util.Map;
import java.util.Properties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.PropertySource;
import org.springframework.util.StringUtils;
import com.alibaba.nacos.spring.factory.NacosServiceFactory;
import com.alibaba.nacos.spring.util.config.NacosConfigLoader;
/** /**
* Nacos {@link PropertySource} Builder * Nacos {@link PropertySource} Builder
* *
@ -50,6 +52,8 @@ class NacosPropertySourceBuilder {
private String groupId; private String groupId;
private String type;
private Properties properties; private Properties properties;
private ConfigurableEnvironment environment; private ConfigurableEnvironment environment;
@ -78,6 +82,11 @@ class NacosPropertySourceBuilder {
return this; return this;
} }
public NacosPropertySourceBuilder type(String type) {
this.type = type;
return this;
}
public NacosPropertySourceBuilder environment(ConfigurableEnvironment environment) { public NacosPropertySourceBuilder environment(ConfigurableEnvironment environment) {
this.environment = environment; this.environment = environment;
return this; return this;
@ -105,21 +114,20 @@ class NacosPropertySourceBuilder {
if (!StringUtils.hasText(config)) { if (!StringUtils.hasText(config)) {
if (logger.isWarnEnabled()) { if (logger.isWarnEnabled()) {
logger.warn(format("There is no content for Nacos PropertySource from dataId[%s] , groupId[%s] , properties[%s].", logger.warn(format(
dataId, "There is no content for Nacos PropertySource from dataId[%s] , groupId[%s] , properties[%s].",
groupId, dataId, groupId, properties));
properties));
} }
return null; return null;
} }
Properties properties = toProperties(config); Map<String, Object> properties = toProperties(dataId, groupId, config, type);
if (!StringUtils.hasText(name)) { if (!StringUtils.hasText(name)) {
name = buildDefaultPropertySourceName(dataId, groupId, properties); name = buildDefaultPropertySourceName(dataId, groupId, properties);
} }
return new PropertiesPropertySource(name, properties); return new MapPropertySource(name, properties);
} }
public NacosConfigLoader getNacosConfigLoader() { public NacosConfigLoader getNacosConfigLoader() {

View File

@ -16,7 +16,11 @@
*/ */
package com.alibaba.nacos.spring.context.annotation.config; package com.alibaba.nacos.spring.context.annotation.config;
import java.lang.annotation.*; import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/** /**
* Multiple {@link NacosPropertySource @NacosPropertySource} annotations. * Multiple {@link NacosPropertySource @NacosPropertySource} annotations.

View File

@ -14,22 +14,10 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.alibaba.nacos.spring.context.annotation.config; package com.alibaba.nacos.spring.context.annotation.config;
import com.alibaba.nacos.api.config.annotation.NacosValue; import static org.springframework.core.annotation.AnnotationUtils.getAnnotation;
import com.alibaba.nacos.spring.context.event.config.NacosConfigReceivedEvent;
import com.alibaba.spring.beans.factory.annotation.AnnotationInjectedBeanPostProcessor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.TypeConverter;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.annotation.InjectionMetadata;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.ApplicationListener;
import org.springframework.core.MethodParameter;
import org.springframework.util.ReflectionUtils;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Member; import java.lang.reflect.Member;
@ -39,48 +27,99 @@ import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Properties;
import static com.alibaba.nacos.spring.util.NacosUtils.toProperties; import org.apache.commons.lang3.StringUtils;
import static org.springframework.core.annotation.AnnotationUtils.getAnnotation; import com.alibaba.nacos.spring.beans.factory.annotation.AbstractAnnotationBeanPostProcessor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.TypeConverter;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.annotation.InjectionMetadata;
import org.springframework.beans.factory.config.BeanExpressionContext;
import org.springframework.beans.factory.config.BeanExpressionResolver;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.ApplicationListener;
import org.springframework.context.EnvironmentAware;
import org.springframework.core.MethodParameter;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.env.Environment;
import org.springframework.util.ReflectionUtils;
import com.alibaba.nacos.api.config.annotation.NacosValue;
import com.alibaba.nacos.common.utils.MD5Utils;
import com.alibaba.nacos.spring.context.event.config.NacosConfigReceivedEvent;
/** /**
* {@link org.springframework.beans.factory.config.BeanPostProcessor} implementation * Injected {@link NacosValue}
* {@link org.springframework.beans.factory.config.BeanPostProcessor} implementation.
* *
* @author <a href="mailto:huangxiaoyu1018@gmail.com">hxy1991</a> * @author <a href="mailto:huangxiaoyu1018@gmail.com">hxy1991</a>
* @see NacosValue * @see NacosValue
* @since 0.1.0 * @since 0.1.0
*/ */
public class NacosValueAnnotationBeanPostProcessor extends AnnotationInjectedBeanPostProcessor<NacosValue> public class NacosValueAnnotationBeanPostProcessor
implements BeanFactoryAware, ApplicationListener<NacosConfigReceivedEvent> { extends AbstractAnnotationBeanPostProcessor implements BeanFactoryAware,
EnvironmentAware, ApplicationListener<NacosConfigReceivedEvent> {
private final Logger logger = LoggerFactory.getLogger(getClass());
/** /**
* The name of {@link NacosValueAnnotationBeanPostProcessor} bean * The name of {@link NacosValueAnnotationBeanPostProcessor} bean.
*/ */
public static final String BEAN_NAME = "nacosValueAnnotationBeanPostProcessor"; public static final String BEAN_NAME = "nacosValueAnnotationBeanPostProcessor";
private static final String SPEL_PREFIX = "#{";
private static final String PLACEHOLDER_PREFIX = "${"; private static final String PLACEHOLDER_PREFIX = "${";
private static final String PLACEHOLDER_SUFFIX = "}"; private static final String PLACEHOLDER_SUFFIX = "}";
private static final char PLACEHOLDER_MATCH_PREFIX = '{';
private static final char PLACEHOLDER_MATCH_SUFFIX = '}';
private static final String VALUE_SEPARATOR = ":"; private static final String VALUE_SEPARATOR = ":";
private final Logger logger = LoggerFactory.getLogger(getClass());
/** /**
* placeholder, nacosValueTarget * placeholder, nacosValueTarget.
*/ */
private Map<String, List<NacosValueTarget>> placeholderNacosValueTargetMap private Map<String, List<NacosValueTarget>> placeholderNacosValueTargetMap = new HashMap<String, List<NacosValueTarget>>();
= new HashMap<String, List<NacosValueTarget>>();
private ConfigurableListableBeanFactory beanFactory; private ConfigurableListableBeanFactory beanFactory;
@Override private Environment environment;
protected Object doGetInjectedBean(NacosValue annotation, Object bean, String beanName, Class<?> injectedType,
InjectionMetadata.InjectedElement injectedElement) {
String annotationValue = annotation.value();
String value = beanFactory.resolveEmbeddedValue(annotationValue);
private BeanExpressionResolver exprResolver;
private BeanExpressionContext exprContext;
public NacosValueAnnotationBeanPostProcessor() {
super(NacosValue.class);
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
if (!(beanFactory instanceof ConfigurableListableBeanFactory)) {
throw new IllegalArgumentException(
"NacosValueAnnotationBeanPostProcessor requires a ConfigurableListableBeanFactory");
}
this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
this.exprResolver = ((ConfigurableListableBeanFactory) beanFactory).getBeanExpressionResolver();
this.exprContext = new BeanExpressionContext((ConfigurableListableBeanFactory) beanFactory, null);
}
@Override
public void setEnvironment(Environment environment) {
this.environment = environment;
}
@Override
protected Object doGetInjectedBean(AnnotationAttributes attributes, Object bean,
String beanName, Class<?> injectedType,
InjectionMetadata.InjectedElement injectedElement) throws Exception {
Object value = resolveStringValue(attributes.getString("value"));
Member member = injectedElement.getMember(); Member member = injectedElement.getMember();
if (member instanceof Field) { if (member instanceof Field) {
return convertIfNecessary((Field) member, value); return convertIfNecessary((Field) member, value);
@ -94,19 +133,10 @@ public class NacosValueAnnotationBeanPostProcessor extends AnnotationInjectedBea
} }
@Override @Override
protected String buildInjectedObjectCacheKey(NacosValue annotation, Object bean, String beanName, protected String buildInjectedObjectCacheKey(AnnotationAttributes attributes,
Class<?> injectedType, Object bean, String beanName, Class<?> injectedType,
InjectionMetadata.InjectedElement injectedElement) { InjectionMetadata.InjectedElement injectedElement) {
return bean.getClass().getName() + annotation; return bean.getClass().getName() + attributes;
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
if (!(beanFactory instanceof ConfigurableListableBeanFactory)) {
throw new IllegalArgumentException(
"NacosValueAnnotationBeanPostProcessor requires a ConfigurableListableBeanFactory");
}
this.beanFactory = (ConfigurableListableBeanFactory)beanFactory;
} }
@Override @Override
@ -122,28 +152,46 @@ public class NacosValueAnnotationBeanPostProcessor extends AnnotationInjectedBea
@Override @Override
public void onApplicationEvent(NacosConfigReceivedEvent event) { public void onApplicationEvent(NacosConfigReceivedEvent event) {
String content = event.getContent(); // In to this event receiver, the environment has been updated the
if (content != null) { // latest configuration information, pull directly from the environment
Properties configProperties = toProperties(content); // fix issue #142
for (Map.Entry<String, List<NacosValueTarget>> entry : placeholderNacosValueTargetMap
.entrySet()) {
String key = environment.resolvePlaceholders(entry.getKey());
String newValue = environment.getProperty(key);
for (Object key : configProperties.keySet()) { if (newValue == null) {
String propertyKey = (String)key;
List<NacosValueTarget> beanPropertyList = placeholderNacosValueTargetMap.get(propertyKey);
if (beanPropertyList == null) {
continue; continue;
} }
List<NacosValueTarget> beanPropertyList = entry.getValue();
for (NacosValueTarget target : beanPropertyList) {
String md5String = MD5Utils.md5Hex(newValue, "UTF-8");
boolean isUpdate = !target.lastMD5.equals(md5String);
if (isUpdate) {
target.updateLastMD5(md5String);
Object evaluatedValue = resolveNotifyValue(target.nacosValueExpr, key, newValue);
if (target.method == null) {
setField(target, evaluatedValue);
}
else {
setMethod(target, evaluatedValue);
}
}
}
}
}
String propertyValue = configProperties.getProperty(propertyKey); private Object resolveNotifyValue(String nacosValueExpr, String key, String newValue) {
for (NacosValueTarget nacosValueTarget : beanPropertyList) { String spelExpr = StringUtils.replace(nacosValueExpr, PLACEHOLDER_PREFIX + key + PLACEHOLDER_SUFFIX, newValue);
if (nacosValueTarget.method == null) { return resolveStringValue(spelExpr);
setField(nacosValueTarget, propertyValue);
} else {
setMethod(nacosValueTarget, propertyValue);
}
}
} }
private Object resolveStringValue(String strVal) {
String value = beanFactory.resolveEmbeddedValue(strVal);
if (exprResolver != null && value != null) {
return exprResolver.evaluate(value, exprContext);
} }
return value;
} }
private Object convertIfNecessary(Field field, Object value) { private Object convertIfNecessary(Field field, Object value) {
@ -158,38 +206,44 @@ public class NacosValueAnnotationBeanPostProcessor extends AnnotationInjectedBea
TypeConverter converter = beanFactory.getTypeConverter(); TypeConverter converter = beanFactory.getTypeConverter();
if (arguments.length == 1) { if (arguments.length == 1) {
return converter.convertIfNecessary(value, paramTypes[0], new MethodParameter(method, 0)); return converter.convertIfNecessary(value, paramTypes[0],
new MethodParameter(method, 0));
} }
for (int i = 0; i < arguments.length; i++) { for (int i = 0; i < arguments.length; i++) {
arguments[i] = converter.convertIfNecessary(value, paramTypes[i], new MethodParameter(method, i)); arguments[i] = converter.convertIfNecessary(value, paramTypes[i],
new MethodParameter(method, i));
} }
return arguments; return arguments;
} }
private void doWithFields(final Object bean, final String beanName) { private void doWithFields(final Object bean, final String beanName) {
ReflectionUtils.doWithFields(bean.getClass(), new ReflectionUtils.FieldCallback() { ReflectionUtils.doWithFields(bean.getClass(),
new ReflectionUtils.FieldCallback() {
@Override @Override
public void doWith(Field field) throws IllegalArgumentException { public void doWith(Field field) throws IllegalArgumentException {
NacosValue annotation = getAnnotation(field, NacosValue.class); NacosValue annotation = getAnnotation(field, NacosValue.class);
doWithAnnotation(beanName, bean, annotation, field.getModifiers(), null, field); doWithAnnotation(beanName, bean, annotation, field.getModifiers(),
null, field);
} }
}); });
} }
private void doWithMethods(final Object bean, final String beanName) { private void doWithMethods(final Object bean, final String beanName) {
ReflectionUtils.doWithMethods(bean.getClass(), new ReflectionUtils.MethodCallback() { ReflectionUtils.doWithMethods(bean.getClass(),
new ReflectionUtils.MethodCallback() {
@Override @Override
public void doWith(Method method) throws IllegalArgumentException { public void doWith(Method method) throws IllegalArgumentException {
NacosValue annotation = getAnnotation(method, NacosValue.class); NacosValue annotation = getAnnotation(method, NacosValue.class);
doWithAnnotation(beanName, bean, annotation, method.getModifiers(), method, null); doWithAnnotation(beanName, bean, annotation,
method.getModifiers(), method, null);
} }
}); });
} }
private void doWithAnnotation(String beanName, Object bean, NacosValue annotation, int modifiers, Method method, private void doWithAnnotation(String beanName, Object bean, NacosValue annotation,
Field field) { int modifiers, Method method, Field field) {
if (annotation != null) { if (annotation != null) {
if (Modifier.isStatic(modifiers)) { if (Modifier.isStatic(modifiers)) {
return; return;
@ -202,14 +256,16 @@ public class NacosValueAnnotationBeanPostProcessor extends AnnotationInjectedBea
return; return;
} }
NacosValueTarget nacosValueTarget = new NacosValueTarget(bean, beanName, method, field); NacosValueTarget nacosValueTarget = new NacosValueTarget(bean, beanName,
put2ListMap(placeholderNacosValueTargetMap, placeholder, nacosValueTarget); method, field, annotation.value());
put2ListMap(placeholderNacosValueTargetMap, placeholder,
nacosValueTarget);
} }
} }
} }
private String resolvePlaceholder(String placeholder) { private String resolvePlaceholder(String placeholder) {
if (!placeholder.startsWith(PLACEHOLDER_PREFIX)) { if (!placeholder.startsWith(PLACEHOLDER_PREFIX) && !placeholder.startsWith(SPEL_PREFIX)) {
return null; return null;
} }
@ -217,12 +273,19 @@ public class NacosValueAnnotationBeanPostProcessor extends AnnotationInjectedBea
return null; return null;
} }
if (placeholder.length() <= PLACEHOLDER_PREFIX.length() + PLACEHOLDER_SUFFIX.length()) { if (placeholder.length() <= PLACEHOLDER_PREFIX.length()
+ PLACEHOLDER_SUFFIX.length()) {
return null;
}
int beginIndex = placeholder.indexOf(PLACEHOLDER_PREFIX);
if (beginIndex == -1) {
return null;
}
beginIndex = beginIndex + PLACEHOLDER_PREFIX.length();
int endIndex = placeholder.indexOf(PLACEHOLDER_SUFFIX, beginIndex);
if (endIndex == -1) {
return null; return null;
} }
int beginIndex = PLACEHOLDER_PREFIX.length();
int endIndex = placeholder.length() - PLACEHOLDER_PREFIX.length() + 1;
placeholder = placeholder.substring(beginIndex, endIndex); placeholder = placeholder.substring(beginIndex, endIndex);
int separatorIndex = placeholder.indexOf(VALUE_SEPARATOR); int separatorIndex = placeholder.indexOf(VALUE_SEPARATOR);
@ -242,26 +305,28 @@ public class NacosValueAnnotationBeanPostProcessor extends AnnotationInjectedBea
map.put(key, valueList); map.put(key, valueList);
} }
private void setMethod(NacosValueTarget nacosValueTarget, String propertyValue) { private void setMethod(NacosValueTarget nacosValueTarget, Object propertyValue) {
Method method = nacosValueTarget.method; Method method = nacosValueTarget.method;
ReflectionUtils.makeAccessible(method); ReflectionUtils.makeAccessible(method);
try { try {
method.invoke(nacosValueTarget.bean, convertIfNecessary(method, propertyValue)); method.invoke(nacosValueTarget.bean,
convertIfNecessary(method, propertyValue));
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
logger.debug("Update value with {} (method) in {} (bean) with {}", logger.debug("Update value with {} (method) in {} (bean) with {}",
method.getName(), nacosValueTarget.beanName, propertyValue); method.getName(), nacosValueTarget.beanName, propertyValue);
} }
} catch (Throwable e) { }
catch (Throwable e) {
if (logger.isErrorEnabled()) { if (logger.isErrorEnabled()) {
logger.error( logger.error("Can't update value with " + method.getName()
"Can't update value with " + method.getName() + " (method) in " + " (method) in " + nacosValueTarget.beanName + " (bean)", e);
+ nacosValueTarget.beanName + " (bean)", e);
} }
} }
} }
private void setField(final NacosValueTarget nacosValueTarget, final String propertyValue) { private void setField(final NacosValueTarget nacosValueTarget,
final Object propertyValue) {
final Object bean = nacosValueTarget.bean; final Object bean = nacosValueTarget.bean;
Field field = nacosValueTarget.field; Field field = nacosValueTarget.field;
@ -276,10 +341,10 @@ public class NacosValueAnnotationBeanPostProcessor extends AnnotationInjectedBea
logger.debug("Update value of the {}" + " (field) in {} (bean) with {}", logger.debug("Update value of the {}" + " (field) in {} (bean) with {}",
fieldName, nacosValueTarget.beanName, propertyValue); fieldName, nacosValueTarget.beanName, propertyValue);
} }
} catch (Throwable e) { }
catch (Throwable e) {
if (logger.isErrorEnabled()) { if (logger.isErrorEnabled()) {
logger.error( logger.error("Can't update value of the " + fieldName + " (field) in "
"Can't update value of the " + fieldName + " (field) in "
+ nacosValueTarget.beanName + " (bean)", e); + nacosValueTarget.beanName + " (bean)", e);
} }
} }
@ -287,15 +352,19 @@ public class NacosValueAnnotationBeanPostProcessor extends AnnotationInjectedBea
private static class NacosValueTarget { private static class NacosValueTarget {
private Object bean; private final Object bean;
private String beanName; private final String beanName;
private Method method; private final Method method;
private Field field; private final Field field;
NacosValueTarget(Object bean, String beanName, Method method, Field field) { private String lastMD5;
private final String nacosValueExpr;
NacosValueTarget(Object bean, String beanName, Method method, Field field, String nacosValueExpr) {
this.bean = bean; this.bean = bean;
this.beanName = beanName; this.beanName = beanName;
@ -303,7 +372,39 @@ public class NacosValueAnnotationBeanPostProcessor extends AnnotationInjectedBea
this.method = method; this.method = method;
this.field = field; this.field = field;
this.lastMD5 = "";
this.nacosValueExpr = resolveExpr(nacosValueExpr);
}
private String resolveExpr(String nacosValueExpr) {
try {
int replaceHolderBegin = nacosValueExpr.indexOf(PLACEHOLDER_PREFIX) + PLACEHOLDER_PREFIX.length();
int replaceHolderEnd = replaceHolderBegin;
for (int i = 0; replaceHolderEnd < nacosValueExpr.length(); replaceHolderEnd++) {
char ch = nacosValueExpr.charAt(replaceHolderEnd);
if (PLACEHOLDER_MATCH_PREFIX == ch) {
i++;
} else if (PLACEHOLDER_MATCH_SUFFIX == ch && --i == -1) {
break;
}
}
String replaceHolder = nacosValueExpr.substring(replaceHolderBegin, replaceHolderEnd);
int separatorIndex = replaceHolder.indexOf(VALUE_SEPARATOR);
if (separatorIndex != -1) {
return nacosValueExpr.substring(0, separatorIndex + replaceHolderBegin) + nacosValueExpr.substring(replaceHolderEnd);
}
return nacosValueExpr;
} catch (Exception e) {
throw new IllegalArgumentException("The expr format is illegal, expr: " + nacosValueExpr, e);
} }
} }
protected void updateLastMD5(String newMD5) {
this.lastMD5 = newMD5;
}
}
} }

View File

@ -0,0 +1,331 @@
/*
* 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 com.alibaba.nacos.spring.context.annotation.config;
import com.alibaba.nacos.common.utils.MD5Utils;
import com.alibaba.nacos.spring.beans.factory.annotation.AbstractAnnotationBeanPostProcessor;
import com.alibaba.nacos.spring.context.event.config.NacosConfigReceivedEvent;
import com.alibaba.nacos.spring.util.NacosUtils;
import com.alibaba.nacos.spring.util.PlaceholderHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.TypeConverter;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.annotation.InjectionMetadata;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.BeanExpressionContext;
import org.springframework.beans.factory.config.BeanExpressionResolver;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.ApplicationListener;
import org.springframework.context.EnvironmentAware;
import org.springframework.core.MethodParameter;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.env.Environment;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;
import java.lang.reflect.Field;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.*;
import static org.springframework.core.annotation.AnnotationUtils.getAnnotation;
/**
* @author wuhaoqiang
* @since 1.1.2
**/
public class SpringValueAnnotationBeanPostProcessor
extends AbstractAnnotationBeanPostProcessor implements BeanFactoryAware,
EnvironmentAware, ApplicationListener<NacosConfigReceivedEvent> {
/**
* The name of {@link SpringValueAnnotationBeanPostProcessor} bean.
*/
public static final String BEAN_NAME = "StringValueAnnotationBeanPostProcessor";
private final Logger logger = LoggerFactory.getLogger(getClass());
/**
* placeholder, valueTarget.
*/
private Map<String, List<StringValueTarget>> placeholderStringValueTargetMap = new HashMap<String, List<StringValueTarget>>();
private ConfigurableListableBeanFactory beanFactory;
private Environment environment;
private BeanExpressionResolver exprResolver;
private BeanExpressionContext exprContext;
public SpringValueAnnotationBeanPostProcessor() {
super(Value.class);
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
if (!(beanFactory instanceof ConfigurableListableBeanFactory)) {
throw new IllegalArgumentException(
"StringValueAnnotationBeanPostProcessor requires a ConfigurableListableBeanFactory");
}
this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
this.exprResolver = ((ConfigurableListableBeanFactory) beanFactory).getBeanExpressionResolver();
this.exprContext = new BeanExpressionContext((ConfigurableListableBeanFactory) beanFactory, null);
}
@Override
public void setEnvironment(Environment environment) {
this.environment = environment;
}
@Override
protected Object doGetInjectedBean(AnnotationAttributes attributes, Object bean,
String beanName, Class<?> injectedType,
InjectionMetadata.InjectedElement injectedElement) throws Exception {
Object value = resolveStringValue(attributes.getString("value"));
Member member = injectedElement.getMember();
if (member instanceof Field) {
return convertIfNecessary((Field) member, value);
}
if (member instanceof Method) {
return convertIfNecessary((Method) member, value);
}
return null;
}
@Override
protected String buildInjectedObjectCacheKey(AnnotationAttributes attributes,
Object bean, String beanName, Class<?> injectedType,
InjectionMetadata.InjectedElement injectedElement) {
return bean.getClass().getName() + attributes;
}
@Override
public Object postProcessBeforeInitialization(Object bean, final String beanName)
throws BeansException {
doWithFields(bean, beanName);
doWithMethods(bean, beanName);
return super.postProcessBeforeInitialization(bean, beanName);
}
@Override
public void onApplicationEvent(NacosConfigReceivedEvent event) {
if (StringUtils.isEmpty(event)) {
return;
}
Map<String, Object> updateProperties = NacosUtils.toProperties(event.getContent(), event.getType());
for (Map.Entry<String, List<StringValueTarget>> entry : placeholderStringValueTargetMap
.entrySet()) {
String key = environment.resolvePlaceholders(entry.getKey());
// Process modified keys, excluding deleted keys
if (!updateProperties.containsKey(key)) {
continue;
}
String newValue = environment.getProperty(key);
if (newValue == null) {
continue;
}
List<StringValueTarget> beanPropertyList = entry.getValue();
for (StringValueTarget target : beanPropertyList) {
String md5String = MD5Utils.md5Hex(newValue, "UTF-8");
boolean isUpdate = !target.lastMD5.equals(md5String);
if (isUpdate) {
target.updateLastMD5(md5String);
Object evaluatedValue = resolveStringValue(target.stringValueExpr);
if (target.method == null) {
setField(target, evaluatedValue);
} else {
setMethod(target, evaluatedValue);
}
}
}
}
}
private Object resolveStringValue(String strVal) {
String value = beanFactory.resolveEmbeddedValue(strVal);
if (exprResolver != null && value != null) {
return exprResolver.evaluate(value, exprContext);
}
return value;
}
private Object convertIfNecessary(Field field, Object value) {
TypeConverter converter = beanFactory.getTypeConverter();
return converter.convertIfNecessary(value, field.getType(), field);
}
private Object convertIfNecessary(Method method, Object value) {
Class<?>[] paramTypes = method.getParameterTypes();
Object[] arguments = new Object[paramTypes.length];
TypeConverter converter = beanFactory.getTypeConverter();
if (arguments.length == 1) {
return converter.convertIfNecessary(value, paramTypes[0],
new MethodParameter(method, 0));
}
for (int i = 0; i < arguments.length; i++) {
arguments[i] = converter.convertIfNecessary(value, paramTypes[i],
new MethodParameter(method, i));
}
return arguments;
}
private void doWithFields(final Object bean, final String beanName) {
ReflectionUtils.doWithFields(bean.getClass(),
new ReflectionUtils.FieldCallback() {
@Override
public void doWith(Field field) throws IllegalArgumentException {
Value annotation = getAnnotation(field, Value.class);
doWithAnnotation(beanName, bean, annotation, field.getModifiers(),
null, field);
}
});
}
private void doWithMethods(final Object bean, final String beanName) {
ReflectionUtils.doWithMethods(bean.getClass(),
new ReflectionUtils.MethodCallback() {
@Override
public void doWith(Method method) throws IllegalArgumentException {
Value annotation = getAnnotation(method, Value.class);
doWithAnnotation(beanName, bean, annotation,
method.getModifiers(), method, null);
}
});
}
private void doWithAnnotation(String beanName, Object bean, Value annotation,
int modifiers, Method method, Field field) {
if (annotation != null) {
if (Modifier.isStatic(modifiers)) {
return;
}
Set<String> placeholderList = PlaceholderHelper.findPlaceholderKeys(annotation.value());
for (String placeholder : placeholderList) {
StringValueTarget stringValueTarget = new StringValueTarget(bean, beanName,
method, field, annotation.value());
put2ListMap(placeholderStringValueTargetMap, placeholder,
stringValueTarget);
}
}
}
private <K, V> void put2ListMap(Map<K, List<V>> map, K key, V value) {
List<V> valueList = map.get(key);
if (valueList == null) {
valueList = new ArrayList<V>();
}
valueList.add(value);
map.put(key, valueList);
}
private void setMethod(StringValueTarget stringValueTarget, Object propertyValue) {
Method method = stringValueTarget.method;
ReflectionUtils.makeAccessible(method);
try {
method.invoke(stringValueTarget.bean,
convertIfNecessary(method, propertyValue));
if (logger.isDebugEnabled()) {
logger.debug("Update value with {} (method) in {} (bean) with {}",
method.getName(), stringValueTarget.beanName, propertyValue);
}
} catch (Throwable e) {
if (logger.isErrorEnabled()) {
logger.error("Can't update value with " + method.getName()
+ " (method) in " + stringValueTarget.beanName + " (bean)", e);
}
}
}
private void setField(final StringValueTarget stringValueTarget,
final Object propertyValue) {
final Object bean = stringValueTarget.bean;
Field field = stringValueTarget.field;
String fieldName = field.getName();
try {
ReflectionUtils.makeAccessible(field);
field.set(bean, convertIfNecessary(field, propertyValue));
if (logger.isDebugEnabled()) {
logger.debug("Update value of the {}" + " (field) in {} (bean) with {}",
fieldName, stringValueTarget.beanName, propertyValue);
}
} catch (Throwable e) {
if (logger.isErrorEnabled()) {
logger.error("Can't update value of the " + fieldName + " (field) in "
+ stringValueTarget.beanName + " (bean)", e);
}
}
}
private static class StringValueTarget {
private final Object bean;
private final String beanName;
private final Method method;
private final Field field;
private String lastMD5;
private final String stringValueExpr;
StringValueTarget(Object bean, String beanName, Method method, Field field, String stringValueExpr) {
this.bean = bean;
this.beanName = beanName;
this.method = method;
this.field = field;
this.lastMD5 = "";
this.stringValueExpr = stringValueExpr;
}
protected void updateLastMD5(String newMD5) {
this.lastMD5 = newMD5;
}
}
}

View File

@ -16,14 +16,28 @@
*/ */
package com.alibaba.nacos.spring.context.annotation.discovery; package com.alibaba.nacos.spring.context.annotation.discovery;
import static com.alibaba.nacos.api.PropertyKeyConst.PASSWORD;
import static com.alibaba.nacos.api.PropertyKeyConst.USERNAME;
import static com.alibaba.nacos.api.annotation.NacosProperties.ACCESS_KEY;
import static com.alibaba.nacos.api.annotation.NacosProperties.CLUSTER_NAME;
import static com.alibaba.nacos.api.annotation.NacosProperties.CONTEXT_PATH;
import static com.alibaba.nacos.api.annotation.NacosProperties.ENCODE;
import static com.alibaba.nacos.api.annotation.NacosProperties.ENDPOINT;
import static com.alibaba.nacos.api.annotation.NacosProperties.NAMESPACE;
import static com.alibaba.nacos.api.annotation.NacosProperties.SECRET_KEY;
import static com.alibaba.nacos.api.annotation.NacosProperties.SERVER_ADDR;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.context.annotation.Import;
import com.alibaba.nacos.api.annotation.NacosInjected; import com.alibaba.nacos.api.annotation.NacosInjected;
import com.alibaba.nacos.api.annotation.NacosProperties; import com.alibaba.nacos.api.annotation.NacosProperties;
import com.alibaba.nacos.spring.context.annotation.NacosBeanDefinitionRegistrar; import com.alibaba.nacos.spring.context.annotation.NacosBeanDefinitionRegistrar;
import org.springframework.context.annotation.Import;
import java.lang.annotation.*;
import static com.alibaba.nacos.api.annotation.NacosProperties.*;
/** /**
* Annotation for enabling Nacos discovery features. * Annotation for enabling Nacos discovery features.
@ -35,9 +49,8 @@ import static com.alibaba.nacos.api.annotation.NacosProperties.*;
@Target({ ElementType.TYPE, ElementType.ANNOTATION_TYPE }) @Target({ ElementType.TYPE, ElementType.ANNOTATION_TYPE })
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Documented @Documented
@Import(NacosDiscoveryBeanDefinitionRegistrar.class) @Import({NacosDiscoveryBeanDefinitionRegistrar.class, EnableNacosDiscoveryAotProcessor.class})
public @interface EnableNacosDiscovery { public @interface EnableNacosDiscovery {
/** /**
* The prefix of property name of Nacos discovery * The prefix of property name of Nacos discovery
*/ */
@ -47,50 +60,71 @@ public @interface EnableNacosDiscovery {
* The placeholder of endpoint, the value is * The placeholder of endpoint, the value is
* <code>"${nacos.discovery.endpoint:${nacos.endpoint:}}"</code> * <code>"${nacos.discovery.endpoint:${nacos.endpoint:}}"</code>
*/ */
String ENDPOINT_PLACEHOLDER = "${" + DISCOVERY_PREFIX + ENDPOINT + ":" + NacosProperties.ENDPOINT_PLACEHOLDER + "}"; String ENDPOINT_PLACEHOLDER = "${" + DISCOVERY_PREFIX + ENDPOINT + ":"
+ NacosProperties.ENDPOINT_PLACEHOLDER + "}";
/** /**
* The placeholder of endpoint, the value is * The placeholder of endpoint, the value is
* <code>"${nacos.discovery.namespace:${nacos.namespace:}}"</code> * <code>"${nacos.discovery.namespace:${nacos.namespace:}}"</code>
*/ */
String NAMESPACE_PLACEHOLDER = "${" + DISCOVERY_PREFIX + NAMESPACE + ":" + NacosProperties.NAMESPACE_PLACEHOLDER + "}"; String NAMESPACE_PLACEHOLDER = "${" + DISCOVERY_PREFIX + NAMESPACE + ":"
+ NacosProperties.NAMESPACE_PLACEHOLDER + "}";
/** /**
* The placeholder of endpoint, the value is * The placeholder of endpoint, the value is
* <code>"${nacos.discovery.access-key:${nacos.access-key:}}"</code> * <code>"${nacos.discovery.access-key:${nacos.access-key:}}"</code>
*/ */
String ACCESS_KEY_PLACEHOLDER = "${" + DISCOVERY_PREFIX + ACCESS_KEY +":" + NacosProperties.ACCESS_KEY_PLACEHOLDER + "}"; String ACCESS_KEY_PLACEHOLDER = "${" + DISCOVERY_PREFIX + ACCESS_KEY + ":"
+ NacosProperties.ACCESS_KEY_PLACEHOLDER + "}";
/** /**
* The placeholder of endpoint, the value is * The placeholder of endpoint, the value is
* <code>"${nacos.discovery.secret-key:${nacos.secret-key:}}"</code> * <code>"${nacos.discovery.secret-key:${nacos.secret-key:}}"</code>
*/ */
String SECRET_KEY_PLACEHOLDER = "${" + DISCOVERY_PREFIX + SECRET_KEY + ":" + NacosProperties.SECRET_KEY_PLACEHOLDER + "}"; String SECRET_KEY_PLACEHOLDER = "${" + DISCOVERY_PREFIX + SECRET_KEY + ":"
+ NacosProperties.SECRET_KEY_PLACEHOLDER + "}";
/** /**
* The placeholder of endpoint, the value is * The placeholder of endpoint, the value is
* <code>"${nacos.discovery.server-addr:${nacos.server-addr:}}"</code> * <code>"${nacos.discovery.server-addr:${nacos.server-addr:}}"</code>
*/ */
String SERVER_ADDR_PLACEHOLDER = "${" + DISCOVERY_PREFIX + SERVER_ADDR + ":" + NacosProperties.SERVER_ADDR_PLACEHOLDER + "}"; String SERVER_ADDR_PLACEHOLDER = "${" + DISCOVERY_PREFIX + SERVER_ADDR + ":"
+ NacosProperties.SERVER_ADDR_PLACEHOLDER + "}";
/** /**
* The placeholder of endpoint, the value is * The placeholder of endpoint, the value is
* <code>"${nacos.discovery.context-path:${nacos.context-path:}}"</code> * <code>"${nacos.discovery.context-path:${nacos.context-path:}}"</code>
*/ */
String CONTEXT_PATH_PLACEHOLDER = "${" + DISCOVERY_PREFIX + CONTEXT_PATH + ":" + NacosProperties.CONTEXT_PATH_PLACEHOLDER + "}"; String CONTEXT_PATH_PLACEHOLDER = "${" + DISCOVERY_PREFIX + CONTEXT_PATH + ":"
+ NacosProperties.CONTEXT_PATH_PLACEHOLDER + "}";
/** /**
* The placeholder of endpoint, the value is * The placeholder of endpoint, the value is
* <code>"${nacos.discovery.cluster-name:${nacos.cluster-name:}}"</code> * <code>"${nacos.discovery.cluster-name:${nacos.cluster-name:}}"</code>
*/ */
String CLUSTER_NAME_PLACEHOLDER = "${" + DISCOVERY_PREFIX + CLUSTER_NAME + ":" + NacosProperties.CLUSTER_NAME_PLACEHOLDER + "}"; String CLUSTER_NAME_PLACEHOLDER = "${" + DISCOVERY_PREFIX + CLUSTER_NAME + ":"
+ NacosProperties.CLUSTER_NAME_PLACEHOLDER + "}";
/** /**
* The placeholder of {@link NacosProperties#ENCODE encode}, the value is * The placeholder of {@link NacosProperties#ENCODE encode}, the value is
* <code>"${nacos.discovery.encode:${nacos.encode:UTF-8}}"</code> * <code>"${nacos.discovery.encode:${nacos.encode:UTF-8}}"</code>
*/ */
String ENCODE_PLACEHOLDER = "${" + DISCOVERY_PREFIX + ENCODE + ":" + NacosProperties.ENCODE_PLACEHOLDER + "}"; String ENCODE_PLACEHOLDER = "${" + DISCOVERY_PREFIX + ENCODE + ":"
+ NacosProperties.ENCODE_PLACEHOLDER + "}";
/**
* The placeholder of endpoint, the value is
* <code>"${nacos.discovery.username:${nacos.username:}}"</code>
*/
String USERNAME_PLACEHOLDER = "${" + DISCOVERY_PREFIX + USERNAME + ":"
+ NacosProperties.USERNAME_PLACEHOLDER + "}";
/**
* The placeholder of endpoint, the value is
* <code>"${nacos.discovery.password:${nacos.password:}}"</code>
*/
String PASSWORD_PLACEHOLDER = "${" + DISCOVERY_PREFIX + PASSWORD + ":"
+ NacosProperties.PASSWORD_PLACEHOLDER + "}";
/** /**
* Global {@link NacosProperties Nacos Properties} * Global {@link NacosProperties Nacos Properties}
@ -98,15 +132,5 @@ public @interface EnableNacosDiscovery {
* @return required * @return required
* @see NacosInjected#properties() * @see NacosInjected#properties()
*/ */
NacosProperties globalProperties() default NacosProperties globalProperties() default @NacosProperties(username = USERNAME_PLACEHOLDER, password = PASSWORD_PLACEHOLDER, endpoint = ENDPOINT_PLACEHOLDER, namespace = NAMESPACE_PLACEHOLDER, accessKey = ACCESS_KEY_PLACEHOLDER, secretKey = SECRET_KEY_PLACEHOLDER, serverAddr = SERVER_ADDR_PLACEHOLDER, contextPath = CONTEXT_PATH_PLACEHOLDER, clusterName = CLUSTER_NAME_PLACEHOLDER, encode = ENCODE_PLACEHOLDER);
@NacosProperties(
endpoint = ENDPOINT_PLACEHOLDER,
namespace = NAMESPACE_PLACEHOLDER,
accessKey = ACCESS_KEY_PLACEHOLDER,
secretKey = SECRET_KEY_PLACEHOLDER,
serverAddr = SERVER_ADDR_PLACEHOLDER,
contextPath = CONTEXT_PATH_PLACEHOLDER,
clusterName = CLUSTER_NAME_PLACEHOLDER,
encode = ENCODE_PLACEHOLDER
);
} }

View File

@ -0,0 +1,92 @@
/*
*
* * 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 com.alibaba.nacos.spring.context.annotation.discovery;
import com.alibaba.nacos.spring.util.aot.AotDetector;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.EnvironmentAware;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotationMetadata;
import java.util.Map;
import static com.alibaba.nacos.spring.util.NacosBeanUtils.*;
/**
* {@link EnableNacosDiscovery} AotProcessor
* Except for the operation of registering BeanDefinition, all other operations in {@link NacosDiscoveryBeanDefinitionRegistrar} must be done here
* because spring will not call {@link NacosDiscoveryBeanDefinitionRegistrar#registerBeanDefinitions} in AOT.
* @author SuperZ1999
*/
public class EnableNacosDiscoveryAotProcessor implements BeanDefinitionRegistryPostProcessor, EnvironmentAware, BeanFactoryAware {
private Environment environment;
private BeanFactory beanFactory;
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
if (!AotDetector.useGeneratedArtifacts()) {
return;
}
DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) this.beanFactory;
Map<String, Object> beansWithAnnotation = beanFactory.getBeansWithAnnotation(EnableNacosDiscovery.class);
Object[] beans = beansWithAnnotation.values().toArray();
if (beans.length != 0) {
// only handle the first one
Class<?> aClass = beans[0].getClass();
if (aClass.getAnnotation(EnableNacosDiscovery.class) == null) {
// cglib proxy object
aClass = aClass.getSuperclass();
}
AnnotationMetadata annotationMetadata = AnnotationMetadata.introspect(aClass);
AnnotationAttributes attributes = AnnotationAttributes
.fromMap(annotationMetadata
.getAnnotationAttributes(EnableNacosDiscovery.class.getName()));
// Register Global Nacos Properties Bean
registerGlobalNacosProperties(attributes, registry, environment,
DISCOVERY_GLOBAL_NACOS_PROPERTIES_BEAN_NAME);
registerGlobalNacosProperties(attributes, registry, environment,
MAINTAIN_GLOBAL_NACOS_PROPERTIES_BEAN_NAME);
}
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
}
@Override
public void setEnvironment(Environment environment) {
this.environment = environment;
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
}

View File

@ -16,8 +16,12 @@
*/ */
package com.alibaba.nacos.spring.context.annotation.discovery; package com.alibaba.nacos.spring.context.annotation.discovery;
import com.alibaba.nacos.spring.context.annotation.config.EnableNacosConfig; import static com.alibaba.nacos.spring.util.NacosBeanUtils.DISCOVERY_GLOBAL_NACOS_PROPERTIES_BEAN_NAME;
import com.alibaba.nacos.spring.util.NacosBeanUtils; import static com.alibaba.nacos.spring.util.NacosBeanUtils.MAINTAIN_GLOBAL_NACOS_PROPERTIES_BEAN_NAME;
import static com.alibaba.nacos.spring.util.NacosBeanUtils.registerGlobalNacosProperties;
import static com.alibaba.nacos.spring.util.NacosBeanUtils.registerNacosCommonBeans;
import static com.alibaba.nacos.spring.util.NacosBeanUtils.registerNacosDiscoveryBeans;
import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.EnvironmentAware; import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
@ -26,28 +30,35 @@ import org.springframework.core.env.Environment;
import org.springframework.core.env.PropertyResolver; import org.springframework.core.env.PropertyResolver;
import org.springframework.core.type.AnnotationMetadata; import org.springframework.core.type.AnnotationMetadata;
import static com.alibaba.nacos.spring.util.NacosBeanUtils.*; import com.alibaba.nacos.spring.context.annotation.config.EnableNacosConfig;
import com.alibaba.nacos.spring.util.NacosBeanUtils;
/** /**
* Nacos Discovery {@link ImportBeanDefinitionRegistrar BeanDefinition Registrar} * Nacos Discovery {@link ImportBeanDefinitionRegistrar BeanDefinition Registrar}
* *
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a> * @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
* @see EnableNacosConfig * @see EnableNacosConfig
* @see NacosBeanUtils#registerGlobalNacosProperties(AnnotationAttributes, BeanDefinitionRegistry, PropertyResolver, String) * @see NacosBeanUtils#registerGlobalNacosProperties(AnnotationAttributes,
* BeanDefinitionRegistry, PropertyResolver, String)
* @see NacosBeanUtils#registerNacosCommonBeans(BeanDefinitionRegistry) * @see NacosBeanUtils#registerNacosCommonBeans(BeanDefinitionRegistry)
* @see NacosBeanUtils#registerNacosConfigBeans(BeanDefinitionRegistry, Environment)
* @since 0.1.0 * @since 0.1.0
*/ */
public class NacosDiscoveryBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar, EnvironmentAware { public class NacosDiscoveryBeanDefinitionRegistrar
implements ImportBeanDefinitionRegistrar, EnvironmentAware {
private Environment environment; private Environment environment;
@Override @Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
AnnotationAttributes attributes = AnnotationAttributes.fromMap( BeanDefinitionRegistry registry) {
importingClassMetadata.getAnnotationAttributes(EnableNacosDiscovery.class.getName())); AnnotationAttributes attributes = AnnotationAttributes
.fromMap(importingClassMetadata
.getAnnotationAttributes(EnableNacosDiscovery.class.getName()));
// Register Global Nacos Properties Bean // Register Global Nacos Properties Bean
registerGlobalNacosProperties(attributes, registry, environment, DISCOVERY_GLOBAL_NACOS_PROPERTIES_BEAN_NAME); registerGlobalNacosProperties(attributes, registry, environment,
DISCOVERY_GLOBAL_NACOS_PROPERTIES_BEAN_NAME);
registerGlobalNacosProperties(attributes, registry, environment,
MAINTAIN_GLOBAL_NACOS_PROPERTIES_BEAN_NAME);
// Register Nacos Common Beans // Register Nacos Common Beans
registerNacosCommonBeans(registry); registerNacosCommonBeans(registry);
// Register Nacos Discovery Beans // Register Nacos Discovery Beans

View File

@ -16,9 +16,20 @@
*/ */
package com.alibaba.nacos.spring.context.config.xml; package com.alibaba.nacos.spring.context.config.xml;
import com.alibaba.nacos.api.PropertyKeyConst; import static com.alibaba.nacos.api.annotation.NacosProperties.ACCESS_KEY;
import com.alibaba.nacos.api.annotation.NacosProperties; import static com.alibaba.nacos.api.annotation.NacosProperties.CLUSTER_NAME;
import com.alibaba.nacos.spring.util.NacosBeanUtils; import static com.alibaba.nacos.api.annotation.NacosProperties.ENCODE;
import static com.alibaba.nacos.api.annotation.NacosProperties.ENDPOINT;
import static com.alibaba.nacos.api.annotation.NacosProperties.NAMESPACE;
import static com.alibaba.nacos.api.annotation.NacosProperties.PASSWORD;
import static com.alibaba.nacos.api.annotation.NacosProperties.SECRET_KEY;
import static com.alibaba.nacos.api.annotation.NacosProperties.SERVER_ADDR;
import static com.alibaba.nacos.api.annotation.NacosProperties.USERNAME;
import static com.alibaba.nacos.spring.util.NacosBeanUtils.GLOBAL_NACOS_PROPERTIES_BEAN_NAME;
import static com.alibaba.nacos.spring.util.NacosBeanUtils.registerGlobalNacosProperties;
import java.util.Properties;
import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.xml.BeanDefinitionParser; import org.springframework.beans.factory.xml.BeanDefinitionParser;
@ -26,14 +37,13 @@ import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.core.env.Environment; import org.springframework.core.env.Environment;
import org.w3c.dom.Element; import org.w3c.dom.Element;
import java.util.Properties; import com.alibaba.nacos.api.PropertyKeyConst;
import com.alibaba.nacos.api.annotation.NacosProperties;
import static com.alibaba.nacos.api.annotation.NacosProperties.*; import com.alibaba.nacos.spring.util.NacosBeanUtils;
import static com.alibaba.nacos.spring.util.NacosBeanUtils.GLOBAL_NACOS_PROPERTIES_BEAN_NAME;
import static com.alibaba.nacos.spring.util.NacosBeanUtils.registerGlobalNacosProperties;
/** /**
* Nacos Global {@link Properties} {@link BeanDefinitionParser} for &lt;nacos:global-properties ...&gt; * Nacos Global {@link Properties} {@link BeanDefinitionParser} for
* &lt;nacos:global-properties ...&gt;
* *
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a> * @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
* @see NacosBeanUtils#GLOBAL_NACOS_PROPERTIES_BEAN_NAME * @see NacosBeanUtils#GLOBAL_NACOS_PROPERTIES_BEAN_NAME
@ -48,20 +58,29 @@ public class GlobalNacosPropertiesBeanDefinitionParser implements BeanDefinition
Properties properties = new Properties(); Properties properties = new Properties();
Environment environment = parserContext.getDelegate().getEnvironment(); Environment environment = parserContext.getDelegate().getReaderContext()
.getReader().getEnvironment();
properties.setProperty(PropertyKeyConst.ENDPOINT, element.getAttribute(ENDPOINT)); properties.setProperty(PropertyKeyConst.ENDPOINT, element.getAttribute(ENDPOINT));
properties.setProperty(PropertyKeyConst.NAMESPACE, element.getAttribute(NAMESPACE)); properties.setProperty(PropertyKeyConst.NAMESPACE,
properties.setProperty(PropertyKeyConst.ACCESS_KEY, element.getAttribute(ACCESS_KEY)); element.getAttribute(NAMESPACE));
properties.setProperty(PropertyKeyConst.SECRET_KEY, element.getAttribute(SECRET_KEY)); properties.setProperty(PropertyKeyConst.ACCESS_KEY,
properties.setProperty(PropertyKeyConst.SERVER_ADDR, element.getAttribute(SERVER_ADDR)); element.getAttribute(ACCESS_KEY));
properties.setProperty(PropertyKeyConst.CLUSTER_NAME, element.getAttribute(CLUSTER_NAME)); properties.setProperty(PropertyKeyConst.SECRET_KEY,
element.getAttribute(SECRET_KEY));
properties.setProperty(PropertyKeyConst.SERVER_ADDR,
element.getAttribute(SERVER_ADDR));
properties.setProperty(PropertyKeyConst.CLUSTER_NAME,
element.getAttribute(CLUSTER_NAME));
properties.setProperty(PropertyKeyConst.ENCODE, element.getAttribute(ENCODE)); properties.setProperty(PropertyKeyConst.ENCODE, element.getAttribute(ENCODE));
properties.setProperty(PropertyKeyConst.USERNAME, element.getAttribute(USERNAME));
properties.setProperty(PropertyKeyConst.PASSWORD, element.getAttribute(PASSWORD));
BeanDefinitionRegistry registry = parserContext.getRegistry(); BeanDefinitionRegistry registry = parserContext.getRegistry();
// Register Global Nacos Properties as Spring singleton bean // Register Global Nacos Properties as Spring singleton bean
registerGlobalNacosProperties(properties, registry, environment, GLOBAL_NACOS_PROPERTIES_BEAN_NAME); registerGlobalNacosProperties(properties, registry, environment,
GLOBAL_NACOS_PROPERTIES_BEAN_NAME);
return null; return null;
} }

View File

@ -16,7 +16,6 @@
*/ */
package com.alibaba.nacos.spring.context.config.xml; package com.alibaba.nacos.spring.context.config.xml;
import com.alibaba.nacos.spring.context.annotation.NacosBeanDefinitionRegistrar;
import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.xml.BeanDefinitionParser; import org.springframework.beans.factory.xml.BeanDefinitionParser;
@ -24,8 +23,11 @@ import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.core.env.Environment; import org.springframework.core.env.Environment;
import org.w3c.dom.Element; import org.w3c.dom.Element;
import com.alibaba.nacos.spring.context.annotation.NacosBeanDefinitionRegistrar;
/** /**
* Nacos Annotation Driven {@link BeanDefinitionParser} for XML element &lt;nacos:annotation-driven/&gt; * Nacos Annotation Driven {@link BeanDefinitionParser} for XML element
* &lt;nacos:annotation-driven/&gt;
* *
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a> * @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
* @see BeanDefinitionParser * @see BeanDefinitionParser
@ -35,8 +37,10 @@ public class NacosAnnotationDrivenBeanDefinitionParser implements BeanDefinition
@Override @Override
public BeanDefinition parse(Element element, ParserContext parserContext) { public BeanDefinition parse(Element element, ParserContext parserContext) {
// Get Environment // Get Environment
Environment environment = parserContext.getDelegate().getEnvironment(); Environment environment = parserContext.getDelegate().getReaderContext()
.getReader().getEnvironment();
// Get BeanDefinitionRegistry // Get BeanDefinitionRegistry
BeanDefinitionRegistry registry = parserContext.getRegistry(); BeanDefinitionRegistry registry = parserContext.getRegistry();
// Register Nacos Annotation Beans // Register Nacos Annotation Beans

View File

@ -30,8 +30,11 @@ public class NacosNamespaceHandler extends NamespaceHandlerSupport {
@Override @Override
public void init() { public void init() {
registerBeanDefinitionParser("annotation-driven", new NacosAnnotationDrivenBeanDefinitionParser()); registerBeanDefinitionParser("annotation-driven",
registerBeanDefinitionParser("global-properties", new GlobalNacosPropertiesBeanDefinitionParser()); new NacosAnnotationDrivenBeanDefinitionParser());
registerBeanDefinitionParser("property-source", new NacosPropertySourceBeanDefinitionParser()); registerBeanDefinitionParser("global-properties",
new GlobalNacosPropertiesBeanDefinitionParser());
registerBeanDefinitionParser("property-source",
new NacosPropertySourceBeanDefinitionParser());
} }
} }

View File

@ -16,7 +16,9 @@
*/ */
package com.alibaba.nacos.spring.context.config.xml; package com.alibaba.nacos.spring.context.config.xml;
import com.alibaba.nacos.spring.context.annotation.config.NacosPropertySource; import static com.alibaba.nacos.spring.util.NacosBeanUtils.registerNacosPropertySourcePostProcessor;
import static com.alibaba.nacos.spring.util.NacosBeanUtils.registerXmlNacosPropertySourceBuilder;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.support.AbstractBeanDefinition; import org.springframework.beans.factory.support.AbstractBeanDefinition;
@ -26,23 +28,25 @@ import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext; import org.springframework.beans.factory.xml.ParserContext;
import org.w3c.dom.Element; import org.w3c.dom.Element;
import static com.alibaba.nacos.spring.util.NacosBeanUtils.registerNacosPropertySourcePostProcessor; import com.alibaba.nacos.spring.context.annotation.config.NacosPropertySource;
import static com.alibaba.nacos.spring.util.NacosBeanUtils.registerXmlNacosPropertySourceBuilder;
/** /**
* Nacos Property Source {@link BeanDefinitionParser} for &lt;nacos:property-source ...&gt; * Nacos Property Source {@link BeanDefinitionParser} for &lt;nacos:property-source
* ...&gt;
* *
* @author <a href="mailto:huangxiaoyu1018@gmail.com">hxy1991</a> * @author <a href="mailto:huangxiaoyu1018@gmail.com">hxy1991</a>
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a> * @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
* @see NacosPropertySource * @see NacosPropertySource
* @since 0.1.0 * @since 0.1.0
*/ */
public class NacosPropertySourceBeanDefinitionParser extends AbstractBeanDefinitionParser { public class NacosPropertySourceBeanDefinitionParser
extends AbstractBeanDefinitionParser {
private final Logger logger = LoggerFactory.getLogger(getClass()); private final Logger logger = LoggerFactory.getLogger(getClass());
@Override @Override
protected AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) { protected AbstractBeanDefinition parseInternal(Element element,
ParserContext parserContext) {
BeanDefinitionRegistry registry = parserContext.getRegistry(); BeanDefinitionRegistry registry = parserContext.getRegistry();
// Register Dependent Beans // Register Dependent Beans

View File

@ -39,20 +39,20 @@ public class NacosPropertySourceXmlBeanDefinition extends GenericBeanDefinition
setBeanClass(getClass()); setBeanClass(getClass());
} }
void setXmlReaderContext(XmlReaderContext xmlReaderContext) { public Element getElement() {
this.xmlReaderContext = xmlReaderContext; return element;
} }
void setElement(Element element) { void setElement(Element element) {
this.element = element; this.element = element;
} }
public Element getElement() {
return element;
}
public XmlReaderContext getXmlReaderContext() { public XmlReaderContext getXmlReaderContext() {
return xmlReaderContext; return xmlReaderContext;
} }
void setXmlReaderContext(XmlReaderContext xmlReaderContext) {
this.xmlReaderContext = xmlReaderContext;
}
} }

View File

@ -29,11 +29,13 @@ public interface NacosConstants {
/** /**
* The parallelism of Nacos Config Listener * The parallelism of Nacos Config Listener
*/ */
String NACOS_CONFIG_LISTENER_PARALLELISM = NacosProperties.PREFIX + "config.listener.parallelism"; String NACOS_CONFIG_LISTENER_PARALLELISM = NacosProperties.PREFIX
+ "config.listener.parallelism";
/** /**
* The default parallelism of Nacos Config Listener (available processors) * The default parallelism of Nacos Config Listener (available processors)
*/ */
int DEFAULT_NACOS_CONFIG_LISTENER_PARALLELISM = Runtime.getRuntime().availableProcessors(); int DEFAULT_NACOS_CONFIG_LISTENER_PARALLELISM = Runtime.getRuntime()
.availableProcessors();
} }

View File

@ -16,8 +16,18 @@
*/ */
package com.alibaba.nacos.spring.context.event; package com.alibaba.nacos.spring.context.event;
import org.apache.commons.logging.Log; import static com.alibaba.nacos.spring.util.NacosUtils.resolveGenericType;
import org.apache.commons.logging.LogFactory; import static java.lang.reflect.Modifier.isAbstract;
import static java.lang.reflect.Modifier.isNative;
import static java.lang.reflect.Modifier.isPublic;
import static java.lang.reflect.Modifier.isStatic;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.support.AopUtils; import org.springframework.aop.support.AopUtils;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationListener; import org.springframework.context.ApplicationListener;
@ -25,14 +35,6 @@ import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.core.annotation.AnnotationUtils; import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.util.ReflectionUtils; import org.springframework.util.ReflectionUtils;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Map;
import static com.alibaba.nacos.spring.util.NacosUtils.resolveGenericType;
import static java.lang.reflect.Modifier.*;
/** /**
* Listener {@link Method method} Processor * Listener {@link Method method} Processor
* <p> * <p>
@ -49,9 +51,10 @@ import static java.lang.reflect.Modifier.*;
* @see Method * @see Method
* @since 0.1.0 * @since 0.1.0
*/ */
public abstract class AnnotationListenerMethodProcessor<A extends Annotation> implements ApplicationListener<ContextRefreshedEvent> { public abstract class AnnotationListenerMethodProcessor<A extends Annotation>
implements ApplicationListener<ContextRefreshedEvent> {
protected final Log logger = LogFactory.getLog(getClass()); protected final Logger logger = LoggerFactory.getLogger(getClass());
private final Class<A> annotationType; private final Class<A> annotationType;
public AnnotationListenerMethodProcessor() { public AnnotationListenerMethodProcessor() {
@ -77,12 +80,8 @@ public abstract class AnnotationListenerMethodProcessor<A extends Annotation> im
Class<?> returnType = method.getReturnType(); Class<?> returnType = method.getReturnType();
return isPublic(modifiers) return isPublic(modifiers) && !isStatic(modifiers) && !isNative(modifiers)
&& !isStatic(modifiers) && !isAbstract(modifiers) && void.class.equals(returnType);
&& !isNative(modifiers)
&& !isAbstract(modifiers)
&& void.class.equals(returnType)
;
} }
@Override @Override
@ -95,13 +94,15 @@ public abstract class AnnotationListenerMethodProcessor<A extends Annotation> im
private void processBeans(ApplicationContext applicationContext) { private void processBeans(ApplicationContext applicationContext) {
Map<String, Object> beansMap = applicationContext.getBeansOfType(Object.class); Map<String, Object> beansMap = applicationContext.getBeansOfType(Object.class,
false, false);
processBeans(beansMap, applicationContext); processBeans(beansMap, applicationContext);
} }
private void processBeans(Map<String, Object> beansMap, ApplicationContext applicationContext) { private void processBeans(Map<String, Object> beansMap,
ApplicationContext applicationContext) {
for (Map.Entry<String, Object> entry : beansMap.entrySet()) { for (Map.Entry<String, Object> entry : beansMap.entrySet()) {
String beanName = entry.getKey(); String beanName = entry.getKey();
@ -123,14 +124,18 @@ public abstract class AnnotationListenerMethodProcessor<A extends Annotation> im
* @param beanClass the {@link Class} of Bean * @param beanClass the {@link Class} of Bean
* @param applicationContext * @param applicationContext
*/ */
private void processBean(final String beanName, final Object bean, final Class<?> beanClass, final ApplicationContext applicationContext) { private void processBean(final String beanName, final Object bean,
final Class<?> beanClass, final ApplicationContext applicationContext) {
ReflectionUtils.doWithMethods(beanClass, new ReflectionUtils.MethodCallback() { ReflectionUtils.doWithMethods(beanClass, new ReflectionUtils.MethodCallback() {
@Override @Override
public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException { public void doWith(Method method)
throws IllegalArgumentException, IllegalAccessException {
A annotation = AnnotationUtils.getAnnotation(method, annotationType); A annotation = AnnotationUtils.getAnnotation(method, annotationType);
if (annotation != null && isCandidateMethod(bean, beanClass, annotation, method, applicationContext)) { if (annotation != null && isCandidateMethod(bean, beanClass, annotation,
processListenerMethod(beanName, bean, beanClass, annotation, method, applicationContext); method, applicationContext)) {
processListenerMethod(beanName, bean, beanClass, annotation, method,
applicationContext);
} }
} }
@ -144,7 +149,9 @@ public abstract class AnnotationListenerMethodProcessor<A extends Annotation> im
} }
/** /**
* Process Listener Method when {@link #isCandidateMethod(Object, Class, Annotation, Method, ApplicationContext)} returns <code>true</code> * Process Listener Method when
* {@link #isCandidateMethod(Object, Class, Annotation, Method, ApplicationContext)}
* returns <code>true</code>
* *
* @param beanName Bean name * @param beanName Bean name
* @param bean Bean object * @param bean Bean object
@ -153,7 +160,8 @@ public abstract class AnnotationListenerMethodProcessor<A extends Annotation> im
* @param method Method * @param method Method
* @param applicationContext ApplicationContext * @param applicationContext ApplicationContext
*/ */
protected abstract void processListenerMethod(String beanName, Object bean, Class<?> beanClass, A annotation, Method method, protected abstract void processListenerMethod(String beanName, Object bean,
Class<?> beanClass, A annotation, Method method,
ApplicationContext applicationContext); ApplicationContext applicationContext);
/** /**
@ -166,8 +174,8 @@ public abstract class AnnotationListenerMethodProcessor<A extends Annotation> im
* @param applicationContext ApplicationContext * @param applicationContext ApplicationContext
* @return <code>true</code> as default * @return <code>true</code> as default
*/ */
protected boolean isCandidateMethod(Object bean, Class<?> beanClass, A annotation, Method method, protected boolean isCandidateMethod(Object bean, Class<?> beanClass, A annotation,
ApplicationContext applicationContext) { Method method, ApplicationContext applicationContext) {
return true; return true;
} }
} }

View File

@ -16,29 +16,35 @@
*/ */
package com.alibaba.nacos.spring.context.event; package com.alibaba.nacos.spring.context.event;
import org.springframework.context.*; import java.util.Iterator;
import java.util.concurrent.ConcurrentLinkedQueue;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationListener;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.event.ContextRefreshedEvent; import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.context.support.AbstractApplicationContext; import org.springframework.context.support.AbstractApplicationContext;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
/** /**
* Deferred {@link ApplicationEventPublisher} to resolve {@link #publishEvent(ApplicationEvent)} too early to publish * Deferred {@link ApplicationEventPublisher} to resolve
* {@link ApplicationEvent} when {@link AbstractApplicationContext#initApplicationEventMulticaster() * {@link #publishEvent(ApplicationEvent)} too early to publish {@link ApplicationEvent}
* Spring ApplicationContexts' ApplicationEventMulticaster} is not ready, thus current class will hold * when {@link AbstractApplicationContext#initApplicationEventMulticaster() Spring
* all early {@link ApplicationEvent events} temporary until {@link ConfigurableApplicationContext#isRunning() Spring * ApplicationContexts' ApplicationEventMulticaster} is not ready, thus current class will
* ApplicationContext is active}, and then those {@link ApplicationEvent events} will be replayed. * hold all early {@link ApplicationEvent events} temporary until
* * {@link ConfigurableApplicationContext#isRunning() Spring ApplicationContext is active},
* and then those {@link ApplicationEvent events} will be replayed.
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a> * @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
* @since 0.1.0 * @since 0.1.0
*/ */
public class DeferredApplicationEventPublisher implements ApplicationEventPublisher, ApplicationListener<ContextRefreshedEvent> { public class DeferredApplicationEventPublisher
implements ApplicationEventPublisher, ApplicationListener<ContextRefreshedEvent> {
private final ConfigurableApplicationContext context; private final ConfigurableApplicationContext context;
private final List<ApplicationEvent> deferredEvents = new LinkedList<ApplicationEvent>(); // fix issue #85
private final ConcurrentLinkedQueue<ApplicationEvent> deferredEvents = new ConcurrentLinkedQueue<ApplicationEvent>();
public DeferredApplicationEventPublisher(ConfigurableApplicationContext context) { public DeferredApplicationEventPublisher(ConfigurableApplicationContext context) {
this.context = context; this.context = context;
@ -48,12 +54,21 @@ public class DeferredApplicationEventPublisher implements ApplicationEventPublis
@Override @Override
public void publishEvent(ApplicationEvent event) { public void publishEvent(ApplicationEvent event) {
try {
if (context.isRunning()) { if (context.isRunning()) {
context.publishEvent(event); context.publishEvent(event);
} else { }
else {
deferredEvents.add(event); deferredEvents.add(event);
} }
}
catch (Exception ignore) {
deferredEvents.add(event);
}
}
public void publishEvent(Object event) {
// TODO
} }
@Override @Override

View File

@ -16,55 +16,80 @@
*/ */
package com.alibaba.nacos.spring.context.event; package com.alibaba.nacos.spring.context.event;
import com.alibaba.nacos.spring.context.event.config.NacosConfigMetadataEvent; import com.alibaba.nacos.api.annotation.NacosProperties;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationListener; import org.springframework.context.ApplicationListener;
import com.alibaba.nacos.spring.context.event.config.NacosConfigMetadataEvent;
import java.util.Iterator;
import java.util.Map;
/** /**
* Logging {@link NacosConfigMetadataEvent} {@link ApplicationListener} * Logging {@link NacosConfigMetadataEvent} {@link ApplicationListener}
* *
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a> * @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
* @since 0.1.0 * @since 0.1.0
*/ */
public class LoggingNacosConfigMetadataEventListener implements ApplicationListener<NacosConfigMetadataEvent> { public class LoggingNacosConfigMetadataEventListener
implements ApplicationListener<NacosConfigMetadataEvent> {
/** /**
* The bean name of {@link LoggingNacosConfigMetadataEventListener} * The bean name of {@link LoggingNacosConfigMetadataEventListener}
*/ */
public static final String BEAN_NAME = "loggingNacosConfigMetadataEventListener"; public static final String BEAN_NAME = "loggingNacosConfigMetadataEventListener";
private final static String LOGGING_MESSAGE = "Nacos Config Metadata : "
+ "dataId='{}'" + ", groupId='{}'" + ", beanName='{}'" + ", bean='{}'"
+ ", beanType='{}'" + ", annotatedElement='{}'" + ", xmlResource='{}'"
+ ", nacosProperties='{}'" + ", nacosPropertiesAttributes='{}'"
+ ", source='{}'" + ", timestamp='{}'";
private final Logger logger = LoggerFactory.getLogger(getClass()); private final Logger logger = LoggerFactory.getLogger(getClass());
private final static String LOGGING_MESSAGE = "Nacos Config Metadata : " +
"dataId='{}'" +
", groupId='{}'" +
", beanName='{}'" +
", bean='{}'" +
", beanType='{}'" +
", annotatedElement='{}'" +
", xmlResource='{}'" +
", nacosProperties='{}'" +
", nacosPropertiesAttributes='{}'" +
", source='{}'" +
", timestamp='{}'";
@Override @Override
public void onApplicationEvent(NacosConfigMetadataEvent event) { public void onApplicationEvent(NacosConfigMetadataEvent event) {
if (logger.isInfoEnabled()) { if (!logger.isInfoEnabled()) {
logger.info(LOGGING_MESSAGE, return;
event.getDataId(), }
event.getGroupId(), logger.info(LOGGING_MESSAGE, event.getDataId(), event.getGroupId(),
event.getBeanName(), event.getBeanName(), event.getBean(), event.getBeanType(),
event.getBean(), event.getAnnotatedElement(), event.getXmlResource(),
event.getBeanType(), obscuresNacosProperties(event.getNacosProperties()), event.getNacosPropertiesAttributes(),
event.getAnnotatedElement(), event.getSource(), event.getTimestamp());
event.getXmlResource(), }
event.getNacosProperties(),
event.getNacosPropertiesAttributes(), /**
event.getSource(), * obscures some private field like password in {@link com.alibaba.nacos.api.annotation.NacosProperties}
event.getTimestamp() * @param nacosProperties {@link com.alibaba.nacos.api.annotation.NacosProperties}
); * @return the properties String after obscures
} */
private String obscuresNacosProperties(Map<Object, Object> nacosProperties) {
String nacosPropertyStr;
if (nacosProperties != null && nacosProperties.size() > 0) {
StringBuilder sb = new StringBuilder("{");
int size = nacosProperties.size();
int idx = 0;
for (Map.Entry<Object, Object> e : nacosProperties.entrySet()) {
Object key = e.getKey();
Object value = e.getValue();
sb.append(key);
sb.append('=');
// hide some private messages
if (key != null && NacosProperties.PASSWORD.equals(key.toString())) {
sb.append("******");
} else {
sb.append(value);
}
if (idx < size - 1) {
sb.append(", ");
}
idx ++;
}
sb.append("}");
nacosPropertyStr = sb.toString();
} else {
nacosPropertyStr = "{}";
}
return nacosPropertyStr;
} }
} }

View File

@ -16,16 +16,19 @@
*/ */
package com.alibaba.nacos.spring.context.event.config; package com.alibaba.nacos.spring.context.event.config;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.listener.Listener;
import org.springframework.context.ApplicationEventPublisher;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import org.springframework.context.ApplicationEventPublisher;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.ConfigType;
import com.alibaba.nacos.api.config.listener.Listener;
/** /**
* A Delegating {@link NacosConfigReceivedEvent Event} Publishing {@link Listener} of Nacos Config {@link Listener} with * A Delegating {@link NacosConfigReceivedEvent Event} Publishing {@link Listener} of
* dataId, groupId and {@link ConfigService} instance. A {@link NacosConfigReceivedEvent Nacos config received event} * Nacos Config {@link Listener} with dataId, groupId and {@link ConfigService} instance.
* will be published when a new Nacos config received. * A {@link NacosConfigReceivedEvent Nacos config received event} will be published when a
* new Nacos config received.
* *
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a> * @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
* @see NacosConfigReceivedEvent * @see NacosConfigReceivedEvent
@ -33,7 +36,7 @@ import java.util.concurrent.Executor;
* @see Listener * @see Listener
* @since 0.1.0 * @since 0.1.0
*/ */
final class DelegatingEventPublishingListener implements Listener { public final class DelegatingEventPublishingListener implements Listener {
private final ConfigService configService; private final ConfigService configService;
@ -43,16 +46,27 @@ final class DelegatingEventPublishingListener implements Listener {
private final ApplicationEventPublisher applicationEventPublisher; private final ApplicationEventPublisher applicationEventPublisher;
private final String configType;
private final Executor executor; private final Executor executor;
private final Listener delegate; private final Listener delegate;
DelegatingEventPublishingListener(ConfigService configService, String dataId, String groupId, DelegatingEventPublishingListener(ConfigService configService, String dataId,
ApplicationEventPublisher applicationEventPublisher, String groupId, ApplicationEventPublisher applicationEventPublisher,
Executor executor, Listener delegate) { Executor executor, Listener delegate) {
this(configService, dataId, groupId, ConfigType.PROPERTIES.getType(),
applicationEventPublisher, executor, delegate);
}
DelegatingEventPublishingListener(ConfigService configService, String dataId,
String groupId, String configType,
ApplicationEventPublisher applicationEventPublisher, Executor executor,
Listener delegate) {
this.configService = configService; this.configService = configService;
this.dataId = dataId; this.dataId = dataId;
this.groupId = groupId; this.groupId = groupId;
this.configType = configType;
this.applicationEventPublisher = applicationEventPublisher; this.applicationEventPublisher = applicationEventPublisher;
this.executor = executor; this.executor = executor;
this.delegate = delegate; this.delegate = delegate;
@ -74,12 +88,13 @@ final class DelegatingEventPublishingListener implements Listener {
*/ */
@Override @Override
public void receiveConfigInfo(String content) { public void receiveConfigInfo(String content) {
publishEvent(content);
onReceived(content); onReceived(content);
publishEvent(content);
} }
private void publishEvent(String content) { private void publishEvent(String content) {
NacosConfigReceivedEvent event = new NacosConfigReceivedEvent(configService, dataId, groupId, content); NacosConfigReceivedEvent event = new NacosConfigReceivedEvent(configService,
dataId, groupId, content, configType);
applicationEventPublisher.publishEvent(event); applicationEventPublisher.publishEvent(event);
} }

View File

@ -14,26 +14,30 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.alibaba.nacos.spring.context.event.config; package com.alibaba.nacos.spring.context.event.config;
import java.util.Properties;
import java.util.concurrent.Executor;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ConfigurableApplicationContext;
import com.alibaba.nacos.api.config.ConfigService; import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.listener.Listener; import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.api.exception.NacosException; import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.spring.context.event.DeferredApplicationEventPublisher; import com.alibaba.nacos.spring.context.event.DeferredApplicationEventPublisher;
import com.alibaba.nacos.spring.metadata.NacosServiceMetaData; import com.alibaba.nacos.spring.metadata.NacosServiceMetaData;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ConfigurableApplicationContext;
import java.util.Properties;
import java.util.concurrent.Executor;
/** /**
* {@link NacosConfigEvent Event} publishing {@link ConfigService} * {@link NacosConfigEvent Event} publishing {@link ConfigService}.
* *
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a> * @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
* @since 0.1.0 * @since 0.1.0
*/ */
public class EventPublishingConfigService implements ConfigService, NacosServiceMetaData { public class EventPublishingConfigService
implements ConfigService, NacosServiceMetaData, DisposableBean {
private final ConfigService configService; private final ConfigService configService;
@ -43,7 +47,8 @@ public class EventPublishingConfigService implements ConfigService, NacosService
private final Properties properties; private final Properties properties;
public EventPublishingConfigService(ConfigService configService, Properties properties, ConfigurableApplicationContext context, public EventPublishingConfigService(ConfigService configService,
Properties properties, ConfigurableApplicationContext context,
Executor executor) { Executor executor) {
this.configService = configService; this.configService = configService;
this.properties = properties; this.properties = properties;
@ -52,28 +57,85 @@ public class EventPublishingConfigService implements ConfigService, NacosService
} }
@Override @Override
public String getConfig(String dataId, String group, long timeoutMs) throws NacosException { public String getConfig(String dataId, String group, long timeoutMs)
throws NacosException {
try { try {
return configService.getConfig(dataId, group, timeoutMs); return configService.getConfig(dataId, group, timeoutMs);
} catch (NacosException e) { }
catch (NacosException e) {
if (NacosException.SERVER_ERROR == e.getErrCode()) { // timeout error if (NacosException.SERVER_ERROR == e.getErrCode()) { // timeout error
publishEvent(new NacosConfigTimeoutEvent(configService, dataId, group, timeoutMs, e.getErrMsg())); publishEvent(new NacosConfigTimeoutEvent(configService, dataId, group,
timeoutMs, e.getErrMsg()));
} }
throw e; // re-throw NacosException throw e; // re-throw NacosException
} }
} }
@Override @Override
public void addListener(String dataId, String group, Listener listener) throws NacosException { public String getConfigAndSignListener(String dataId, String group, long timeoutMs,
Listener listenerAdapter = new DelegatingEventPublishingListener(configService, dataId, group, applicationEventPublisher, executor, listener); Listener listener) throws NacosException {
configService.addListener(dataId, group, listenerAdapter); Listener listenerAdapter = new DelegatingEventPublishingListener(configService,
publishEvent(new NacosConfigListenerRegisteredEvent(configService, dataId, group, listener, true)); dataId, group, applicationEventPublisher, executor, listener);
return configService.getConfigAndSignListener(dataId, group, timeoutMs,
listenerAdapter);
}
/**
* Implementation of the new version of support for multiple configuration file type
* resolution.
*
* @param dataId dataId
* @param group group
* @param type config's type
* @param listener listener
* @throws NacosException NacosException
*/
public void addListener(String dataId, String group, String type, Listener listener)
throws NacosException {
Listener listenerAdapter = new DelegatingEventPublishingListener(configService,
dataId, group, type, applicationEventPublisher, executor, listener);
addListener(dataId, group, listenerAdapter);
} }
@Override @Override
public boolean publishConfig(String dataId, String group, String content) throws NacosException { public void addListener(String dataId, String group, Listener listener)
throws NacosException {
configService.addListener(dataId, group, listener);
publishEvent(new NacosConfigListenerRegisteredEvent(configService, dataId, group,
listener, true));
}
@Override
public boolean publishConfig(String dataId, String group, String content)
throws NacosException {
boolean published = configService.publishConfig(dataId, group, content); boolean published = configService.publishConfig(dataId, group, content);
publishEvent(new NacosConfigPublishedEvent(configService, dataId, group, content, published)); publishEvent(new NacosConfigPublishedEvent(configService, dataId, group, content,
published));
return published;
}
@Override
public boolean publishConfig(String dataId, String group, String content, String type) throws NacosException {
boolean published = configService.publishConfig(dataId, group, content, type);
publishEvent(new NacosConfigPublishedEvent(configService, dataId, group, content,
published));
return published;
}
@Override
public boolean publishConfigCas(String dataId, String group, String content, String casMd5) throws NacosException {
boolean published = configService.publishConfigCas(dataId, group, content, casMd5);
publishEvent(new NacosConfigPublishedEvent(configService, dataId, group, content,
published));
return published;
}
@Override
public boolean publishConfigCas(String dataId, String group, String content, String casMd5, String type)
throws NacosException {
boolean published = configService.publishConfigCas(dataId, group, content, casMd5, type);
publishEvent(new NacosConfigPublishedEvent(configService, dataId, group, content,
published));
return published; return published;
} }
@ -87,7 +149,8 @@ public class EventPublishingConfigService implements ConfigService, NacosService
@Override @Override
public void removeListener(String dataId, String group, Listener listener) { public void removeListener(String dataId, String group, Listener listener) {
configService.removeListener(dataId, group, listener); configService.removeListener(dataId, group, listener);
publishEvent(new NacosConfigListenerRegisteredEvent(configService, dataId, group, listener, false)); publishEvent(new NacosConfigListenerRegisteredEvent(configService, dataId, group,
listener, false));
} }
@Override @Override
@ -95,6 +158,11 @@ public class EventPublishingConfigService implements ConfigService, NacosService
return configService.getServerStatus(); return configService.getServerStatus();
} }
@Override
public void shutDown() throws NacosException {
configService.shutDown();
}
private void publishEvent(NacosConfigEvent nacosConfigEvent) { private void publishEvent(NacosConfigEvent nacosConfigEvent) {
applicationEventPublisher.publishEvent(nacosConfigEvent); applicationEventPublisher.publishEvent(nacosConfigEvent);
} }
@ -103,4 +171,14 @@ public class EventPublishingConfigService implements ConfigService, NacosService
public Properties getProperties() { public Properties getProperties() {
return properties; return properties;
} }
/**
* Destroy lifecycle method to invoke {@link #shutDown()}
* @throws Exception throw exception
* @since 1.0.0
*/
@Override
public void destroy() throws Exception {
shutDown();
}
} }

View File

@ -16,9 +16,10 @@
*/ */
package com.alibaba.nacos.spring.context.event.config; package com.alibaba.nacos.spring.context.event.config;
import com.alibaba.nacos.api.config.ConfigService;
import org.springframework.context.ApplicationEvent; import org.springframework.context.ApplicationEvent;
import com.alibaba.nacos.api.config.ConfigService;
/** /**
* The Event of Nacos Configuration is used on Spring Event * The Event of Nacos Configuration is used on Spring Event
* *

View File

@ -39,8 +39,8 @@ public class NacosConfigListenerRegisteredEvent extends NacosConfigEvent {
* @param listener {@link Listener} instance * @param listener {@link Listener} instance
* @param registered registered or not unregistered * @param registered registered or not unregistered
*/ */
public NacosConfigListenerRegisteredEvent(ConfigService configService, String dataId, String groupId, public NacosConfigListenerRegisteredEvent(ConfigService configService, String dataId,
Listener listener, boolean registered) { String groupId, Listener listener, boolean registered) {
super(configService, dataId, groupId); super(configService, dataId, groupId);
this.listener = listener; this.listener = listener;
this.registered = registered; this.registered = registered;

View File

@ -16,18 +16,18 @@
*/ */
package com.alibaba.nacos.spring.context.event.config; package com.alibaba.nacos.spring.context.event.config;
import com.alibaba.nacos.api.config.annotation.NacosConfigListener;
import com.alibaba.nacos.api.config.annotation.NacosConfigurationProperties;
import com.alibaba.nacos.spring.context.annotation.config.NacosPropertySource;
import org.springframework.context.ApplicationEvent;
import org.springframework.core.io.Resource;
import org.w3c.dom.Element;
import java.lang.annotation.Annotation; import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement; import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.Map; import java.util.Map;
import java.util.Properties;
import org.springframework.context.ApplicationEvent;
import org.springframework.core.io.Resource;
import org.w3c.dom.Element;
import com.alibaba.nacos.api.config.annotation.NacosConfigListener;
import com.alibaba.nacos.api.config.annotation.NacosConfigurationProperties;
import com.alibaba.nacos.spring.context.annotation.config.NacosPropertySource;
/** /**
* Nacos Config Meta-Data {@link NacosConfigEvent event} * Nacos Config Meta-Data {@link NacosConfigEvent event}
@ -51,7 +51,7 @@ public class NacosConfigMetadataEvent extends ApplicationEvent {
private Resource xmlResource; private Resource xmlResource;
private Properties nacosProperties; private Map<Object, Object> nacosProperties;
private Map<String, Object> nacosPropertiesAttributes; private Map<String, Object> nacosPropertiesAttributes;
@ -138,20 +138,21 @@ public class NacosConfigMetadataEvent extends ApplicationEvent {
} }
/** /**
* Actual effective Nacos {@link Properties} * Actual effective Nacos {@link Map}
* *
* @return non-null * @return non-null
*/ */
public Properties getNacosProperties() { public Map<Object, Object> getNacosProperties() {
return nacosProperties; return nacosProperties;
} }
public void setNacosProperties(Properties nacosProperties) { public void setNacosProperties(Map<Object, Object> nacosProperties) {
this.nacosProperties = nacosProperties; this.nacosProperties = nacosProperties;
} }
/** /**
* Nacos {@link Properties}'s attributes that may come frome {@link Annotation} or {@link Element XML element} * Nacos {@link Map}'s attributes that may come frome {@link Annotation} or
* {@link Element XML element}
* *
* @return non-null * @return non-null
*/ */
@ -159,7 +160,8 @@ public class NacosConfigMetadataEvent extends ApplicationEvent {
return nacosPropertiesAttributes; return nacosPropertiesAttributes;
} }
public void setNacosPropertiesAttributes(Map<String, Object> nacosPropertiesAttributes) { public void setNacosPropertiesAttributes(
Map<String, Object> nacosPropertiesAttributes) {
this.nacosPropertiesAttributes = nacosPropertiesAttributes; this.nacosPropertiesAttributes = nacosPropertiesAttributes;
} }
} }

View File

@ -30,8 +30,8 @@ public class NacosConfigPublishedEvent extends NacosConfigEvent {
private final boolean published; private final boolean published;
public NacosConfigPublishedEvent(ConfigService configService, String dataId, String groupId, String content, public NacosConfigPublishedEvent(ConfigService configService, String dataId,
boolean published) { String groupId, String content, boolean published) {
super(configService, dataId, groupId); super(configService, dataId, groupId);
this.content = content; this.content = content;
this.published = published; this.published = published;
@ -47,7 +47,9 @@ public class NacosConfigPublishedEvent extends NacosConfigEvent {
} }
/** /**
* Is published or not from {@link ConfigService#publishConfig(String, String, String)} method executing result. * Is published or not from
* {@link ConfigService#publishConfig(String, String, String)} method executing
* result.
* *
* @return if published , return <code>true</code> * @return if published , return <code>true</code>
*/ */

View File

@ -27,10 +27,13 @@ import com.alibaba.nacos.api.config.ConfigService;
public class NacosConfigReceivedEvent extends NacosConfigEvent { public class NacosConfigReceivedEvent extends NacosConfigEvent {
private final String content; private final String content;
private final String type;
public NacosConfigReceivedEvent(ConfigService configService, String dataId, String groupId, String content) { public NacosConfigReceivedEvent(ConfigService configService, String dataId,
String groupId, String content, String type) {
super(configService, dataId, groupId); super(configService, dataId, groupId);
this.content = content; this.content = content;
this.type = type;
} }
/** /**
@ -41,4 +44,9 @@ public class NacosConfigReceivedEvent extends NacosConfigEvent {
public String getContent() { public String getContent() {
return content; return content;
} }
public String getType() {
return type;
}
} }

View File

@ -28,13 +28,15 @@ public class NacosConfigRemovedEvent extends NacosConfigEvent {
private final boolean removed; private final boolean removed;
public NacosConfigRemovedEvent(ConfigService configService, String dataId, String groupId, boolean removed) { public NacosConfigRemovedEvent(ConfigService configService, String dataId,
String groupId, boolean removed) {
super(configService, dataId, groupId); super(configService, dataId, groupId);
this.removed = removed; this.removed = removed;
} }
/** /**
* Is removed or not from {@link ConfigService#removeConfig(String, String)} method executing result. * Is removed or not from {@link ConfigService#removeConfig(String, String)} method
* executing result.
* *
* @return if removed , return <code>true</code> * @return if removed , return <code>true</code>
*/ */

View File

@ -19,7 +19,8 @@ package com.alibaba.nacos.spring.context.event.config;
import com.alibaba.nacos.api.config.ConfigService; import com.alibaba.nacos.api.config.ConfigService;
/** /**
* {@link NacosConfigEvent Nacos config event} for {@link ConfigService#getConfig(String, String, long) getting} timeout. * {@link NacosConfigEvent Nacos config event} for
* {@link ConfigService#getConfig(String, String, long) getting} timeout.
* *
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a> * @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
* @since 0.1.0 * @since 0.1.0
@ -37,7 +38,8 @@ public class NacosConfigTimeoutEvent extends NacosConfigEvent {
* @param timeout timeout in Millis. * @param timeout timeout in Millis.
* @param errorMessage error message * @param errorMessage error message
*/ */
public NacosConfigTimeoutEvent(ConfigService configService, String dataId, String groupId, long timeout, String errorMessage) { public NacosConfigTimeoutEvent(ConfigService configService, String dataId,
String groupId, long timeout, String errorMessage) {
super(configService, dataId, groupId); super(configService, dataId, groupId);
this.timeout = timeout; this.timeout = timeout;
this.errorMessage = errorMessage; this.errorMessage = errorMessage;

View File

@ -16,11 +16,11 @@
*/ */
package com.alibaba.nacos.spring.context.event.config; package com.alibaba.nacos.spring.context.event.config;
import java.util.EventObject;
import com.alibaba.nacos.api.config.ConfigService; import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.annotation.NacosConfigurationProperties; import com.alibaba.nacos.api.config.annotation.NacosConfigurationProperties;
import java.util.EventObject;
/** /**
* {@link NacosConfigurationProperties} Bean Bound {@link EventObject event}. * {@link NacosConfigurationProperties} Bean Bound {@link EventObject event}.
* *
@ -47,12 +47,8 @@ public class NacosConfigurationPropertiesBeanBoundEvent extends NacosConfigEvent
* @param content the Nacos content for binding * @param content the Nacos content for binding
*/ */
public NacosConfigurationPropertiesBeanBoundEvent(ConfigService configService, public NacosConfigurationPropertiesBeanBoundEvent(ConfigService configService,
String dataId, String dataId, String groupId, Object bean, String beanName,
String groupId, NacosConfigurationProperties properties, String content) {
Object bean,
String beanName,
NacosConfigurationProperties properties,
String content) {
super(configService, dataId, groupId); super(configService, dataId, groupId);
this.bean = bean; this.bean = bean;
this.beanName = beanName; this.beanName = beanName;

View File

@ -16,12 +16,20 @@
*/ */
package com.alibaba.nacos.spring.context.event.config; package com.alibaba.nacos.spring.context.event.config;
import com.alibaba.nacos.api.config.listener.AbstractListener; import java.util.concurrent.ExecutionException;
import com.alibaba.nacos.api.config.listener.Listener; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicInteger;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.util.concurrent.*; import com.alibaba.nacos.api.config.listener.AbstractListener;
import com.alibaba.nacos.api.config.listener.Listener;
/** /**
* Timeout {@link Listener Nacos Config Listener} * Timeout {@link Listener Nacos Config Listener}
@ -31,6 +39,20 @@ import java.util.concurrent.*;
*/ */
public abstract class TimeoutNacosConfigListener extends AbstractListener { public abstract class TimeoutNacosConfigListener extends AbstractListener {
private static AtomicInteger id = new AtomicInteger(0);
private static ExecutorService executorService = Executors.newScheduledThreadPool(8,
new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r);
t.setDaemon(true);
t.setName("com.alibaba.nacos.spring.configListener-"
+ id.incrementAndGet());
return t;
}
});
private final Logger logger = LoggerFactory.getLogger(getClass()); private final Logger logger = LoggerFactory.getLogger(getClass());
private final String dataId; private final String dataId;
@ -45,32 +67,30 @@ public abstract class TimeoutNacosConfigListener extends AbstractListener {
this.timeout = timeout; this.timeout = timeout;
} }
public final void receiveConfigInfo(final String content) { @Override
public void receiveConfigInfo(final String content) {
ExecutorService executorService = Executors.newSingleThreadExecutor();
Future future = executorService.submit(new Runnable() { Future future = executorService.submit(new Runnable() {
@Override @Override
public void run() { public void run() {
onReceived(content); onReceived(content);
} }
}); });
try { try {
future.get(timeout, TimeUnit.MILLISECONDS); future.get(timeout, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) { }
catch (InterruptedException e) {
Thread.currentThread().interrupt(); Thread.currentThread().interrupt();
throw new RuntimeException(e); throw new RuntimeException(e);
} catch (ExecutionException e) {
throw new RuntimeException(e);
} catch (TimeoutException e) {
future.cancel(true);
if (logger.isWarnEnabled()) {
logger.warn("Listening on Nacos Config exceeds timeout {} ms " +
"[dataId : {}, groupId : {}, data : {}]", timeout, dataId, groupId, content);
} }
} finally { catch (ExecutionException e) {
executorService.shutdown(); throw new RuntimeException(e);
}
catch (TimeoutException e) {
future.cancel(true);
logger.warn(
"Listening on Nacos Config exceeds timeout {} ms "
+ "[dataId : {}, groupId : {}, data : {}]",
timeout, dataId, groupId, content);
} }
} }

View File

@ -16,37 +16,38 @@
*/ */
package com.alibaba.nacos.spring.context.properties.config; package com.alibaba.nacos.spring.context.properties.config;
import com.alibaba.nacos.api.annotation.NacosProperties; import static com.alibaba.nacos.spring.util.NacosBeanUtils.getConfigServiceBeanBuilder;
import com.alibaba.nacos.api.config.ConfigService; import static com.alibaba.nacos.spring.util.NacosUtils.getContent;
import com.alibaba.nacos.api.config.annotation.NacosConfigurationProperties; import static org.springframework.core.annotation.AnnotationUtils.findAnnotation;
import com.alibaba.nacos.api.config.annotation.NacosIgnore; import static org.springframework.core.annotation.AnnotationUtils.getAnnotationAttributes;
import com.alibaba.nacos.api.config.annotation.NacosProperty; import static org.springframework.util.StringUtils.hasText;
import com.alibaba.nacos.api.config.listener.AbstractListener;
import com.alibaba.nacos.api.exception.NacosException; import java.util.Map;
import com.alibaba.nacos.spring.beans.factory.annotation.ConfigServiceBeanBuilder; import java.util.Properties;
import com.alibaba.nacos.spring.context.event.config.NacosConfigEvent;
import com.alibaba.nacos.spring.context.event.config.NacosConfigMetadataEvent;
import com.alibaba.nacos.spring.context.event.config.NacosConfigurationPropertiesBeanBoundEvent;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.PropertyValues; import org.springframework.beans.PropertyValues;
import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.Environment; import org.springframework.core.env.Environment;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import org.springframework.util.ReflectionUtils;
import org.springframework.validation.DataBinder; import org.springframework.validation.DataBinder;
import java.lang.reflect.Field; import com.alibaba.nacos.api.annotation.NacosProperties;
import java.util.Map; import com.alibaba.nacos.api.config.ConfigService;
import java.util.Properties; import com.alibaba.nacos.api.config.ConfigType;
import com.alibaba.nacos.api.config.annotation.NacosConfigurationProperties;
import static com.alibaba.nacos.spring.util.NacosBeanUtils.getConfigServiceBeanBuilder; import com.alibaba.nacos.api.config.listener.AbstractListener;
import static com.alibaba.nacos.spring.util.NacosUtils.getContent; import com.alibaba.nacos.api.config.listener.Listener;
import static com.alibaba.nacos.spring.util.NacosUtils.toProperties; import com.alibaba.nacos.api.exception.NacosException;
import static org.springframework.core.annotation.AnnotationUtils.*; import com.alibaba.nacos.spring.beans.factory.annotation.ConfigServiceBeanBuilder;
import static org.springframework.util.StringUtils.hasText; import com.alibaba.nacos.spring.context.event.config.EventPublishingConfigService;
import com.alibaba.nacos.spring.context.event.config.NacosConfigEvent;
import com.alibaba.nacos.spring.context.event.config.NacosConfigMetadataEvent;
import com.alibaba.nacos.spring.context.event.config.NacosConfigurationPropertiesBeanBoundEvent;
import com.alibaba.nacos.spring.util.NacosUtils;
import com.alibaba.nacos.spring.util.ObjectUtils;
/** /**
* {@link NacosConfigurationProperties} Bean Binder * {@link NacosConfigurationProperties} Bean Binder
@ -54,9 +55,12 @@ import static org.springframework.util.StringUtils.hasText;
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a> * @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
* @since 0.1.0 * @since 0.1.0
*/ */
class NacosConfigurationPropertiesBinder { public class NacosConfigurationPropertiesBinder {
private static final Logger logger = LoggerFactory.getLogger(NacosConfigurationPropertiesBinder.class); public static final String BEAN_NAME = "nacosConfigurationPropertiesBinder";
private static final Logger logger = LoggerFactory
.getLogger(NacosConfigurationPropertiesBinder.class);
private final ConfigurableApplicationContext applicationContext; private final ConfigurableApplicationContext applicationContext;
@ -66,8 +70,10 @@ class NacosConfigurationPropertiesBinder {
private final ConfigServiceBeanBuilder configServiceBeanBuilder; private final ConfigServiceBeanBuilder configServiceBeanBuilder;
NacosConfigurationPropertiesBinder(ConfigurableApplicationContext applicationContext) { protected NacosConfigurationPropertiesBinder(
Assert.notNull(applicationContext, "ConfigurableApplicationContext must not be null!"); ConfigurableApplicationContext applicationContext) {
Assert.notNull(applicationContext,
"ConfigurableApplicationContext must not be null!");
this.applicationContext = applicationContext; this.applicationContext = applicationContext;
this.environment = applicationContext.getEnvironment(); this.environment = applicationContext.getEnvironment();
this.applicationEventPublisher = applicationContext; this.applicationEventPublisher = applicationContext;
@ -76,57 +82,86 @@ class NacosConfigurationPropertiesBinder {
protected void bind(Object bean, String beanName) { protected void bind(Object bean, String beanName) {
NacosConfigurationProperties properties = findAnnotation(bean.getClass(), NacosConfigurationProperties.class); NacosConfigurationProperties properties = findAnnotation(bean.getClass(),
NacosConfigurationProperties.class);
bind(bean, beanName, properties); bind(bean, beanName, properties);
} }
protected void bind(final Object bean, final String beanName, final NacosConfigurationProperties properties) { protected void bind(final Object bean, final String beanName,
final NacosConfigurationProperties properties) {
Assert.notNull(bean, "Bean must not be null!"); Assert.notNull(bean, "Bean must not be null!");
Assert.notNull(properties, "NacosConfigurationProperties must not be null!"); Assert.notNull(properties, "NacosConfigurationProperties must not be null!");
final String dataId = properties.dataId(); // support read data-id and group-id from spring environment
final String dataId = NacosUtils.readFromEnvironment(properties.dataId(),
environment);
final String groupId = NacosUtils.readFromEnvironment(properties.groupId(),
environment);
final String type;
final String groupId = properties.groupId(); ConfigType typeEunm = properties.type();
if (ConfigType.UNSET.equals(typeEunm)) {
type = NacosUtils.readFileExtension(dataId);
}
else {
type = typeEunm.getType();
}
final ConfigService configService = configServiceBeanBuilder.build(properties.properties()); final ConfigService configService = configServiceBeanBuilder
.build(properties.properties());
if (properties.autoRefreshed()) { // Add a Listener if auto-refreshed // Add a Listener if auto-refreshed
if (properties.autoRefreshed()) {
try { String content = getContent(configService, dataId, groupId);
configService.addListener(dataId, groupId, new AbstractListener() {
if (hasText(content)) {
doBind(bean, beanName, dataId, groupId, type, properties, content,
configService);
}
Listener listener = new AbstractListener() {
@Override @Override
public void receiveConfigInfo(String config) { public void receiveConfigInfo(String config) {
doBind(bean, beanName, dataId, groupId, properties, config, configService); doBind(bean, beanName, dataId, groupId, type, properties, config,
configService);
} }
}); };
} catch (NacosException e) { try {//
if (configService instanceof EventPublishingConfigService) {
((EventPublishingConfigService) configService).addListener(dataId,
groupId, type, listener);
}
else {
configService.addListener(dataId, groupId, listener);
}
}
catch (NacosException e) {
if (logger.isErrorEnabled()) { if (logger.isErrorEnabled()) {
logger.error(e.getMessage(), e); logger.error(e.getMessage(), e);
} }
} }
} }
String content = getContent(configService, dataId, groupId);
if (hasText(content)) {
doBind(bean, beanName, dataId, groupId, properties, content, configService);
}
} }
private void doBind(Object bean, String beanName, String dataId, String groupId, protected void doBind(Object bean, String beanName, String dataId, String groupId,
NacosConfigurationProperties properties, String content, ConfigService configService) { String type, NacosConfigurationProperties properties, String content,
PropertyValues propertyValues = resolvePropertyValues(bean, content); ConfigService configService) {
final String prefix = properties.prefix();
PropertyValues propertyValues = NacosUtils.resolvePropertyValues(bean, prefix,
dataId, groupId, content, type);
doBind(bean, properties, propertyValues); doBind(bean, properties, propertyValues);
publishBoundEvent(bean, beanName, dataId, groupId, properties, content, configService); publishBoundEvent(bean, beanName, dataId, groupId, properties, content,
configService);
publishMetadataEvent(bean, beanName, dataId, groupId, properties); publishMetadataEvent(bean, beanName, dataId, groupId, properties);
} }
private void publishMetadataEvent(Object bean, String beanName, String dataId, String groupId, protected void publishMetadataEvent(Object bean, String beanName, String dataId,
NacosConfigurationProperties properties) { String groupId, NacosConfigurationProperties properties) {
NacosProperties nacosProperties = properties.properties(); NacosProperties nacosProperties = properties.properties();
@ -135,8 +170,10 @@ class NacosConfigurationPropertiesBinder {
// Nacos Metadata // Nacos Metadata
metadataEvent.setDataId(dataId); metadataEvent.setDataId(dataId);
metadataEvent.setGroupId(groupId); metadataEvent.setGroupId(groupId);
Properties resolvedNacosProperties = configServiceBeanBuilder.resolveProperties(nacosProperties); Properties resolvedNacosProperties = configServiceBeanBuilder
Map<String, Object> nacosPropertiesAttributes = getAnnotationAttributes(nacosProperties); .resolveProperties(nacosProperties);
Map<String, Object> nacosPropertiesAttributes = getAnnotationAttributes(
nacosProperties);
metadataEvent.setNacosPropertiesAttributes(nacosPropertiesAttributes); metadataEvent.setNacosPropertiesAttributes(nacosPropertiesAttributes);
metadataEvent.setNacosProperties(resolvedNacosProperties); metadataEvent.setNacosProperties(resolvedNacosProperties);
@ -151,15 +188,17 @@ class NacosConfigurationPropertiesBinder {
applicationEventPublisher.publishEvent(metadataEvent); applicationEventPublisher.publishEvent(metadataEvent);
} }
private void publishBoundEvent(Object bean, String beanName, String dataId, String groupId, protected void publishBoundEvent(Object bean, String beanName, String dataId,
NacosConfigurationProperties properties, String content, ConfigService configService) { String groupId, NacosConfigurationProperties properties, String content,
NacosConfigEvent event = new NacosConfigurationPropertiesBeanBoundEvent(configService, dataId, groupId, bean, ConfigService configService) {
beanName, properties, content); NacosConfigEvent event = new NacosConfigurationPropertiesBeanBoundEvent(
configService, dataId, groupId, bean, beanName, properties, content);
applicationEventPublisher.publishEvent(event); applicationEventPublisher.publishEvent(event);
} }
private void doBind(Object bean, NacosConfigurationProperties properties, private void doBind(Object bean, NacosConfigurationProperties properties,
PropertyValues propertyValues) { PropertyValues propertyValues) {
ObjectUtils.cleanMapOrCollectionField(bean);
DataBinder dataBinder = new DataBinder(bean); DataBinder dataBinder = new DataBinder(bean);
dataBinder.setAutoGrowNestedPaths(properties.ignoreNestedProperties()); dataBinder.setAutoGrowNestedPaths(properties.ignoreNestedProperties());
dataBinder.setIgnoreInvalidFields(properties.ignoreInvalidFields()); dataBinder.setIgnoreInvalidFields(properties.ignoreInvalidFields());
@ -167,30 +206,4 @@ class NacosConfigurationPropertiesBinder {
dataBinder.bind(propertyValues); dataBinder.bind(propertyValues);
} }
private PropertyValues resolvePropertyValues(Object bean, String content) {
final Properties configProperties = toProperties(content);
final MutablePropertyValues propertyValues = new MutablePropertyValues();
ReflectionUtils.doWithFields(bean.getClass(), new ReflectionUtils.FieldCallback() {
@Override
public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException {
String propertyName = resolvePropertyName(field);
if (hasText(propertyName) && configProperties.containsKey(propertyName)) {
String propertyValue = configProperties.getProperty(propertyName);
propertyValues.add(field.getName(), propertyValue);
}
}
});
return propertyValues;
}
private String resolvePropertyName(Field field) {
// Ignore property name if @NacosIgnore present
if (getAnnotation(field, NacosIgnore.class) != null) {
return null;
}
NacosProperty nacosProperty = getAnnotation(field, NacosProperty.class);
// If @NacosProperty present ,return its value() , or field name
return nacosProperty != null ? nacosProperty.value() : field.getName();
}
} }

View File

@ -16,8 +16,10 @@
*/ */
package com.alibaba.nacos.spring.context.properties.config; package com.alibaba.nacos.spring.context.properties.config;
import com.alibaba.nacos.api.config.annotation.NacosConfigurationProperties; import static org.springframework.core.annotation.AnnotationUtils.findAnnotation;
import com.alibaba.nacos.spring.factory.NacosServiceFactory;
import java.util.Properties;
import org.springframework.beans.BeansException; import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
@ -26,9 +28,8 @@ import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.Environment; import org.springframework.core.env.Environment;
import java.util.Properties; import com.alibaba.nacos.api.config.annotation.NacosConfigurationProperties;
import com.alibaba.nacos.spring.factory.NacosServiceFactory;
import static org.springframework.core.annotation.AnnotationUtils.findAnnotation;
/** /**
* {@link NacosConfigurationProperties} Binding {@link BeanPostProcessor} * {@link NacosConfigurationProperties} Binding {@link BeanPostProcessor}
@ -38,7 +39,8 @@ import static org.springframework.core.annotation.AnnotationUtils.findAnnotation
* @see BeanPostProcessor * @see BeanPostProcessor
* @since 0.1.0 * @since 0.1.0
*/ */
public class NacosConfigurationPropertiesBindingPostProcessor implements BeanPostProcessor, ApplicationContextAware { public class NacosConfigurationPropertiesBindingPostProcessor
implements BeanPostProcessor, ApplicationContextAware {
/** /**
* The name of {@link NacosConfigurationPropertiesBindingPostProcessor} Bean * The name of {@link NacosConfigurationPropertiesBindingPostProcessor} Bean
@ -56,9 +58,11 @@ public class NacosConfigurationPropertiesBindingPostProcessor implements BeanPos
private ConfigurableApplicationContext applicationContext; private ConfigurableApplicationContext applicationContext;
@Override @Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
NacosConfigurationProperties nacosConfigurationProperties = findAnnotation(bean.getClass(), NacosConfigurationProperties.class); NacosConfigurationProperties nacosConfigurationProperties = findAnnotation(
bean.getClass(), NacosConfigurationProperties.class);
if (nacosConfigurationProperties != null) { if (nacosConfigurationProperties != null) {
bind(bean, beanName, nacosConfigurationProperties); bind(bean, beanName, nacosConfigurationProperties);
@ -67,22 +71,36 @@ public class NacosConfigurationPropertiesBindingPostProcessor implements BeanPos
return bean; return bean;
} }
private void bind(Object bean, String beanName, NacosConfigurationProperties nacosConfigurationProperties) { private void bind(Object bean, String beanName,
NacosConfigurationProperties nacosConfigurationProperties) {
NacosConfigurationPropertiesBinder binder = new NacosConfigurationPropertiesBinder(applicationContext); NacosConfigurationPropertiesBinder binder;
try {
binder = applicationContext.getBean(
NacosConfigurationPropertiesBinder.BEAN_NAME,
NacosConfigurationPropertiesBinder.class);
if (binder == null) {
binder = new NacosConfigurationPropertiesBinder(applicationContext);
}
}
catch (Exception e) {
binder = new NacosConfigurationPropertiesBinder(applicationContext);
}
binder.bind(bean, beanName, nacosConfigurationProperties); binder.bind(bean, beanName, nacosConfigurationProperties);
} }
@Override @Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException {
return bean; return bean;
} }
@Override @Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
this.applicationContext = (ConfigurableApplicationContext) applicationContext; this.applicationContext = (ConfigurableApplicationContext) applicationContext;
} }
} }

View File

@ -16,10 +16,14 @@
*/ */
package com.alibaba.nacos.spring.convert.converter.config; package com.alibaba.nacos.spring.convert.converter.config;
import com.alibaba.nacos.api.config.convert.NacosConfigConverter; import java.util.Map;
import org.springframework.core.convert.ConversionService; import org.springframework.core.convert.ConversionService;
import org.springframework.format.support.DefaultFormattingConversionService; import org.springframework.format.support.DefaultFormattingConversionService;
import com.alibaba.nacos.api.config.convert.NacosConfigConverter;
import com.alibaba.nacos.spring.util.ConfigParseUtils;
/** /**
* Default {@link NacosConfigConverter} implementation * Default {@link NacosConfigConverter} implementation
* *
@ -32,17 +36,28 @@ public class DefaultNacosConfigConverter<T> implements NacosConfigConverter<T> {
private final ConversionService conversionService; private final ConversionService conversionService;
private final String type;
public DefaultNacosConfigConverter(Class<T> targetType) { public DefaultNacosConfigConverter(Class<T> targetType) {
this(targetType, new DefaultFormattingConversionService()); this(targetType, new DefaultFormattingConversionService(), "properties");
} }
public DefaultNacosConfigConverter(Class<T> targetType, ConversionService conversionService) { public DefaultNacosConfigConverter(Class<T> targetType,
ConversionService conversionService, String type) {
this.targetType = targetType; this.targetType = targetType;
this.conversionService = conversionService; this.conversionService = conversionService;
this.type = type;
} }
@Override @Override
public T convert(String source) { public T convert(String source) {
// If the parameter is of Map type, the configuration is automatically formatted
if (Map.class.isAssignableFrom(targetType)) {
return (T) ConfigParseUtils.toProperties(source, type);
}
if (conversionService.canConvert(source.getClass(), targetType)) { if (conversionService.canConvert(source.getClass(), targetType)) {
return conversionService.convert(source, targetType); return conversionService.convert(source, targetType);
} }

View File

@ -16,9 +16,26 @@
*/ */
package com.alibaba.nacos.spring.core.env; package com.alibaba.nacos.spring.core.env;
import com.alibaba.nacos.spring.context.event.DeferredApplicationEventPublisher; import static com.alibaba.nacos.spring.context.annotation.config.NacosPropertySource.CONFIG_TYPE_ATTRIBUTE_NAME;
import com.alibaba.nacos.spring.context.event.config.NacosConfigMetadataEvent; import static com.alibaba.nacos.spring.context.annotation.config.NacosPropertySource.DATA_ID_ATTRIBUTE_NAME;
import com.alibaba.nacos.spring.util.config.NacosConfigLoader; import static com.alibaba.nacos.spring.context.annotation.config.NacosPropertySource.GROUP_ID_ATTRIBUTE_NAME;
import static com.alibaba.nacos.spring.context.annotation.config.NacosPropertySource.NAME_ATTRIBUTE_NAME;
import static com.alibaba.nacos.spring.context.annotation.config.NacosPropertySource.PROPERTIES_ATTRIBUTE_NAME;
import static com.alibaba.nacos.spring.util.GlobalNacosPropertiesSource.CONFIG;
import static com.alibaba.nacos.spring.util.NacosBeanUtils.getNacosServiceFactoryBean;
import static com.alibaba.nacos.spring.util.NacosUtils.buildDefaultPropertySourceName;
import static com.alibaba.nacos.spring.util.NacosUtils.resolveProperties;
import static com.alibaba.spring.util.ClassUtils.resolveGenericType;
import static java.lang.String.format;
import static org.springframework.util.ClassUtils.resolveClassName;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import com.alibaba.nacos.api.config.ConfigService;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException; import org.springframework.beans.BeansException;
@ -26,24 +43,23 @@ import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.*; import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.EnvironmentAware;
import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment; import org.springframework.core.env.Environment;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import java.util.*; import com.alibaba.nacos.api.config.ConfigType;
import com.alibaba.nacos.spring.context.event.DeferredApplicationEventPublisher;
import static com.alibaba.nacos.spring.context.annotation.config.NacosPropertySource.*; import com.alibaba.nacos.spring.context.event.config.NacosConfigMetadataEvent;
import static com.alibaba.nacos.spring.util.GlobalNacosPropertiesSource.CONFIG; import com.alibaba.nacos.spring.util.NacosUtils;
import static com.alibaba.nacos.spring.util.NacosBeanUtils.getNacosServiceFactoryBean; import com.alibaba.nacos.spring.util.config.NacosConfigLoader;
import static com.alibaba.nacos.spring.util.NacosUtils.buildDefaultPropertySourceName;
import static com.alibaba.nacos.spring.util.NacosUtils.resolveProperties;
import static com.alibaba.spring.util.ClassUtils.resolveGenericType;
import static java.lang.String.format;
import static java.lang.String.valueOf;
import static org.springframework.util.ClassUtils.resolveClassName;
/** /**
* Abstract implementation of {@link NacosPropertySource} Builder * Abstract implementation of {@link NacosPropertySource} Builder
@ -52,21 +68,16 @@ import static org.springframework.util.ClassUtils.resolveClassName;
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a> * @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
* @since 0.1.0 * @since 0.1.0
*/ */
public abstract class AbstractNacosPropertySourceBuilder<T extends BeanDefinition> implements EnvironmentAware, public abstract class AbstractNacosPropertySourceBuilder<T extends BeanDefinition>
BeanFactoryAware, BeanClassLoaderAware, ApplicationContextAware, InitializingBean { implements EnvironmentAware, BeanFactoryAware, BeanClassLoaderAware,
ApplicationContextAware, InitializingBean, DisposableBean {
protected final Logger logger = LoggerFactory.getLogger(this.getClass()); protected final Logger logger = LoggerFactory.getLogger(this.getClass());
protected ConfigurableEnvironment environment;
protected BeanFactory beanFactory;
private NacosConfigLoader nacosConfigLoader;
private Properties globalNacosProperties;
private final Class<T> beanDefinitionType; private final Class<T> beanDefinitionType;
protected ConfigurableEnvironment environment;
protected BeanFactory beanFactory;
private NacosConfigLoader nacosConfigLoader;
private Properties globalNacosProperties;
private ClassLoader classLoader; private ClassLoader classLoader;
private ApplicationEventPublisher applicationEventPublisher; private ApplicationEventPublisher applicationEventPublisher;
@ -84,7 +95,8 @@ public abstract class AbstractNacosPropertySourceBuilder<T extends BeanDefinitio
*/ */
public List<NacosPropertySource> build(String beanName, T beanDefinition) { public List<NacosPropertySource> build(String beanName, T beanDefinition) {
Map<String, Object>[] attributesArray = resolveRuntimeAttributesArray(beanDefinition, globalNacosProperties); Map<String, Object>[] attributesArray = resolveRuntimeAttributesArray(
beanDefinition, globalNacosProperties);
int size = attributesArray == null ? 0 : attributesArray.length; int size = attributesArray == null ? 0 : attributesArray.length;
@ -92,15 +104,18 @@ public abstract class AbstractNacosPropertySourceBuilder<T extends BeanDefinitio
return Collections.emptyList(); return Collections.emptyList();
} }
List<NacosPropertySource> nacosPropertySources = new ArrayList<NacosPropertySource>(size); List<NacosPropertySource> nacosPropertySources = new ArrayList<NacosPropertySource>(
size);
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
Map<String, Object> attributes = attributesArray[i]; Map<String, Object> attributes = attributesArray[i];
if (!CollectionUtils.isEmpty(attributes)) { if (!CollectionUtils.isEmpty(attributes)) {
NacosPropertySource nacosPropertySource = doBuild(beanName, beanDefinition, attributesArray[i]); NacosPropertySource nacosPropertySource = doBuild(beanName,
beanDefinition, attributesArray[i]);
NacosConfigMetadataEvent metadataEvent = createMetaEvent(nacosPropertySource, beanDefinition); NacosConfigMetadataEvent metadataEvent = createMetaEvent(
nacosPropertySource, beanDefinition);
initMetadataEvent(nacosPropertySource, beanDefinition, metadataEvent); initMetadataEvent(nacosPropertySource, beanDefinition, metadataEvent);
@ -114,17 +129,20 @@ public abstract class AbstractNacosPropertySourceBuilder<T extends BeanDefinitio
return nacosPropertySources; return nacosPropertySources;
} }
protected abstract NacosConfigMetadataEvent createMetaEvent(NacosPropertySource nacosPropertySource, T beanDefinition); protected abstract NacosConfigMetadataEvent createMetaEvent(
NacosPropertySource nacosPropertySource, T beanDefinition);
private void initMetadataEvent(NacosPropertySource nacosPropertySource, T beanDefinition, private void initMetadataEvent(NacosPropertySource nacosPropertySource,
NacosConfigMetadataEvent metadataEvent) { T beanDefinition, NacosConfigMetadataEvent metadataEvent) {
metadataEvent.setDataId(nacosPropertySource.getDataId()); metadataEvent.setDataId(nacosPropertySource.getDataId());
metadataEvent.setGroupId(nacosPropertySource.getGroupId()); metadataEvent.setGroupId(nacosPropertySource.getGroupId());
metadataEvent.setBeanName(nacosPropertySource.getBeanName()); metadataEvent.setBeanName(nacosPropertySource.getBeanName());
metadataEvent.setBeanType(nacosPropertySource.getBeanType()); metadataEvent.setBeanType(nacosPropertySource.getBeanType());
metadataEvent.setNacosProperties(nacosPropertySource.getProperties()); metadataEvent.setNacosProperties(nacosPropertySource.getProperties());
Map<String, Object> attributesMetadata = nacosPropertySource.getAttributesMetadata(); Map<String, Object> attributesMetadata = nacosPropertySource
Map<String, Object> nacosPropertiesAttributes = (Map<String, Object>) attributesMetadata.get(PROPERTIES_ATTRIBUTE_NAME); .getAttributesMetadata();
Map<String, Object> nacosPropertiesAttributes = (Map<String, Object>) attributesMetadata
.get(PROPERTIES_ATTRIBUTE_NAME);
metadataEvent.setNacosPropertiesAttributes(nacosPropertiesAttributes); metadataEvent.setNacosPropertiesAttributes(nacosPropertiesAttributes);
doInitMetadataEvent(nacosPropertySource, beanDefinition, metadataEvent); doInitMetadataEvent(nacosPropertySource, beanDefinition, metadataEvent);
} }
@ -133,29 +151,43 @@ public abstract class AbstractNacosPropertySourceBuilder<T extends BeanDefinitio
applicationEventPublisher.publishEvent(metadataEvent); applicationEventPublisher.publishEvent(metadataEvent);
} }
protected abstract void doInitMetadataEvent(NacosPropertySource nacosPropertySource,
T beanDefinition, NacosConfigMetadataEvent metadataEvent);
protected abstract void doInitMetadataEvent(NacosPropertySource nacosPropertySource, T beanDefinition, protected NacosPropertySource doBuild(String beanName, T beanDefinition,
NacosConfigMetadataEvent metadataEvent); Map<String, Object> runtimeAttributes) {
protected NacosPropertySource doBuild(String beanName, T beanDefinition, Map<String, Object> runtimeAttributes) {
// Get annotation metadata // Get annotation metadata
String name = (String) runtimeAttributes.get(NAME_ATTRIBUTE_NAME); String name = (String) runtimeAttributes.get(NAME_ATTRIBUTE_NAME);
String dataId = (String) runtimeAttributes.get(DATA_ID_ATTRIBUTE_NAME); String dataId = (String) runtimeAttributes.get(DATA_ID_ATTRIBUTE_NAME);
String groupId = (String) runtimeAttributes.get(GROUP_ID_ATTRIBUTE_NAME); String groupId = (String) runtimeAttributes.get(GROUP_ID_ATTRIBUTE_NAME);
Map<String, Object> nacosPropertiesAttributes = (Map<String, Object>) runtimeAttributes.get(PROPERTIES_ATTRIBUTE_NAME);
Properties nacosProperties = resolveProperties(nacosPropertiesAttributes, environment, globalNacosProperties); dataId = NacosUtils.readFromEnvironment(dataId, environment);
groupId = NacosUtils.readFromEnvironment(groupId, environment);
final String type;
ConfigType typeEunm = (ConfigType) runtimeAttributes.get(CONFIG_TYPE_ATTRIBUTE_NAME);
if (ConfigType.UNSET.equals(typeEunm)) {
type = NacosUtils.readFileExtension(dataId);
}
else {
type = typeEunm.getType();
}
Map<String, Object> nacosPropertiesAttributes = (Map<String, Object>) runtimeAttributes
.get(PROPERTIES_ATTRIBUTE_NAME);
Properties nacosProperties = resolveProperties(nacosPropertiesAttributes,
environment, globalNacosProperties);
String nacosConfig = nacosConfigLoader.load(dataId, groupId, nacosProperties); String nacosConfig = nacosConfigLoader.load(dataId, groupId, nacosProperties);
if (!StringUtils.hasText(nacosConfig)) { if (!StringUtils.hasText(nacosConfig)) {
if (logger.isWarnEnabled()) { if (logger.isWarnEnabled()) {
logger.warn(format("There is no content for NacosPropertySource from dataId[%s] , groupId[%s] , properties[%s].", logger.warn(format(
dataId, "There is no content for NacosPropertySource from dataId[%s] , groupId[%s] , properties[%s].",
groupId, dataId, groupId, nacosPropertiesAttributes));
valueOf(nacosPropertiesAttributes)));
} }
} }
@ -163,7 +195,8 @@ public abstract class AbstractNacosPropertySourceBuilder<T extends BeanDefinitio
name = buildDefaultPropertySourceName(dataId, groupId, nacosProperties); name = buildDefaultPropertySourceName(dataId, groupId, nacosProperties);
} }
NacosPropertySource nacosPropertySource = new NacosPropertySource(name, nacosConfig); NacosPropertySource nacosPropertySource = new NacosPropertySource(dataId, groupId,
name, nacosConfig, type);
nacosPropertySource.setBeanName(beanName); nacosPropertySource.setBeanName(beanName);
@ -194,9 +227,11 @@ public abstract class AbstractNacosPropertySourceBuilder<T extends BeanDefinitio
* @param globalNacosProperties Global Nacos {@link Properties} * @param globalNacosProperties Global Nacos {@link Properties}
* @return a non-null attributes array * @return a non-null attributes array
*/ */
protected abstract Map<String, Object>[] resolveRuntimeAttributesArray(T beanDefinition, Properties globalNacosProperties); protected abstract Map<String, Object>[] resolveRuntimeAttributesArray(
T beanDefinition, Properties globalNacosProperties);
protected abstract void initNacosPropertySource(NacosPropertySource nacosPropertySource, T beanDefinition, protected abstract void initNacosPropertySource(
NacosPropertySource nacosPropertySource, T beanDefinition,
Map<String, Object> attributes); Map<String, Object> attributes);
/** /**
@ -240,6 +275,17 @@ public abstract class AbstractNacosPropertySourceBuilder<T extends BeanDefinitio
globalNacosProperties = CONFIG.getMergedGlobalProperties(beanFactory); globalNacosProperties = CONFIG.getMergedGlobalProperties(beanFactory);
} }
@Override
public void destroy() throws Exception {
if (nacosConfigLoader == null) {
return;
}
ConfigService configService = nacosConfigLoader.getConfigService();
if (configService != null) {
configService.shutDown();
}
}
/** /**
* The type of {@link T Bean Definition} * The type of {@link T Bean Definition}
* *

View File

@ -16,17 +16,27 @@
*/ */
package com.alibaba.nacos.spring.core.env; package com.alibaba.nacos.spring.core.env;
import com.alibaba.nacos.spring.context.annotation.config.NacosPropertySources; import static com.alibaba.nacos.spring.context.annotation.config.NacosPropertySource.AFTER_ATTRIBUTE_NAME;
import com.alibaba.nacos.spring.context.event.config.NacosConfigMetadataEvent; import static com.alibaba.nacos.spring.context.annotation.config.NacosPropertySource.AUTO_REFRESHED_ATTRIBUTE_NAME;
import static com.alibaba.nacos.spring.context.annotation.config.NacosPropertySource.BEFORE_ATTRIBUTE_NAME;
import static com.alibaba.nacos.spring.context.annotation.config.NacosPropertySource.FIRST_ATTRIBUTE_NAME;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition; import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.core.type.AnnotationMetadata; import org.springframework.core.type.AnnotationMetadata;
import java.util.*; import com.alibaba.nacos.spring.context.annotation.config.NacosPropertySources;
import com.alibaba.nacos.spring.context.event.config.NacosConfigMetadataEvent;
import static com.alibaba.nacos.spring.context.annotation.config.NacosPropertySource.*;
/** /**
* Annotation {@link NacosPropertySource @NacosPropertySource} {@link AbstractNacosPropertySourceBuilder Builder} * Annotation {@link NacosPropertySource @NacosPropertySource}
* {@link AbstractNacosPropertySourceBuilder Builder}
* *
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a> * @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
* @see NacosPropertySource * @see NacosPropertySource
@ -34,7 +44,8 @@ import static com.alibaba.nacos.spring.context.annotation.config.NacosPropertySo
* @see AnnotatedBeanDefinition * @see AnnotatedBeanDefinition
* @since 0.1.0 * @since 0.1.0
*/ */
public class AnnotationNacosPropertySourceBuilder extends AbstractNacosPropertySourceBuilder<AnnotatedBeanDefinition> { public class AnnotationNacosPropertySourceBuilder
extends AbstractNacosPropertySourceBuilder<AnnotatedBeanDefinition> {
/** /**
* The bean name of {@link AnnotationNacosPropertySourceBuilder} * The bean name of {@link AnnotationNacosPropertySourceBuilder}
@ -42,7 +53,8 @@ public class AnnotationNacosPropertySourceBuilder extends AbstractNacosPropertyS
public static final String BEAN_NAME = "annotationNacosPropertySourceBuilder"; public static final String BEAN_NAME = "annotationNacosPropertySourceBuilder";
@Override @Override
protected Map<String, Object>[] resolveRuntimeAttributesArray(AnnotatedBeanDefinition beanDefinition, Properties globalNacosProperties) { protected Map<String, Object>[] resolveRuntimeAttributesArray(
AnnotatedBeanDefinition beanDefinition, Properties globalNacosProperties) {
// Get AnnotationMetadata // Get AnnotationMetadata
AnnotationMetadata metadata = beanDefinition.getMetadata(); AnnotationMetadata metadata = beanDefinition.getMetadata();
@ -51,29 +63,37 @@ public class AnnotationNacosPropertySourceBuilder extends AbstractNacosPropertyS
List<Map<String, Object>> annotationAttributesList = new LinkedList<Map<String, Object>>(); List<Map<String, Object>> annotationAttributesList = new LinkedList<Map<String, Object>>();
for (String annotationType : annotationTypes) { for (String annotationType : annotationTypes) {
annotationAttributesList.addAll(getAnnotationAttributesList(metadata, annotationType)); annotationAttributesList
.addAll(getAnnotationAttributesList(metadata, annotationType));
} }
return annotationAttributesList.toArray(new Map[0]); return annotationAttributesList.toArray(new Map[0]);
} }
private List<Map<String, Object>> getAnnotationAttributesList(AnnotationMetadata metadata, String annotationType) { private List<Map<String, Object>> getAnnotationAttributesList(
AnnotationMetadata metadata, String annotationType) {
List<Map<String, Object>> annotationAttributesList = new LinkedList<Map<String, Object>>(); List<Map<String, Object>> annotationAttributesList = new LinkedList<Map<String, Object>>();
if (NacosPropertySources.class.getName().equals(annotationType)) { if (NacosPropertySources.class.getName().equals(annotationType)) {
Map<String, Object> annotationAttributes = metadata.getAnnotationAttributes(annotationType); Map<String, Object> annotationAttributes = metadata
.getAnnotationAttributes(annotationType);
if (annotationAttributes != null) { if (annotationAttributes != null) {
annotationAttributesList.addAll(Arrays.asList((Map<String, Object>[]) annotationAttributes.get("value"))); annotationAttributesList.addAll(Arrays.asList(
(Map<String, Object>[]) annotationAttributes.get("value")));
} }
} else if (com.alibaba.nacos.spring.context.annotation.config.NacosPropertySource.class.getName().equals(annotationType)) { }
annotationAttributesList.add(metadata.getAnnotationAttributes(annotationType)); else if (com.alibaba.nacos.spring.context.annotation.config.NacosPropertySource.class
.getName().equals(annotationType)) {
annotationAttributesList
.add(metadata.getAnnotationAttributes(annotationType));
} }
return annotationAttributesList; return annotationAttributesList;
} }
@Override @Override
protected void initNacosPropertySource(NacosPropertySource nacosPropertySource, AnnotatedBeanDefinition beanDefinition, protected void initNacosPropertySource(NacosPropertySource nacosPropertySource,
AnnotatedBeanDefinition beanDefinition,
Map<String, Object> annotationAttributes) { Map<String, Object> annotationAttributes) {
// AttributesMetadata // AttributesMetadata
initAttributesMetadata(nacosPropertySource, annotationAttributes); initAttributesMetadata(nacosPropertySource, annotationAttributes);
@ -86,22 +106,28 @@ public class AnnotationNacosPropertySourceBuilder extends AbstractNacosPropertyS
} }
private void initAttributesMetadata(NacosPropertySource nacosPropertySource, Map<String, Object> annotationAttributes) { private void initAttributesMetadata(NacosPropertySource nacosPropertySource,
Map<String, Object> annotationAttributes) {
nacosPropertySource.setAttributesMetadata(annotationAttributes); nacosPropertySource.setAttributesMetadata(annotationAttributes);
} }
private void initAutoRefreshed(NacosPropertySource nacosPropertySource, Map<String, Object> annotationAttributes) { private void initAutoRefreshed(NacosPropertySource nacosPropertySource,
boolean autoRefreshed = Boolean.TRUE.equals(annotationAttributes.get(AUTO_REFRESHED_ATTRIBUTE_NAME)); Map<String, Object> annotationAttributes) {
boolean autoRefreshed = Boolean.TRUE
.equals(annotationAttributes.get(AUTO_REFRESHED_ATTRIBUTE_NAME));
nacosPropertySource.setAutoRefreshed(autoRefreshed); nacosPropertySource.setAutoRefreshed(autoRefreshed);
} }
private void initOrigin(NacosPropertySource nacosPropertySource, AnnotatedBeanDefinition beanDefinition) { private void initOrigin(NacosPropertySource nacosPropertySource,
AnnotatedBeanDefinition beanDefinition) {
AnnotationMetadata metadata = beanDefinition.getMetadata(); AnnotationMetadata metadata = beanDefinition.getMetadata();
nacosPropertySource.setOrigin(metadata.getClassName()); nacosPropertySource.setOrigin(metadata.getClassName());
} }
private void initOrder(NacosPropertySource nacosPropertySource, Map<String, Object> annotationAttributes) { private void initOrder(NacosPropertySource nacosPropertySource,
boolean first = Boolean.TRUE.equals(annotationAttributes.get(FIRST_ATTRIBUTE_NAME)); Map<String, Object> annotationAttributes) {
boolean first = Boolean.TRUE
.equals(annotationAttributes.get(FIRST_ATTRIBUTE_NAME));
String before = (String) annotationAttributes.get(BEFORE_ATTRIBUTE_NAME); String before = (String) annotationAttributes.get(BEFORE_ATTRIBUTE_NAME);
String after = (String) annotationAttributes.get(AFTER_ATTRIBUTE_NAME); String after = (String) annotationAttributes.get(AFTER_ATTRIBUTE_NAME);
nacosPropertySource.setFirst(first); nacosPropertySource.setFirst(first);
@ -110,13 +136,15 @@ public class AnnotationNacosPropertySourceBuilder extends AbstractNacosPropertyS
} }
@Override @Override
protected NacosConfigMetadataEvent createMetaEvent(NacosPropertySource nacosPropertySource, protected NacosConfigMetadataEvent createMetaEvent(
NacosPropertySource nacosPropertySource,
AnnotatedBeanDefinition beanDefinition) { AnnotatedBeanDefinition beanDefinition) {
return new NacosConfigMetadataEvent(beanDefinition.getMetadata()); return new NacosConfigMetadataEvent(beanDefinition.getMetadata());
} }
@Override @Override
protected void doInitMetadataEvent(NacosPropertySource nacosPropertySource, AnnotatedBeanDefinition beanDefinition, protected void doInitMetadataEvent(NacosPropertySource nacosPropertySource,
AnnotatedBeanDefinition beanDefinition,
NacosConfigMetadataEvent metadataEvent) { NacosConfigMetadataEvent metadataEvent) {
metadataEvent.setAnnotatedElement(metadataEvent.getAnnotatedElement()); metadataEvent.setAnnotatedElement(metadataEvent.getAnnotatedElement());
} }

View File

@ -16,14 +16,13 @@
*/ */
package com.alibaba.nacos.spring.core.env; package com.alibaba.nacos.spring.core.env;
import org.springframework.core.env.PropertiesPropertySource; import static com.alibaba.nacos.spring.util.NacosUtils.toProperties;
import org.springframework.core.env.PropertySource;
import java.util.Collections; import java.util.Collections;
import java.util.Map; import java.util.Map;
import java.util.Properties;
import static com.alibaba.nacos.spring.util.NacosUtils.toProperties; import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.PropertySource;
/** /**
* Nacos {@link PropertySource}, all read methods are immutable. * Nacos {@link PropertySource}, all read methods are immutable.
@ -32,7 +31,7 @@ import static com.alibaba.nacos.spring.util.NacosUtils.toProperties;
* @see com.alibaba.nacos.spring.context.annotation.config.NacosPropertySource * @see com.alibaba.nacos.spring.context.annotation.config.NacosPropertySource
* @since 0.1.0 * @since 0.1.0
*/ */
public class NacosPropertySource extends PropertiesPropertySource { public class NacosPropertySource extends MapPropertySource {
private String groupId; private String groupId;
@ -46,7 +45,9 @@ public class NacosPropertySource extends PropertiesPropertySource {
private String after; private String after;
private Properties properties; private String type;
private Map<Object, Object> properties;
private Map<String, Object> attributesMetadata; private Map<String, Object> attributesMetadata;
@ -56,12 +57,10 @@ public class NacosPropertySource extends PropertiesPropertySource {
private Class<?> beanType; private Class<?> beanType;
/** public NacosPropertySource(String dataId, String groupId, String name,
* @param name the name of Nacos {@link PropertySource} String nacosConfig, String type) {
* @param nacosConfig the Nacos Config with {@link Properties} format super(name, toProperties(dataId, groupId, nacosConfig, type));
*/ this.type = type;
public NacosPropertySource(String name, String nacosConfig) {
super(name, toProperties(nacosConfig));
} }
public String getGroupId() { public String getGroupId() {
@ -112,14 +111,32 @@ public class NacosPropertySource extends PropertiesPropertySource {
this.after = after; this.after = after;
} }
public Properties getProperties() { public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public Map<Object, Object> getProperties() {
return properties; return properties;
} }
public void setProperties(Properties properties) { public void setProperties(Map<Object, Object> properties) {
this.properties = properties; this.properties = properties;
} }
/**
* @return the attributesMetadata of attributes from
* {@link com.alibaba.nacos.spring.context.annotation.config.NacosPropertySource @NacosPropertySource}
* or &lt;nacos:property-source ... &gt;
*/
public Map<String, Object> getAttributesMetadata() {
return attributesMetadata != null ? attributesMetadata
: Collections.<String, Object> emptyMap();
}
/** /**
* @param attributesMetadata the attributesMetadata of attributes from * @param attributesMetadata the attributesMetadata of attributes from
* {@link com.alibaba.nacos.spring.context.annotation.config.NacosPropertySource @NacosPropertySource} * {@link com.alibaba.nacos.spring.context.annotation.config.NacosPropertySource @NacosPropertySource}
@ -129,22 +146,6 @@ public class NacosPropertySource extends PropertiesPropertySource {
this.attributesMetadata = attributesMetadata; this.attributesMetadata = attributesMetadata;
} }
/**
* @param origin where Nacos {@link PropertySource} comes from
*/
public void setOrigin(Object origin) {
this.origin = origin;
}
/**
* @return the attributesMetadata of attributes from
* {@link com.alibaba.nacos.spring.context.annotation.config.NacosPropertySource @NacosPropertySource}
* or &lt;nacos:property-source ... &gt;
*/
public Map<String, Object> getAttributesMetadata() {
return attributesMetadata != null ? attributesMetadata : Collections.<String, Object>emptyMap();
}
/** /**
* @return where Nacos {@link PropertySource} comes from * @return where Nacos {@link PropertySource} comes from
*/ */
@ -152,6 +153,13 @@ public class NacosPropertySource extends PropertiesPropertySource {
return origin; return origin;
} }
/**
* @param origin where Nacos {@link PropertySource} comes from
*/
public void setOrigin(Object origin) {
this.origin = origin;
}
public String getBeanName() { public String getBeanName() {
return beanName; return beanName;
} }
@ -175,6 +183,7 @@ public class NacosPropertySource extends PropertiesPropertySource {
this.first = original.first; this.first = original.first;
this.before = original.before; this.before = original.before;
this.after = original.after; this.after = original.after;
this.type = original.type;
this.properties = original.properties; this.properties = original.properties;
this.attributesMetadata = original.attributesMetadata; this.attributesMetadata = original.attributesMetadata;
this.origin = original.origin; this.origin = original.origin;

View File

@ -16,15 +16,23 @@
*/ */
package com.alibaba.nacos.spring.core.env; package com.alibaba.nacos.spring.core.env;
import com.alibaba.nacos.api.config.ConfigService; import static com.alibaba.nacos.spring.util.NacosBeanUtils.getConfigServiceBeanBuilder;
import com.alibaba.nacos.api.config.listener.AbstractListener; import static com.alibaba.nacos.spring.util.NacosBeanUtils.getNacosServiceFactoryBean;
import com.alibaba.nacos.api.exception.NacosException; import static com.alibaba.nacos.spring.util.NacosUtils.DEFAULT_STRING_ATTRIBUTE_VALUE;
import com.alibaba.nacos.spring.beans.factory.annotation.ConfigServiceBeanBuilder; import static org.springframework.util.ObjectUtils.nullSafeEquals;
import com.alibaba.nacos.spring.context.annotation.config.NacosPropertySources;
import com.alibaba.nacos.spring.context.config.xml.NacosPropertySourceXmlBeanDefinition;
import com.alibaba.spring.util.BeanUtils; import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import com.alibaba.nacos.spring.util.aot.AotDetector;
import org.springframework.beans.BeansException; import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.annotation.AnnotatedGenericBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor; import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
@ -39,24 +47,23 @@ import org.springframework.core.env.Environment;
import org.springframework.core.env.MutablePropertySources; import org.springframework.core.env.MutablePropertySources;
import org.springframework.core.env.PropertySources; import org.springframework.core.env.PropertySources;
import java.util.ArrayList; import com.alibaba.nacos.api.config.ConfigService;
import java.util.Collection; import com.alibaba.nacos.api.config.listener.AbstractListener;
import java.util.Collections; import com.alibaba.nacos.api.config.listener.Listener;
import java.util.LinkedHashSet; import com.alibaba.nacos.api.exception.NacosException;
import java.util.List; import com.alibaba.nacos.spring.beans.factory.annotation.ConfigServiceBeanBuilder;
import java.util.Map; import com.alibaba.nacos.spring.context.annotation.config.NacosPropertySources;
import java.util.Set; import com.alibaba.nacos.spring.context.config.xml.NacosPropertySourceXmlBeanDefinition;
import com.alibaba.nacos.spring.context.event.config.EventPublishingConfigService;
import static com.alibaba.nacos.spring.util.NacosBeanUtils.getConfigServiceBeanBuilder; import com.alibaba.nacos.spring.factory.NacosServiceFactory;
import static com.alibaba.nacos.spring.util.NacosUtils.DEFAULT_STRING_ATTRIBUTE_VALUE; import com.alibaba.spring.util.BeanUtils;
import static org.springframework.util.ObjectUtils.nullSafeEquals;
/** /**
* {@link BeanFactoryPostProcessor Post Processor} resolves {@link com.alibaba.nacos.spring.context.annotation.config.NacosPropertySource @NacosPropertySource} or * {@link BeanFactoryPostProcessor Post Processor} resolves
* {@link NacosPropertySources @NacosPropertySources} or {@link NacosPropertySourceXmlBeanDefinition} * {@link com.alibaba.nacos.spring.context.annotation.config.NacosPropertySource @NacosPropertySource}
* to be {@link PropertySource}, and append into Spring * or {@link NacosPropertySources @NacosPropertySources} or
* {@link PropertySources} * {@link NacosPropertySourceXmlBeanDefinition} to be {@link PropertySource}, and append
* {@link } * into Spring {@link PropertySources} {@link }
* *
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a> * @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
* @see com.alibaba.nacos.spring.context.annotation.config.NacosPropertySource * @see com.alibaba.nacos.spring.context.annotation.config.NacosPropertySource
@ -66,7 +73,8 @@ import static org.springframework.util.ObjectUtils.nullSafeEquals;
* @see BeanDefinitionRegistryPostProcessor * @see BeanDefinitionRegistryPostProcessor
* @since 0.1.0 * @since 0.1.0
*/ */
public class NacosPropertySourcePostProcessor implements BeanDefinitionRegistryPostProcessor, BeanFactoryPostProcessor, public class NacosPropertySourcePostProcessor
implements BeanDefinitionRegistryPostProcessor, BeanFactoryPostProcessor,
EnvironmentAware, Ordered { EnvironmentAware, Ordered {
/** /**
@ -74,31 +82,86 @@ public class NacosPropertySourcePostProcessor implements BeanDefinitionRegistryP
*/ */
public static final String BEAN_NAME = "nacosPropertySourcePostProcessor"; public static final String BEAN_NAME = "nacosPropertySourcePostProcessor";
private final Set<String> processedBeanNames = new LinkedHashSet<String>(); protected static BeanFactory beanFactory;
protected final Set<String> processedBeanNames = new LinkedHashSet<String>();
private ConfigurableEnvironment environment; private ConfigurableEnvironment environment;
private Collection<AbstractNacosPropertySourceBuilder> nacosPropertySourceBuilders; protected Collection<AbstractNacosPropertySourceBuilder> nacosPropertySourceBuilders;
private ConfigServiceBeanBuilder configServiceBeanBuilder; protected ConfigServiceBeanBuilder configServiceBeanBuilder;
public static void addListenerIfAutoRefreshed(
final NacosPropertySource nacosPropertySource, final Properties properties,
final ConfigurableEnvironment environment) {
if (!nacosPropertySource.isAutoRefreshed()) { // Disable Auto-Refreshed
return;
}
final String dataId = nacosPropertySource.getDataId();
final String groupId = nacosPropertySource.getGroupId();
final String type = nacosPropertySource.getType();
final NacosServiceFactory nacosServiceFactory = getNacosServiceFactoryBean(
beanFactory);
try {
ConfigService configService = nacosServiceFactory
.createConfigService(properties);
Listener listener = new AbstractListener() {
@Override @Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException { public void receiveConfigInfo(String config) {
String name = nacosPropertySource.getName();
NacosPropertySource newNacosPropertySource = new NacosPropertySource(
dataId, groupId, name, config, type);
newNacosPropertySource.copy(nacosPropertySource);
MutablePropertySources propertySources = environment
.getPropertySources();
// replace NacosPropertySource
propertySources.replace(name, newNacosPropertySource);
}
};
if (configService instanceof EventPublishingConfigService) {
((EventPublishingConfigService) configService).addListener(dataId,
groupId, type, listener);
}
else {
configService.addListener(dataId, groupId, listener);
}
}
catch (NacosException e) {
throw new RuntimeException(
"ConfigService can't add Listener with properties : " + properties,
e);
}
} }
@Override @Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry)
String[] abstractNacosPropertySourceBuilderBeanNames = BeanUtils.getBeanNames(beanFactory, throws BeansException {
AbstractNacosPropertySourceBuilder.class); }
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
throws BeansException {
String[] abstractNacosPropertySourceBuilderBeanNames = BeanUtils
.getBeanNames(beanFactory, AbstractNacosPropertySourceBuilder.class);
this.nacosPropertySourceBuilders = new ArrayList<AbstractNacosPropertySourceBuilder>( this.nacosPropertySourceBuilders = new ArrayList<AbstractNacosPropertySourceBuilder>(
abstractNacosPropertySourceBuilderBeanNames.length); abstractNacosPropertySourceBuilderBeanNames.length);
for (String beanName : abstractNacosPropertySourceBuilderBeanNames) { for (String beanName : abstractNacosPropertySourceBuilderBeanNames) {
this.nacosPropertySourceBuilders.add( this.nacosPropertySourceBuilders.add(beanFactory.getBean(beanName,
beanFactory.getBean(beanName, AbstractNacosPropertySourceBuilder.class)); AbstractNacosPropertySourceBuilder.class));
} }
NacosPropertySourcePostProcessor.beanFactory = beanFactory;
this.configServiceBeanBuilder = getConfigServiceBeanBuilder(beanFactory); this.configServiceBeanBuilder = getConfigServiceBeanBuilder(beanFactory);
String[] beanNames = beanFactory.getBeanDefinitionNames(); String[] beanNames = beanFactory.getBeanDefinitionNames();
@ -109,7 +172,8 @@ public class NacosPropertySourcePostProcessor implements BeanDefinitionRegistryP
} }
private void processPropertySource(String beanName, ConfigurableListableBeanFactory beanFactory) { protected void processPropertySource(String beanName,
ConfigurableListableBeanFactory beanFactory) {
if (processedBeanNames.contains(beanName)) { if (processedBeanNames.contains(beanName)) {
return; return;
@ -117,19 +181,27 @@ public class NacosPropertySourcePostProcessor implements BeanDefinitionRegistryP
BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName); BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);
// Build multiple instance if possible doProcessPropertySource(beanName, beanDefinition);
List<NacosPropertySource> nacosPropertySources = buildNacosPropertySources(beanName, beanDefinition);
// Add Orderly
for (NacosPropertySource nacosPropertySource : nacosPropertySources) {
addNacosPropertySource(nacosPropertySource);
addListenerIfAutoRefreshed(nacosPropertySource);
}
processedBeanNames.add(beanName); processedBeanNames.add(beanName);
} }
private List<NacosPropertySource> buildNacosPropertySources(String beanName, BeanDefinition beanDefinition) { protected void doProcessPropertySource(String beanName, BeanDefinition beanDefinition) {
// Build multiple instance if possible
List<NacosPropertySource> nacosPropertySources = buildNacosPropertySources(
beanName, beanDefinition);
// Add Orderly
for (NacosPropertySource nacosPropertySource : nacosPropertySources) {
addNacosPropertySource(nacosPropertySource);
Properties properties = configServiceBeanBuilder
.resolveProperties(nacosPropertySource.getAttributesMetadata());
addListenerIfAutoRefreshed(nacosPropertySource, properties, environment);
}
}
private List<NacosPropertySource> buildNacosPropertySources(String beanName,
BeanDefinition beanDefinition) {
for (AbstractNacosPropertySourceBuilder builder : nacosPropertySourceBuilders) { for (AbstractNacosPropertySourceBuilder builder : nacosPropertySourceBuilders) {
if (builder.supports(beanDefinition)) { if (builder.supports(beanDefinition)) {
return builder.build(beanName, beanDefinition); return builder.build(beanName, beanDefinition);
@ -153,50 +225,23 @@ public class NacosPropertySourcePostProcessor implements BeanDefinitionRegistryP
if (first) { // If First if (first) { // If First
propertySources.addFirst(nacosPropertySource); propertySources.addFirst(nacosPropertySource);
} else if (isRelative) { // If relative }
else if (isRelative) { // If relative
if (hasBefore) { if (hasBefore) {
propertySources.addBefore(before, nacosPropertySource); propertySources.addBefore(before, nacosPropertySource);
} }
if (hasAfter) { if (hasAfter) {
propertySources.addAfter(after, nacosPropertySource); propertySources.addAfter(after, nacosPropertySource);
} }
} else { }
else {
propertySources.addLast(nacosPropertySource); // default add last propertySources.addLast(nacosPropertySource); // default add last
} }
} }
private void addListenerIfAutoRefreshed(final NacosPropertySource nacosPropertySource) {
if (!nacosPropertySource.isAutoRefreshed()) { // Disable Auto-Refreshed
return;
}
final String dataId = nacosPropertySource.getDataId();
final String groupId = nacosPropertySource.getGroupId();
final Map<String, Object> nacosPropertiesAttributes = nacosPropertySource.getAttributesMetadata();
final ConfigService configService = configServiceBeanBuilder.build(nacosPropertiesAttributes);
try {
configService.addListener(dataId, groupId, new AbstractListener() {
@Override
public void receiveConfigInfo(String config) {
String name = nacosPropertySource.getName();
NacosPropertySource newNacosPropertySource = new NacosPropertySource(name, config);
newNacosPropertySource.copy(nacosPropertySource);
MutablePropertySources propertySources = environment.getPropertySources();
// replace NacosPropertySource
propertySources.replace(name, newNacosPropertySource);
}
});
} catch (NacosException e) {
throw new RuntimeException("ConfigService can't add Listener with properties : " + nacosPropertiesAttributes, e);
}
}
/** /**
* The order is closed to {@link ConfigurationClassPostProcessor#getOrder() HIGHEST_PRECEDENCE} almost. * The order is closed to {@link ConfigurationClassPostProcessor#getOrder()
* HIGHEST_PRECEDENCE} almost.
* *
* @return <code>Ordered.HIGHEST_PRECEDENCE + 1</code> * @return <code>Ordered.HIGHEST_PRECEDENCE + 1</code>
* @see ConfigurationClassPostProcessor#getOrder() * @see ConfigurationClassPostProcessor#getOrder()
@ -206,7 +251,6 @@ public class NacosPropertySourcePostProcessor implements BeanDefinitionRegistryP
return Ordered.HIGHEST_PRECEDENCE + 1; return Ordered.HIGHEST_PRECEDENCE + 1;
} }
@Override @Override
public void setEnvironment(Environment environment) { public void setEnvironment(Environment environment) {
this.environment = (ConfigurableEnvironment) environment; this.environment = (ConfigurableEnvironment) environment;

View File

@ -16,8 +16,24 @@
*/ */
package com.alibaba.nacos.spring.core.env; package com.alibaba.nacos.spring.core.env;
import com.alibaba.nacos.spring.context.config.xml.NacosPropertySourceXmlBeanDefinition; import static com.alibaba.nacos.api.common.Constants.DEFAULT_GROUP;
import com.alibaba.nacos.spring.context.event.config.NacosConfigMetadataEvent; import static com.alibaba.nacos.spring.context.annotation.config.NacosPropertySource.AFTER_ATTRIBUTE_NAME;
import static com.alibaba.nacos.spring.context.annotation.config.NacosPropertySource.AUTO_REFRESHED_ATTRIBUTE_NAME;
import static com.alibaba.nacos.spring.context.annotation.config.NacosPropertySource.BEFORE_ATTRIBUTE_NAME;
import static com.alibaba.nacos.spring.context.annotation.config.NacosPropertySource.CONFIG_TYPE_ATTRIBUTE_NAME;
import static com.alibaba.nacos.spring.context.annotation.config.NacosPropertySource.DATA_ID_ATTRIBUTE_NAME;
import static com.alibaba.nacos.spring.context.annotation.config.NacosPropertySource.FIRST_ATTRIBUTE_NAME;
import static com.alibaba.nacos.spring.context.annotation.config.NacosPropertySource.GROUP_ID_ATTRIBUTE_NAME;
import static com.alibaba.nacos.spring.context.annotation.config.NacosPropertySource.NAME_ATTRIBUTE_NAME;
import static com.alibaba.nacos.spring.context.annotation.config.NacosPropertySource.PROPERTIES_ATTRIBUTE_NAME;
import static com.alibaba.nacos.spring.util.NacosUtils.DEFAULT_BOOLEAN_ATTRIBUTE_VALUE;
import static com.alibaba.nacos.spring.util.NacosUtils.DEFAULT_CONFIG_TYPE_VALUE;
import static com.alibaba.nacos.spring.util.NacosUtils.DEFAULT_STRING_ATTRIBUTE_VALUE;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import org.springframework.beans.factory.xml.XmlReaderContext; import org.springframework.beans.factory.xml.XmlReaderContext;
import org.springframework.core.convert.ConversionService; import org.springframework.core.convert.ConversionService;
import org.springframework.core.io.Resource; import org.springframework.core.io.Resource;
@ -25,14 +41,9 @@ import org.springframework.util.StringUtils;
import org.w3c.dom.Element; import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap; import org.w3c.dom.NamedNodeMap;
import java.util.HashMap; import com.alibaba.nacos.api.config.ConfigType;
import java.util.Map; import com.alibaba.nacos.spring.context.config.xml.NacosPropertySourceXmlBeanDefinition;
import java.util.Properties; import com.alibaba.nacos.spring.context.event.config.NacosConfigMetadataEvent;
import static com.alibaba.nacos.api.common.Constants.DEFAULT_GROUP;
import static com.alibaba.nacos.spring.context.annotation.config.NacosPropertySource.*;
import static com.alibaba.nacos.spring.util.NacosUtils.DEFAULT_BOOLEAN_ATTRIBUTE_VALUE;
import static com.alibaba.nacos.spring.util.NacosUtils.DEFAULT_STRING_ATTRIBUTE_VALUE;
/** /**
* XML {@link NacosPropertySource} {@link AbstractNacosPropertySourceBuilder Builder} * XML {@link NacosPropertySource} {@link AbstractNacosPropertySourceBuilder Builder}
@ -40,8 +51,8 @@ import static com.alibaba.nacos.spring.util.NacosUtils.DEFAULT_STRING_ATTRIBUTE_
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a> * @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
* @since 0.1.0 * @since 0.1.0
*/ */
public class XmlNacosPropertySourceBuilder extends public class XmlNacosPropertySourceBuilder
AbstractNacosPropertySourceBuilder<NacosPropertySourceXmlBeanDefinition> { extends AbstractNacosPropertySourceBuilder<NacosPropertySourceXmlBeanDefinition> {
/** /**
* The bean name of {@link XmlNacosPropertySourceBuilder} * The bean name of {@link XmlNacosPropertySourceBuilder}
@ -49,23 +60,53 @@ public class XmlNacosPropertySourceBuilder extends
public static final String BEAN_NAME = "xmlNacosPropertySourceBuilder"; public static final String BEAN_NAME = "xmlNacosPropertySourceBuilder";
@Override @Override
protected Map<String, Object>[] resolveRuntimeAttributesArray(NacosPropertySourceXmlBeanDefinition beanDefinition, protected Map<String, Object>[] resolveRuntimeAttributesArray(
NacosPropertySourceXmlBeanDefinition beanDefinition,
Properties globalNacosProperties) { Properties globalNacosProperties) {
Element element = beanDefinition.getElement(); Element element = beanDefinition.getElement();
Map<String, Object> runtimeAttributes = new HashMap<String, Object>(4); Map<String, Object> runtimeAttributes = new HashMap<String, Object>(4);
// Nacos Metadata // Nacos Metadata
runtimeAttributes.put(DATA_ID_ATTRIBUTE_NAME, getAttribute(element, "data-id", DEFAULT_STRING_ATTRIBUTE_VALUE)); runtimeAttributes.put(DATA_ID_ATTRIBUTE_NAME,
runtimeAttributes.put(GROUP_ID_ATTRIBUTE_NAME, getAttribute(element, "group-id", DEFAULT_GROUP)); getAttribute(element, "data-id", DEFAULT_STRING_ATTRIBUTE_VALUE));
runtimeAttributes.put(GROUP_ID_ATTRIBUTE_NAME,
getAttribute(element, "group-id", DEFAULT_GROUP));
// PropertySource Name // PropertySource Name
runtimeAttributes.put(NAME_ATTRIBUTE_NAME, getAttribute(element, NAME_ATTRIBUTE_NAME, DEFAULT_STRING_ATTRIBUTE_VALUE)); runtimeAttributes.put(NAME_ATTRIBUTE_NAME, getAttribute(element,
NAME_ATTRIBUTE_NAME, DEFAULT_STRING_ATTRIBUTE_VALUE));
// auto-refresh
runtimeAttributes.put(AUTO_REFRESHED_ATTRIBUTE_NAME, getAttribute(element,
AUTO_REFRESHED_ATTRIBUTE_NAME, DEFAULT_BOOLEAN_ATTRIBUTE_VALUE));
// is first order
runtimeAttributes.put(FIRST_ATTRIBUTE_NAME, getAttribute(element,
FIRST_ATTRIBUTE_NAME, DEFAULT_BOOLEAN_ATTRIBUTE_VALUE));
// The relative order before specified
runtimeAttributes.put(BEFORE_ATTRIBUTE_NAME, getAttribute(element,
BEFORE_ATTRIBUTE_NAME, DEFAULT_STRING_ATTRIBUTE_VALUE));
// The relative order after specified
runtimeAttributes.put(AFTER_ATTRIBUTE_NAME, getAttribute(element,
AFTER_ATTRIBUTE_NAME, DEFAULT_STRING_ATTRIBUTE_VALUE));
// Config type
String type = getAttribute(element, CONFIG_TYPE_ATTRIBUTE_NAME,
DEFAULT_CONFIG_TYPE_VALUE);
try {
runtimeAttributes.put(CONFIG_TYPE_ATTRIBUTE_NAME,
ConfigType.valueOf(type.toUpperCase()));
// TODO support nested properties // TODO support nested properties
runtimeAttributes.put(PROPERTIES_ATTRIBUTE_NAME, new Properties()); runtimeAttributes.put(PROPERTIES_ATTRIBUTE_NAME, new Properties());
return new Map[] { runtimeAttributes }; return new Map[] { runtimeAttributes };
} }
catch (IllegalArgumentException e) {
throw new IllegalArgumentException(
"Now the config type just support [properties, json, yaml, xml, text, html]");
}
}
@Override @Override
protected void initNacosPropertySource(NacosPropertySource nacosPropertySource, protected void initNacosPropertySource(NacosPropertySource nacosPropertySource,
NacosPropertySourceXmlBeanDefinition beanDefinition, Map<String, Object> attributes) { NacosPropertySourceXmlBeanDefinition beanDefinition,
Map<String, Object> attributes) {
Element element = beanDefinition.getElement(); Element element = beanDefinition.getElement();
// Attributes Metadata // Attributes Metadata
@ -78,54 +119,61 @@ public class XmlNacosPropertySourceBuilder extends
initOrder(nacosPropertySource, element); initOrder(nacosPropertySource, element);
} }
private void initOrigin(NacosPropertySource nacosPropertySource, XmlReaderContext xmlReaderContext) { private void initOrigin(NacosPropertySource nacosPropertySource,
XmlReaderContext xmlReaderContext) {
// Resource // Resource
Resource resource = xmlReaderContext.getResource(); Resource resource = xmlReaderContext.getResource();
nacosPropertySource.setOrigin(resource); nacosPropertySource.setOrigin(resource);
} }
private void initAutoRefreshed(NacosPropertySource nacosPropertySource, Element element) { private void initAutoRefreshed(NacosPropertySource nacosPropertySource,
boolean autoRefreshed = getAttribute(element, "auto-refreshed", DEFAULT_BOOLEAN_ATTRIBUTE_VALUE); Element element) {
boolean autoRefreshed = getAttribute(element, "auto-refreshed",
DEFAULT_BOOLEAN_ATTRIBUTE_VALUE);
nacosPropertySource.setAutoRefreshed(autoRefreshed); nacosPropertySource.setAutoRefreshed(autoRefreshed);
} }
private void initAttributesMetadata(NacosPropertySource nacosPropertySource, Element element) { private void initAttributesMetadata(NacosPropertySource nacosPropertySource,
Element element) {
NamedNodeMap elementAttributes = element.getAttributes(); NamedNodeMap elementAttributes = element.getAttributes();
int length = elementAttributes.getLength(); int length = elementAttributes.getLength();
} }
private void initOrder(NacosPropertySource nacosPropertySource, Element element) { private void initOrder(NacosPropertySource nacosPropertySource, Element element) {
// Order // Order
boolean first = getAttribute(element, FIRST_ATTRIBUTE_NAME, DEFAULT_BOOLEAN_ATTRIBUTE_VALUE); boolean first = getAttribute(element, FIRST_ATTRIBUTE_NAME,
String before = getAttribute(element, BEFORE_ATTRIBUTE_NAME, DEFAULT_STRING_ATTRIBUTE_VALUE); DEFAULT_BOOLEAN_ATTRIBUTE_VALUE);
String after = getAttribute(element, AFTER_ATTRIBUTE_NAME, DEFAULT_STRING_ATTRIBUTE_VALUE); String before = getAttribute(element, BEFORE_ATTRIBUTE_NAME,
DEFAULT_STRING_ATTRIBUTE_VALUE);
String after = getAttribute(element, AFTER_ATTRIBUTE_NAME,
DEFAULT_STRING_ATTRIBUTE_VALUE);
nacosPropertySource.setFirst(first); nacosPropertySource.setFirst(first);
nacosPropertySource.setBefore(before); nacosPropertySource.setBefore(before);
nacosPropertySource.setAfter(after); nacosPropertySource.setAfter(after);
} }
private <T> T getAttribute(Element element, String name, T defaultValue) { private <T> T getAttribute(Element element, String name, T defaultValue) {
ConversionService conversionService = environment.getConversionService(); ConversionService conversionService = environment.getConversionService();
String value = element.getAttribute(name); String value = element.getAttribute(name);
String resolvedValue = environment.resolvePlaceholders(value); String resolvedValue = environment.resolvePlaceholders(value);
T attributeValue = StringUtils.hasText(resolvedValue) ? T attributeValue = StringUtils.hasText(resolvedValue)
(T) conversionService.convert(resolvedValue, defaultValue.getClass()) : ? (T) conversionService.convert(resolvedValue, defaultValue.getClass())
defaultValue; : defaultValue;
return attributeValue; return attributeValue;
} }
@Override @Override
protected NacosConfigMetadataEvent createMetaEvent(NacosPropertySource nacosPropertySource, protected NacosConfigMetadataEvent createMetaEvent(
NacosPropertySource nacosPropertySource,
NacosPropertySourceXmlBeanDefinition beanDefinition) { NacosPropertySourceXmlBeanDefinition beanDefinition) {
return new NacosConfigMetadataEvent(beanDefinition.getElement()); return new NacosConfigMetadataEvent(beanDefinition.getElement());
} }
@Override @Override
protected void doInitMetadataEvent(NacosPropertySource nacosPropertySource, protected void doInitMetadataEvent(NacosPropertySource nacosPropertySource,
NacosPropertySourceXmlBeanDefinition beanDefinition, NacosConfigMetadataEvent metadataEvent) { NacosPropertySourceXmlBeanDefinition beanDefinition,
NacosConfigMetadataEvent metadataEvent) {
metadataEvent.setXmlResource(beanDefinition.getXmlReaderContext().getResource()); metadataEvent.setXmlResource(beanDefinition.getXmlReaderContext().getResource());
} }
} }

View File

@ -0,0 +1,105 @@
/*
* 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 com.alibaba.nacos.spring.enums;
import com.alibaba.nacos.common.utils.StringUtils;
/**
* Config file type enum.
*
*/
public enum FileTypeEnum {
/**
* Yaml file.
*/
YML("yaml"),
/**
* Yaml file.
*/
YAML("yaml"),
/**
* Text file.
*/
TXT("text"),
/**
* Text file.
*/
TEXT("text"),
/**
* Json file.
*/
JSON("json"),
/**
* Xml file.
*/
XML("xml"),
/**
* Html file.
*/
HTM("html"),
/**
* Html file.
*/
HTML("html"),
/**
* Properties file.
*/
PROPERTIES("properties");
/**
* File type corresponding to file extension.
*/
private String fileType;
FileTypeEnum(String fileType) {
this.fileType = fileType;
}
public String getFileType() {
return this.fileType;
}
/**
* Get the corresponding FileTypeEnum by file extension or fileType. If not found FileTypeEnum.TEXT is returned
*
* @param extOrFileType file extension or fileType
* @return return {@link FileTypeEnum}
*/
public static FileTypeEnum getFileTypeEnumByFileExtensionOrFileType(String extOrFileType) {
if (StringUtils.isNotBlank(extOrFileType)) {
String upperExtName = extOrFileType.trim().toUpperCase();
for (FileTypeEnum value : VALUES) {
if (value.name().equals(upperExtName)) {
return value;
}
}
}
return FileTypeEnum.PROPERTIES;
}
private static final FileTypeEnum[] VALUES = FileTypeEnum.values();
}

View File

@ -0,0 +1,43 @@
/*
* 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 com.alibaba.nacos.spring.factory;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ConfigurableApplicationContext;
/**
* @author <a href="mailto:liaochunyhm@live.com">liaochuntao</a>
* @since 0.3.0
*/
public class ApplicationContextHolder implements ApplicationContextAware {
public static final String BEAN_NAME = "nacosApplicationContextHolder";
private ConfigurableApplicationContext context;
public ConfigurableApplicationContext getApplicationContext() {
return context;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
context = (ConfigurableApplicationContext) applicationContext;
}
}

View File

@ -16,24 +16,28 @@
*/ */
package com.alibaba.nacos.spring.factory; package com.alibaba.nacos.spring.factory;
import com.alibaba.nacos.api.NacosFactory; import static com.alibaba.nacos.spring.util.NacosBeanUtils.getNacosConfigListenerExecutorIfPresent;
import com.alibaba.nacos.api.config.ConfigService; import static com.alibaba.nacos.spring.util.NacosUtils.identify;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.spring.context.event.config.EventPublishingConfigService;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ConfigurableApplicationContext;
import java.util.Collection; import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.Map; import java.util.Map;
import java.util.Properties; import java.util.Properties;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import static com.alibaba.nacos.spring.util.NacosBeanUtils.getNacosConfigListenerExecutorIfPresent; import org.springframework.beans.BeansException;
import static com.alibaba.nacos.spring.util.NacosUtils.identify; import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import com.alibaba.nacos.api.NacosFactory;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.NamingMaintainService;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.spring.context.event.config.EventPublishingConfigService;
/** /**
* Cacheable Event Publishing {@link NacosServiceFactory} * Cacheable Event Publishing {@link NacosServiceFactory}
@ -41,63 +45,110 @@ import static com.alibaba.nacos.spring.util.NacosUtils.identify;
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a> * @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
* @since 0.1.0 * @since 0.1.0
*/ */
public class CacheableEventPublishingNacosServiceFactory implements NacosServiceFactory, ApplicationContextAware { @SuppressWarnings("unchecked")
public class CacheableEventPublishingNacosServiceFactory implements NacosServiceFactory {
private final Map<String, ConfigService> configServicesCache = new LinkedHashMap<String, ConfigService>(2); private static volatile CacheableEventPublishingNacosServiceFactory SINGLETON = new CacheableEventPublishingNacosServiceFactory();
private final Map<String, NamingService> namingServicesCache = new LinkedHashMap<String, NamingService>(2); private final Map<String, ConfigService> configServicesCache = new LinkedHashMap<String, ConfigService>(
2);
private final Map<String, NamingService> namingServicesCache = new LinkedHashMap<String, NamingService>(
2);
private final Map<String, NamingMaintainService> maintainServiceCache = new LinkedHashMap<String, NamingMaintainService>(
2);
private final LinkedList<DeferServiceHolder> deferServiceCache = new LinkedList<DeferServiceHolder>();
private ConfigurableApplicationContext context; private ConfigurableApplicationContext context;
private ExecutorService nacosConfigListenerExecutor; private ExecutorService nacosConfigListenerExecutor;
@Override private Map<ServiceType, AbstractCreateWorker> createWorkerManager = new HashMap<ServiceType, AbstractCreateWorker>(
public ConfigService createConfigService(Properties properties) throws NacosException { 3);
public CacheableEventPublishingNacosServiceFactory() {
createWorkerManager.put(ServiceType.CONFIG, new ConfigCreateWorker());
createWorkerManager.put(ServiceType.NAMING, new NamingCreateWorker());
createWorkerManager.put(ServiceType.MAINTAIN, new MaintainCreateWorker());
createWorkerManager = Collections.unmodifiableMap(createWorkerManager);
}
public static CacheableEventPublishingNacosServiceFactory getSingleton() {
return SINGLETON;
}
@Override
public ConfigService createConfigService(Properties properties)
throws NacosException {
Properties copy = new Properties(); Properties copy = new Properties();
copy.putAll(properties); copy.putAll(properties);
return (ConfigService) createWorkerManager.get(ServiceType.CONFIG).run(copy,
String cacheKey = identify(copy); null);
ConfigService configService = configServicesCache.get(cacheKey);
if (configService == null) {
configService = doCreateConfigService(copy);
configServicesCache.put(cacheKey, configService);
}
return configService;
}
private ConfigService doCreateConfigService(Properties properties) throws NacosException {
ConfigService configService = NacosFactory.createConfigService(properties);
return new EventPublishingConfigService(configService, properties, context, nacosConfigListenerExecutor);
} }
@Override @Override
public NamingService createNamingService(Properties properties) throws NacosException { public NamingService createNamingService(Properties properties)
throws NacosException {
Properties copy = new Properties(); Properties copy = new Properties();
copy.putAll(properties); copy.putAll(properties);
return (NamingService) createWorkerManager.get(ServiceType.NAMING).run(copy,
String cacheKey = identify(copy); null);
NamingService namingService = namingServicesCache.get(cacheKey);
if (namingService == null) {
namingService = new DelegatingNamingService(NacosFactory.createNamingService(copy), properties);
namingServicesCache.put(cacheKey, namingService);
} }
return namingService; // Exist some cases need to create the ConfigService | NamingService |
} // NamingMaintainService
// before loading the Context object, lazy loading
@Override @Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { public NamingMaintainService createNamingMaintainService(Properties properties)
throws NacosException {
Properties copy = new Properties();
copy.putAll(properties);
return (NamingMaintainService) createWorkerManager.get(ServiceType.MAINTAIN)
.run(copy, null);
}
public <T> T deferCreateService(T service, Properties properties) {
DeferServiceHolder serviceHolder = new DeferServiceHolder();
serviceHolder.setHolder(service);
serviceHolder.setProperties(properties);
deferServiceCache.add(serviceHolder);
return service;
}
@SuppressWarnings("unchecked")
public void publishDeferService(ApplicationContext context) throws NacosException {
setApplicationContext(context);
for (DeferServiceHolder holder : deferServiceCache) {
final Object o = holder.getHolder();
final Properties properties = holder.getProperties();
if (o instanceof ConfigService) {
ConfigService configService = (ConfigService) o;
createWorkerManager.get(ServiceType.CONFIG).run(properties,
configService);
}
else if (o instanceof NamingService) {
NamingService namingService = (NamingService) o;
createWorkerManager.get(ServiceType.NAMING).run(properties,
namingService);
}
else if (o instanceof NamingMaintainService) {
NamingMaintainService maintainService = (NamingMaintainService) o;
createWorkerManager.get(ServiceType.MAINTAIN).run(properties,
maintainService);
}
}
deferServiceCache.clear();
}
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
this.context = (ConfigurableApplicationContext) applicationContext; this.context = (ConfigurableApplicationContext) applicationContext;
this.nacosConfigListenerExecutor = getNacosConfigListenerExecutorIfPresent(applicationContext); this.nacosConfigListenerExecutor = getSingleton().nacosConfigListenerExecutor == null
? getNacosConfigListenerExecutorIfPresent(applicationContext)
: getSingleton().nacosConfigListenerExecutor;
} }
@Override @Override
@ -109,4 +160,148 @@ public class CacheableEventPublishingNacosServiceFactory implements NacosService
public Collection<NamingService> getNamingServices() { public Collection<NamingService> getNamingServices() {
return namingServicesCache.values(); return namingServicesCache.values();
} }
@Override
public Collection<NamingMaintainService> getNamingMaintainService() {
return maintainServiceCache.values();
}
private static enum ServiceType {
/**
* Config
*/
CONFIG,
/**
* Naming
*/
NAMING,
/**
* Maintain
*/
MAINTAIN
}
static class DeferServiceHolder {
private Properties properties;
private Object holder;
private ServiceType type;
public Properties getProperties() {
return properties;
}
public void setProperties(Properties properties) {
this.properties = properties;
}
Object getHolder() {
return holder;
}
void setHolder(Object holder) {
this.holder = holder;
}
public ServiceType getType() {
return type;
}
public void setType(ServiceType type) {
this.type = type;
}
}
abstract static class AbstractCreateWorker<T> {
AbstractCreateWorker() {
}
/**
* To perform the corresponding create and logic object cache
*
* @param properties Set the parameters
* @param service nacos service {ConfigService | NamingService |
* NamingMaintainService}
* @return T service
* @throws NacosException
*/
public abstract T run(Properties properties, T service) throws NacosException;
}
class ConfigCreateWorker extends AbstractCreateWorker<ConfigService> {
ConfigCreateWorker() {
}
@Override
public ConfigService run(Properties properties, ConfigService service)
throws NacosException {
String cacheKey = identify(properties);
ConfigService configService = configServicesCache.get(cacheKey);
if (configService == null) {
if (service == null) {
service = NacosFactory.createConfigService(properties);
}
configService = new EventPublishingConfigService(service, properties,
getSingleton().context,
getSingleton().nacosConfigListenerExecutor);
configServicesCache.put(cacheKey, configService);
}
return configService;
}
}
class NamingCreateWorker extends AbstractCreateWorker<NamingService> {
NamingCreateWorker() {
}
@Override
public NamingService run(Properties properties, NamingService service)
throws NacosException {
String cacheKey = identify(properties);
NamingService namingService = namingServicesCache.get(cacheKey);
if (namingService == null) {
if (service == null) {
service = NacosFactory.createNamingService(properties);
}
namingService = new DelegatingNamingService(service, properties);
namingServicesCache.put(cacheKey, namingService);
}
return namingService;
}
}
class MaintainCreateWorker extends AbstractCreateWorker<NamingMaintainService> {
MaintainCreateWorker() {
}
@Override
public NamingMaintainService run(Properties properties,
NamingMaintainService service) throws NacosException {
String cacheKey = identify(properties);
NamingMaintainService namingMaintainService = maintainServiceCache
.get(cacheKey);
if (namingMaintainService == null) {
if (service == null) {
service = NacosFactory.createMaintainService(properties);
}
namingMaintainService = new DelegatingNamingMaintainService(service,
properties);
maintainServiceCache.put(cacheKey, namingMaintainService);
}
return namingMaintainService;
}
}
} }

View File

@ -0,0 +1,136 @@
/*
* 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 com.alibaba.nacos.spring.factory;
import java.util.Map;
import java.util.Properties;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.NamingMaintainService;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.alibaba.nacos.api.naming.pojo.Service;
import com.alibaba.nacos.api.selector.AbstractSelector;
import com.alibaba.nacos.spring.metadata.NacosServiceMetaData;
/**
* @author <a href="mailto:liaochunyhm@live.com">liaochuntao</a>
* @since 0.3.0
*/
class DelegatingNamingMaintainService
implements NamingMaintainService, NacosServiceMetaData {
private final NamingMaintainService delegate;
private final Properties properties;
DelegatingNamingMaintainService(NamingMaintainService delegate,
Properties properties) {
this.delegate = delegate;
this.properties = properties;
}
@Override
public void updateInstance(String serviceName, Instance instance)
throws NacosException {
delegate.updateInstance(serviceName, instance);
}
@Override
public void updateInstance(String serviceName, String groupName, Instance instance)
throws NacosException {
delegate.updateInstance(serviceName, groupName, instance);
}
@Override
public Service queryService(String serviceName) throws NacosException {
return delegate.queryService(serviceName);
}
@Override
public Service queryService(String serviceName, String groupName)
throws NacosException {
return delegate.queryService(serviceName, groupName);
}
@Override
public void createService(String serviceName) throws NacosException {
delegate.createService(serviceName);
}
@Override
public void createService(String serviceName, String groupName)
throws NacosException {
delegate.createService(serviceName, groupName);
}
@Override
public void createService(String serviceName, String groupName,
float protectThreshold) throws NacosException {
delegate.createService(serviceName, groupName, protectThreshold);
}
@Override
public void createService(String serviceName, String groupName,
float protectThreshold, String expression) throws NacosException {
delegate.createService(serviceName, groupName, protectThreshold, expression);
}
@Override
public void createService(Service service, AbstractSelector selector)
throws NacosException {
delegate.createService(service, selector);
}
@Override
public boolean deleteService(String serviceName) throws NacosException {
return delegate.deleteService(serviceName);
}
@Override
public boolean deleteService(String serviceName, String groupName)
throws NacosException {
return delegate.deleteService(serviceName, groupName);
}
@Override
public void updateService(String serviceName, String groupName,
float protectThreshold) throws NacosException {
delegate.updateService(serviceName, groupName, protectThreshold);
}
@Override
public void updateService(String serviceName, String groupName,
float protectThreshold, Map<String, String> metadata) throws NacosException {
delegate.updateService(serviceName, groupName, protectThreshold, metadata);
}
@Override
public void updateService(Service service, AbstractSelector selector)
throws NacosException {
delegate.updateService(service, selector);
}
@Override
public void shutDown() throws NacosException {
delegate.shutDown();
}
@Override
public Properties getProperties() {
return properties;
}
}

View File

@ -14,28 +14,33 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.alibaba.nacos.spring.factory; package com.alibaba.nacos.spring.factory;
import java.util.List;
import java.util.Properties;
import org.springframework.beans.factory.DisposableBean;
import com.alibaba.nacos.api.exception.NacosException; import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.NamingService; import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.listener.EventListener; import com.alibaba.nacos.api.naming.listener.EventListener;
import com.alibaba.nacos.api.naming.pojo.Instance; import com.alibaba.nacos.api.naming.pojo.Instance;
import com.alibaba.nacos.api.naming.pojo.ListView; import com.alibaba.nacos.api.naming.pojo.ListView;
import com.alibaba.nacos.api.naming.pojo.ServiceInfo; import com.alibaba.nacos.api.naming.pojo.ServiceInfo;
import com.alibaba.nacos.api.selector.AbstractSelector;
import com.alibaba.nacos.spring.metadata.NacosServiceMetaData; import com.alibaba.nacos.spring.metadata.NacosServiceMetaData;
import java.util.List;
import java.util.Properties;
/** /**
* Delegating {@link NamingService} with {@link NacosServiceMetaData} * Delegating {@link NamingService} with {@link NacosServiceMetaData}.
* *
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a> * @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
* @see NamingService * @see NamingService
* @see NacosServiceMetaData * @see NacosServiceMetaData
* @since 0.1.0 * @since 0.1.0
*/ */
class DelegatingNamingService implements NamingService, NacosServiceMetaData { class DelegatingNamingService
implements NamingService, NacosServiceMetaData, DisposableBean {
private final NamingService delegate; private final NamingService delegate;
@ -47,85 +52,306 @@ class DelegatingNamingService implements NamingService, NacosServiceMetaData {
} }
@Override @Override
public void registerInstance(String serviceName, String ip, int port) throws NacosException { public void registerInstance(String serviceName, String ip, int port)
throws NacosException {
delegate.registerInstance(serviceName, ip, port); delegate.registerInstance(serviceName, ip, port);
} }
@Override @Override
public void registerInstance(String serviceName, String ip, int port, String clusterName) throws NacosException { public void registerInstance(String serviceName, String groupName, String ip,
int port) throws NacosException {
delegate.registerInstance(serviceName, groupName, ip, port);
}
@Override
public void registerInstance(String serviceName, String ip, int port,
String clusterName) throws NacosException {
delegate.registerInstance(serviceName, ip, port, clusterName); delegate.registerInstance(serviceName, ip, port, clusterName);
} }
@Override @Override
public void registerInstance(String serviceName, Instance instance) throws NacosException { public void registerInstance(String serviceName, String groupName, String ip,
int port, String clusterName) throws NacosException {
delegate.registerInstance(serviceName, groupName, ip, port, clusterName);
}
@Override
public void registerInstance(String serviceName, Instance instance)
throws NacosException {
delegate.registerInstance(serviceName, instance); delegate.registerInstance(serviceName, instance);
} }
@Override @Override
public void deregisterInstance(String serviceName, String ip, int port) throws NacosException { public void registerInstance(String serviceName, String groupName, Instance instance)
throws NacosException {
delegate.registerInstance(serviceName, groupName, instance);
}
@Override
public void batchRegisterInstance(String serviceName, String groupName, List<Instance> instances)
throws NacosException {
delegate.batchRegisterInstance(serviceName, groupName, instances);
}
@Override
public void batchDeregisterInstance(String serviceName, String groupName, List<Instance> instances)
throws NacosException {
delegate.batchDeregisterInstance(serviceName, groupName, instances);
}
@Override
public void deregisterInstance(String serviceName, String ip, int port)
throws NacosException {
delegate.deregisterInstance(serviceName, ip, port); delegate.deregisterInstance(serviceName, ip, port);
} }
@Override @Override
public void deregisterInstance(String serviceName, String ip, int port, String clusterName) throws NacosException { public void deregisterInstance(String serviceName, String groupName, String ip,
int port) throws NacosException {
delegate.deregisterInstance(serviceName, groupName, ip, port);
}
@Override
public void deregisterInstance(String serviceName, String ip, int port,
String clusterName) throws NacosException {
delegate.deregisterInstance(serviceName, ip, port, clusterName); delegate.deregisterInstance(serviceName, ip, port, clusterName);
} }
@Override
public void deregisterInstance(String serviceName, String groupName, String ip,
int port, String clusterName) throws NacosException {
delegate.deregisterInstance(serviceName, groupName, ip, port, clusterName);
}
@Override
public void deregisterInstance(String serviceName, Instance instance)
throws NacosException {
delegate.deregisterInstance(serviceName, instance);
}
@Override
public void deregisterInstance(String serviceName, String groupName,
Instance instance) throws NacosException {
delegate.deregisterInstance(serviceName, groupName, instance);
}
@Override @Override
public List<Instance> getAllInstances(String serviceName) throws NacosException { public List<Instance> getAllInstances(String serviceName) throws NacosException {
return delegate.getAllInstances(serviceName); return delegate.getAllInstances(serviceName);
} }
@Override @Override
public List<Instance> getAllInstances(String serviceName, List<String> clusters) throws NacosException { public List<Instance> getAllInstances(String serviceName, String groupName)
throws NacosException {
return delegate.getAllInstances(serviceName, groupName);
}
@Override
public List<Instance> getAllInstances(String serviceName, boolean subscribe)
throws NacosException {
return delegate.getAllInstances(serviceName, subscribe);
}
@Override
public List<Instance> getAllInstances(String serviceName, String groupName,
boolean subscribe) throws NacosException {
return delegate.getAllInstances(serviceName, groupName, subscribe);
}
@Override
public List<Instance> getAllInstances(String serviceName, List<String> clusters)
throws NacosException {
return delegate.getAllInstances(serviceName, clusters); return delegate.getAllInstances(serviceName, clusters);
} }
@Override @Override
public List<Instance> selectInstances(String serviceName, boolean healthy) throws NacosException { public List<Instance> getAllInstances(String serviceName, String groupName,
List<String> clusters) throws NacosException {
return delegate.getAllInstances(serviceName, groupName, clusters);
}
@Override
public List<Instance> getAllInstances(String serviceName, List<String> clusters,
boolean subscribe) throws NacosException {
return delegate.getAllInstances(serviceName, clusters, subscribe);
}
@Override
public List<Instance> getAllInstances(String serviceName, String groupName,
List<String> clusters, boolean subscribe) throws NacosException {
return delegate.getAllInstances(serviceName, groupName, clusters, subscribe);
}
@Override
public List<Instance> selectInstances(String serviceName, boolean healthy)
throws NacosException {
return delegate.selectInstances(serviceName, healthy); return delegate.selectInstances(serviceName, healthy);
} }
@Override @Override
public List<Instance> selectInstances(String serviceName, List<String> clusters, boolean healthy) throws NacosException { public List<Instance> selectInstances(String serviceName, String groupName,
boolean healthy) throws NacosException {
return delegate.selectInstances(serviceName, groupName, healthy);
}
@Override
public List<Instance> selectInstances(String serviceName, boolean healthy,
boolean subscribe) throws NacosException {
return delegate.selectInstances(serviceName, healthy, subscribe);
}
@Override
public List<Instance> selectInstances(String serviceName, String groupName,
boolean healthy, boolean subscribe) throws NacosException {
return delegate.selectInstances(serviceName, groupName, healthy, subscribe);
}
@Override
public List<Instance> selectInstances(String serviceName, List<String> clusters,
boolean healthy) throws NacosException {
return delegate.selectInstances(serviceName, clusters, healthy); return delegate.selectInstances(serviceName, clusters, healthy);
} }
@Override
public List<Instance> selectInstances(String serviceName, String groupName,
List<String> clusters, boolean healthy) throws NacosException {
return delegate.selectInstances(serviceName, groupName, clusters, healthy);
}
@Override
public List<Instance> selectInstances(String serviceName, List<String> clusters,
boolean healthy, boolean subscribe) throws NacosException {
return delegate.selectInstances(serviceName, clusters, healthy, subscribe);
}
@Override
public List<Instance> selectInstances(String serviceName, String groupName,
List<String> clusters, boolean healthy, boolean subscribe)
throws NacosException {
return delegate.selectInstances(serviceName, groupName, clusters, healthy,
subscribe);
}
@Override @Override
public Instance selectOneHealthyInstance(String serviceName) throws NacosException { public Instance selectOneHealthyInstance(String serviceName) throws NacosException {
return delegate.selectOneHealthyInstance(serviceName); return delegate.selectOneHealthyInstance(serviceName);
} }
@Override @Override
public Instance selectOneHealthyInstance(String serviceName, List<String> clusters) throws NacosException { public Instance selectOneHealthyInstance(String serviceName, String groupName)
throws NacosException {
return delegate.selectOneHealthyInstance(serviceName, groupName);
}
@Override
public Instance selectOneHealthyInstance(String serviceName, boolean subscribe)
throws NacosException {
return delegate.selectOneHealthyInstance(serviceName, subscribe);
}
@Override
public Instance selectOneHealthyInstance(String serviceName, String groupName,
boolean subscribe) throws NacosException {
return delegate.selectOneHealthyInstance(serviceName, groupName, subscribe);
}
@Override
public Instance selectOneHealthyInstance(String serviceName, List<String> clusters)
throws NacosException {
return delegate.selectOneHealthyInstance(serviceName, clusters); return delegate.selectOneHealthyInstance(serviceName, clusters);
} }
@Override @Override
public void subscribe(String serviceName, EventListener listener) throws NacosException { public Instance selectOneHealthyInstance(String serviceName, String groupName,
List<String> clusters) throws NacosException {
return delegate.selectOneHealthyInstance(serviceName, groupName, clusters);
}
@Override
public Instance selectOneHealthyInstance(String serviceName, List<String> clusters,
boolean subscribe) throws NacosException {
return delegate.selectOneHealthyInstance(serviceName, clusters, subscribe);
}
@Override
public Instance selectOneHealthyInstance(String serviceName, String groupName,
List<String> clusters, boolean subscribe) throws NacosException {
return delegate.selectOneHealthyInstance(serviceName, groupName, clusters,
subscribe);
}
@Override
public void subscribe(String serviceName, EventListener listener)
throws NacosException {
delegate.subscribe(serviceName, listener); delegate.subscribe(serviceName, listener);
} }
@Override @Override
public void subscribe(String serviceName, List<String> clusters, EventListener listener) throws NacosException { public void subscribe(String serviceName, String groupName, EventListener listener)
throws NacosException {
delegate.subscribe(serviceName, groupName, listener);
}
@Override
public void subscribe(String serviceName, List<String> clusters,
EventListener listener) throws NacosException {
delegate.subscribe(serviceName, clusters, listener); delegate.subscribe(serviceName, clusters, listener);
} }
@Override @Override
public void unsubscribe(String serviceName, EventListener listener) throws NacosException { public void subscribe(String serviceName, String groupName, List<String> clusters,
EventListener listener) throws NacosException {
delegate.subscribe(serviceName, groupName, clusters, listener);
}
@Override
public void unsubscribe(String serviceName, EventListener listener)
throws NacosException {
delegate.unsubscribe(serviceName, listener); delegate.unsubscribe(serviceName, listener);
} }
@Override @Override
public void unsubscribe(String serviceName, List<String> clusters, EventListener listener) throws NacosException { public void unsubscribe(String serviceName, String groupName, EventListener listener)
throws NacosException {
delegate.unsubscribe(serviceName, groupName, listener);
}
@Override
public void unsubscribe(String serviceName, List<String> clusters,
EventListener listener) throws NacosException {
delegate.unsubscribe(serviceName, clusters, listener); delegate.unsubscribe(serviceName, clusters, listener);
} }
@Override @Override
public ListView<String> getServicesOfServer(int pageNo, int pageSize) throws NacosException { public void unsubscribe(String serviceName, String groupName, List<String> clusters,
EventListener listener) throws NacosException {
delegate.unsubscribe(serviceName, groupName, clusters, listener);
}
@Override
public ListView<String> getServicesOfServer(int pageNo, int pageSize)
throws NacosException {
return delegate.getServicesOfServer(pageNo, pageSize); return delegate.getServicesOfServer(pageNo, pageSize);
} }
@Override
public ListView<String> getServicesOfServer(int pageNo, int pageSize,
String groupName) throws NacosException {
return delegate.getServicesOfServer(pageNo, pageSize, groupName);
}
@Override
public ListView<String> getServicesOfServer(int pageNo, int pageSize,
AbstractSelector selector) throws NacosException {
return delegate.getServicesOfServer(pageNo, pageSize, selector);
}
@Override
public ListView<String> getServicesOfServer(int pageNo, int pageSize,
String groupName, AbstractSelector selector) throws NacosException {
return delegate.getServicesOfServer(pageNo, pageSize, groupName, selector);
}
@Override @Override
public List<ServiceInfo> getSubscribeServices() throws NacosException { public List<ServiceInfo> getSubscribeServices() throws NacosException {
return delegate.getSubscribeServices(); return delegate.getSubscribeServices();
@ -136,8 +362,23 @@ class DelegatingNamingService implements NamingService, NacosServiceMetaData {
return delegate.getServerStatus(); return delegate.getServerStatus();
} }
@Override
public void shutDown() throws NacosException {
delegate.shutDown();
}
@Override @Override
public Properties getProperties() { public Properties getProperties() {
return properties; return properties;
} }
/**
* Destroy lifecycle method to invoke {@link #shutDown()}
* @throws Exception
* @since 1.0.0
*/
@Override
public void destroy() throws Exception {
shutDown();
}
} }

View File

@ -16,14 +16,15 @@
*/ */
package com.alibaba.nacos.spring.factory; package com.alibaba.nacos.spring.factory;
import java.util.Collection;
import java.util.Properties;
import com.alibaba.nacos.api.NacosFactory; import com.alibaba.nacos.api.NacosFactory;
import com.alibaba.nacos.api.config.ConfigService; import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.exception.NacosException; import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.NamingMaintainService;
import com.alibaba.nacos.api.naming.NamingService; import com.alibaba.nacos.api.naming.NamingService;
import java.util.Collection;
import java.util.Properties;
/** /**
* Nacos Service Factory * Nacos Service Factory
* *
@ -58,6 +59,17 @@ public interface NacosServiceFactory {
*/ */
NamingService createNamingService(Properties properties) throws NacosException; NamingService createNamingService(Properties properties) throws NacosException;
/**
* Create {@link NamingMaintainService} instance
*
* @param properties init param
* @return a {@link NamingMaintainService} instance
* @throws NacosException If creation is failed.
* @see NacosFactory#createNamingService(Properties)
*/
NamingMaintainService createNamingMaintainService(Properties properties)
throws NacosException;
/** /**
* Get all instances of {@link ConfigService} * Get all instances of {@link ConfigService}
* *
@ -72,4 +84,11 @@ public interface NacosServiceFactory {
*/ */
Collection<NamingService> getNamingServices(); Collection<NamingService> getNamingServices();
/**
* Get all instances of {@link NamingMaintainService}
*
* @return read-only {@link Collection}
*/
Collection<NamingMaintainService> getNamingMaintainService();
} }

View File

@ -16,12 +16,12 @@
*/ */
package com.alibaba.nacos.spring.metadata; package com.alibaba.nacos.spring.metadata;
import java.util.Properties;
import com.alibaba.nacos.api.annotation.NacosProperties; import com.alibaba.nacos.api.annotation.NacosProperties;
import com.alibaba.nacos.api.config.ConfigService; import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.naming.NamingService; import com.alibaba.nacos.api.naming.NamingService;
import java.util.Properties;
/** /**
* An interface exposes the Meta-Data of Nacos Service * An interface exposes the Meta-Data of Nacos Service
* *

View File

@ -0,0 +1,40 @@
/*
* 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 com.alibaba.nacos.spring.util;
/**
* The user inherits the AbstraceConfigParse abstract class and adds the implementation
* class in META-INF/com.alibaba.nacos.spring.util.ConfigParse to implement the addition
* of custom parsing rules. If the dataId and group methods are not overridden, Will
* override the original parsing rule implementation, otherwise the user-defined parsing
* rules will only be applied to specific dataId and group
*
* @author <a href="mailto:liaochunyhm@live.com">liaochuntao</a>
* @since 0.3.0
*/
public abstract class AbstractConfigParse implements ConfigParse {
@Override
public String dataId() {
return "";
}
@Override
public String group() {
return "";
}
}

View File

@ -0,0 +1,57 @@
/*
* 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 com.alibaba.nacos.spring.util;
import java.util.Map;
import java.util.Properties;
/**
* @author <a href="mailto:liaochunyhm@live.com">liaochuntao</a>
* @since 0.3.0
*/
public interface ConfigParse {
/**
* parse config context to map
*
* @param configText receive config context
* @return {@link Properties}
*/
Map<String, Object> parse(String configText);
/**
* get this ConfigParse process config type
*
* @return this parse process type
*/
String processType();
/**
* get config dataId
*
* @return dataId
*/
String dataId();
/**
* get config group
*
* @return group
*/
String group();
}

View File

@ -0,0 +1,142 @@
/*
* 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 com.alibaba.nacos.spring.util;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.ServiceLoader;
import com.alibaba.nacos.spring.util.parse.DefaultJsonConfigParse;
import com.alibaba.nacos.spring.util.parse.DefaultPropertiesConfigParse;
import com.alibaba.nacos.spring.util.parse.DefaultXmlConfigParse;
import com.alibaba.nacos.spring.util.parse.DefaultYamlConfigParse;
/**
* @author <a href="mailto:liaochunyhm@live.com">liaochuntao</a>
* @since 0.3.0
*/
public final class ConfigParseUtils {
private static final String LINK_CHAR = "#@#";
private static Map<String, ConfigParse> DEFAULT_CONFIG_PARSE_MAP = new HashMap(8);
private static Map<String, Map<String, ConfigParse>> CUSTOMER_CONFIG_PARSE_MAP = new HashMap(
8);
static {
DefaultJsonConfigParse jsonConfigParse = new DefaultJsonConfigParse();
DefaultPropertiesConfigParse propertiesConfigParse = new DefaultPropertiesConfigParse();
DefaultYamlConfigParse yamlConfigParse = new DefaultYamlConfigParse();
DefaultXmlConfigParse xmlConfigParse = new DefaultXmlConfigParse();
// register nacos default ConfigParse
DEFAULT_CONFIG_PARSE_MAP.put(jsonConfigParse.processType().toLowerCase(),
jsonConfigParse);
DEFAULT_CONFIG_PARSE_MAP.put(propertiesConfigParse.processType().toLowerCase(),
propertiesConfigParse);
DEFAULT_CONFIG_PARSE_MAP.put(yamlConfigParse.processType().toLowerCase(),
yamlConfigParse);
DEFAULT_CONFIG_PARSE_MAP.put(xmlConfigParse.processType().toLowerCase(),
xmlConfigParse);
// register customer ConfigParse
ServiceLoader<ConfigParse> configParses = ServiceLoader.load(ConfigParse.class);
StringBuilder sb = new StringBuilder();
for (ConfigParse configParse : configParses) {
String type = configParse.processType().toLowerCase();
if (!CUSTOMER_CONFIG_PARSE_MAP.containsKey(type)) {
CUSTOMER_CONFIG_PARSE_MAP.put(type, new HashMap<String, ConfigParse>(1));
}
sb.setLength(0);
sb.append(configParse.dataId()).append(LINK_CHAR).append(configParse.group());
if (LINK_CHAR.equals(sb.toString())) {
// If the user does not set the data id and group processed by config
// parse,
// this type of config is resolved globally by default
DEFAULT_CONFIG_PARSE_MAP.put(type, configParse);
}
else {
CUSTOMER_CONFIG_PARSE_MAP.get(type).put(sb.toString(), configParse);
}
}
DEFAULT_CONFIG_PARSE_MAP = Collections.unmodifiableMap(DEFAULT_CONFIG_PARSE_MAP);
CUSTOMER_CONFIG_PARSE_MAP = Collections
.unmodifiableMap(CUSTOMER_CONFIG_PARSE_MAP);
}
public static Map<String, Object> toProperties(final String context, String type) {
if (context == null) {
return new LinkedHashMap<String, Object>();
}
// Again the type lowercase, ensure the search
type = type.toLowerCase();
if (DEFAULT_CONFIG_PARSE_MAP.containsKey(type)) {
ConfigParse configParse = DEFAULT_CONFIG_PARSE_MAP.get(type);
Map<String, Object> parseMap = configParse.parse(context);
return parseMap == null ? new HashMap<>() : parseMap;
}
else {
throw new UnsupportedOperationException(
"Parsing is not yet supported for this type profile : " + type);
}
}
public static Map<String, Object> toProperties(final String dataId,
final String group, final String context, String type) {
if (context == null) {
return new LinkedHashMap<String, Object>();
}
// Again the type lowercase, ensure the search
type = type.toLowerCase();
String configParseKey = dataId + LINK_CHAR + group;
if (CUSTOMER_CONFIG_PARSE_MAP.isEmpty() || LINK_CHAR.equals(configParseKey)) {
return toProperties(context, type);
}
if (CUSTOMER_CONFIG_PARSE_MAP.get(type) == null
|| CUSTOMER_CONFIG_PARSE_MAP.get(type).isEmpty()) {
return toProperties(context, type);
}
if (CUSTOMER_CONFIG_PARSE_MAP.get(type).get(configParseKey) == null) {
return toProperties(context, type);
}
else {
if (CUSTOMER_CONFIG_PARSE_MAP.containsKey(type)) {
ConfigParse configParse = CUSTOMER_CONFIG_PARSE_MAP.get(type)
.get(configParseKey);
if (configParse == null) {
throw new NoSuchElementException(
"This config can't find ConfigParse to parse");
}
return configParse.parse(context);
}
else {
throw new UnsupportedOperationException(
"Parsing is not yet supported for this type profile : " + type);
}
}
}
}

View File

@ -16,15 +16,19 @@
*/ */
package com.alibaba.nacos.spring.util; package com.alibaba.nacos.spring.util;
import com.alibaba.nacos.api.annotation.NacosProperties; import static com.alibaba.nacos.spring.util.NacosBeanUtils.CONFIG_GLOBAL_NACOS_PROPERTIES_BEAN_NAME;
import org.springframework.beans.factory.BeanFactory; import static com.alibaba.nacos.spring.util.NacosBeanUtils.DISCOVERY_GLOBAL_NACOS_PROPERTIES_BEAN_NAME;
import static com.alibaba.nacos.spring.util.NacosBeanUtils.GLOBAL_NACOS_PROPERTIES_BEAN_NAME;
import static com.alibaba.nacos.spring.util.NacosBeanUtils.MAINTAIN_GLOBAL_NACOS_PROPERTIES_BEAN_NAME;
import static com.alibaba.nacos.spring.util.NacosUtils.merge;
import static java.util.Collections.emptyMap;
import java.util.Map; import java.util.Map;
import java.util.Properties; import java.util.Properties;
import static com.alibaba.nacos.spring.util.NacosBeanUtils.*; import org.springframework.beans.factory.BeanFactory;
import static com.alibaba.nacos.spring.util.NacosUtils.merge;
import static java.util.Collections.emptyMap; import com.alibaba.nacos.api.annotation.NacosProperties;
/** /**
* The source enumeration of Global {@link NacosProperties} * The source enumeration of Global {@link NacosProperties}
@ -47,8 +51,12 @@ public enum GlobalNacosPropertiesSource {
/** /**
* Global {@link NacosProperties} for Nacos discovery * Global {@link NacosProperties} for Nacos discovery
*/ */
DISCOVERY(DISCOVERY_GLOBAL_NACOS_PROPERTIES_BEAN_NAME); DISCOVERY(DISCOVERY_GLOBAL_NACOS_PROPERTIES_BEAN_NAME),
/**
* Global {@link NacosProperties} for Nacos maintain
*/
MAINTAIN(MAINTAIN_GLOBAL_NACOS_PROPERTIES_BEAN_NAME);
private final String beanName; private final String beanName;
@ -64,18 +72,19 @@ public enum GlobalNacosPropertiesSource {
*/ */
public Properties getMergedGlobalProperties(BeanFactory beanFactory) { public Properties getMergedGlobalProperties(BeanFactory beanFactory) {
Properties currentProperties = getProperties(beanFactory, beanName); Properties currentProperties = getProperties(beanFactory, beanName);
Properties globalProperties = getProperties(beanFactory, GLOBAL_NACOS_PROPERTIES_BEAN_NAME); Properties globalProperties = getProperties(beanFactory,
GLOBAL_NACOS_PROPERTIES_BEAN_NAME);
// merge // merge
merge(globalProperties, currentProperties); merge(globalProperties, currentProperties);
return globalProperties; return globalProperties;
} }
private Properties getProperties(BeanFactory beanFactory, String beanName) { private Properties getProperties(BeanFactory beanFactory, String beanName) {
Properties properties = new Properties(); Properties properties = new Properties();
// If Bean is absent , source will be empty. // If Bean is absent , source will be empty.
Map<?, ?> propertiesSource = beanFactory.containsBean(beanName) ? Map<?, ?> propertiesSource = beanFactory.containsBean(beanName)
beanFactory.getBean(beanName, Properties.class) : emptyMap(); ? beanFactory.getBean(beanName, Properties.class)
: emptyMap();
properties.putAll(propertiesSource); properties.putAll(propertiesSource);
return properties; return properties;
} }

View File

@ -16,19 +16,20 @@
*/ */
package com.alibaba.nacos.spring.util; package com.alibaba.nacos.spring.util;
import com.alibaba.nacos.spring.beans.factory.annotation.AnnotationNacosInjectedBeanPostProcessor; import static com.alibaba.nacos.spring.context.constants.NacosConstants.DEFAULT_NACOS_CONFIG_LISTENER_PARALLELISM;
import com.alibaba.nacos.spring.beans.factory.annotation.ConfigServiceBeanBuilder; import static com.alibaba.nacos.spring.context.constants.NacosConstants.NACOS_CONFIG_LISTENER_PARALLELISM;
import com.alibaba.nacos.spring.beans.factory.annotation.NamingServiceBeanBuilder; import static com.alibaba.nacos.spring.util.NacosUtils.resolveProperties;
import com.alibaba.nacos.spring.context.annotation.config.NacosConfigListenerMethodProcessor;
import com.alibaba.nacos.spring.context.annotation.config.NacosValueAnnotationBeanPostProcessor; import java.lang.reflect.Constructor;
import com.alibaba.nacos.spring.context.event.LoggingNacosConfigMetadataEventListener; import java.util.Map;
import com.alibaba.nacos.spring.context.properties.config.NacosConfigurationPropertiesBindingPostProcessor; import java.util.Properties;
import com.alibaba.nacos.spring.core.env.AnnotationNacosPropertySourceBuilder; import java.util.concurrent.Executor;
import com.alibaba.nacos.spring.core.env.NacosPropertySourcePostProcessor; import java.util.concurrent.ExecutorService;
import com.alibaba.nacos.spring.core.env.XmlNacosPropertySourceBuilder; import java.util.concurrent.Executors;
import com.alibaba.nacos.spring.factory.CacheableEventPublishingNacosServiceFactory; import java.util.concurrent.ThreadFactory;
import com.alibaba.nacos.spring.factory.NacosServiceFactory; import java.util.concurrent.atomic.AtomicInteger;
import com.alibaba.spring.util.BeanUtils;
import com.alibaba.nacos.spring.context.annotation.config.SpringValueAnnotationBeanPostProcessor;
import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.ArrayUtils;
import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.ListableBeanFactory; import org.springframework.beans.factory.ListableBeanFactory;
@ -44,18 +45,21 @@ import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.env.Environment; import org.springframework.core.env.Environment;
import org.springframework.core.env.PropertyResolver; import org.springframework.core.env.PropertyResolver;
import java.lang.reflect.Constructor; import com.alibaba.nacos.spring.beans.factory.annotation.AnnotationNacosInjectedBeanPostProcessor;
import java.util.Map; import com.alibaba.nacos.spring.beans.factory.annotation.ConfigServiceBeanBuilder;
import java.util.Properties; import com.alibaba.nacos.spring.beans.factory.annotation.NamingMaintainServiceBeanBuilder;
import java.util.concurrent.Executor; import com.alibaba.nacos.spring.beans.factory.annotation.NamingServiceBeanBuilder;
import java.util.concurrent.ExecutorService; import com.alibaba.nacos.spring.context.annotation.config.NacosConfigListenerMethodProcessor;
import java.util.concurrent.Executors; import com.alibaba.nacos.spring.context.annotation.config.NacosValueAnnotationBeanPostProcessor;
import java.util.concurrent.ThreadFactory; import com.alibaba.nacos.spring.context.event.LoggingNacosConfigMetadataEventListener;
import java.util.concurrent.atomic.AtomicInteger; import com.alibaba.nacos.spring.context.properties.config.NacosConfigurationPropertiesBindingPostProcessor;
import com.alibaba.nacos.spring.core.env.AnnotationNacosPropertySourceBuilder;
import static com.alibaba.nacos.spring.context.constants.NacosConstants.DEFAULT_NACOS_CONFIG_LISTENER_PARALLELISM; import com.alibaba.nacos.spring.core.env.NacosPropertySourcePostProcessor;
import static com.alibaba.nacos.spring.context.constants.NacosConstants.NACOS_CONFIG_LISTENER_PARALLELISM; import com.alibaba.nacos.spring.core.env.XmlNacosPropertySourceBuilder;
import static com.alibaba.nacos.spring.util.NacosUtils.resolveProperties; import com.alibaba.nacos.spring.factory.ApplicationContextHolder;
import com.alibaba.nacos.spring.factory.CacheableEventPublishingNacosServiceFactory;
import com.alibaba.nacos.spring.factory.NacosServiceFactory;
import com.alibaba.spring.util.BeanUtils;
/** /**
* Nacos Bean Utilities class * Nacos Bean Utilities class
@ -84,14 +88,31 @@ public abstract class NacosBeanUtils {
/** /**
* The bean name of global Nacos {@link Properties} for discovery * The bean name of global Nacos {@link Properties} for discovery
*/ */
public static final String DISCOVERY_GLOBAL_NACOS_PROPERTIES_BEAN_NAME = GLOBAL_NACOS_PROPERTIES_BEAN_NAME + public static final String DISCOVERY_GLOBAL_NACOS_PROPERTIES_BEAN_NAME = GLOBAL_NACOS_PROPERTIES_BEAN_NAME
"$discovery"; + "$discovery";
/**
* The bean name of global Nacos {@link Properties} for maintain
*/
public static final String MAINTAIN_GLOBAL_NACOS_PROPERTIES_BEAN_NAME = GLOBAL_NACOS_PROPERTIES_BEAN_NAME
+ "$maintain";
/** /**
* The bean name of {@link Executor} for Nacos Config Listener * The bean name of {@link Executor} for Nacos Config Listener
*/ */
public static final String NACOS_CONFIG_LISTENER_EXECUTOR_BEAN_NAME = "nacosConfigListenerExecutor"; public static final String NACOS_CONFIG_LISTENER_EXECUTOR_BEAN_NAME = "nacosConfigListenerExecutor";
/**
* the ignoreResourceNotFound property for propertySourcesPlaceholderConfigurer
*/
public static final String IGNORE_RESOURCE_NOT_FOUND = "ignoreResourceNotFound";
/**
* the ignoreUnresolvablePlaceholders property for
* propertySourcesPlaceholderConfigurer
*/
public static final String IGNORE_UNRESOLVABLE_PLACEHOLDERS = "ignoreUnresolvablePlaceholders";
/** /**
* Register an object to be Singleton Bean * Register an object to be Singleton Bean
* *
@ -99,19 +120,24 @@ public abstract class NacosBeanUtils {
* @param beanName bean name * @param beanName bean name
* @param singletonObject singleton object * @param singletonObject singleton object
*/ */
public static void registerSingleton(BeanDefinitionRegistry registry, String beanName, Object singletonObject) { public static void registerSingleton(BeanDefinitionRegistry registry, String beanName,
Object singletonObject) {
SingletonBeanRegistry beanRegistry = null; SingletonBeanRegistry beanRegistry = null;
if (registry instanceof SingletonBeanRegistry) { if (registry instanceof SingletonBeanRegistry) {
beanRegistry = (SingletonBeanRegistry) registry; beanRegistry = (SingletonBeanRegistry) registry;
} else if (registry instanceof AbstractApplicationContext) { }
else if (registry instanceof AbstractApplicationContext) {
// Maybe AbstractApplicationContext or its sub-classes // Maybe AbstractApplicationContext or its sub-classes
beanRegistry = ((AbstractApplicationContext) registry).getBeanFactory(); beanRegistry = ((AbstractApplicationContext) registry).getBeanFactory();
} }
// Register Singleton Object if possible // Register Singleton Object if possible
if (beanRegistry != null) { if (beanRegistry != null) {
// Determine in advance whether injected with beans
if (!beanRegistry.containsSingleton(beanName)) {
beanRegistry.registerSingleton(beanName, singletonObject); beanRegistry.registerSingleton(beanName, singletonObject);
} }
} }
}
/** /**
* Register Infrastructure Bean * Register Infrastructure Bean
@ -121,17 +147,19 @@ public abstract class NacosBeanUtils {
* @param beanClass the class of bean * @param beanClass the class of bean
* @param constructorArgs the arguments of {@link Constructor} * @param constructorArgs the arguments of {@link Constructor}
*/ */
public static void registerInfrastructureBean(BeanDefinitionRegistry registry, String beanName, Class<?> beanClass, public static void registerInfrastructureBean(BeanDefinitionRegistry registry,
Object... constructorArgs) { String beanName, Class<?> beanClass, Object... constructorArgs) {
// Build a BeanDefinition for NacosServiceFactory class // Build a BeanDefinition for NacosServiceFactory class
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.rootBeanDefinition(beanClass); BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder
.rootBeanDefinition(beanClass);
for (Object constructorArg : constructorArgs) { for (Object constructorArg : constructorArgs) {
beanDefinitionBuilder.addConstructorArgValue(constructorArg); beanDefinitionBuilder.addConstructorArgValue(constructorArg);
} }
// ROLE_INFRASTRUCTURE // ROLE_INFRASTRUCTURE
beanDefinitionBuilder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); beanDefinitionBuilder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
// Register // Register
registry.registerBeanDefinition(beanName, beanDefinitionBuilder.getBeanDefinition()); registry.registerBeanDefinition(beanName,
beanDefinitionBuilder.getBeanDefinition());
} }
/** /**
@ -142,9 +170,10 @@ public abstract class NacosBeanUtils {
* @param beanClass the class of bean * @param beanClass the class of bean
* @param constructorArgs the arguments of {@link Constructor} * @param constructorArgs the arguments of {@link Constructor}
*/ */
public static void registerInfrastructureBeanIfAbsent(BeanDefinitionRegistry registry, String beanName, Class<?> beanClass, public static void registerInfrastructureBeanIfAbsent(BeanDefinitionRegistry registry,
Object... constructorArgs) { String beanName, Class<?> beanClass, Object... constructorArgs) {
if (!isBeanDefinitionPresent(registry, beanName, beanClass) && !registry.containsBeanDefinition(beanName)) { if (!isBeanDefinitionPresent(registry, beanName, beanClass)
&& !registry.containsBeanDefinition(beanName)) {
registerInfrastructureBean(registry, beanName, beanClass, constructorArgs); registerInfrastructureBean(registry, beanName, beanClass, constructorArgs);
} }
} }
@ -174,8 +203,10 @@ public abstract class NacosBeanUtils {
* @param targetBeanClass the type of bean * @param targetBeanClass the type of bean
* @return If Present , return <code>true</code> * @return If Present , return <code>true</code>
*/ */
public static boolean isBeanDefinitionPresent(BeanDefinitionRegistry registry, String beanName, Class<?> targetBeanClass) { public static boolean isBeanDefinitionPresent(BeanDefinitionRegistry registry,
String[] beanNames = BeanUtils.getBeanNames((ListableBeanFactory) registry, targetBeanClass); String beanName, Class<?> targetBeanClass) {
String[] beanNames = BeanUtils.getBeanNames((ListableBeanFactory) registry,
targetBeanClass);
return ArrayUtils.contains(beanNames, beanName); return ArrayUtils.contains(beanNames, beanName);
} }
@ -183,95 +214,128 @@ public abstract class NacosBeanUtils {
* Register {@link PropertySourcesPlaceholderConfigurer} Bean * Register {@link PropertySourcesPlaceholderConfigurer} Bean
* *
* @param registry {@link BeanDefinitionRegistry} * @param registry {@link BeanDefinitionRegistry}
* @param beanFactory {@link BeanFactory}
*/ */
public static void registerPropertySourcesPlaceholderConfigurer(BeanDefinitionRegistry registry) { public static void registerPropertySourcesPlaceholderConfigurer(
BeanDefinitionRegistry registry, BeanFactory beanFactory) {
registerInfrastructureBeanIfAbsent(registry, PLACEHOLDER_CONFIGURER_BEAN_NAME, registerInfrastructureBeanIfAbsent(registry, PLACEHOLDER_CONFIGURER_BEAN_NAME,
PropertySourcesPlaceholderConfigurer.class); PropertySourcesPlaceholderConfigurer.class);
}
/*
* If you can't guarantee your old project properties file and config items are
* complete please setIgnoreUnresolvablePlaceholders setIgnoreResourceNotFound
* is true if not,you may not be able to start the spring container and your
* application
*/
boolean ignoreResourceNotFound = Boolean
.parseBoolean(System.getProperty(IGNORE_RESOURCE_NOT_FOUND));
boolean ignoreUnresolvablePlaceholders = Boolean
.parseBoolean(System.getProperty(IGNORE_UNRESOLVABLE_PLACEHOLDERS));
if (ignoreResourceNotFound || ignoreUnresolvablePlaceholders) {
PropertySourcesPlaceholderConfigurer configurer = (PropertySourcesPlaceholderConfigurer) beanFactory
.getBean(NacosBeanUtils.PLACEHOLDER_CONFIGURER_BEAN_NAME);
if (configurer != null) {
configurer.setIgnoreResourceNotFound(ignoreResourceNotFound);
configurer.setIgnoreUnresolvablePlaceholders(
ignoreUnresolvablePlaceholders);
}
}
}
/** /**
* Register Global Nacos Properties Bean with specified name * Register Global Nacos Properties Bean with specified name
* *
* @param attributes the attributes of Global Nacos Properties may contain placeholders * @param attributes the attributes of Global Nacos Properties may contain
* placeholders
* @param registry {@link BeanDefinitionRegistry} * @param registry {@link BeanDefinitionRegistry}
* @param propertyResolver {@link PropertyResolver} * @param propertyResolver {@link PropertyResolver}
* @param beanName Bean name * @param beanName Bean name
*/ */
public static void registerGlobalNacosProperties(AnnotationAttributes attributes, public static void registerGlobalNacosProperties(AnnotationAttributes attributes,
BeanDefinitionRegistry registry, BeanDefinitionRegistry registry, PropertyResolver propertyResolver,
PropertyResolver propertyResolver,
String beanName) { String beanName) {
if (attributes == null) { if (attributes == null) {
return; // Compatible with null return; // Compatible with null
} }
AnnotationAttributes globalPropertiesAttributes = attributes.getAnnotation("globalProperties"); AnnotationAttributes globalPropertiesAttributes = attributes
registerGlobalNacosProperties((Map<?, ?>) globalPropertiesAttributes, registry, propertyResolver, .getAnnotation("globalProperties");
beanName); registerGlobalNacosProperties((Map<?, ?>) globalPropertiesAttributes, registry,
propertyResolver, beanName);
} }
/** /**
* Register Global Nacos Properties Bean with specified name * Register Global Nacos Properties Bean with specified name
* *
* @param globalPropertiesAttributes the attributes of Global Nacos Properties may contain placeholders * @param globalPropertiesAttributes the attributes of Global Nacos Properties may
* contain placeholders
* @param registry {@link BeanDefinitionRegistry} * @param registry {@link BeanDefinitionRegistry}
* @param propertyResolver {@link PropertyResolver} * @param propertyResolver {@link PropertyResolver}
* @param beanName Bean name * @param beanName Bean name
*/ */
public static void registerGlobalNacosProperties(Map<?, ?> globalPropertiesAttributes, public static void registerGlobalNacosProperties(Map<?, ?> globalPropertiesAttributes,
BeanDefinitionRegistry registry, BeanDefinitionRegistry registry, PropertyResolver propertyResolver,
PropertyResolver propertyResolver,
String beanName) { String beanName) {
Properties globalProperties = resolveProperties(globalPropertiesAttributes, propertyResolver); Properties globalProperties = resolveProperties(globalPropertiesAttributes,
propertyResolver);
registerSingleton(registry, beanName, globalProperties); registerSingleton(registry, beanName, globalProperties);
} }
public static void registerNacosApplicationContextHolder(
/** BeanDefinitionRegistry registry) {
* Register {@link CacheableEventPublishingNacosServiceFactory NacosServiceFactory} registerInfrastructureBeanIfAbsent(registry, ApplicationContextHolder.BEAN_NAME,
* ApplicationContextHolder.class);
* @param registry {@link BeanDefinitionRegistry}
*/
public static void registerNacosServiceFactory(BeanDefinitionRegistry registry) {
registerInfrastructureBeanIfAbsent(registry, CacheableEventPublishingNacosServiceFactory.BEAN_NAME,
CacheableEventPublishingNacosServiceFactory.class);
} }
public static void registerNacosConfigPropertiesBindingPostProcessor(BeanDefinitionRegistry registry) { public static void registerNacosConfigPropertiesBindingPostProcessor(
registerInfrastructureBeanIfAbsent(registry, NacosConfigurationPropertiesBindingPostProcessor.BEAN_NAME, BeanDefinitionRegistry registry) {
registerInfrastructureBeanIfAbsent(registry,
NacosConfigurationPropertiesBindingPostProcessor.BEAN_NAME,
NacosConfigurationPropertiesBindingPostProcessor.class); NacosConfigurationPropertiesBindingPostProcessor.class);
} }
public static void registerNacosConfigListenerMethodProcessor(BeanDefinitionRegistry registry) { public static void registerNacosConfigListenerMethodProcessor(
registerInfrastructureBeanIfAbsent(registry, NacosConfigListenerMethodProcessor.BEAN_NAME, BeanDefinitionRegistry registry) {
registerInfrastructureBeanIfAbsent(registry,
NacosConfigListenerMethodProcessor.BEAN_NAME,
NacosConfigListenerMethodProcessor.class); NacosConfigListenerMethodProcessor.class);
} }
public static void registerNacosPropertySourcePostProcessor(BeanDefinitionRegistry registry) { public static void registerNacosPropertySourcePostProcessor(
registerInfrastructureBeanIfAbsent(registry, NacosPropertySourcePostProcessor.BEAN_NAME, BeanDefinitionRegistry registry) {
registerInfrastructureBeanIfAbsent(registry,
NacosPropertySourcePostProcessor.BEAN_NAME,
NacosPropertySourcePostProcessor.class); NacosPropertySourcePostProcessor.class);
} }
public static void registerAnnotationNacosPropertySourceBuilder(BeanDefinitionRegistry registry) { public static void registerAnnotationNacosPropertySourceBuilder(
registerInfrastructureBeanIfAbsent(registry, AnnotationNacosPropertySourceBuilder.BEAN_NAME, BeanDefinitionRegistry registry) {
registerInfrastructureBeanIfAbsent(registry,
AnnotationNacosPropertySourceBuilder.BEAN_NAME,
AnnotationNacosPropertySourceBuilder.class); AnnotationNacosPropertySourceBuilder.class);
} }
public static void registerXmlNacosPropertySourceBuilder(BeanDefinitionRegistry registry) { public static void registerXmlNacosPropertySourceBuilder(
registerInfrastructureBeanIfAbsent(registry, XmlNacosPropertySourceBuilder.BEAN_NAME, BeanDefinitionRegistry registry) {
registerInfrastructureBeanIfAbsent(registry,
XmlNacosPropertySourceBuilder.BEAN_NAME,
XmlNacosPropertySourceBuilder.class); XmlNacosPropertySourceBuilder.class);
} }
public static void registerNacosConfigListenerExecutor(BeanDefinitionRegistry registry, Environment environment) { public static void registerNacosConfigListenerExecutor(
BeanDefinitionRegistry registry, Environment environment) {
final String beanName = NACOS_CONFIG_LISTENER_EXECUTOR_BEAN_NAME; final String beanName = NACOS_CONFIG_LISTENER_EXECUTOR_BEAN_NAME;
if (registry instanceof BeanFactory && ((BeanFactory) registry).containsBean(beanName)) { if (registry instanceof BeanFactory
&& ((BeanFactory) registry).containsBean(beanName)) {
return; return;
} }
ExecutorService nacosConfigListenerExecutor = buildNacosConfigListenerExecutor(environment); ExecutorService nacosConfigListenerExecutor = buildNacosConfigListenerExecutor(
environment);
registerSingleton(registry, beanName, nacosConfigListenerExecutor); registerSingleton(registry, beanName, nacosConfigListenerExecutor);
} }
private static ExecutorService buildNacosConfigListenerExecutor(Environment environment) { private static ExecutorService buildNacosConfigListenerExecutor(
Environment environment) {
int parallelism = getParallelism(environment); int parallelism = getParallelism(environment);
return Executors.newFixedThreadPool(parallelism, new ThreadFactory() { return Executors.newFixedThreadPool(parallelism, new ThreadFactory() {
private final AtomicInteger threadNumber = new AtomicInteger(1); private final AtomicInteger threadNumber = new AtomicInteger(1);
@ -279,31 +343,41 @@ public abstract class NacosBeanUtils {
@Override @Override
public Thread newThread(Runnable r) { public Thread newThread(Runnable r) {
Thread thread = new Thread(r); Thread thread = new Thread(r);
thread.setName("NacosConfigListener-ThreadPool-" + threadNumber.getAndIncrement()); thread.setName("NacosConfigListener-ThreadPool-"
+ threadNumber.getAndIncrement());
return thread; return thread;
} }
}); });
} }
private static int getParallelism(Environment environment) { private static int getParallelism(Environment environment) {
int parallelism = environment.getProperty(NACOS_CONFIG_LISTENER_PARALLELISM, int.class, int parallelism = environment.getProperty(NACOS_CONFIG_LISTENER_PARALLELISM,
DEFAULT_NACOS_CONFIG_LISTENER_PARALLELISM); int.class, DEFAULT_NACOS_CONFIG_LISTENER_PARALLELISM);
return parallelism < 1 ? DEFAULT_NACOS_CONFIG_LISTENER_PARALLELISM : parallelism; return parallelism < 1 ? DEFAULT_NACOS_CONFIG_LISTENER_PARALLELISM : parallelism;
} }
public static void registerNacosValueAnnotationBeanPostProcessor(BeanDefinitionRegistry registry) { public static void registerNacosValueAnnotationBeanPostProcessor(
registerInfrastructureBeanIfAbsent(registry, NacosValueAnnotationBeanPostProcessor.BEAN_NAME, BeanDefinitionRegistry registry) {
registerInfrastructureBeanIfAbsent(registry,
NacosValueAnnotationBeanPostProcessor.BEAN_NAME,
NacosValueAnnotationBeanPostProcessor.class); NacosValueAnnotationBeanPostProcessor.class);
} }
public static void registerStringValueAnnotationBeanPostProcessor(
BeanDefinitionRegistry registry) {
registerInfrastructureBeanIfAbsent(registry,
SpringValueAnnotationBeanPostProcessor.BEAN_NAME,
SpringValueAnnotationBeanPostProcessor.class);
}
/** /**
* Register Nacos Common Beans * Register Nacos Common Beans
* *
* @param registry {@link BeanDefinitionRegistry} * @param registry {@link BeanDefinitionRegistry}
*/ */
public static void registerNacosCommonBeans(BeanDefinitionRegistry registry) { public static void registerNacosCommonBeans(BeanDefinitionRegistry registry) {
// Register NacosServiceFactory Bean // Register NacosApplicationContextHolder Bean
registerNacosServiceFactory(registry); registerNacosApplicationContextHolder(registry);
// Register AnnotationNacosInjectedBeanPostProcessor Bean // Register AnnotationNacosInjectedBeanPostProcessor Bean
registerAnnotationNacosInjectedBeanPostProcessor(registry); registerAnnotationNacosInjectedBeanPostProcessor(registry);
} }
@ -313,10 +387,12 @@ public abstract class NacosBeanUtils {
* *
* @param registry {@link BeanDefinitionRegistry} * @param registry {@link BeanDefinitionRegistry}
* @param environment {@link Environment} * @param environment {@link Environment}
* @param beanFactory {@link BeanFactory}
*/ */
public static void registerNacosConfigBeans(BeanDefinitionRegistry registry, Environment environment) { public static void registerNacosConfigBeans(BeanDefinitionRegistry registry,
Environment environment, BeanFactory beanFactory) {
// Register PropertySourcesPlaceholderConfigurer Bean // Register PropertySourcesPlaceholderConfigurer Bean
registerPropertySourcesPlaceholderConfigurer(registry); registerPropertySourcesPlaceholderConfigurer(registry, beanFactory);
registerNacosConfigPropertiesBindingPostProcessor(registry); registerNacosConfigPropertiesBindingPostProcessor(registry);
@ -330,6 +406,8 @@ public abstract class NacosBeanUtils {
registerNacosValueAnnotationBeanPostProcessor(registry); registerNacosValueAnnotationBeanPostProcessor(registry);
registerStringValueAnnotationBeanPostProcessor(registry);
registerConfigServiceBeanBuilder(registry); registerConfigServiceBeanBuilder(registry);
registerLoggingNacosConfigMetadataEventListener(registry); registerLoggingNacosConfigMetadataEventListener(registry);
@ -341,9 +419,11 @@ public abstract class NacosBeanUtils {
* @param beanFactory {@link BeanFactory} * @param beanFactory {@link BeanFactory}
*/ */
public static void invokeNacosPropertySourcePostProcessor(BeanFactory beanFactory) { public static void invokeNacosPropertySourcePostProcessor(BeanFactory beanFactory) {
NacosPropertySourcePostProcessor postProcessor = NacosPropertySourcePostProcessor postProcessor = beanFactory.getBean(
beanFactory.getBean(NacosPropertySourcePostProcessor.BEAN_NAME, NacosPropertySourcePostProcessor.class); NacosPropertySourcePostProcessor.BEAN_NAME,
postProcessor.postProcessBeanFactory((ConfigurableListableBeanFactory) beanFactory); NacosPropertySourcePostProcessor.class);
postProcessor
.postProcessBeanFactory((ConfigurableListableBeanFactory) beanFactory);
} }
/** /**
@ -351,8 +431,10 @@ public abstract class NacosBeanUtils {
* *
* @param registry {@link BeanDefinitionRegistry} * @param registry {@link BeanDefinitionRegistry}
*/ */
private static void registerLoggingNacosConfigMetadataEventListener(BeanDefinitionRegistry registry) { private static void registerLoggingNacosConfigMetadataEventListener(
registerInfrastructureBeanIfAbsent(registry, LoggingNacosConfigMetadataEventListener.BEAN_NAME, BeanDefinitionRegistry registry) {
registerInfrastructureBeanIfAbsent(registry,
LoggingNacosConfigMetadataEventListener.BEAN_NAME,
LoggingNacosConfigMetadataEventListener.class); LoggingNacosConfigMetadataEventListener.class);
} }
@ -363,6 +445,7 @@ public abstract class NacosBeanUtils {
*/ */
public static void registerNacosDiscoveryBeans(BeanDefinitionRegistry registry) { public static void registerNacosDiscoveryBeans(BeanDefinitionRegistry registry) {
registerNamingServiceBeanBuilder(registry); registerNamingServiceBeanBuilder(registry);
registerNamingMaintainServiceBeanBuilder(registry);
} }
/** /**
@ -371,17 +454,30 @@ public abstract class NacosBeanUtils {
* *
* @param registry {@link BeanDefinitionRegistry} * @param registry {@link BeanDefinitionRegistry}
*/ */
private static void registerAnnotationNacosInjectedBeanPostProcessor(BeanDefinitionRegistry registry) { private static void registerAnnotationNacosInjectedBeanPostProcessor(
registerInfrastructureBeanIfAbsent(registry, AnnotationNacosInjectedBeanPostProcessor.BEAN_NAME, BeanDefinitionRegistry registry) {
registerInfrastructureBeanIfAbsent(registry,
AnnotationNacosInjectedBeanPostProcessor.BEAN_NAME,
AnnotationNacosInjectedBeanPostProcessor.class); AnnotationNacosInjectedBeanPostProcessor.class);
} }
private static void registerConfigServiceBeanBuilder(BeanDefinitionRegistry registry) { private static void registerConfigServiceBeanBuilder(
registerInfrastructureBeanIfAbsent(registry, ConfigServiceBeanBuilder.BEAN_NAME, ConfigServiceBeanBuilder.class); BeanDefinitionRegistry registry) {
registerInfrastructureBeanIfAbsent(registry, ConfigServiceBeanBuilder.BEAN_NAME,
ConfigServiceBeanBuilder.class);
} }
private static void registerNamingServiceBeanBuilder(BeanDefinitionRegistry registry) { private static void registerNamingServiceBeanBuilder(
registerInfrastructureBeanIfAbsent(registry, NamingServiceBeanBuilder.BEAN_NAME, NamingServiceBeanBuilder.class); BeanDefinitionRegistry registry) {
registerInfrastructureBeanIfAbsent(registry, NamingServiceBeanBuilder.BEAN_NAME,
NamingServiceBeanBuilder.class);
}
private static void registerNamingMaintainServiceBeanBuilder(
BeanDefinitionRegistry registry) {
registerInfrastructureBeanIfAbsent(registry,
NamingMaintainServiceBeanBuilder.BEAN_NAME,
NamingMaintainServiceBeanBuilder.class);
} }
/** /**
@ -391,7 +487,8 @@ public abstract class NacosBeanUtils {
* @return Global Properties Bean * @return Global Properties Bean
* @throws NoSuchBeanDefinitionException if there is no such bean definition * @throws NoSuchBeanDefinitionException if there is no such bean definition
*/ */
public static Properties getGlobalPropertiesBean(BeanFactory beanFactory) throws NoSuchBeanDefinitionException { public static Properties getGlobalPropertiesBean(BeanFactory beanFactory)
throws NoSuchBeanDefinitionException {
return beanFactory.getBean(GLOBAL_NACOS_PROPERTIES_BEAN_NAME, Properties.class); return beanFactory.getBean(GLOBAL_NACOS_PROPERTIES_BEAN_NAME, Properties.class);
} }
@ -402,8 +499,29 @@ public abstract class NacosBeanUtils {
* @return {@link NacosServiceFactory} Bean * @return {@link NacosServiceFactory} Bean
* @throws NoSuchBeanDefinitionException if there is no such bean definition * @throws NoSuchBeanDefinitionException if there is no such bean definition
*/ */
public static NacosServiceFactory getNacosServiceFactoryBean(BeanFactory beanFactory) throws NoSuchBeanDefinitionException { public static NacosServiceFactory getNacosServiceFactoryBean(BeanFactory beanFactory)
return beanFactory.getBean(CacheableEventPublishingNacosServiceFactory.BEAN_NAME, NacosServiceFactory.class); throws NoSuchBeanDefinitionException {
if (null == beanFactory) {
return getNacosServiceFactoryBean();
}
ApplicationContextHolder applicationContextHolder = getApplicationContextHolder(
beanFactory);
CacheableEventPublishingNacosServiceFactory nacosServiceFactory = CacheableEventPublishingNacosServiceFactory
.getSingleton();
nacosServiceFactory
.setApplicationContext(applicationContextHolder.getApplicationContext());
return nacosServiceFactory;
}
public static NacosServiceFactory getNacosServiceFactoryBean()
throws NoSuchBeanDefinitionException {
return CacheableEventPublishingNacosServiceFactory.getSingleton();
}
public static ApplicationContextHolder getApplicationContextHolder(
BeanFactory beanFactory) throws NoSuchBeanDefinitionException {
return beanFactory.getBean(ApplicationContextHolder.BEAN_NAME,
ApplicationContextHolder.class);
} }
/** /**
@ -412,11 +530,13 @@ public abstract class NacosBeanUtils {
* @param beanFactory {@link BeanFactory} * @param beanFactory {@link BeanFactory}
* @return {@link Executor} Bean If Present, or <code>null</code> * @return {@link Executor} Bean If Present, or <code>null</code>
*/ */
public static ExecutorService getNacosConfigListenerExecutorIfPresent(BeanFactory beanFactory) { public static ExecutorService getNacosConfigListenerExecutorIfPresent(
BeanFactory beanFactory) {
if (!beanFactory.containsBean(NACOS_CONFIG_LISTENER_EXECUTOR_BEAN_NAME)) { if (!beanFactory.containsBean(NACOS_CONFIG_LISTENER_EXECUTOR_BEAN_NAME)) {
return null; return null;
} }
return beanFactory.getBean(NACOS_CONFIG_LISTENER_EXECUTOR_BEAN_NAME, ExecutorService.class); return beanFactory.getBean(NACOS_CONFIG_LISTENER_EXECUTOR_BEAN_NAME,
ExecutorService.class);
} }
/** /**
@ -426,19 +546,36 @@ public abstract class NacosBeanUtils {
* @return {@link ConfigServiceBeanBuilder} Bean * @return {@link ConfigServiceBeanBuilder} Bean
* @throws NoSuchBeanDefinitionException if there is no such bean definition * @throws NoSuchBeanDefinitionException if there is no such bean definition
*/ */
public static ConfigServiceBeanBuilder getConfigServiceBeanBuilder(BeanFactory beanFactory) throws NoSuchBeanDefinitionException { public static ConfigServiceBeanBuilder getConfigServiceBeanBuilder(
return beanFactory.getBean(ConfigServiceBeanBuilder.BEAN_NAME, ConfigServiceBeanBuilder.class); BeanFactory beanFactory) throws NoSuchBeanDefinitionException {
return beanFactory.getBean(ConfigServiceBeanBuilder.BEAN_NAME,
ConfigServiceBeanBuilder.class);
} }
/** /**
* Get {@link NamingServiceBeanBuilder} Bean * Get {@link NamingServiceBeanBuilder} Bean
* *
* @param beanFactory {@link BeanFactory} * @param beanFactory {@link BeanFactory}
* @return {@link ConfigServiceBeanBuilder} Bean * @return {@link NamingServiceBeanBuilder} Bean
* @throws NoSuchBeanDefinitionException if there is no such bean definition * @throws NoSuchBeanDefinitionException if there is no such bean definition
*/ */
public static NamingServiceBeanBuilder getNamingServiceBeanBuilder(BeanFactory beanFactory) throws NoSuchBeanDefinitionException { public static NamingServiceBeanBuilder getNamingServiceBeanBuilder(
return beanFactory.getBean(NamingServiceBeanBuilder.BEAN_NAME, NamingServiceBeanBuilder.class); BeanFactory beanFactory) throws NoSuchBeanDefinitionException {
return beanFactory.getBean(NamingServiceBeanBuilder.BEAN_NAME,
NamingServiceBeanBuilder.class);
}
/**
* Get {@link NamingMaintainServiceBeanBuilder} Bean
*
* @param beanFactory {@link BeanFactory}
* @return {@link NamingMaintainServiceBeanBuilder} Bean
* @throws NoSuchBeanDefinitionException if there is no such bean definition
*/
public static NamingMaintainServiceBeanBuilder getNamingMaintainServiceBeanBuilder(
BeanFactory beanFactory) throws NoSuchBeanDefinitionException {
return beanFactory.getBean(NamingMaintainServiceBeanBuilder.BEAN_NAME,
NamingMaintainServiceBeanBuilder.class);
} }
} }

View File

@ -19,29 +19,40 @@ package com.alibaba.nacos.spring.util;
import com.alibaba.nacos.api.annotation.NacosProperties; import com.alibaba.nacos.api.annotation.NacosProperties;
import com.alibaba.nacos.api.config.ConfigService; import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.annotation.NacosConfigurationProperties; import com.alibaba.nacos.api.config.annotation.NacosConfigurationProperties;
import com.alibaba.nacos.api.config.annotation.NacosIgnore;
import com.alibaba.nacos.api.config.annotation.NacosProperty;
import com.alibaba.nacos.api.exception.NacosException; import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.spring.enums.FileTypeEnum;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.config.BeanExpressionContext;
import org.springframework.beans.factory.config.BeanExpressionResolver;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.expression.EnvironmentAccessor;
import org.springframework.context.expression.StandardBeanExpressionResolver;
import org.springframework.core.env.Environment; import org.springframework.core.env.Environment;
import org.springframework.core.env.PropertyResolver; import org.springframework.core.env.PropertyResolver;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.common.TemplateParserContext;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
import org.springframework.util.ReflectionUtils; import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import java.io.IOException;
import java.io.StringReader;
import java.lang.annotation.Annotation; import java.lang.annotation.Annotation;
import java.lang.reflect.Method; import java.lang.reflect.*;
import java.lang.reflect.Modifier; import java.util.*;
import java.lang.reflect.ParameterizedType; import java.util.concurrent.ConcurrentHashMap;
import java.lang.reflect.Type; import java.util.regex.Pattern;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import static com.alibaba.nacos.api.PropertyKeyConst.*; import static com.alibaba.nacos.api.PropertyKeyConst.*;
import static org.springframework.core.annotation.AnnotationUtils.getAnnotation;
import static org.springframework.core.annotation.AnnotationUtils.getAnnotationAttributes; import static org.springframework.core.annotation.AnnotationUtils.getAnnotationAttributes;
import static org.springframework.util.StringUtils.hasText;
/** /**
* Nacos Utilities class * Nacos Utilities class
@ -56,6 +67,10 @@ public abstract class NacosUtils {
*/ */
public static final String DEFAULT_STRING_ATTRIBUTE_VALUE = ""; public static final String DEFAULT_STRING_ATTRIBUTE_VALUE = "";
/**
* Default value of {@link String} attribute for {@link Annotation}
*/
public static final String DEFAULT_CONFIG_TYPE_VALUE = "properties";
/** /**
* Default value of boolean attribute for {@link Annotation} * Default value of boolean attribute for {@link Annotation}
@ -70,7 +85,21 @@ public abstract class NacosUtils {
/** /**
* Default timeout for getting Nacos configuration * Default timeout for getting Nacos configuration
*/ */
public static final long DEFAULT_TIMEOUT = Long.getLong("nacos.default.timeout", 5000L); public static final long DEFAULT_TIMEOUT = Long.getLong("nacos.default.timeout",
5000L);
private static final Set<Class<?>> NON_BEAN_CLASSES = Collections.unmodifiableSet(
new HashSet<Class<?>>(Arrays.asList(Object.class, Class.class)));
private static ExpressionParser parser = new SpelExpressionParser();
private static BeanExpressionResolver resolver = new StandardBeanExpressionResolver();
private static ConcurrentHashMap<String, Expression> expressionCache
= new ConcurrentHashMap();
private static ConcurrentHashMap<Environment, StandardEvaluationContext> environmentContextCache
= new ConcurrentHashMap();
private static final Logger logger = LoggerFactory.getLogger(NacosUtils.class); private static final Logger logger = LoggerFactory.getLogger(NacosUtils.class);
@ -82,7 +111,8 @@ public abstract class NacosUtils {
* @param properties Nacos Properties * @param properties Nacos Properties
* @return non-null * @return non-null
*/ */
public static String buildDefaultPropertySourceName(String dataId, String groupId, Map<?, ?> properties) { public static String buildDefaultPropertySourceName(String dataId, String groupId,
Map<?, ?> properties) {
return build(dataId, groupId, identify(properties)); return build(dataId, groupId, identify(properties));
} }
@ -114,7 +144,8 @@ public abstract class NacosUtils {
String secretKey = (String) properties.get(SECRET_KEY); String secretKey = (String) properties.get(SECRET_KEY);
String encode = (String) properties.get(ENCODE); String encode = (String) properties.get(ENCODE);
return build(namespace, clusterName, serverAddress, contextPath, endpoint, accessKey, secretKey, encode); return build(namespace, clusterName, serverAddress, contextPath, endpoint,
accessKey, secretKey, encode);
} }
@ -143,10 +174,13 @@ public abstract class NacosUtils {
final List<Object> records = new LinkedList<Object>(); final List<Object> records = new LinkedList<Object>();
ReflectionUtils.doWithMethods(nacosProperties.annotationType(), new ReflectionUtils.MethodCallback() { ReflectionUtils.doWithMethods(nacosProperties.annotationType(),
new ReflectionUtils.MethodCallback() {
@Override @Override
public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException { public void doWith(Method method)
if (Modifier.isPublic(method.getModifiers()) && method.getParameterTypes().length == 0) { throws IllegalArgumentException, IllegalAccessException {
if (Modifier.isPublic(method.getModifiers())
&& method.getParameterTypes().length == 0) {
Object defaultValue = method.getDefaultValue(); Object defaultValue = method.getDefaultValue();
if (defaultValue != null) { if (defaultValue != null) {
try { try {
@ -154,7 +188,8 @@ public abstract class NacosUtils {
if (!defaultValue.equals(returnValue)) { if (!defaultValue.equals(returnValue)) {
records.add(returnValue); records.add(returnValue);
} }
} catch (Exception e) { }
catch (Exception e) {
} }
} }
} }
@ -164,12 +199,106 @@ public abstract class NacosUtils {
return records.isEmpty(); return records.isEmpty();
} }
public static Properties resolveProperties(NacosProperties nacosProperties, PropertyResolver propertyResolver) { public static String readFromEnvironment(String label, Environment environment) {
String value = resolvePlaceholders(label, environment);
return StringUtils.hasText(value)
? evaluate(value, environment)
: value;
}
public static Object readFromBeanFactory(String label, ConfigurableBeanFactory beanFactory) {
if (beanFactory == null) {
return label;
}
String value = beanFactory.resolveEmbeddedValue(label);
return StringUtils.hasText(value) ? evaluate(value, beanFactory) : value;
}
public static String resolvePlaceholders(String label, Environment environment) {
return environment == null ? label : environment.resolvePlaceholders(label);
}
public static String evaluate(String value, Environment environment) {
Expression expression = expressionCache.get(value);
if (expression == null) {
expression = parser.parseExpression(value, new TemplateParserContext());
expressionCache.put(value, expression);
}
StandardEvaluationContext evaluationContext = environmentContextCache.get(environment);
if (evaluationContext == null) {
evaluationContext = new StandardEvaluationContext(environment);
evaluationContext.addPropertyAccessor(new EnvironmentAccessor());
environmentContextCache.put(environment, evaluationContext);
}
return expression.getValue(evaluationContext, String.class);
}
public static Object evaluate(String value, ConfigurableBeanFactory beanFactory) {
return resolver.evaluate(value, new BeanExpressionContext(beanFactory, null));
}
public static String readFileExtension(String dataId) {
int lastIndex = dataId.lastIndexOf(".");
final String extName = dataId.substring(lastIndex + 1);
FileTypeEnum fileTypeEnum = FileTypeEnum.getFileTypeEnumByFileExtensionOrFileType(extName);
return fileTypeEnum.getFileType();
}
public static PropertyValues resolvePropertyValues(Object bean, String content,
String type) {
return resolvePropertyValues(bean, "", "", "", content, type);
}
public static PropertyValues resolvePropertyValues(Object bean, final String prefix,
String dataId, String groupId, String content, String type) {
final Map<String, Object> configProperties = toProperties(dataId, groupId,
content, type);
final MutablePropertyValues propertyValues = new MutablePropertyValues();
ReflectionUtils.doWithFields(bean.getClass(),
new ReflectionUtils.FieldCallback() {
@Override
public void doWith(Field field)
throws IllegalArgumentException, IllegalAccessException {
String propertyName = NacosUtils.resolvePropertyName(field);
propertyName = StringUtils.isEmpty(prefix) ? propertyName
: prefix + "." + propertyName;
if (hasText(propertyName)) {
// If it is a map, the data will not be fetched
// fix issue #91
if (Collection.class.isAssignableFrom(field.getType())
|| Map.class.isAssignableFrom(field.getType())) {
bindContainer(prefix, propertyName, configProperties,
propertyValues);
return;
}
if (containsDescendantOf(configProperties.keySet(),
propertyName) && !isUnbindableBean(field.getType())) {
bindBean(propertyName, field.getType(), configProperties,
propertyValues);
return;
}
if (configProperties.containsKey(propertyName)) {
String propertyValue = String
.valueOf(configProperties.get(propertyName));
propertyValues.add(field.getName(), propertyValue);
}
}
}
});
return propertyValues;
}
public static Properties resolveProperties(NacosProperties nacosProperties,
PropertyResolver propertyResolver) {
return resolveProperties(nacosProperties, propertyResolver, null); return resolveProperties(nacosProperties, propertyResolver, null);
} }
public static Properties resolveProperties(NacosProperties nacosProperties, PropertyResolver propertyResolver, public static Properties resolveProperties(NacosProperties nacosProperties,
Properties defaultProperties) { PropertyResolver propertyResolver, Properties defaultProperties) {
Map<String, Object> attributes = getAnnotationAttributes(nacosProperties); Map<String, Object> attributes = getAnnotationAttributes(nacosProperties);
@ -178,9 +307,10 @@ public abstract class NacosUtils {
} }
/** /**
* {@link #resolveProperties(Map, PropertyResolver) Resolve} placeholders of {@link NacosProperties @NacosProperties}'s attributes via specified * {@link #resolveProperties(Map, PropertyResolver) Resolve} placeholders of
* {@link PropertyResolver} if present, or try to {@link #merge(Properties, Properties) merge} from * {@link NacosProperties @NacosProperties}'s attributes via specified
* default properties * {@link PropertyResolver} if present, or try to
* {@link #merge(Properties, Properties) merge} from default properties
* *
* @param attributes {@link NacosProperties @NacosProperties}'s attributes * @param attributes {@link NacosProperties @NacosProperties}'s attributes
* @param propertyResolver the resolver of properties' placeholder * @param propertyResolver the resolver of properties' placeholder
@ -188,8 +318,8 @@ public abstract class NacosUtils {
* @return a new resolved {@link Properties} properties * @return a new resolved {@link Properties} properties
* @see #resolveProperties(Map, PropertyResolver) * @see #resolveProperties(Map, PropertyResolver)
*/ */
public static Properties resolveProperties(Map<String, Object> attributes, PropertyResolver propertyResolver, public static Properties resolveProperties(Map<String, Object> attributes,
Properties defaultProperties) { PropertyResolver propertyResolver, Properties defaultProperties) {
if (CollectionUtils.isEmpty(attributes)) { if (CollectionUtils.isEmpty(attributes)) {
return defaultProperties; return defaultProperties;
@ -202,16 +332,19 @@ public abstract class NacosUtils {
return resolveProperties; return resolveProperties;
} }
/** /**
* Resolve placeholders of properties via specified {@link PropertyResolver} if present * Resolve placeholders of properties via specified {@link PropertyResolver} if
* present
* *
* @param properties The properties * @param properties The properties
* @param propertyResolver {@link PropertyResolver} instance, for instance, {@link Environment} * @param propertyResolver {@link PropertyResolver} instance, for instance,
* {@link Environment}
* @return a new instance of {@link Properties} after resolving. * @return a new instance of {@link Properties} after resolving.
*/ */
public static Properties resolveProperties(Map<?, ?> properties, PropertyResolver propertyResolver) { public static Properties resolveProperties(Map<?, ?> properties,
PropertiesPlaceholderResolver propertiesPlaceholderResolver = new PropertiesPlaceholderResolver(propertyResolver); PropertyResolver propertyResolver) {
PropertiesPlaceholderResolver propertiesPlaceholderResolver = new PropertiesPlaceholderResolver(
propertyResolver);
return propertiesPlaceholderResolver.resolve(properties); return propertiesPlaceholderResolver.resolve(properties);
} }
@ -221,7 +354,8 @@ public abstract class NacosUtils {
* @param targetProperties {@link Properties target Properties} * @param targetProperties {@link Properties target Properties}
* @param sourceProperties {@link Properties source Properties} * @param sourceProperties {@link Properties source Properties}
*/ */
protected static void merge(Properties targetProperties, Properties sourceProperties) { protected static void merge(Properties targetProperties,
Properties sourceProperties) {
if (CollectionUtils.isEmpty(sourceProperties)) { if (CollectionUtils.isEmpty(sourceProperties)) {
return; return;
@ -245,37 +379,168 @@ public abstract class NacosUtils {
* @param groupId groupId * @param groupId groupId
* @return If available , return content , or <code>null</code> * @return If available , return content , or <code>null</code>
*/ */
public static String getContent(ConfigService configService, String dataId, String groupId) { public static String getContent(ConfigService configService, String dataId,
String groupId) {
String content = null; String content = null;
try { try {
content = configService.getConfig(dataId, groupId, DEFAULT_TIMEOUT); content = configService.getConfig(dataId, groupId, DEFAULT_TIMEOUT);
} catch (NacosException e) { }
catch (NacosException e) {
if (logger.isErrorEnabled()) { if (logger.isErrorEnabled()) {
logger.error("Can't get content from dataId : " + dataId + " , groupId : " + groupId, e); logger.error("Can't get content from dataId : " + dataId + " , groupId : "
+ groupId, e);
} }
} }
return content; return content;
} }
public static <T> Class<T> resolveGenericType(Class<?> declaredClass) { /**
ParameterizedType parameterizedType = (ParameterizedType) declaredClass.getGenericSuperclass(); * bind properties to bean
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments(); *
return (Class<T>) actualTypeArguments[0]; * @param propertyName propertyName
* @param target bind target
* @param configProperties config context
* @param propertyValues {@link MutablePropertyValues}
*/
private static void bindBean(String propertyName, Class<?> target,
Map<String, Object> configProperties, MutablePropertyValues propertyValues) {
Object propertyValue = configProperties.get(propertyName);
if (propertyValue != null) {
propertyValues.add(propertyName, propertyValue);
}
if (isUnbindableBean(target)) {
return;
} }
public static Properties toProperties(String text) { Field[] fields = target.getDeclaredFields();
Properties properties = new Properties(); for (Field field : fields) {
try { String mergePropertyName = propertyName + "."
if (StringUtils.hasText(text)) { + NacosUtils.resolvePropertyName(field);
properties.load(new StringReader(text)); bindBean(mergePropertyName, field.getType(), configProperties,
propertyValues);
} }
} catch (IOException e) {
if (logger.isErrorEnabled()) {
logger.error(e.getMessage(), e);
} }
private static boolean containsDescendantOf(Set<String> names, String propertyName) {
for (String name : names) {
if (name.startsWith(propertyName + ".")) {
return true;
}
}
return false;
}
private static boolean isUnbindableBean(Class<?> resolved) {
if (resolved.isPrimitive() || NON_BEAN_CLASSES.contains(resolved)) {
return true;
}
return resolved.getName().startsWith("java.");
}
/**
* Simple solutions to support {@link Map} or {@link Collection}
*
* @param fieldName property name
* @param configProperties config context
* @param propertyValues {@link MutablePropertyValues}
*/
private static void bindContainer(String prefix, String fieldName,
Map<String, Object> configProperties, MutablePropertyValues propertyValues) {
String regx1 = fieldName + "\\[(.*)\\]";
String regx2 = fieldName + "\\..*";
Pattern pattern1 = Pattern.compile(regx1);
Pattern pattern2 = Pattern.compile(regx2);
Set<String> enumeration = configProperties.keySet();
for (Object item : enumeration) {
final String s = String.valueOf(item);
String name = StringUtils.isEmpty(prefix) ? s : s.replace(prefix + ".", "");
Object value = configProperties.get(s);
if (configProperties.containsKey(fieldName)) {
// for example: list=1,2,3,4,5 will be into here
bindContainer(prefix, fieldName,
listToProperties(fieldName,
String.valueOf(configProperties.get(fieldName))),
propertyValues);
}
else if (pattern1.matcher(s).find()) {
propertyValues.add(name, value);
}
else if (pattern2.matcher(s).find()) {
int index = s.indexOf('.');
if (index != -1) {
String key = s.substring(index + 1);
propertyValues.add(s.substring(0, index) + "[" + key + "]", value);
}
}
}
}
/**
* convert list=1,2,3,4 to list[0]=1, list[1]=2, list[2]=3, list[3]=4
*
* @param fieldName fieldName
* @param content content
* @return {@link Properties}
*/
private static Map<String, Object> listToProperties(String fieldName,
String content) {
String[] splits = content.split(",");
int index = 0;
Map<String, Object> properties = new LinkedHashMap<String, Object>();
for (String s : splits) {
properties.put(fieldName + "[" + index + "]", s.trim());
index++;
} }
return properties; return properties;
} }
private static String resolvePropertyName(Field field) {
// Ignore property name if @NacosIgnore present
if (getAnnotation(field, NacosIgnore.class) != null) {
return null;
}
NacosProperty nacosProperty = getAnnotation(field, NacosProperty.class);
// If @NacosProperty present ,return its value() , or field name
return nacosProperty != null ? nacosProperty.value() : field.getName();
}
public static <T> Class<T> resolveGenericType(Class<?> declaredClass) {
ParameterizedType parameterizedType = (ParameterizedType) declaredClass
.getGenericSuperclass();
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
return (Class<T>) actualTypeArguments[0];
}
public static Map<String, Object> toProperties(String text) {
return toProperties(text, "properties");
}
public static Map<String, Object> toProperties(String text, String type) {
return toProperties("", "", text, type);
}
public static Map<String, Object> toProperties(String dataId, String group,
String text) {
return toProperties(dataId, group, text, "properties");
}
/**
* XML configuration parsing to support different schemas
*
* @param dataId config dataId
* @param group config group
* @param text config context
* @param type config type
* @return map format of result
*/
public static Map<String, Object> toProperties(String dataId, String group,
String text, String type) {
type = type.toLowerCase();
if ("yml".equalsIgnoreCase(type)) {
type = "yaml";
}
return ConfigParseUtils.toProperties(dataId, group, text, type);
}
} }

View File

@ -0,0 +1,87 @@
/*
* 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 com.alibaba.nacos.spring.util;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Map;
import org.springframework.beans.TypeConverter;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.core.MethodParameter;
import org.springframework.util.ReflectionUtils;
import com.alibaba.nacos.api.config.annotation.NacosIgnore;
/**
* @author <a href="mailto:liaochunyhm@live.com">liaochuntao</a>
* @since 0.3.0
*/
public final class ObjectUtils {
private ObjectUtils() {
}
public static void cleanMapOrCollectionField(final Object bean) {
ReflectionUtils.doWithFields(bean.getClass(),
new ReflectionUtils.FieldCallback() {
@Override
public void doWith(Field field)
throws IllegalArgumentException, IllegalAccessException {
field.setAccessible(true);
if (field.isAnnotationPresent(NacosIgnore.class)) {
return;
}
Class<?> type = field.getType();
if (Map.class.isAssignableFrom(type)
|| Collection.class.isAssignableFrom(type)) {
field.set(bean, null);
}
}
});
}
public static Object convertIfNecessary(ConfigurableListableBeanFactory beanFactory,
Field field, Object value) {
TypeConverter converter = beanFactory.getTypeConverter();
return converter.convertIfNecessary(value, field.getType(), field);
}
public static Object convertIfNecessary(ConfigurableListableBeanFactory beanFactory,
Method method, Object value) {
Class<?>[] paramTypes = method.getParameterTypes();
Object[] arguments = new Object[paramTypes.length];
TypeConverter converter = beanFactory.getTypeConverter();
if (arguments.length == 1) {
return converter.convertIfNecessary(value, paramTypes[0],
new MethodParameter(method, 0));
}
for (int i = 0; i < arguments.length; i++) {
arguments[i] = converter.convertIfNecessary(value, paramTypes[i],
new MethodParameter(method, i));
}
return arguments;
}
}

View File

@ -0,0 +1,126 @@
package com.alibaba.nacos.spring.util;
import com.google.common.base.Strings;
import com.google.common.collect.Sets;
import org.springframework.util.StringUtils;
import java.util.Set;
import java.util.Stack;
/**
* @author wuhaoqiang
* @since 1.1.2
**/
public class PlaceholderHelper {
private static final String PLACEHOLDER_PREFIX = "${";
private static final String PLACEHOLDER_SUFFIX = "}";
private static final String VALUE_SEPARATOR = ":";
private static final String SIMPLE_PLACEHOLDER_PREFIX = "{";
/**
* find keys from placeholder
* ${key} - "key"
* xxx${key}yyy - "key"
* ${key:${key2:1}} - "key", "key2"
* ${${key}} - "key"
* ${${key:100}} - "key"
* ${${key}:${key2}} - "key", "key2"
* @param propertyString ${key}
* @return key
*/
public static Set<String> findPlaceholderKeys(String propertyString) {
Set<String> placeholderKeys = Sets.newHashSet();
if (Strings.isNullOrEmpty(propertyString) ||
!(propertyString.contains(PLACEHOLDER_PREFIX) && propertyString.contains(PLACEHOLDER_SUFFIX))) {
return placeholderKeys;
}
// handle xxx${yyy}zzz -> ${yyy}zzz
propertyString = propertyString.substring(propertyString.indexOf(PLACEHOLDER_PREFIX));
Stack<String> stack = new Stack<String>();
stack.push(propertyString);
while (!stack.isEmpty()) {
String strVal = stack.pop();
int startIndex = strVal.indexOf(PLACEHOLDER_PREFIX);
if (startIndex == -1) {
placeholderKeys.add(strVal);
continue;
}
int endIndex = findPlaceholderEndIndex(strVal, startIndex);
if (endIndex == -1) {
// invalid placeholder
continue;
}
String placeholderCandidate = strVal.substring(startIndex + PLACEHOLDER_PREFIX.length(), endIndex);
// ${key}
// startsWith '${' continue
if (placeholderCandidate.startsWith(PLACEHOLDER_PREFIX)) {
stack.push(placeholderCandidate);
} else {
// exist ':' -> key:${key2:2}
int separatorIndex = placeholderCandidate.indexOf(VALUE_SEPARATOR);
if (separatorIndex == -1) {
stack.push(placeholderCandidate);
} else {
stack.push(placeholderCandidate.substring(0, separatorIndex));
String defaultValuePart =
normalizeToPlaceholder(placeholderCandidate.substring(separatorIndex + VALUE_SEPARATOR.length()));
if (!Strings.isNullOrEmpty(defaultValuePart)) {
stack.push(defaultValuePart);
}
}
}
// has remaining part, e.g. ${a}.${b}
if (endIndex + PLACEHOLDER_SUFFIX.length() < strVal.length() - 1) {
String remainingPart = normalizeToPlaceholder(strVal.substring(endIndex + PLACEHOLDER_SUFFIX.length()));
if (!Strings.isNullOrEmpty(remainingPart)) {
stack.push(remainingPart);
}
}
}
return placeholderKeys;
}
private static String normalizeToPlaceholder(String strVal) {
int startIndex = strVal.indexOf(PLACEHOLDER_PREFIX);
if (startIndex == -1) {
return null;
}
int endIndex = strVal.lastIndexOf(PLACEHOLDER_SUFFIX);
if (endIndex == -1) {
return null;
}
return strVal.substring(startIndex, endIndex + PLACEHOLDER_SUFFIX.length());
}
private static int findPlaceholderEndIndex(CharSequence buf, int startIndex) {
int index = startIndex + PLACEHOLDER_PREFIX.length();
int withinNestedPlaceholder = 0;
while (index < buf.length()) {
if (StringUtils.substringMatch(buf, index, PLACEHOLDER_SUFFIX)) {
if (withinNestedPlaceholder > 0) {
withinNestedPlaceholder--;
index = index + PLACEHOLDER_SUFFIX.length();
} else {
return index;
}
} else if (StringUtils.substringMatch(buf, index, SIMPLE_PLACEHOLDER_PREFIX)) {
withinNestedPlaceholder++;
index = index + SIMPLE_PLACEHOLDER_PREFIX.length();
} else {
index++;
}
}
return -1;
}
}

View File

@ -16,14 +16,14 @@
*/ */
package com.alibaba.nacos.spring.util; package com.alibaba.nacos.spring.util;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.env.PropertyResolver;
import org.springframework.util.StringUtils;
import java.lang.annotation.Annotation; import java.lang.annotation.Annotation;
import java.util.Map; import java.util.Map;
import java.util.Properties; import java.util.Properties;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.env.PropertyResolver;
import org.springframework.util.StringUtils;
/** /**
* Placeholder Resolver for {@link Properties properties} * Placeholder Resolver for {@link Properties properties}
* *
@ -45,7 +45,8 @@ public class PropertiesPlaceholderResolver {
* @return Resolved {@link Properties source properties} * @return Resolved {@link Properties source properties}
*/ */
public Properties resolve(Annotation annotation) { public Properties resolve(Annotation annotation) {
Map<String, Object> attributes = AnnotationUtils.getAnnotationAttributes(annotation); Map<String, Object> attributes = AnnotationUtils
.getAnnotationAttributes(annotation);
return resolve(attributes); return resolve(attributes);
} }

View File

@ -0,0 +1,61 @@
/*
* 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 com.alibaba.nacos.spring.util;
/**
* @author <a href="mailto:liaochunyhm@live.com">liaochuntao</a>
* @since 0.0.1
*/
public class Tuple<A, B> {
private static final Tuple empty = new Tuple();
private A first;
private B second;
private Tuple() {
}
;
public static <A, B> Tuple<A, B> empty() {
return empty;
}
public static <A, B> Tuple<A, B> of(A first, B second) {
Tuple<A, B> tuple = new Tuple<A, B>();
tuple.setFirst(first);
tuple.setSecond(second);
return tuple;
}
public A getFirst() {
return first;
}
public void setFirst(A first) {
this.first = first;
}
public B getSecond() {
return second;
}
public void setSecond(B second) {
this.second = second;
}
}

View File

@ -0,0 +1,44 @@
/*
*
* * 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 com.alibaba.nacos.spring.util.aot;
import org.springframework.core.SpringProperties;
public abstract class AotDetector {
/**
* System property that indicates the application should run with AOT
* generated artifacts. If such optimizations are not available, it is
* recommended to throw an exception rather than fall back to the regular
* runtime behavior.
*/
public static final String AOT_ENABLED = "spring.aot.enabled";
/**
* Determine whether AOT optimizations must be considered at runtime. This
* is mandatory in a native image but can be triggered on the JVM using
* the {@value #AOT_ENABLED} Spring property.
* @return whether AOT optimizations must be considered
*/
public static boolean useGeneratedArtifacts() {
return (NativeDetector.inNativeImage() || SpringProperties.getFlag(AOT_ENABLED));
}
}

View File

@ -0,0 +1,33 @@
/*
*
* * 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 com.alibaba.nacos.spring.util.aot;
public abstract class NativeDetector {
// See https://github.com/oracle/graal/blob/master/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/ImageInfo.java
private static final boolean imageCode = (System.getProperty("org.graalvm.nativeimage.imagecode") != null);
/**
* @return Returns {@code true} if invoked in the context of image building or during image runtime, else {@code false}.
*/
public static boolean inNativeImage() {
return imageCode;
}
}

View File

@ -16,6 +16,11 @@
*/ */
package com.alibaba.nacos.spring.util.config; package com.alibaba.nacos.spring.util.config;
import java.util.Properties;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.env.ConfigurableEnvironment;
import com.alibaba.nacos.api.NacosFactory; import com.alibaba.nacos.api.NacosFactory;
import com.alibaba.nacos.api.annotation.NacosProperties; import com.alibaba.nacos.api.annotation.NacosProperties;
import com.alibaba.nacos.api.config.ConfigService; import com.alibaba.nacos.api.config.ConfigService;
@ -23,10 +28,6 @@ import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.spring.factory.NacosServiceFactory; import com.alibaba.nacos.spring.factory.NacosServiceFactory;
import com.alibaba.nacos.spring.util.NacosUtils; import com.alibaba.nacos.spring.util.NacosUtils;
import com.alibaba.nacos.spring.util.PropertiesPlaceholderResolver; import com.alibaba.nacos.spring.util.PropertiesPlaceholderResolver;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.env.ConfigurableEnvironment;
import java.util.Properties;
/** /**
* Nacos Configuration Loader * Nacos Configuration Loader
@ -61,7 +62,8 @@ public class NacosConfigLoader {
* @return Nacos config * @return Nacos config
* @throws RuntimeException If {@link ConfigService} creating is failed. * @throws RuntimeException If {@link ConfigService} creating is failed.
*/ */
public String load(String dataId, String groupId, NacosProperties nacosProperties) throws RuntimeException { public String load(String dataId, String groupId, NacosProperties nacosProperties)
throws RuntimeException {
Properties properties = resolver.resolve(nacosProperties); Properties properties = resolver.resolve(nacosProperties);
return load(dataId, groupId, properties); return load(dataId, groupId, properties);
} }
@ -75,15 +77,17 @@ public class NacosConfigLoader {
* @return Nacos config * @return Nacos config
* @throws RuntimeException If {@link ConfigService} creating is failed. * @throws RuntimeException If {@link ConfigService} creating is failed.
*/ */
public String load(String dataId, String groupId, Properties nacosProperties) throws RuntimeException { public String load(String dataId, String groupId, Properties nacosProperties)
throws RuntimeException {
try { try {
configService = nacosServiceFactory != null ? configService = nacosServiceFactory != null
nacosServiceFactory.createConfigService(nacosProperties) : ? nacosServiceFactory.createConfigService(nacosProperties)
NacosFactory.createConfigService(nacosProperties); : NacosFactory.createConfigService(nacosProperties);
} catch (NacosException e) { }
catch (NacosException e) {
throw new RuntimeException("ConfigService can't be created with dataId :" throw new RuntimeException("ConfigService can't be created with dataId :"
+ dataId + " , groupId : " + groupId + " , properties : " + nacosProperties + dataId + " , groupId : " + groupId + " , properties : "
, e); + nacosProperties, e);
} }
return NacosUtils.getContent(configService, dataId, groupId); return NacosUtils.getContent(configService, dataId, groupId);
} }
@ -100,7 +104,8 @@ public class NacosConfigLoader {
* @throws RuntimeException {@link #load(String, String, NacosProperties)} * @throws RuntimeException {@link #load(String, String, NacosProperties)}
* @see #load(String, String, NacosProperties) * @see #load(String, String, NacosProperties)
*/ */
public <T> T load(String dataId, String groupId, NacosProperties nacosProperties, Class<T> targetClass) throws RuntimeException { public <T> T load(String dataId, String groupId, NacosProperties nacosProperties,
Class<T> targetClass) throws RuntimeException {
String config = load(dataId, groupId, nacosProperties); String config = load(dataId, groupId, nacosProperties);
return conversionService.convert(config, targetClass); return conversionService.convert(config, targetClass);
} }

View File

@ -0,0 +1,28 @@
/*
* 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 com.alibaba.nacos.spring.util.parse;
/**
* @author <a href="mailto:liaochunyhm@live.com">liaochuntao</a>
* @since 0.3.0
*/
class ConfigParseException extends RuntimeException {
ConfigParseException(Throwable cause) {
super(cause);
}
}

View File

@ -0,0 +1,51 @@
/*
* 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 com.alibaba.nacos.spring.util.parse;
import static com.alibaba.nacos.spring.util.parse.DefaultYamlConfigParse.createYaml;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;
import com.alibaba.nacos.api.config.ConfigType;
import com.alibaba.nacos.spring.util.AbstractConfigParse;
/**
* @author <a href="mailto:liaochunyhm@live.com">liaochuntao</a>
* @since 0.3.0
*/
public class DefaultJsonConfigParse extends AbstractConfigParse {
@Override
public Map<String, Object> parse(String configText) {
final AtomicReference<Map<String, Object>> result = new AtomicReference<Map<String, Object>>();
configText = configText.replaceAll("\t", "");
DefaultYamlConfigParse.process(new DefaultYamlConfigParse.MatchCallback() {
@Override
public void process(Map<String, Object> map) {
result.set(map);
}
}, createYaml(), configText);
return result.get();
}
@Override
public String processType() {
return ConfigType.JSON.getType();
}
}

View File

@ -0,0 +1,582 @@
/*
* 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 com.alibaba.nacos.spring.util.parse;
import java.io.Closeable;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.LineNumberReader;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.LinkedHashMap;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.Resource;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import com.alibaba.nacos.api.config.ConfigType;
import com.alibaba.nacos.spring.util.AbstractConfigParse;
/**
* @author <a href="mailto:liaochunyhm@live.com">liaochuntao</a>
* @since 0.3.0
*/
public class DefaultPropertiesConfigParse extends AbstractConfigParse {
private static final Logger logger = LoggerFactory
.getLogger(DefaultPropertiesConfigParse.class);
@Override
public Map<String, Object> parse(String configText) {
OriginTrackedPropertiesLoader loader = new OriginTrackedPropertiesLoader(
new ByteArrayResource(configText.getBytes(Charset.defaultCharset())));
try {
if (StringUtils.hasText(configText)) {
return loader.load();
}
return new LinkedHashMap<String, Object>();
}
catch (IOException e) {
throw new ConfigParseException(e);
}
}
@Override
public String processType() {
return ConfigType.PROPERTIES.getType();
}
public interface OriginProvider {
/**
* Return the source origin or {@code null} if the origin is not known.
*
* @return the origin or {@code null}
*/
Origin getOrigin();
}
public abstract static class Origin {
/**
* Find the {@link Origin} that an object originated from. Checks if the source
* object is an {@link OriginProvider} and also searches exception stacks.
*
* @param source the source object or {@code null}
* @return an optional {@link Origin}
*/
static Origin from(Object source) {
if (source instanceof Origin) {
return (Origin) source;
}
Origin origin = null;
if (source != null && source instanceof OriginProvider) {
origin = ((OriginProvider) source).getOrigin();
}
if (origin == null && source != null && source instanceof Throwable) {
return from(((Throwable) source).getCause());
}
return origin;
}
}
public static class OriginTrackedValue implements OriginProvider {
private final Object value;
private final Origin origin;
private OriginTrackedValue(Object value, Origin origin) {
this.value = value;
this.origin = origin;
}
public static OriginTrackedValue of(Object value) {
return of(value, null);
}
/**
* Create an {@link OriginTrackedValue} containing the specified {@code
* value} and {@code origin}. If the source value implements {@link CharSequence}
* then so will the resulting {@link OriginTrackedValue}.
*
* @param value the source value
* @param origin the origin
* @return an {@link OriginTrackedValue} or {@code null} if the source value was
* {@code null}.
*/
public static OriginTrackedValue of(Object value, Origin origin) {
if (value == null) {
return null;
}
if (value instanceof CharSequence) {
return new OriginTrackedCharSequence((CharSequence) value, origin);
}
return new OriginTrackedValue(value, origin);
}
/**
* Return the tracked value.
*
* @return the tracked value
*/
public Object getValue() {
return this.value;
}
@Override
public Origin getOrigin() {
return this.origin;
}
@Override
public String toString() {
return (this.value != null ? this.value.toString() : null);
}
@Override
public int hashCode() {
return ObjectUtils.nullSafeHashCode(this.value);
}
@Override
public boolean equals(Object obj) {
if (obj == null || obj.getClass() != getClass()) {
return false;
}
return ObjectUtils.nullSafeEquals(this.value,
((OriginTrackedValue) obj).value);
}
/**
* {@link OriginTrackedValue} for a {@link CharSequence}.
*/
private static class OriginTrackedCharSequence extends OriginTrackedValue
implements CharSequence {
OriginTrackedCharSequence(CharSequence value, Origin origin) {
super(value, origin);
}
@Override
public int length() {
return getValue().length();
}
@Override
public char charAt(int index) {
return getValue().charAt(index);
}
@Override
public CharSequence subSequence(int start, int end) {
return getValue().subSequence(start, end);
}
@Override
public CharSequence getValue() {
return (CharSequence) super.getValue();
}
}
}
/**
* A location (line and column number) within the resource.
*/
static class Location {
private final int line;
private final int column;
/**
* Create a new {@link Location} instance.
*
* @param line the line number (zero indexed)
* @param column the column number (zero indexed)
*/
public Location(int line, int column) {
this.line = line;
this.column = column;
}
/**
* Return the line of the text resource where the property originated.
*
* @return the line number (zero indexed)
*/
public int getLine() {
return this.line;
}
/**
* Return the column of the text resource where the property originated.
*
* @return the column number (zero indexed)
*/
public int getColumn() {
return this.column;
}
@Override
public int hashCode() {
return (31 * this.line) + this.column;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
Location other = (Location) obj;
boolean result = true;
result = result && this.line == other.line;
result = result && this.column == other.column;
return result;
}
@Override
public String toString() {
return (this.line + 1) + ":" + (this.column + 1);
}
}
class OriginTrackedPropertiesLoader {
private final Resource resource;
/**
* Create a new {@link OriginTrackedPropertiesLoader} instance.
*
* @param resource the resource of the {@code .properties} data
*/
OriginTrackedPropertiesLoader(Resource resource) {
Assert.notNull(resource, "Resource must not be null");
this.resource = resource;
}
/**
* Load {@code .properties} data and return a map of {@code String} ->
* {@link OriginTrackedValue}.
*
* @return the loaded properties
* @throws IOException on read error
*/
public Map<String, Object> load() throws IOException {
return load(true);
}
/**
* Load {@code .properties} data and return a map of {@code String} ->
* {@link OriginTrackedValue}.
*
* @param expandLists if list {@code name[]=a,b,c} shortcuts should be expanded
* @return the loaded properties
* @throws IOException on read error
*/
public Map<String, Object> load(boolean expandLists) throws IOException {
OriginTrackedPropertiesLoader.CharacterReader reader = new OriginTrackedPropertiesLoader.CharacterReader(
this.resource);
try {
Map<String, Object> result = new LinkedHashMap<String, Object>();
StringBuilder buffer = new StringBuilder();
while (reader.read()) {
String key = loadKey(buffer, reader).trim();
if (expandLists && key.endsWith("[]")) {
key = key.substring(0, key.length() - 2);
int index = 0;
do {
OriginTrackedValue value = loadValue(buffer, reader, true);
put(result, key + "[" + (index++) + "]", value);
if (!reader.isEndOfLine()) {
reader.read();
}
}
while (!reader.isEndOfLine());
}
else {
OriginTrackedValue value = loadValue(buffer, reader, false);
put(result, key, value);
}
}
return result;
}
finally {
reader.close();
}
}
private void put(Map<String, Object> result, String key,
OriginTrackedValue value) {
if (!key.isEmpty()) {
result.put(key, value.value);
}
}
private String loadKey(StringBuilder buffer,
OriginTrackedPropertiesLoader.CharacterReader reader) throws IOException {
buffer.setLength(0);
boolean previousWhitespace = false;
while (!reader.isEndOfLine()) {
if (reader.isPropertyDelimiter()) {
reader.read();
return buffer.toString();
}
if (!reader.isWhiteSpace() && previousWhitespace) {
return buffer.toString();
}
previousWhitespace = reader.isWhiteSpace();
buffer.append(reader.getCharacter());
reader.read();
}
return buffer.toString();
}
private OriginTrackedValue loadValue(StringBuilder buffer,
OriginTrackedPropertiesLoader.CharacterReader reader, boolean splitLists)
throws IOException {
buffer.setLength(0);
while (reader.isWhiteSpace() && !reader.isEndOfLine()) {
reader.read();
}
Location location = reader.getLocation();
while (!reader.isEndOfLine() && !(splitLists && reader.isListDelimiter())) {
buffer.append(reader.getCharacter());
reader.read();
}
TextResourceOrigin origin = new TextResourceOrigin(this.resource, location);
return OriginTrackedValue.of(buffer.toString(), origin);
}
/**
* Reads characters from the source resource, taking care of skipping comments,
* handling multi-line values and tracking {@code '\'} escapes.
*/
private class CharacterReader implements Closeable {
private final String[] ESCAPES = { "trnf", "\t\r\n\f" };
private final LineNumberReader reader;
private int columnNumber = -1;
private boolean escaped;
private int character;
CharacterReader(Resource resource) throws IOException {
this.reader = new LineNumberReader(new InputStreamReader(
resource.getInputStream(), StandardCharsets.UTF_8));
}
@Override
public void close() throws IOException {
this.reader.close();
}
public boolean read() throws IOException {
return read(false);
}
public boolean read(boolean wrappedLine) throws IOException {
this.escaped = false;
this.character = this.reader.read();
this.columnNumber++;
if (this.columnNumber == 0) {
skipLeadingWhitespace();
if (!wrappedLine) {
skipComment();
}
}
if (this.character == '\\') {
this.escaped = true;
readEscaped();
}
else if (this.character == '\n') {
this.columnNumber = -1;
}
return !isEndOfFile();
}
private void skipLeadingWhitespace() throws IOException {
while (isWhiteSpace()) {
this.character = this.reader.read();
this.columnNumber++;
}
}
private void skipComment() throws IOException {
if (this.character == '#' || this.character == '!') {
while (this.character != '\n' && this.character != -1) {
this.character = this.reader.read();
}
this.columnNumber = -1;
read();
}
}
private void readEscaped() throws IOException {
this.character = this.reader.read();
int escapeIndex = ESCAPES[0].indexOf(this.character);
if (escapeIndex != -1) {
this.character = ESCAPES[1].charAt(escapeIndex);
}
else if (this.character == '\n') {
this.columnNumber = -1;
read(true);
}
else if (this.character == 'u') {
readUnicode();
}
}
private void readUnicode() throws IOException {
this.character = 0;
for (int i = 0; i < 4; i++) {
int digit = this.reader.read();
if (digit >= '0' && digit <= '9') {
this.character = (this.character << 4) + digit - '0';
}
else if (digit >= 'a' && digit <= 'f') {
this.character = (this.character << 4) + digit - 'a' + 10;
}
else if (digit >= 'A' && digit <= 'F') {
this.character = (this.character << 4) + digit - 'A' + 10;
}
else {
throw new IllegalStateException("Malformed \\uxxxx encoding.");
}
}
}
public boolean isWhiteSpace() {
return !this.escaped && (this.character == ' ' || this.character == '\t'
|| this.character == '\f');
}
public boolean isEndOfFile() {
return this.character == -1;
}
public boolean isEndOfLine() {
return this.character == -1 || (!this.escaped && this.character == '\n');
}
public boolean isListDelimiter() {
return !this.escaped && this.character == ',';
}
public boolean isPropertyDelimiter() {
return !this.escaped && (this.character == '=' || this.character == ':');
}
public char getCharacter() {
return (char) this.character;
}
public Location getLocation() {
return new Location(this.reader.getLineNumber(), this.columnNumber);
}
}
}
public class TextResourceOrigin extends Origin {
private final Resource resource;
private final Location location;
public TextResourceOrigin(Resource resource, Location location) {
this.resource = resource;
this.location = location;
}
/**
* Return the resource where the property originated.
*
* @return the text resource or {@code null}
*/
public Resource getResource() {
return this.resource;
}
/**
* Return the location of the property within the source (if known).
*
* @return the location or {@code null}
*/
public Location getLocation() {
return this.location;
}
@Override
public int hashCode() {
int result = 1;
result = 31 * result + ObjectUtils.nullSafeHashCode(this.resource);
result = 31 * result + ObjectUtils.nullSafeHashCode(this.location);
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (obj instanceof TextResourceOrigin) {
TextResourceOrigin other = (TextResourceOrigin) obj;
boolean result = true;
result = result
&& ObjectUtils.nullSafeEquals(this.resource, other.resource);
result = result
&& ObjectUtils.nullSafeEquals(this.location, other.location);
return result;
}
return super.equals(obj);
}
@Override
public String toString() {
StringBuilder result = new StringBuilder();
result.append(this.resource != null ? this.resource.getDescription()
: "unknown resource [?]");
if (this.location != null) {
result.append(":").append(this.location);
}
return result.toString();
}
}
}

View File

@ -0,0 +1,162 @@
/*
* 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 com.alibaba.nacos.spring.util.parse;
import java.io.ByteArrayInputStream;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import javax.xml.parsers.DocumentBuilderFactory;
import org.springframework.util.StringUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import com.alibaba.nacos.api.config.ConfigType;
import com.alibaba.nacos.spring.util.AbstractConfigParse;
/*
<xmlSign>
<Students>
<Student>
<Name>lct-1</Name>
<Num>1006010022</Num>
<Classes>major-1</Classes>
<Address>hangzhou</Address>
<Tel>123456</Tel>
</Student>
<Student>
<Name>lct-2</Name>
<Num>1006010033</Num>
<Classes>major-2</Classes>
<Address>shengzheng</Address>
<Tel>234567</Tel>
</Student>
<Student>
<Name>lct-3</Name>
<Num>1006010044</Num>
<Classes>major-3</Classes>
<Address>wenzhou</Address>
<Tel>345678</Tel>
</Student>
<Student>
<Name>lct-4</Name>
<Num>1006010055</Num>
<Classes>major-3</Classes>
<Address>wuhan</Address>
<Tel>456789</Tel>
</Student>
</Students>
</xmlSign>
*/
/**
* Just support xml config like this
*
* @author <a href="mailto:liaochunyhm@live.com">liaochuntao</a>
* @since 0.3.0
*/
public class DefaultXmlConfigParse extends AbstractConfigParse {
private DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
@Override
public Map<String, Object> parse(String configText) {
Map<String, Object> properties = new LinkedHashMap<String, Object>(8);
try {
Document document = factory.newDocumentBuilder()
.parse(new ByteArrayInputStream(configText.getBytes("UTF-8")));
Element root = document.getDocumentElement();
Map<String, Object> map = new LinkedHashMap<String, Object>(8);
recursionXmlToMap(map, root);
mapToProperties("", properties, map);
}
catch (Exception e) {
throw new ConfigParseException(e);
}
return properties;
}
private void recursionXmlToMap(Map<String, Object> outMap, Element element) {
NodeList nodeList = element.getChildNodes();
String name = element.getNodeName();
if (nodeList.getLength() == 1 && !nodeList.item(0).hasChildNodes()) {
addData(outMap, name, element.getTextContent());
}
else {
Map<String, Object> innerMap = new LinkedHashMap<String, Object>(1);
int length = nodeList.getLength();
for (int i = 0; i < length; i++) {
Node node = nodeList.item(i);
if (node.getNodeType() == Node.ELEMENT_NODE) {
Element tElement = (Element) node;
recursionXmlToMap(innerMap, tElement);
}
}
addData(outMap, name, innerMap);
}
}
private void addData(Map<String, Object> map, String key, Object data) {
if (map.containsKey(key)) {
if (map.get(key) instanceof List) {
((List) map.get(key)).add(data);
}
else {
List<Object> list = new LinkedList<Object>();
list.add(map.get(key));
map.put(key, list);
}
}
else {
map.put(key, data);
}
}
private void mapToProperties(String prefixName, Map<String, Object> properties,
Object data) {
if (data instanceof List) {
List list = (List) data;
for (int i = 0; i < list.size(); i++) {
int lastIndex = prefixName.lastIndexOf('.');
String preName = prefixName.substring(0, lastIndex);
String lastName = prefixName.substring(lastIndex);
mapToProperties(preName + "[" + i + "]", properties, list.get(i));
}
}
else if (data instanceof Map) {
Map<String, Object> map = (Map<String, Object>) data;
for (Map.Entry<String, Object> entry : map.entrySet()) {
String tmpPrefix = StringUtils.isEmpty(prefixName) ? entry.getKey()
: prefixName + "." + entry.getKey();
mapToProperties(tmpPrefix, properties, entry.getValue());
}
}
else {
properties.put(prefixName, String.valueOf(data));
}
}
@Override
public String processType() {
return ConfigType.XML.getType();
}
}

View File

@ -0,0 +1,196 @@
/*
* 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 com.alibaba.nacos.spring.util.parse;
import com.alibaba.nacos.api.config.ConfigType;
import com.alibaba.nacos.spring.util.AbstractConfigParse;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.LoaderOptions;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.constructor.Constructor;
import org.yaml.snakeyaml.constructor.SafeConstructor;
import org.yaml.snakeyaml.nodes.Tag;
import org.yaml.snakeyaml.representer.Representer;
import org.yaml.snakeyaml.resolver.Resolver;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;
import java.util.regex.Pattern;
/**
* DefaultYamlConfigParse.
*
* @author <a href="mailto:liaochunyhm@live.com">liaochuntao</a>
* @since 0.3.0
*/
public class DefaultYamlConfigParse extends AbstractConfigParse {
protected static final Logger LOGGER = LoggerFactory.getLogger(DefaultYamlConfigParse.class);
private static final String YAML_ALLOW_COMPLEX_OBJECT = "yamlAllowComplexObject";
private static boolean getYamlAllowComplexObject() {
return Boolean.getBoolean(YAML_ALLOW_COMPLEX_OBJECT);
}
protected static Yaml createYaml() {
LoaderOptions loaderOptions = new LoaderOptions();
loaderOptions.setAllowDuplicateKeys(false);
SafeConstructor constructor;
if (getYamlAllowComplexObject()) {
constructor = new Constructor(loaderOptions);
} else {
constructor = new SafeConstructor(loaderOptions);
}
DumperOptions dumperOptions = new DumperOptions();
Representer representer = new Representer(dumperOptions);
LimitedResolver resolver = new LimitedResolver();
return new Yaml(constructor, representer, dumperOptions, loaderOptions, resolver);
}
protected static boolean process(MatchCallback callback, Yaml yaml, String content) {
int count = 0;
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Loading from YAML: " + content);
}
for (Object object : yaml.loadAll(content)) {
if (object != null && process(asMap(object), callback)) {
count++;
}
}
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Loaded " + count + " document" + (count > 1 ? "s" : "") + " from YAML resource: " + content);
}
return (count > 0);
}
protected static boolean process(Map<String, Object> map, MatchCallback callback) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Merging document (no matchers set): " + map);
}
callback.process(getFlattenedMap(map));
return true;
}
@SuppressWarnings("unchecked")
protected static Map<String, Object> asMap(Object object) {
// YAML can have numbers as keys
Map<String, Object> result = new LinkedHashMap();
if (!(object instanceof Map)) {
// A document can be a text literal
result.put("document", object);
return result;
}
Map<Object, Object> map = (Map<Object, Object>) object;
for (Map.Entry<Object, Object> entry : map.entrySet()) {
Object key = entry.getKey();
Object value = entry.getValue();
if (value instanceof Map) {
value = asMap(value);
}
if (key instanceof CharSequence) {
result.put(key.toString(), value);
} else {
result.put("[" + key.toString() + "]", value);
}
}
return result;
}
private static class LimitedResolver extends Resolver {
@Override
public void addImplicitResolver(Tag tag, Pattern regexp, String first) {
if (tag == Tag.TIMESTAMP) {
return;
}
super.addImplicitResolver(tag, regexp, first);
}
}
protected static Map<String, Object> getFlattenedMap(Map<String, Object> source) {
Map<String, Object> result = new LinkedHashMap<String, Object>();
buildFlattenedMap(result, source, null);
return result;
}
protected static void buildFlattenedMap(Map<String, Object> result, Map<String, Object> source, String path) {
for (Map.Entry<String, Object> entry : source.entrySet()) {
String key = entry.getKey();
if (!StringUtils.isBlank(path)) {
if (key.startsWith("[")) {
key = path + key;
} else {
key = path + '.' + key;
}
}
Object value = entry.getValue();
if (value instanceof String) {
result.put(key, value);
} else if (value instanceof Map) {
// Need a compound key
@SuppressWarnings("unchecked") Map<String, Object> map = (Map<String, Object>) value;
buildFlattenedMap(result, map, key);
} else if (value instanceof Collection) {
// Need a compound key
@SuppressWarnings("unchecked") Collection<Object> collection = (Collection<Object>) value;
int count = 0;
for (Object object : collection) {
buildFlattenedMap(result, Collections.singletonMap("[" + (count++) + "]", object), key);
}
} else {
result.put(key, (value != null ? value.toString() : ""));
}
}
}
@Override
public Map<String, Object> parse(String configText) {
final AtomicReference<Map<String, Object>> result = new AtomicReference<Map<String, Object>>();
process(new MatchCallback() {
@Override
public void process(Map<String, Object> map) {
result.set(map);
}
}, createYaml(), configText);
return result.get();
}
@Override
public String processType() {
return ConfigType.YAML.getType();
}
protected interface MatchCallback {
/**
* Put Map to Properties.
*
* @param map {@link Map}
*/
void process(Map<String, Object> map);
}
}

View File

@ -35,13 +35,15 @@
</xsd:annotation> </xsd:annotation>
<xsd:complexType> <xsd:complexType>
<xsd:attribute name="endpoint" default="${nacos.endpoint:}"/> <xsd:attribute name="endpoint" default="${nacos.endpoint:}"/>
<xsd:attribute name="namespace" default="${nacos.endpoint:}"/> <xsd:attribute name="namespace" default="${nacos.namespace:}"/>
<xsd:attribute name="access-key" default="${nacos.access-key:}"/> <xsd:attribute name="access-key" default="${nacos.access-key:}"/>
<xsd:attribute name="secret-key" default="${nacos.secret-key:}"/> <xsd:attribute name="secret-key" default="${nacos.secret-key:}"/>
<xsd:attribute name="server-addr" default="${nacos.server-addr:}"/> <xsd:attribute name="server-addr" default="${nacos.server-addr:}"/>
<xsd:attribute name="context-path" default="${nacos.context-path:}"/> <xsd:attribute name="context-path" default="${nacos.context-path:}"/>
<xsd:attribute name="cluster-name" default="${nacos.cluster-name:}"/> <xsd:attribute name="cluster-name" default="${nacos.cluster-name:}"/>
<xsd:attribute name="encode" default="${nacos.encode:UTF-8}"/> <xsd:attribute name="encode" default="${nacos.encode:UTF-8}"/>
<xsd:attribute name="username" default="${nacos.username:}"/>
<xsd:attribute name="password" default="${nacos.password:}"/>
</xsd:complexType> </xsd:complexType>
</xsd:element> </xsd:element>
@ -57,11 +59,11 @@
<xsd:attribute name="name" default=""/> <xsd:attribute name="name" default=""/>
<xsd:attribute name="group-id" default="DEFAULT_GROUP"/> <xsd:attribute name="group-id" default="DEFAULT_GROUP"/>
<xsd:attribute name="data-id" use="required"/> <xsd:attribute name="data-id" use="required"/>
<xsd:attribute name="data-ids"/>
<xsd:attribute name="auto-refreshed" default="false"/> <xsd:attribute name="auto-refreshed" default="false"/>
<xsd:attribute name="first" default="false"/> <xsd:attribute name="first" default="false"/>
<xsd:attribute name="before" default=""/> <xsd:attribute name="before" default=""/>
<xsd:attribute name="after" default=""/> <xsd:attribute name="after" default=""/>
<xsd:attribute name="type" default="properties"/>
</xsd:complexType> </xsd:complexType>
</xsd:element> </xsd:element>

View File

@ -0,0 +1,52 @@
/*
*
* * 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 com.alibaba.nacos.spring.beans.factory.annotation;
import org.junit.Assert;
import org.junit.Test;
import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
/**
* {@link AbstractAnnotationBeanPostProcessor} Test
* @author SuperZ1999
* @date 2023/9/28
*/
public class AbstractAnnotationBeanPostProcessorTest {
@Test
public void testPropertyDescriptor() throws IntrospectionException {
PropertyDescriptor pd = new PropertyDescriptor("name", Student.class);
Class<?> type = pd.getPropertyType();
Assert.assertEquals(type, String.class);
}
static class Student {
String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
}

View File

@ -16,19 +16,33 @@
*/ */
package com.alibaba.nacos.spring.beans.factory.annotation; package com.alibaba.nacos.spring.beans.factory.annotation;
import static com.alibaba.nacos.spring.test.MockNacosServiceFactory.CONTENT;
import static com.alibaba.nacos.spring.test.MockNacosServiceFactory.DATA_ID;
import static com.alibaba.nacos.spring.test.MockNacosServiceFactory.GROUP_ID;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
import org.springframework.test.context.support.DirtiesContextTestExecutionListener;
import com.alibaba.nacos.api.annotation.NacosInjected; import com.alibaba.nacos.api.annotation.NacosInjected;
import com.alibaba.nacos.api.annotation.NacosProperties; import com.alibaba.nacos.api.annotation.NacosProperties;
import com.alibaba.nacos.api.config.ConfigService; import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.exception.NacosException; import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.NamingService; import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.spring.context.annotation.EnableNacos;
import com.alibaba.nacos.spring.factory.ApplicationContextHolder;
import com.alibaba.nacos.spring.test.AbstractNacosHttpServerTestExecutionListener;
import com.alibaba.nacos.spring.test.TestConfiguration; import com.alibaba.nacos.spring.test.TestConfiguration;
import org.junit.Assert; import com.alibaba.nacos.spring.util.NacosUtils;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import static com.alibaba.nacos.spring.test.MockNacosServiceFactory.*;
/** /**
* {@link AnnotationNacosInjectedBeanPostProcessor} Test * {@link AnnotationNacosInjectedBeanPostProcessor} Test
@ -37,33 +51,42 @@ import static com.alibaba.nacos.spring.test.MockNacosServiceFactory.*;
* @since 0.1.0 * @since 0.1.0
*/ */
@RunWith(SpringJUnit4ClassRunner.class) @RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { @ContextConfiguration(classes = { TestConfiguration.class, ConfigServiceBeanBuilder.class,
TestConfiguration.class, NamingServiceBeanBuilder.class, AnnotationNacosInjectedBeanPostProcessor.class,
ConfigServiceBeanBuilder.class, AnnotationNacosInjectedBeanPostProcessorTest.class })
NamingServiceBeanBuilder.class, @TestExecutionListeners({ DependencyInjectionTestExecutionListener.class,
AnnotationNacosInjectedBeanPostProcessor.class, DirtiesContextTestExecutionListener.class,
AnnotationNacosInjectedBeanPostProcessorTest.class AnnotationNacosInjectedBeanPostProcessorTest.class })
}) @EnableNacos(globalProperties = @NacosProperties(serverAddr = "${server.addr}"))
public class AnnotationNacosInjectedBeanPostProcessorTest { public class AnnotationNacosInjectedBeanPostProcessorTest
extends AbstractNacosHttpServerTestExecutionListener {
@NacosInjected @NacosInjected
private ConfigService configService; private ConfigService configService;
@NacosInjected(properties = @NacosProperties(encode = "UTF-8")) @NacosInjected(properties = @NacosProperties(encode = "UTF-8"))
private ConfigService configService2; private ConfigService configService2;
@NacosInjected(properties = @NacosProperties(encode = "GBK")) @NacosInjected(properties = @NacosProperties(encode = "GBK"))
private ConfigService configService3; private ConfigService configService3;
@NacosInjected @NacosInjected
private NamingService namingService; private NamingService namingService;
@NacosInjected(properties = @NacosProperties(encode = "UTF-8")) @NacosInjected(properties = @NacosProperties(encode = "UTF-8"))
private NamingService namingService2; private NamingService namingService2;
@NacosInjected(properties = @NacosProperties(encode = "GBK")) @NacosInjected(properties = @NacosProperties(encode = "GBK"))
private NamingService namingService3; private NamingService namingService3;
@Bean(name = ApplicationContextHolder.BEAN_NAME)
public ApplicationContextHolder applicationContextHolder(
ApplicationContext applicationContext) {
ApplicationContextHolder applicationContextHolder = new ApplicationContextHolder();
applicationContextHolder.setApplicationContext(applicationContext);
return applicationContextHolder;
}
@Override
protected String getServerAddressPropertyName() {
return "server.addr";
}
@Test @Test
public void testInjection() { public void testInjection() {

View File

@ -16,14 +16,15 @@
*/ */
package com.alibaba.nacos.spring.config; package com.alibaba.nacos.spring.config;
import com.alibaba.nacos.api.annotation.NacosInjected; import static com.alibaba.nacos.api.common.Constants.DEFAULT_GROUP;
import com.alibaba.nacos.api.config.ConfigService; import static com.alibaba.nacos.embedded.web.server.NacosConfigHttpHandler.CONTENT_PARAM_NAME;
import com.alibaba.nacos.embedded.web.server.EmbeddedNacosHttpServer; import static com.alibaba.nacos.embedded.web.server.NacosConfigHttpHandler.DATA_ID_PARAM_NAME;
import com.alibaba.nacos.spring.context.config.xml.GlobalNacosPropertiesBeanDefinitionParser; import static com.alibaba.nacos.embedded.web.server.NacosConfigHttpHandler.GROUP_ID_PARAM_NAME;
import com.alibaba.nacos.spring.context.config.xml.NacosAnnotationDrivenBeanDefinitionParser; import static com.alibaba.nacos.spring.test.MockNacosServiceFactory.DATA_ID;
import com.alibaba.nacos.spring.context.config.xml.NacosNamespaceHandler;
import com.alibaba.nacos.spring.test.AbstractNacosHttpServerTestExecutionListener; import java.util.HashMap;
import com.alibaba.nacos.spring.test.User; import java.util.Map;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
@ -35,12 +36,16 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener; import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
import org.springframework.test.context.support.DirtiesContextTestExecutionListener; import org.springframework.test.context.support.DirtiesContextTestExecutionListener;
import java.util.HashMap; import com.alibaba.nacos.api.annotation.NacosInjected;
import java.util.Map; import com.alibaba.nacos.api.annotation.NacosProperties;
import com.alibaba.nacos.api.config.ConfigService;
import static com.alibaba.nacos.api.common.Constants.DEFAULT_GROUP; import com.alibaba.nacos.embedded.web.server.EmbeddedNacosHttpServer;
import static com.alibaba.nacos.embedded.web.server.NacosConfigHttpHandler.*; import com.alibaba.nacos.spring.context.annotation.EnableNacos;
import static com.alibaba.nacos.spring.test.MockNacosServiceFactory.DATA_ID; import com.alibaba.nacos.spring.context.config.xml.GlobalNacosPropertiesBeanDefinitionParser;
import com.alibaba.nacos.spring.context.config.xml.NacosAnnotationDrivenBeanDefinitionParser;
import com.alibaba.nacos.spring.context.config.xml.NacosNamespaceHandler;
import com.alibaba.nacos.spring.test.AbstractNacosHttpServerTestExecutionListener;
import com.alibaba.nacos.spring.test.User;
/** /**
* {@link NacosNamespaceHandler} Test * {@link NacosNamespaceHandler} Test
@ -51,17 +56,18 @@ import static com.alibaba.nacos.spring.test.MockNacosServiceFactory.DATA_ID;
* @since 0.1.0 * @since 0.1.0
*/ */
@RunWith(SpringJUnit4ClassRunner.class) @RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { @ContextConfiguration(locations = { "classpath:/META-INF/nacos-context.xml",
"classpath:/META-INF/nacos-context.xml", "classpath:/META-INF/nacos-property-source.xml" })
"classpath:/META-INF/nacos-property-source.xml"
})
@DirtiesContext @DirtiesContext
@TestExecutionListeners({ DependencyInjectionTestExecutionListener.class, @TestExecutionListeners({ DependencyInjectionTestExecutionListener.class,
DirtiesContextTestExecutionListener.class, NacosNamespaceHandlerTest.class }) DirtiesContextTestExecutionListener.class, NacosNamespaceHandlerTest.class })
public class NacosNamespaceHandlerTest extends AbstractNacosHttpServerTestExecutionListener { @EnableNacos(globalProperties = @NacosProperties(serverAddr = "${nacos.server-addr}"))
public class NacosNamespaceHandlerTest
extends AbstractNacosHttpServerTestExecutionListener {
@Autowired @Autowired
private User user; private User user;
@NacosInjected
private ConfigService configService;
@Override @Override
protected String getServerAddressPropertyName() { protected String getServerAddressPropertyName() {
@ -77,13 +83,11 @@ public class NacosNamespaceHandlerTest extends AbstractNacosHttpServerTestExecut
server.initConfig(config); server.initConfig(config);
} }
@NacosInjected
private ConfigService configService;
@Test @Test
public void testGetConfig() throws Exception { public void testGetConfig() throws Exception {
configService.publishConfig(DATA_ID, DEFAULT_GROUP, "9527"); configService.publishConfig(DATA_ID, DEFAULT_GROUP, "9527");
Assert.assertEquals("9527", configService.getConfig(DATA_ID, DEFAULT_GROUP, 5000)); Assert.assertEquals("9527",
configService.getConfig(DATA_ID, DEFAULT_GROUP, 5000));
} }
@Test @Test

View File

@ -16,25 +16,15 @@
*/ */
package com.alibaba.nacos.spring.context.annotation; package com.alibaba.nacos.spring.context.annotation;
import com.alibaba.nacos.api.annotation.NacosInjected; import static com.alibaba.nacos.api.common.Constants.DEFAULT_GROUP;
import com.alibaba.nacos.api.annotation.NacosProperties; import static com.alibaba.nacos.spring.test.MockNacosServiceFactory.DATA_ID;
import com.alibaba.nacos.api.config.ConfigService; import static com.alibaba.nacos.spring.util.NacosBeanUtils.NACOS_CONFIG_LISTENER_EXECUTOR_BEAN_NAME;
import com.alibaba.nacos.api.naming.NamingService; import static com.alibaba.nacos.spring.util.NacosBeanUtils.PLACEHOLDER_CONFIGURER_BEAN_NAME;
import com.alibaba.nacos.spring.beans.factory.annotation.AnnotationNacosInjectedBeanPostProcessor;
import com.alibaba.nacos.spring.beans.factory.annotation.ConfigServiceBeanBuilder; import java.util.Properties;
import com.alibaba.nacos.spring.beans.factory.annotation.NamingServiceBeanBuilder; import java.util.concurrent.ExecutorService;
import com.alibaba.nacos.spring.context.annotation.config.EnableNacosConfig;
import com.alibaba.nacos.spring.context.annotation.config.NacosConfigListenerMethodProcessor; import org.junit.AfterClass;
import com.alibaba.nacos.spring.context.annotation.config.NacosValueAnnotationBeanPostProcessor;
import com.alibaba.nacos.spring.context.annotation.discovery.EnableNacosDiscovery;
import com.alibaba.nacos.spring.context.properties.config.NacosConfigurationPropertiesBindingPostProcessor;
import com.alibaba.nacos.spring.core.env.AnnotationNacosPropertySourceBuilder;
import com.alibaba.nacos.spring.core.env.NacosPropertySourcePostProcessor;
import com.alibaba.nacos.spring.factory.CacheableEventPublishingNacosServiceFactory;
import com.alibaba.nacos.spring.factory.NacosServiceFactory;
import com.alibaba.nacos.spring.test.AbstractNacosHttpServerTestExecutionListener;
import com.alibaba.nacos.spring.test.Config;
import com.alibaba.nacos.spring.util.NacosBeanUtils;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
@ -49,13 +39,24 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener; import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
import org.springframework.test.context.support.DirtiesContextTestExecutionListener; import org.springframework.test.context.support.DirtiesContextTestExecutionListener;
import java.util.Properties; import com.alibaba.nacos.api.annotation.NacosInjected;
import java.util.concurrent.ExecutorService; import com.alibaba.nacos.api.annotation.NacosProperties;
import com.alibaba.nacos.api.config.ConfigService;
import static com.alibaba.nacos.api.common.Constants.DEFAULT_GROUP; import com.alibaba.nacos.api.naming.NamingService;
import static com.alibaba.nacos.spring.test.MockNacosServiceFactory.DATA_ID; import com.alibaba.nacos.spring.beans.factory.annotation.AnnotationNacosInjectedBeanPostProcessor;
import static com.alibaba.nacos.spring.util.NacosBeanUtils.NACOS_CONFIG_LISTENER_EXECUTOR_BEAN_NAME; import com.alibaba.nacos.spring.beans.factory.annotation.ConfigServiceBeanBuilder;
import static com.alibaba.nacos.spring.util.NacosBeanUtils.PLACEHOLDER_CONFIGURER_BEAN_NAME; import com.alibaba.nacos.spring.beans.factory.annotation.NamingServiceBeanBuilder;
import com.alibaba.nacos.spring.context.annotation.config.EnableNacosConfig;
import com.alibaba.nacos.spring.context.annotation.config.NacosConfigListenerMethodProcessor;
import com.alibaba.nacos.spring.context.annotation.config.NacosValueAnnotationBeanPostProcessor;
import com.alibaba.nacos.spring.context.annotation.discovery.EnableNacosDiscovery;
import com.alibaba.nacos.spring.context.properties.config.NacosConfigurationPropertiesBindingPostProcessor;
import com.alibaba.nacos.spring.core.env.AnnotationNacosPropertySourceBuilder;
import com.alibaba.nacos.spring.core.env.NacosPropertySourcePostProcessor;
import com.alibaba.nacos.spring.test.AbstractNacosHttpServerTestExecutionListener;
import com.alibaba.nacos.spring.test.Config;
import com.alibaba.nacos.spring.util.NacosBeanUtils;
import com.alibaba.nacos.spring.util.NacosUtils;
/** /**
* {@link NacosBeanDefinitionRegistrar} Test * {@link NacosBeanDefinitionRegistrar} Test
@ -64,19 +65,69 @@ import static com.alibaba.nacos.spring.util.NacosBeanUtils.PLACEHOLDER_CONFIGURE
* @since 0.1.0 * @since 0.1.0
*/ */
@RunWith(SpringJUnit4ClassRunner.class) @RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { @ContextConfiguration(classes = { NacosBeanDefinitionRegistrarTest.class, })
NacosBeanDefinitionRegistrarTest.class,
})
@TestExecutionListeners({ DependencyInjectionTestExecutionListener.class, @TestExecutionListeners({ DependencyInjectionTestExecutionListener.class,
DirtiesContextTestExecutionListener.class, NacosBeanDefinitionRegistrarTest.class}) DirtiesContextTestExecutionListener.class,
@EnableNacos(globalProperties = @NacosProperties(serverAddr = "${serverAddr}")) NacosBeanDefinitionRegistrarTest.class })
@EnableNacos(globalProperties = @NacosProperties(serverAddr = "${server.addr}"))
@EnableNacosConfig @EnableNacosConfig
@EnableNacosDiscovery @EnableNacosDiscovery
public class NacosBeanDefinitionRegistrarTest extends AbstractNacosHttpServerTestExecutionListener { public class NacosBeanDefinitionRegistrarTest
extends AbstractNacosHttpServerTestExecutionListener {
@Autowired
@Qualifier(NacosBeanUtils.GLOBAL_NACOS_PROPERTIES_BEAN_NAME)
private Properties globalProperties;
@Autowired
@Qualifier(NacosBeanUtils.CONFIG_GLOBAL_NACOS_PROPERTIES_BEAN_NAME)
private Properties configGlobalProperties;
@Autowired
@Qualifier(NacosBeanUtils.DISCOVERY_GLOBAL_NACOS_PROPERTIES_BEAN_NAME)
private Properties discoveryGlobalProperties;
@Autowired
@Qualifier(AnnotationNacosInjectedBeanPostProcessor.BEAN_NAME)
private AnnotationNacosInjectedBeanPostProcessor annotationNacosInjectedBeanPostProcessor;
@Autowired
@Qualifier(PLACEHOLDER_CONFIGURER_BEAN_NAME)
private PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer;
@Autowired
@Qualifier(NacosConfigurationPropertiesBindingPostProcessor.BEAN_NAME)
private NacosConfigurationPropertiesBindingPostProcessor nacosConfigurationPropertiesBindingPostProcessor;
@Autowired
@Qualifier(NacosConfigListenerMethodProcessor.BEAN_NAME)
private NacosConfigListenerMethodProcessor nacosConfigListenerMethodProcessor;
@Autowired
@Qualifier(NacosPropertySourcePostProcessor.BEAN_NAME)
private NacosPropertySourcePostProcessor nacosPropertySourcePostProcessor;
@Autowired
@Qualifier(AnnotationNacosPropertySourceBuilder.BEAN_NAME)
private AnnotationNacosPropertySourceBuilder annotationNacosPropertySourceBuilder;
@Autowired
@Qualifier(NacosValueAnnotationBeanPostProcessor.BEAN_NAME)
private NacosValueAnnotationBeanPostProcessor nacosValueAnnotationBeanPostProcessor;
@Autowired
@Qualifier(ConfigServiceBeanBuilder.BEAN_NAME)
private ConfigServiceBeanBuilder configServiceBeanBuilder;
@Autowired
@Qualifier(NACOS_CONFIG_LISTENER_EXECUTOR_BEAN_NAME)
private ExecutorService nacosConfigListenerExecutor;
@Autowired
@Qualifier(NamingServiceBeanBuilder.BEAN_NAME)
private NamingServiceBeanBuilder namingServiceBeanBuilder;
@NacosInjected
private ConfigService globalConfigService;
@NacosInjected(properties = @NacosProperties(serverAddr = "${server.addr}"))
private ConfigService configService;
@NacosInjected
private NamingService namingService;
@Autowired
private Config config;
@Value("${user.home:${user.dir}}")
private String dir;
@Override @Override
protected String getServerAddressPropertyName() { protected String getServerAddressPropertyName() {
return "serverAddr"; return "server.addr";
} }
@Bean @Bean
@ -84,81 +135,11 @@ public class NacosBeanDefinitionRegistrarTest extends AbstractNacosHttpServerTes
return new Config(); return new Config();
} }
@Autowired
@Qualifier(NacosBeanUtils.GLOBAL_NACOS_PROPERTIES_BEAN_NAME)
private Properties globalProperties;
@Autowired
@Qualifier(NacosBeanUtils.CONFIG_GLOBAL_NACOS_PROPERTIES_BEAN_NAME)
private Properties configGlobalProperties;
@Autowired
@Qualifier(NacosBeanUtils.DISCOVERY_GLOBAL_NACOS_PROPERTIES_BEAN_NAME)
private Properties discoveryGlobalProperties;
@Autowired
@Qualifier(CacheableEventPublishingNacosServiceFactory.BEAN_NAME)
private NacosServiceFactory nacosServiceFactory;
@Autowired
@Qualifier(AnnotationNacosInjectedBeanPostProcessor.BEAN_NAME)
private AnnotationNacosInjectedBeanPostProcessor annotationNacosInjectedBeanPostProcessor;
@Autowired
@Qualifier(PLACEHOLDER_CONFIGURER_BEAN_NAME)
private PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer;
@Autowired
@Qualifier(NacosConfigurationPropertiesBindingPostProcessor.BEAN_NAME)
private NacosConfigurationPropertiesBindingPostProcessor nacosConfigurationPropertiesBindingPostProcessor;
@Autowired
@Qualifier(NacosConfigListenerMethodProcessor.BEAN_NAME)
private NacosConfigListenerMethodProcessor nacosConfigListenerMethodProcessor;
@Autowired
@Qualifier(NacosPropertySourcePostProcessor.BEAN_NAME)
private NacosPropertySourcePostProcessor nacosPropertySourcePostProcessor;
@Autowired
@Qualifier(AnnotationNacosPropertySourceBuilder.BEAN_NAME)
private AnnotationNacosPropertySourceBuilder annotationNacosPropertySourceBuilder;
@Autowired
@Qualifier(NacosValueAnnotationBeanPostProcessor.BEAN_NAME)
private NacosValueAnnotationBeanPostProcessor nacosValueAnnotationBeanPostProcessor;
@Autowired
@Qualifier(ConfigServiceBeanBuilder.BEAN_NAME)
private ConfigServiceBeanBuilder configServiceBeanBuilder;
@Autowired
@Qualifier(NACOS_CONFIG_LISTENER_EXECUTOR_BEAN_NAME)
private ExecutorService nacosConfigListenerExecutor;
@Autowired
@Qualifier(NamingServiceBeanBuilder.BEAN_NAME)
private NamingServiceBeanBuilder namingServiceBeanBuilder;
@NacosInjected
private ConfigService globalConfigService;
@NacosInjected(properties = @NacosProperties(serverAddr = "${serverAddr}"))
private ConfigService configService;
@NacosInjected
private NamingService namingService;
@Autowired
private Config config;
@Value("${user.home:${user.dir}}")
private String dir;
@Test @Test
public void testGetConfig() throws Exception { public void testGetConfig() throws Exception {
configService.publishConfig(DATA_ID, DEFAULT_GROUP, "9527"); configService.publishConfig(DATA_ID, DEFAULT_GROUP, "9527");
Assert.assertEquals("9527", configService.getConfig(DATA_ID, DEFAULT_GROUP, 5000)); Assert.assertEquals("9527",
configService.getConfig(DATA_ID, DEFAULT_GROUP, 5000));
} }
} }

View File

@ -16,12 +16,19 @@
*/ */
package com.alibaba.nacos.spring.context.annotation.config; package com.alibaba.nacos.spring.context.annotation.config;
import static com.alibaba.nacos.spring.context.annotation.config.EnableNacosConfig.ACCESS_KEY_PLACEHOLDER;
import static com.alibaba.nacos.spring.context.annotation.config.EnableNacosConfig.CLUSTER_NAME_PLACEHOLDER;
import static com.alibaba.nacos.spring.context.annotation.config.EnableNacosConfig.CONTEXT_PATH_PLACEHOLDER;
import static com.alibaba.nacos.spring.context.annotation.config.EnableNacosConfig.ENCODE_PLACEHOLDER;
import static com.alibaba.nacos.spring.context.annotation.config.EnableNacosConfig.ENDPOINT_PLACEHOLDER;
import static com.alibaba.nacos.spring.context.annotation.config.EnableNacosConfig.NAMESPACE_PLACEHOLDER;
import static com.alibaba.nacos.spring.context.annotation.config.EnableNacosConfig.SECRET_KEY_PLACEHOLDER;
import static com.alibaba.nacos.spring.context.annotation.config.EnableNacosConfig.SERVER_ADDR_PLACEHOLDER;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
import org.springframework.mock.env.MockEnvironment; import org.springframework.mock.env.MockEnvironment;
import static com.alibaba.nacos.spring.context.annotation.config.EnableNacosConfig.*;
/** /**
* {@link EnableNacosConfig} Test * {@link EnableNacosConfig} Test
* *
@ -32,52 +39,77 @@ public class EnableNacosConfigTest {
@Test @Test
public void testPlaceholders() { public void testPlaceholders() {
Assert.assertEquals("${nacos.config.endpoint:${nacos.endpoint:}}", ENDPOINT_PLACEHOLDER); Assert.assertEquals("${nacos.config.endpoint:${nacos.endpoint:}}",
Assert.assertEquals("${nacos.config.namespace:${nacos.namespace:}}", NAMESPACE_PLACEHOLDER); ENDPOINT_PLACEHOLDER);
Assert.assertEquals("${nacos.config.access-key:${nacos.access-key:}}", ACCESS_KEY_PLACEHOLDER); Assert.assertEquals("${nacos.config.namespace:${nacos.namespace:}}",
Assert.assertEquals("${nacos.config.secret-key:${nacos.secret-key:}}", SECRET_KEY_PLACEHOLDER); NAMESPACE_PLACEHOLDER);
Assert.assertEquals("${nacos.config.server-addr:${nacos.server-addr:}}", SERVER_ADDR_PLACEHOLDER); Assert.assertEquals("${nacos.config.access-key:${nacos.access-key:}}",
Assert.assertEquals("${nacos.config.context-path:${nacos.context-path:}}", CONTEXT_PATH_PLACEHOLDER); ACCESS_KEY_PLACEHOLDER);
Assert.assertEquals("${nacos.config.cluster-name:${nacos.cluster-name:}}", CLUSTER_NAME_PLACEHOLDER); Assert.assertEquals("${nacos.config.secret-key:${nacos.secret-key:}}",
Assert.assertEquals("${nacos.config.encode:${nacos.encode:UTF-8}}", ENCODE_PLACEHOLDER); SECRET_KEY_PLACEHOLDER);
Assert.assertEquals("${nacos.config.server-addr:${nacos.server-addr:}}",
SERVER_ADDR_PLACEHOLDER);
Assert.assertEquals("${nacos.config.context-path:${nacos.context-path:}}",
CONTEXT_PATH_PLACEHOLDER);
Assert.assertEquals("${nacos.config.cluster-name:${nacos.cluster-name:}}",
CLUSTER_NAME_PLACEHOLDER);
Assert.assertEquals("${nacos.config.encode:${nacos.encode:UTF-8}}",
ENCODE_PLACEHOLDER);
} }
@Test @Test
public void testResolvePlaceholders() { public void testResolvePlaceholders() {
testResolvePlaceholder(ENDPOINT_PLACEHOLDER, "nacos.config.endpoint", "test-value", "test-value"); testResolvePlaceholder(ENDPOINT_PLACEHOLDER, "nacos.config.endpoint",
testResolvePlaceholder(ENDPOINT_PLACEHOLDER, "nacos.endpoint", "test-value", "test-value"); "test-value", "test-value");
testResolvePlaceholder(ENDPOINT_PLACEHOLDER, "nacos.endpoint", "test-value",
"test-value");
testResolvePlaceholder(ENDPOINT_PLACEHOLDER, "", "test-value", ""); testResolvePlaceholder(ENDPOINT_PLACEHOLDER, "", "test-value", "");
testResolvePlaceholder(NAMESPACE_PLACEHOLDER, "nacos.config.namespace", "test-value", "test-value"); testResolvePlaceholder(NAMESPACE_PLACEHOLDER, "nacos.config.namespace",
testResolvePlaceholder(NAMESPACE_PLACEHOLDER, "nacos.namespace", "test-value", "test-value"); "test-value", "test-value");
testResolvePlaceholder(NAMESPACE_PLACEHOLDER, "nacos.namespace", "test-value",
"test-value");
testResolvePlaceholder(NAMESPACE_PLACEHOLDER, "", "test-value", ""); testResolvePlaceholder(NAMESPACE_PLACEHOLDER, "", "test-value", "");
testResolvePlaceholder(ACCESS_KEY_PLACEHOLDER, "nacos.config.access-key", "test-value", "test-value"); testResolvePlaceholder(ACCESS_KEY_PLACEHOLDER, "nacos.config.access-key",
testResolvePlaceholder(ACCESS_KEY_PLACEHOLDER, "nacos.access-key", "test-value", "test-value"); "test-value", "test-value");
testResolvePlaceholder(ACCESS_KEY_PLACEHOLDER, "nacos.access-key", "test-value",
"test-value");
testResolvePlaceholder(ACCESS_KEY_PLACEHOLDER, "", "test-value", ""); testResolvePlaceholder(ACCESS_KEY_PLACEHOLDER, "", "test-value", "");
testResolvePlaceholder(SECRET_KEY_PLACEHOLDER, "nacos.config.secret-key", "test-value", "test-value"); testResolvePlaceholder(SECRET_KEY_PLACEHOLDER, "nacos.config.secret-key",
testResolvePlaceholder(SECRET_KEY_PLACEHOLDER, "nacos.secret-key", "test-value", "test-value"); "test-value", "test-value");
testResolvePlaceholder(SECRET_KEY_PLACEHOLDER, "nacos.secret-key", "test-value",
"test-value");
testResolvePlaceholder(SECRET_KEY_PLACEHOLDER, "", "test-value", ""); testResolvePlaceholder(SECRET_KEY_PLACEHOLDER, "", "test-value", "");
testResolvePlaceholder(SERVER_ADDR_PLACEHOLDER, "nacos.config.server-addr", "test-value", "test-value"); testResolvePlaceholder(SERVER_ADDR_PLACEHOLDER, "nacos.config.server-addr",
testResolvePlaceholder(SERVER_ADDR_PLACEHOLDER, "nacos.server-addr", "test-value", "test-value"); "test-value", "test-value");
testResolvePlaceholder(SERVER_ADDR_PLACEHOLDER, "nacos.server-addr", "test-value",
"test-value");
testResolvePlaceholder(SERVER_ADDR_PLACEHOLDER, "", "test-value", ""); testResolvePlaceholder(SERVER_ADDR_PLACEHOLDER, "", "test-value", "");
testResolvePlaceholder(CONTEXT_PATH_PLACEHOLDER, "nacos.config.context-path", "test-value", "test-value"); testResolvePlaceholder(CONTEXT_PATH_PLACEHOLDER, "nacos.config.context-path",
testResolvePlaceholder(CONTEXT_PATH_PLACEHOLDER, "nacos.context-path", "test-value", "test-value"); "test-value", "test-value");
testResolvePlaceholder(CONTEXT_PATH_PLACEHOLDER, "nacos.context-path",
"test-value", "test-value");
testResolvePlaceholder(CONTEXT_PATH_PLACEHOLDER, "", "test-value", ""); testResolvePlaceholder(CONTEXT_PATH_PLACEHOLDER, "", "test-value", "");
testResolvePlaceholder(CLUSTER_NAME_PLACEHOLDER, "nacos.config.cluster-name", "test-value", "test-value"); testResolvePlaceholder(CLUSTER_NAME_PLACEHOLDER, "nacos.config.cluster-name",
testResolvePlaceholder(CLUSTER_NAME_PLACEHOLDER, "nacos.cluster-name", "test-value", "test-value"); "test-value", "test-value");
testResolvePlaceholder(CLUSTER_NAME_PLACEHOLDER, "nacos.cluster-name",
"test-value", "test-value");
testResolvePlaceholder(CLUSTER_NAME_PLACEHOLDER, "", "test-value", ""); testResolvePlaceholder(CLUSTER_NAME_PLACEHOLDER, "", "test-value", "");
testResolvePlaceholder(ENCODE_PLACEHOLDER, "nacos.config.encode", "test-value", "test-value"); testResolvePlaceholder(ENCODE_PLACEHOLDER, "nacos.config.encode", "test-value",
testResolvePlaceholder(ENCODE_PLACEHOLDER, "nacos.encode", "test-value", "test-value"); "test-value");
testResolvePlaceholder(ENCODE_PLACEHOLDER, "nacos.encode", "test-value",
"test-value");
testResolvePlaceholder(ENCODE_PLACEHOLDER, "", "test-value", "UTF-8"); testResolvePlaceholder(ENCODE_PLACEHOLDER, "", "test-value", "UTF-8");
} }
private void testResolvePlaceholder(String placeholder, String propertyName, String propertyValue, String expectValue) { private void testResolvePlaceholder(String placeholder, String propertyName,
String propertyValue, String expectValue) {
MockEnvironment environment = new MockEnvironment(); MockEnvironment environment = new MockEnvironment();
environment.setProperty(propertyName, propertyValue); environment.setProperty(propertyName, propertyValue);
String resolvedValue = environment.resolvePlaceholders(placeholder); String resolvedValue = environment.resolvePlaceholders(placeholder);

View File

@ -16,7 +16,12 @@
*/ */
package com.alibaba.nacos.spring.context.annotation.config; package com.alibaba.nacos.spring.context.annotation.config;
import com.alibaba.nacos.api.annotation.NacosProperties; import static com.alibaba.nacos.spring.util.NacosBeanUtils.CONFIG_GLOBAL_NACOS_PROPERTIES_BEAN_NAME;
import java.util.Properties;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactory;
@ -26,9 +31,8 @@ import org.springframework.stereotype.Component;
import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.util.Properties; import com.alibaba.nacos.api.annotation.NacosProperties;
import com.alibaba.nacos.spring.util.NacosUtils;
import static com.alibaba.nacos.spring.util.NacosBeanUtils.CONFIG_GLOBAL_NACOS_PROPERTIES_BEAN_NAME;
/** /**
* {@link NacosConfigBeanDefinitionRegistrar} Test * {@link NacosConfigBeanDefinitionRegistrar} Test
@ -38,13 +42,12 @@ import static com.alibaba.nacos.spring.util.NacosBeanUtils.CONFIG_GLOBAL_NACOS_P
*/ */
@RunWith(SpringJUnit4ClassRunner.class) @RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = NacosConfigBeanDefinitionRegistrarTest.class) @ContextConfiguration(classes = NacosConfigBeanDefinitionRegistrarTest.class)
@EnableNacosConfig(globalProperties = @NacosProperties) @EnableNacosConfig(globalProperties = @NacosProperties(enableRemoteSyncConfig = "true", maxRetry = "5", configRetryTime = "2600", configLongPollTimeout = "26000"))
@Component @Component
public class NacosConfigBeanDefinitionRegistrarTest { public class NacosConfigBeanDefinitionRegistrarTest {
@Autowired @Autowired
private BeanFactory beanFactory; private BeanFactory beanFactory;
@Autowired @Autowired
@Qualifier(CONFIG_GLOBAL_NACOS_PROPERTIES_BEAN_NAME) @Qualifier(CONFIG_GLOBAL_NACOS_PROPERTIES_BEAN_NAME)
private Properties properties; private Properties properties;

View File

@ -16,7 +16,28 @@
*/ */
package com.alibaba.nacos.spring.context.annotation.config; package com.alibaba.nacos.spring.context.annotation.config;
import static com.alibaba.nacos.api.common.Constants.DEFAULT_GROUP;
import static com.alibaba.nacos.spring.test.MockNacosServiceFactory.DATA_ID;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import javax.annotation.PostConstruct;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
import org.springframework.test.context.support.DirtiesContextTestExecutionListener;
import com.alibaba.nacos.api.annotation.NacosInjected; import com.alibaba.nacos.api.annotation.NacosInjected;
import com.alibaba.nacos.api.annotation.NacosProperties;
import com.alibaba.nacos.api.config.ConfigService; import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.annotation.NacosConfigListener; import com.alibaba.nacos.api.config.annotation.NacosConfigListener;
import com.alibaba.nacos.api.config.listener.AbstractListener; import com.alibaba.nacos.api.config.listener.AbstractListener;
@ -24,21 +45,12 @@ import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.spring.beans.factory.annotation.AnnotationNacosInjectedBeanPostProcessor; import com.alibaba.nacos.spring.beans.factory.annotation.AnnotationNacosInjectedBeanPostProcessor;
import com.alibaba.nacos.spring.beans.factory.annotation.ConfigServiceBeanBuilder; import com.alibaba.nacos.spring.beans.factory.annotation.ConfigServiceBeanBuilder;
import com.alibaba.nacos.spring.convert.converter.config.UserNacosConfigConverter; import com.alibaba.nacos.spring.convert.converter.config.UserNacosConfigConverter;
import com.alibaba.nacos.spring.factory.ApplicationContextHolder;
import com.alibaba.nacos.spring.test.AbstractNacosHttpServerTestExecutionListener;
import com.alibaba.nacos.spring.test.Listeners; import com.alibaba.nacos.spring.test.Listeners;
import com.alibaba.nacos.spring.test.TestConfiguration; import com.alibaba.nacos.spring.test.TestConfiguration;
import com.alibaba.nacos.spring.test.User; import com.alibaba.nacos.spring.test.User;
import org.junit.Test; import com.alibaba.nacos.spring.util.NacosUtils;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import javax.annotation.PostConstruct;
import static com.alibaba.nacos.api.common.Constants.DEFAULT_GROUP;
import static com.alibaba.nacos.spring.test.MockNacosServiceFactory.DATA_ID;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
/** /**
* {@link NacosConfigListenerMethodProcessor} Test * {@link NacosConfigListenerMethodProcessor} Test
@ -47,22 +59,35 @@ import static org.junit.Assert.assertNull;
* @since 0.1.0 * @since 0.1.0
*/ */
@RunWith(SpringJUnit4ClassRunner.class) @RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { @ContextConfiguration(classes = { TestConfiguration.class, Listeners.class,
TestConfiguration.class, ConfigServiceBeanBuilder.class, AnnotationNacosInjectedBeanPostProcessor.class,
Listeners.class,
ConfigServiceBeanBuilder.class,
AnnotationNacosInjectedBeanPostProcessor.class,
NacosConfigListenerMethodProcessor.class, NacosConfigListenerMethodProcessor.class,
NacosConfigListenerMethodProcessorTest.class, NacosConfigListenerMethodProcessorTest.class })
@TestExecutionListeners({ DependencyInjectionTestExecutionListener.class,
}) DirtiesContextTestExecutionListener.class,
public class NacosConfigListenerMethodProcessorTest { NacosConfigListenerMethodProcessorTest.class })
@EnableNacosConfig(globalProperties = @NacosProperties(serverAddr = "${server.addr}"))
public class NacosConfigListenerMethodProcessorTest
extends AbstractNacosHttpServerTestExecutionListener {
@Autowired @Autowired
private Listeners listeners; private Listeners listeners;
@NacosInjected @NacosInjected
private ConfigService configService; private ConfigService configService;
private volatile boolean received = false;
@Bean(name = ApplicationContextHolder.BEAN_NAME)
public ApplicationContextHolder applicationContextHolder(
ApplicationContext applicationContext) {
ApplicationContextHolder applicationContextHolder = new ApplicationContextHolder();
applicationContextHolder.setApplicationContext(applicationContext);
return applicationContextHolder;
}
@Override
protected String getServerAddressPropertyName() {
return "server.addr";
}
@PostConstruct @PostConstruct
public void initListener() throws NacosException { public void initListener() throws NacosException {
@ -90,22 +115,31 @@ public class NacosConfigListenerMethodProcessorTest {
} }
@Test @Test
public void testPublishConfig() throws NacosException { public void testPublishConfig() throws NacosException, InterruptedException {
configService.publishConfig(DATA_ID, DEFAULT_GROUP, "9527"); configService.publishConfig(DATA_ID, DEFAULT_GROUP, "9527");
Thread.sleep(3000);
assertNull(listeners.getIntegerValue()); // asserts true assertNull(listeners.getIntegerValue()); // asserts true
assertEquals(Double.valueOf(9527), listeners.getDoubleValue()); // asserts true assertEquals(Double.valueOf(9527), listeners.getDoubleValue()); // asserts true
} }
@Test @Test
public void testPublishUser() throws NacosException { public void testPublishUser() throws NacosException, InterruptedException {
configService.publishConfig("user", DEFAULT_GROUP, "{\"id\":1,\"name\":\"mercyblitz\"}"); configService.publishConfig("user", DEFAULT_GROUP,
"{\"id\":1,\"name\":\"mercyblitz\"}");
int cnt = 3;
while (cnt >= 0 && !received) {
Thread.sleep(1000);
cnt--;
}
} }
@NacosConfigListener(dataId = "user", converter = UserNacosConfigConverter.class) @NacosConfigListener(dataId = "user", converter = UserNacosConfigConverter.class)
public void onUser(User user) { public void onUser(User user) {
assertEquals(Long.valueOf(1L), user.getId()); assertEquals(Long.valueOf(1L), user.getId());
assertEquals("mercyblitz", user.getName()); assertEquals("mercyblitz", user.getName());
received = true;
} }
} }

View File

@ -0,0 +1,126 @@
/*
* 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 com.alibaba.nacos.spring.context.annotation.config;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
import org.springframework.test.context.support.DirtiesContextTestExecutionListener;
import com.alibaba.nacos.api.annotation.NacosInjected;
import com.alibaba.nacos.api.annotation.NacosProperties;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.annotation.NacosConfigListener;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.spring.test.AbstractNacosHttpServerTestExecutionListener;
import com.alibaba.nacos.spring.util.NacosUtils;
/**
* NacosConfigListenerTest.
*
* @author <a href="mailto:liaochunyhm@live.com">liaochuntao</a>
* @since
*/
@RunWith(SpringJUnit4ClassRunner.class)
@TestExecutionListeners({ DependencyInjectionTestExecutionListener.class,
DirtiesContextTestExecutionListener.class, NacosConfigListenerTest.class })
@ContextConfiguration(classes = { NacosConfigListenerTest.NacosConfiguration.class,
NacosConfigListenerTest.class })
public class NacosConfigListenerTest
extends AbstractNacosHttpServerTestExecutionListener {
private static volatile String content = "";
private static volatile boolean receiveOne = false;
private static volatile boolean receiveTwo = false;
private static volatile boolean receiveThree = false;
@NacosInjected
private ConfigService configService;
@Override
protected String getServerAddressPropertyName() {
return "server.addr";
}
@NacosConfigListener(dataId = "com.alibaba.nacos.example.properties", timeout = 2000L)
public void onMessage(String config) {
System.out.println("onMessage: " + config);
receiveOne = true;
content = config;
}
@NacosConfigListener(dataId = "convert_map.properties", timeout = 2000L)
public void onMessage(Map config) {
System.out.println("onMessage: " + config);
receiveTwo = true;
}
@NacosConfigListener(dataId = "convert_map.yaml", timeout = 2000L)
public void onMessageYaml(Map config) {
System.out.println("onMessage: " + config);
receiveThree = true;
}
@Before
public void before() {
}
@Test
public void testConfigListener() throws InterruptedException {
final long currentTimeMillis = System.currentTimeMillis();
boolean result = false;
try {
result = configService.publishConfig("com.alibaba.nacos.example.properties",
"DEFAULT_GROUP", "" + currentTimeMillis);
result = configService.publishConfig("convert_map.properties",
"DEFAULT_GROUP", "this.is.test=true");
result = configService.publishConfig("convert_map.yaml", "DEFAULT_GROUP",
"routingMap:\n" + " - aaa\n" + " - bbb\n" + " - ccc\n"
+ " - ddd\n" + " - eee\n" + "endPointMap:\n" + " - fff\n"
+ "testMap:\n" + " abc: def1");
}
catch (NacosException e) {
e.printStackTrace();
}
Assert.assertTrue(result);
while (!receiveOne && !receiveTwo && !receiveThree) {
TimeUnit.SECONDS.sleep(3);
}
Assert.assertEquals("" + currentTimeMillis, content);
}
@Configuration
// 在命名空间详情处可以获取到 endpoint namespaceaccessKey secretKey 推荐使用 RAM 账户的
@EnableNacosConfig(globalProperties = @NacosProperties(serverAddr = "${server.addr}"))
public static class NacosConfiguration {
}
}

View File

@ -16,12 +16,16 @@
*/ */
package com.alibaba.nacos.spring.context.annotation.config; package com.alibaba.nacos.spring.context.annotation.config;
import com.alibaba.nacos.api.annotation.NacosProperties; import org.junit.AfterClass;
import com.alibaba.nacos.spring.context.annotation.EnableNacos;
import org.junit.Assert; import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test; import org.junit.Test;
import org.springframework.mock.env.MockEnvironment; import org.springframework.mock.env.MockEnvironment;
import com.alibaba.nacos.api.annotation.NacosProperties;
import com.alibaba.nacos.spring.context.annotation.EnableNacos;
import com.alibaba.nacos.spring.util.NacosUtils;
/** /**
* {@link NacosProperties} Test * {@link NacosProperties} Test
* *
@ -31,26 +35,6 @@ import org.springframework.mock.env.MockEnvironment;
*/ */
public class NacosPropertiesTest { public class NacosPropertiesTest {
@EnableNacos(globalProperties = @NacosProperties)
private static class NacosPropertiesDefaultValues {
}
@EnableNacos(
globalProperties =
@NacosProperties(
endpoint = "e",
namespace = "n",
accessKey = "a",
secretKey = "s",
serverAddr = "127.0.0.1",
contextPath = "/",
clusterName = "c",
encode = "GBK"
)
)
private static class NacosPropertiesValues {
}
@Test @Test
public void testConstants() { public void testConstants() {
Assert.assertEquals("nacos.", NacosProperties.PREFIX); Assert.assertEquals("nacos.", NacosProperties.PREFIX);
@ -79,7 +63,8 @@ public class NacosPropertiesTest {
@Test @Test
public void testAttributeValues() { public void testAttributeValues() {
EnableNacos enableNacos = NacosPropertiesValues.class.getAnnotation(EnableNacos.class); EnableNacos enableNacos = NacosPropertiesValues.class
.getAnnotation(EnableNacos.class);
NacosProperties nacosProperties = enableNacos.globalProperties(); NacosProperties nacosProperties = enableNacos.globalProperties();
Assert.assertEquals("e", nacosProperties.endpoint()); Assert.assertEquals("e", nacosProperties.endpoint());
Assert.assertEquals("n", nacosProperties.namespace()); Assert.assertEquals("n", nacosProperties.namespace());
@ -95,14 +80,22 @@ public class NacosPropertiesTest {
public void testAttributeResolvedDefaultValues() { public void testAttributeResolvedDefaultValues() {
NacosProperties nacosProperties = getDefaultNacosProperties(); NacosProperties nacosProperties = getDefaultNacosProperties();
MockEnvironment environment = new MockEnvironment(); MockEnvironment environment = new MockEnvironment();
Assert.assertEquals("", environment.resolvePlaceholders(nacosProperties.endpoint())); Assert.assertEquals("",
Assert.assertEquals("", environment.resolvePlaceholders(nacosProperties.namespace())); environment.resolvePlaceholders(nacosProperties.endpoint()));
Assert.assertEquals("", environment.resolvePlaceholders(nacosProperties.accessKey())); Assert.assertEquals("",
Assert.assertEquals("", environment.resolvePlaceholders(nacosProperties.secretKey())); environment.resolvePlaceholders(nacosProperties.namespace()));
Assert.assertEquals("", environment.resolvePlaceholders(nacosProperties.serverAddr())); Assert.assertEquals("",
Assert.assertEquals("", environment.resolvePlaceholders(nacosProperties.contextPath())); environment.resolvePlaceholders(nacosProperties.accessKey()));
Assert.assertEquals("", environment.resolvePlaceholders(nacosProperties.clusterName())); Assert.assertEquals("",
Assert.assertEquals("UTF-8", environment.resolvePlaceholders(nacosProperties.encode())); environment.resolvePlaceholders(nacosProperties.secretKey()));
Assert.assertEquals("",
environment.resolvePlaceholders(nacosProperties.serverAddr()));
Assert.assertEquals("",
environment.resolvePlaceholders(nacosProperties.contextPath()));
Assert.assertEquals("",
environment.resolvePlaceholders(nacosProperties.clusterName()));
Assert.assertEquals("UTF-8",
environment.resolvePlaceholders(nacosProperties.encode()));
} }
@Test @Test
@ -118,20 +111,37 @@ public class NacosPropertiesTest {
environment.setProperty("nacos.cluster-name", "c"); environment.setProperty("nacos.cluster-name", "c");
environment.setProperty("nacos.encode", "GBK"); environment.setProperty("nacos.encode", "GBK");
Assert.assertEquals("e", environment.resolvePlaceholders(nacosProperties.endpoint())); Assert.assertEquals("e",
Assert.assertEquals("n", environment.resolvePlaceholders(nacosProperties.namespace())); environment.resolvePlaceholders(nacosProperties.endpoint()));
Assert.assertEquals("a", environment.resolvePlaceholders(nacosProperties.accessKey())); Assert.assertEquals("n",
Assert.assertEquals("s", environment.resolvePlaceholders(nacosProperties.secretKey())); environment.resolvePlaceholders(nacosProperties.namespace()));
Assert.assertEquals("127.0.0.1", environment.resolvePlaceholders(nacosProperties.serverAddr())); Assert.assertEquals("a",
Assert.assertEquals("/", environment.resolvePlaceholders(nacosProperties.contextPath())); environment.resolvePlaceholders(nacosProperties.accessKey()));
Assert.assertEquals("c", environment.resolvePlaceholders(nacosProperties.clusterName())); Assert.assertEquals("s",
Assert.assertEquals("GBK", environment.resolvePlaceholders(nacosProperties.encode())); environment.resolvePlaceholders(nacosProperties.secretKey()));
Assert.assertEquals("127.0.0.1",
environment.resolvePlaceholders(nacosProperties.serverAddr()));
Assert.assertEquals("/",
environment.resolvePlaceholders(nacosProperties.contextPath()));
Assert.assertEquals("c",
environment.resolvePlaceholders(nacosProperties.clusterName()));
Assert.assertEquals("GBK",
environment.resolvePlaceholders(nacosProperties.encode()));
} }
private NacosProperties getDefaultNacosProperties() { private NacosProperties getDefaultNacosProperties() {
EnableNacos enableNacos = NacosPropertiesDefaultValues.class.getAnnotation(EnableNacos.class); EnableNacos enableNacos = NacosPropertiesDefaultValues.class
.getAnnotation(EnableNacos.class);
NacosProperties nacosProperties = enableNacos.globalProperties(); NacosProperties nacosProperties = enableNacos.globalProperties();
return nacosProperties; return nacosProperties;
} }
@EnableNacos(globalProperties = @NacosProperties)
private static class NacosPropertiesDefaultValues {
}
@EnableNacos(globalProperties = @NacosProperties(endpoint = "e", namespace = "n", accessKey = "a", secretKey = "s", serverAddr = "127.0.0.1", contextPath = "/", clusterName = "c", encode = "GBK"))
private static class NacosPropertiesValues {
}
} }

View File

@ -0,0 +1,104 @@
/*
* 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 com.alibaba.nacos.spring.context.annotation.config;
import static com.alibaba.nacos.api.common.Constants.DEFAULT_GROUP;
import static com.alibaba.nacos.embedded.web.server.NacosConfigHttpHandler.CONTENT_PARAM_NAME;
import static com.alibaba.nacos.embedded.web.server.NacosConfigHttpHandler.DATA_ID_PARAM_NAME;
import static com.alibaba.nacos.embedded.web.server.NacosConfigHttpHandler.GROUP_ID_PARAM_NAME;
import java.util.HashMap;
import java.util.Map;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
import org.springframework.test.context.support.DirtiesContextTestExecutionListener;
import com.alibaba.nacos.api.annotation.NacosInjected;
import com.alibaba.nacos.api.annotation.NacosProperties;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.embedded.web.server.EmbeddedNacosHttpServer;
import com.alibaba.nacos.spring.test.AbstractNacosHttpServerTestExecutionListener;
import com.alibaba.nacos.spring.test.YamlBean;
import com.alibaba.nacos.spring.util.NacosUtils;
/**
* @author mai.jh
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { NacosPropertySourceBeanTest.class })
@TestExecutionListeners({ DependencyInjectionTestExecutionListener.class,
DirtiesContextTestExecutionListener.class, NacosPropertySourceBeanTest.class })
@NacosPropertySources(value = { @NacosPropertySource(dataId = YamlBean.DATA_ID_YAML
+ ".yml", autoRefreshed = true) })
@EnableNacosConfig(globalProperties = @NacosProperties(serverAddr = "${server.addr}"))
@Component
public class NacosPropertySourceBeanTest
extends AbstractNacosHttpServerTestExecutionListener {
private String yaml = "student:\n" + " name: lct-1\n" + " num: 12\n"
+ " testApp: \n" + " name: test";
private String except = "YamlBean{student=Student{name='lct-1', num='12', testApp=TestApp{name='test'}}}";
@NacosInjected
private ConfigService configService;
@Autowired
private YamlBean yamlBean;
@Override
public void init(EmbeddedNacosHttpServer httpServer) {
Map<String, String> config = new HashMap<String, String>(1);
config.put(DATA_ID_PARAM_NAME, YamlBean.DATA_ID_YAML + ".yml");
config.put(GROUP_ID_PARAM_NAME, DEFAULT_GROUP);
config.put(CONTENT_PARAM_NAME, yaml);
httpServer.initConfig(config);
}
@Bean
public YamlBean yamlBean() {
return new YamlBean();
}
@Override
protected String getServerAddressPropertyName() {
return "server.addr";
}
@Test
public void testValue() throws NacosException, InterruptedException {
configService.publishConfig(YamlBean.DATA_ID_YAML + ".yml", DEFAULT_GROUP, yaml);
Thread.sleep(2000);
Assert.assertEquals(except, yamlBean.toString());
}
}

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 com.alibaba.nacos.spring.context.annotation.config;
import org.junit.Assert;
import org.junit.Test;
import org.springframework.core.env.MapPropertySource;
import java.util.HashMap;
/**
* {@link NacosPropertySourceBuilder} Test
* @author SuperZ1999
* @date 2023/9/28
*/
public class NacosPropertySourceBuilderTest {
@Test
public void test() {
MapPropertySource propertySource = new MapPropertySource("test", new HashMap<>());
Assert.assertNotNull(propertySource);
}
}

View File

@ -0,0 +1,136 @@
/*
* 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 com.alibaba.nacos.spring.context.annotation.config;
import static com.alibaba.nacos.api.common.Constants.DEFAULT_GROUP;
import static com.alibaba.nacos.embedded.web.server.NacosConfigHttpHandler.CONTENT_PARAM_NAME;
import static com.alibaba.nacos.embedded.web.server.NacosConfigHttpHandler.DATA_ID_PARAM_NAME;
import static com.alibaba.nacos.embedded.web.server.NacosConfigHttpHandler.GROUP_ID_PARAM_NAME;
import java.util.HashMap;
import java.util.Map;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
import org.springframework.test.context.support.DirtiesContextTestExecutionListener;
import com.alibaba.nacos.api.annotation.NacosInjected;
import com.alibaba.nacos.api.annotation.NacosProperties;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.ConfigType;
import com.alibaba.nacos.api.config.annotation.NacosValue;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.embedded.web.server.EmbeddedNacosHttpServer;
import com.alibaba.nacos.spring.test.AbstractNacosHttpServerTestExecutionListener;
import com.alibaba.nacos.spring.util.NacosUtils;
/**
* @author <a href="mailto:liaochunyhm@live.com">liaochuntao</a>
* @since
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { NacosPropertySourceJsonTest.class })
@TestExecutionListeners({ DependencyInjectionTestExecutionListener.class,
DirtiesContextTestExecutionListener.class, NacosPropertySourceJsonTest.class })
@NacosPropertySource(dataId = NacosPropertySourceJsonTest.DATA_ID, autoRefreshed = true, type = ConfigType.JSON)
@EnableNacosConfig(globalProperties = @NacosProperties(serverAddr = "${server.addr}"))
@Component
public class NacosPropertySourceJsonTest
extends AbstractNacosHttpServerTestExecutionListener {
public static final String DATA_ID = "data_json";
private String configStr = "{\n" + " \"people\":{\n"
+ " \"a\":\"liaochuntao\",\n" + " \"b\":\"this is test\"\n"
+ " }\n" + "}";
private String newConfigStr = "{\n" + " \"people\":{\n"
+ " \"a\":\"liaochuntao\",\n"
+ " \"b\":\"refresh this is test\"\n" + " }\n" + "}";
@NacosInjected
private ConfigService configService;
@Autowired
private App app;
@Override
protected String getServerAddressPropertyName() {
return "server.addr";
}
@Override
public void init(EmbeddedNacosHttpServer httpServer) {
Map<String, String> config = new HashMap<String, String>(1);
config.put(DATA_ID_PARAM_NAME, DATA_ID);
config.put(GROUP_ID_PARAM_NAME, DEFAULT_GROUP);
config.put(CONTENT_PARAM_NAME, configStr);
httpServer.initConfig(config);
}
@Bean
public App app() {
return new App();
}
@Test
public void testValue() throws NacosException, InterruptedException {
Assert.assertEquals("liaochuntao", app.a);
Assert.assertEquals("this is test", app.b);
configService.publishConfig(DATA_ID, DEFAULT_GROUP, newConfigStr);
Thread.sleep(2000);
Assert.assertEquals("liaochuntao", app.a);
Assert.assertEquals("refresh this is test", app.b);
}
public static class App {
@Value("${people.a}")
private String a;
@NacosValue(value = "${people.b}", autoRefreshed = true)
private String b;
public String getA() {
return a;
}
public void setA(String a) {
this.a = a;
}
public String getB() {
return b;
}
public void setB(String b) {
this.b = b;
}
}
}

View File

@ -16,27 +16,50 @@
*/ */
package com.alibaba.nacos.spring.context.annotation.config; package com.alibaba.nacos.spring.context.annotation.config;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.spring.beans.factory.annotation.AnnotationNacosInjectedBeanPostProcessor;
import com.alibaba.nacos.spring.beans.factory.annotation.ConfigServiceBeanBuilder;
import com.alibaba.nacos.spring.core.env.AnnotationNacosPropertySourceBuilder;
import com.alibaba.nacos.spring.core.env.NacosPropertySourcePostProcessor;
import com.alibaba.nacos.spring.test.MockConfigService;
import com.alibaba.nacos.spring.test.TestConfiguration;
import org.junit.Assert;
import org.junit.Test;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.PropertySource;
import static com.alibaba.nacos.api.common.Constants.DEFAULT_GROUP; import static com.alibaba.nacos.api.common.Constants.DEFAULT_GROUP;
import static com.alibaba.nacos.embedded.web.server.NacosConfigHttpHandler.CONTENT_PARAM_NAME;
import static com.alibaba.nacos.embedded.web.server.NacosConfigHttpHandler.DATA_ID_PARAM_NAME;
import static com.alibaba.nacos.embedded.web.server.NacosConfigHttpHandler.GROUP_ID_PARAM_NAME;
import static com.alibaba.nacos.spring.test.MockNacosServiceFactory.DATA_ID; import static com.alibaba.nacos.spring.test.MockNacosServiceFactory.DATA_ID;
import static com.alibaba.nacos.spring.test.TestConfiguration.CONFIG_SERVICE_BEAN_NAME; import static com.alibaba.nacos.spring.test.TestConfiguration.CONFIG_SERVICE_BEAN_NAME;
import static org.springframework.core.env.StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME; import static org.springframework.core.env.StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME;
import static org.springframework.core.env.StandardEnvironment.SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME; import static org.springframework.core.env.StandardEnvironment.SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME;
import java.util.HashMap;
import java.util.Map;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.PropertySource;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
import org.springframework.test.context.support.DirtiesContextTestExecutionListener;
import com.alibaba.nacos.api.annotation.NacosInjected;
import com.alibaba.nacos.api.annotation.NacosProperties;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.embedded.web.server.EmbeddedNacosHttpServer;
import com.alibaba.nacos.spring.beans.factory.annotation.AnnotationNacosInjectedBeanPostProcessor;
import com.alibaba.nacos.spring.beans.factory.annotation.ConfigServiceBeanBuilder;
import com.alibaba.nacos.spring.core.env.AnnotationNacosPropertySourceBuilder;
import com.alibaba.nacos.spring.core.env.NacosPropertySourcePostProcessor;
import com.alibaba.nacos.spring.factory.ApplicationContextHolder;
import com.alibaba.nacos.spring.test.AbstractNacosHttpServerTestExecutionListener;
import com.alibaba.nacos.spring.test.TestApplicationHolder;
import com.alibaba.nacos.spring.test.TestConfiguration;
import com.alibaba.nacos.spring.util.NacosUtils;
/** /**
* {@link NacosPropertySourcePostProcessor} Test * {@link NacosPropertySourcePostProcessor} Test
* *
@ -44,51 +67,51 @@ import static org.springframework.core.env.StandardEnvironment.SYSTEM_PROPERTIES
* @ee NacosPropertySourcePostProcessor * @ee NacosPropertySourcePostProcessor
* @since 0.1.0 * @since 0.1.0
*/ */
public class NacosPropertySourcePostProcessorTest { @RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { NacosPropertySourcePostProcessorTest.class })
@TestExecutionListeners({ DependencyInjectionTestExecutionListener.class,
DirtiesContextTestExecutionListener.class,
NacosPropertySourcePostProcessorTest.class })
@EnableNacosConfig(globalProperties = @NacosProperties(serverAddr = "${server.addr}"))
public class NacosPropertySourcePostProcessorTest
extends AbstractNacosHttpServerTestExecutionListener {
private static final String TEST_PROPERTY_NAME = "user.name"; private static final String TEST_PROPERTY_NAME = "user.name";
private static final String TEST_PROPERTY_VALUE = "mercyblitz@"
private static final String TEST_PROPERTY_VALUE = "mercyblitz@" + System.currentTimeMillis(); + System.currentTimeMillis();
private static final String TEST_CONTENT = TEST_PROPERTY_NAME + "="
private static final String TEST_CONTENT = TEST_PROPERTY_NAME + "=" + TEST_PROPERTY_VALUE + TEST_PROPERTY_VALUE + System.getProperty("line.separator")
+ System.getProperty("line.separator")
+ "PATH = /My/Path"; + "PATH = /My/Path";
@NacosInjected
private ConfigService configService;
@NacosPropertySources({ @Override
@NacosPropertySource( public void init(EmbeddedNacosHttpServer httpServer) {
name = "second", Map<String, String> config = new HashMap<String, String>(1);
dataId = DATA_ID, config.put(DATA_ID_PARAM_NAME, DATA_ID);
first = true, config.put(GROUP_ID_PARAM_NAME, DEFAULT_GROUP);
before = SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME, config.put(CONTENT_PARAM_NAME, TEST_CONTENT);
after = SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME), httpServer.initConfig(config);
@NacosPropertySource(
name = "first",
dataId = DATA_ID,
first = true,
before = SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME,
after = SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME)
})
@NacosPropertySource(
dataId = DATA_ID,
before = SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME,
after = SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME)
private static class FirstOrderNacosPropertySource {
} }
@NacosPropertySource( @Override
dataId = DATA_ID, protected String getServerAddressPropertyName() {
before = SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, return "server.addr";
after = SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME)
private static class RelativeOrderNacosPropertySource {
} }
@Bean(name = ApplicationContextHolder.BEAN_NAME)
public ApplicationContextHolder applicationContextHolder(
ApplicationContext applicationContext) {
ApplicationContextHolder applicationContextHolder = new ApplicationContextHolder();
applicationContextHolder.setApplicationContext(applicationContext);
return applicationContextHolder;
}
@Test @Test
public void testFirstOrder() throws NacosException { public void testFirstOrder() throws NacosException {
AnnotationConfigApplicationContext context = createContext(DATA_ID, DEFAULT_GROUP, TEST_CONTENT); AnnotationConfigApplicationContext context = createContext(DATA_ID, DEFAULT_GROUP,
TEST_CONTENT);
context.register(FirstOrderNacosPropertySource.class); context.register(FirstOrderNacosPropertySource.class);
@ -98,7 +121,8 @@ public class NacosPropertySourcePostProcessorTest {
PropertySource propertySource = environment.getPropertySources().get("first"); PropertySource propertySource = environment.getPropertySources().get("first");
PropertySource firstPropertySource = environment.getPropertySources().iterator().next(); PropertySource firstPropertySource = environment.getPropertySources().iterator()
.next();
Assert.assertNotNull(propertySource); Assert.assertNotNull(propertySource);
@ -112,14 +136,16 @@ public class NacosPropertySourcePostProcessorTest {
Assert.assertEquals(TEST_PROPERTY_VALUE, propertyValue); Assert.assertEquals(TEST_PROPERTY_VALUE, propertyValue);
Assert.assertEquals(TEST_PROPERTY_VALUE, propertySource.getProperty(TEST_PROPERTY_NAME)); Assert.assertEquals(TEST_PROPERTY_VALUE,
propertySource.getProperty(TEST_PROPERTY_NAME));
} }
@Test @Test
public void testRelativeOrder() throws NacosException { public void testRelativeOrder() throws NacosException {
AnnotationConfigApplicationContext context = createContext(DATA_ID, DEFAULT_GROUP, TEST_CONTENT); AnnotationConfigApplicationContext context = createContext(DATA_ID, DEFAULT_GROUP,
TEST_CONTENT);
context.register(RelativeOrderNacosPropertySource.class); context.register(RelativeOrderNacosPropertySource.class);
@ -144,20 +170,33 @@ public class NacosPropertySourcePostProcessorTest {
Assert.assertEquals("/My/Path", propertyValue); Assert.assertEquals("/My/Path", propertyValue);
} }
private AnnotationConfigApplicationContext createContext(String dataId, String groupId, String content) throws NacosException { private AnnotationConfigApplicationContext createContext(String dataId,
String groupId, String content) throws NacosException {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory(); ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
ConfigService configService = new MockConfigService();
configService.publishConfig(dataId, groupId, content); configService.publishConfig(dataId, groupId, content);
beanFactory.registerSingleton(CONFIG_SERVICE_BEAN_NAME, configService); beanFactory.registerSingleton(CONFIG_SERVICE_BEAN_NAME, configService);
context.register(TestConfiguration.class, AnnotationNacosInjectedBeanPostProcessor.class, context.register(AnnotationNacosInjectedBeanPostProcessor.class,
NacosPropertySourcePostProcessor.class, ConfigServiceBeanBuilder.class, NacosPropertySourcePostProcessor.class, ConfigServiceBeanBuilder.class,
AnnotationNacosPropertySourceBuilder.class); AnnotationNacosPropertySourceBuilder.class, TestConfiguration.class,
TestApplicationHolder.class);
return context; return context;
} }
@NacosPropertySources({
@NacosPropertySource(name = "second", dataId = DATA_ID, first = true, before = SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME, after = SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME),
@NacosPropertySource(name = "first", dataId = DATA_ID, first = true, before = SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME, after = SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME) })
@NacosPropertySource(dataId = DATA_ID, before = SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, after = SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME)
private static class FirstOrderNacosPropertySource {
}
@NacosPropertySource(dataId = DATA_ID, before = SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, after = SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME)
private static class RelativeOrderNacosPropertySource {
}
} }

View File

@ -0,0 +1,201 @@
/*
* 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 com.alibaba.nacos.spring.context.annotation.config;
import static com.alibaba.nacos.embedded.web.server.NacosConfigHttpHandler.CONTENT_PARAM_NAME;
import static com.alibaba.nacos.embedded.web.server.NacosConfigHttpHandler.DATA_ID_PARAM_NAME;
import static com.alibaba.nacos.embedded.web.server.NacosConfigHttpHandler.GROUP_ID_PARAM_NAME;
import static com.alibaba.nacos.spring.context.annotation.config.NacosPropertySourceReadFromEnvironmentTest.ENV_GROUP_ID;
import java.util.HashMap;
import java.util.Map;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.stereotype.Component;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
import org.springframework.test.context.support.DirtiesContextTestExecutionListener;
import com.alibaba.nacos.api.annotation.NacosInjected;
import com.alibaba.nacos.api.annotation.NacosProperties;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.annotation.NacosValue;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.embedded.web.server.EmbeddedNacosHttpServer;
import com.alibaba.nacos.spring.test.AbstractNacosHttpServerTestExecutionListener;
import com.alibaba.nacos.spring.util.NacosUtils;
/**
* @author <a href="mailto:liaochunyhm@live.com">liaochuntao</a>
* @since
*/
@Ignore
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { NacosPropertySourceReadFromEnvironmentTest.class })
@TestExecutionListeners({ DependencyInjectionTestExecutionListener.class,
DirtiesContextTestExecutionListener.class,
NacosPropertySourceReadFromEnvironmentTest.class })
@NacosPropertySource(dataId = NacosPropertySourceReadFromEnvironmentTest.ENV_DATA_ID, groupId = ENV_GROUP_ID, autoRefreshed = true)
@EnableNacosConfig(globalProperties = @NacosProperties(serverAddr = "${server.addr}", enableRemoteSyncConfig = "true", maxRetry = "5", configRetryTime = "2600", configLongPollTimeout = "26000"))
@Component
public class NacosPropertySourceReadFromEnvironmentTest
extends AbstractNacosHttpServerTestExecutionListener {
public static final String ENV_DATA_ID = "${data-id}";
public static final String ENV_GROUP_ID = "${group-id:nacos_env_test}";
public static final String DATA_ID = "app.properties";
private static final String LINE_SEPARATOR = System.getProperty("line.separator");
private static final String APP_NAME = "Nacos-Spring";
private static final String ANOTHER_APP_NAME = "Nacos-Spring-1";
private static final int VALUE_1 = 1;
private static final int VALUE_2 = 2;
private static final int VALUE_3 = 3;
private static final int VALUE_4 = 4;
@NacosInjected
private ConfigService configService;
@Autowired
private App app;
@Autowired
private ConfigurableEnvironment environment;
@BeforeClass
public static void init() {
System.setProperty("data-id", "app.properties");
}
@Override
public void init(EmbeddedNacosHttpServer httpServer) {
Map<String, String> config = new HashMap<String, String>(1);
config.put(DATA_ID_PARAM_NAME, DATA_ID);
config.put(GROUP_ID_PARAM_NAME, "nacos_env_test");
config.put(CONTENT_PARAM_NAME, "app.name=" + APP_NAME + LINE_SEPARATOR
+ "app.nacosFieldIntValueAutoRefreshed=" + VALUE_1 + LINE_SEPARATOR
+ "app.nacosMethodIntValueAutoRefreshed=" + VALUE_2);
httpServer.initConfig(config);
}
@Override
protected String getServerAddressPropertyName() {
return "server.addr";
}
@Bean
public App app() {
return new App();
}
@Test
public void testValue() throws NacosException, InterruptedException {
Assert.assertEquals(APP_NAME, app.name);
Assert.assertEquals(APP_NAME, app.nameWithDefaultValue);
Assert.assertEquals(APP_NAME, app.nacosNameAutoRefreshed);
Assert.assertEquals(APP_NAME, app.nacosNameAutoRefreshedWithDefaultValue);
Assert.assertEquals(APP_NAME, app.nacosNameNotAutoRefreshed);
Assert.assertEquals(APP_NAME, environment.getProperty("app.name"));
Assert.assertEquals(VALUE_1, app.nacosFieldIntValue);
Assert.assertEquals(VALUE_2, app.nacosMethodIntValue);
Assert.assertEquals(VALUE_1, app.nacosFieldIntValueAutoRefreshed);
Assert.assertEquals(VALUE_2, app.nacosMethodIntValueAutoRefreshed);
configService.publishConfig(DATA_ID, "nacos_env_test",
"app.name=" + ANOTHER_APP_NAME + LINE_SEPARATOR
+ "app.nacosFieldIntValueAutoRefreshed=" + VALUE_3
+ LINE_SEPARATOR + "app.nacosMethodIntValueAutoRefreshed="
+ VALUE_4);
Thread.sleep(1000);
Assert.assertEquals(APP_NAME, app.name);
Assert.assertEquals(APP_NAME, app.nameWithDefaultValue);
Assert.assertEquals(ANOTHER_APP_NAME, app.nacosNameAutoRefreshed);
Assert.assertEquals(ANOTHER_APP_NAME, app.nacosNameAutoRefreshedWithDefaultValue);
Assert.assertEquals(APP_NAME, app.nacosNameNotAutoRefreshed);
Assert.assertEquals(ANOTHER_APP_NAME, environment.getProperty("app.name"));
Assert.assertEquals(VALUE_1, app.nacosFieldIntValue);
Assert.assertEquals(VALUE_2, app.nacosMethodIntValue);
Assert.assertEquals(VALUE_3, app.nacosFieldIntValueAutoRefreshed);
Assert.assertEquals(VALUE_4, app.nacosMethodIntValueAutoRefreshed);
}
public static class App {
@Value("${app.name}")
private String name;
@Value("${app.name:Nacos}")
private String nameWithDefaultValue;
@NacosValue(value = "${app.name}", autoRefreshed = true)
private String nacosNameAutoRefreshed;
@NacosValue(value = "${app.name:Nacos}", autoRefreshed = true)
private String nacosNameAutoRefreshedWithDefaultValue;
@NacosValue("${app.name}")
private String nacosNameNotAutoRefreshed;
@NacosValue("${app.nacosFieldIntValue:" + VALUE_1 + "}")
private int nacosFieldIntValue;
@NacosValue(value = "${app.nacosFieldIntValueAutoRefreshed}", autoRefreshed = true)
private int nacosFieldIntValueAutoRefreshed;
private int nacosMethodIntValue;
private int nacosMethodIntValueAutoRefreshed;
@NacosValue("${app.nacosMethodIntValue:" + VALUE_2 + "}")
public void setNacosMethodIntValue(int nacosMethodIntValue) {
this.nacosMethodIntValue = nacosMethodIntValue;
}
@NacosValue(value = "${app.nacosMethodIntValueAutoRefreshed}", autoRefreshed = true)
public void setNacosMethodIntValueAutoRefreshed(
int nacosMethodIntValueAutoRefreshed) {
this.nacosMethodIntValueAutoRefreshed = nacosMethodIntValueAutoRefreshed;
}
}
}

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