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.

4
.gitignore vendored
View File

@ -23,6 +23,7 @@
hs_err_pid* hs_err_pid*
target target
classes
.project .project
.classpath .classpath
.settings/ .settings/
@ -34,4 +35,5 @@ target
/bin/ /bin/
*.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.
@ -541,4 +569,4 @@ Nacos Event/Listener Driven is based on the standard Spring Event/Listener mecha
# 6. Relative Projects # 6. Relative Projects
- [Alibaba Nacos](https://github.com/alibaba/nacos) - [Alibaba Nacos](https://github.com/alibaba/nacos)
- [Alibaba Spring Context Support](https://github.com/alibaba/spring-context-support) - [Alibaba Spring Context Support](https://github.com/alibaba/spring-context-support)

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,91 +43,94 @@ 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 final Class<?> type;
private final GlobalNacosPropertiesSource source;
private BeanFactory beanFactory;
private Environment environment;
private Environment environment; protected AbstractNacosServiceBeanBuilder(GlobalNacosPropertiesSource source) {
type = resolveGenericType(getClass());
this.source = source;
}
private final Class<?> type; public S build(NacosProperties nacosProperties) {
return build(getAnnotationAttributes(nacosProperties));
}
private final GlobalNacosPropertiesSource source; public S build(Map<String, Object> nacosPropertiesAttributes) {
protected AbstractNacosServiceBeanBuilder(GlobalNacosPropertiesSource source) { NacosServiceFactory nacosServiceFactory = getNacosServiceFactoryBean(beanFactory);
type = resolveGenericType(getClass()); Properties properties = resolveProperties(nacosPropertiesAttributes);
this.source = source;
}
public S build(NacosProperties nacosProperties) { if (properties.isEmpty()) {
return build(getAnnotationAttributes(nacosProperties)); throw new BeanCreationException(
} format("The @%s attributes must be configured",
NacosProperties.class.getSimpleName()));
}
public S build(Map<String, Object> nacosPropertiesAttributes) { try {
return createService(nacosServiceFactory, properties);
}
catch (NacosException e) {
throw new BeanCreationException(e.getErrMsg(), e);
}
}
NacosServiceFactory nacosServiceFactory = getNacosServiceFactoryBean(beanFactory); /**
Properties properties = resolveProperties(nacosPropertiesAttributes); * Subtype would implement this method to create target Nacos Service
*
* @param nacosServiceFactory {@link NacosServiceFactory}
* @param properties {@link Properties}
* @return target Nacos Service instance
* @throws NacosException When Nacos Service creation is failed
*/
protected abstract S createService(NacosServiceFactory nacosServiceFactory,
Properties properties) throws NacosException;
if (properties.isEmpty()) { /**
throw new BeanCreationException( * Resolve Nacos {@link Properties} from {@link NacosProperties @NacosProperties}
format("The @%s attributes must be configured", *
NacosProperties.class.getSimpleName())); * @param nacosProperties {@link NacosProperties @NacosProperties}
} * @return non-null
*/
public final Properties resolveProperties(NacosProperties nacosProperties) {
Properties globalNacosProperties = resolveGlobalNacosProperties();
return NacosUtils.resolveProperties(nacosProperties, environment,
globalNacosProperties);
}
try { /**
return createService(nacosServiceFactory, properties); * Resolve Nacos {@link Properties} from {@link NacosProperties @NacosProperties}
} catch (NacosException e) { *
throw new BeanCreationException(e.getErrMsg(), e); * @param nacosPropertiesAttributes {@link NacosProperties Nacos Properties}'s
} * attributes
} * @return non-null
*/
public final Properties resolveProperties(
Map<String, Object> nacosPropertiesAttributes) {
Properties globalNacosProperties = resolveGlobalNacosProperties();
return NacosUtils.resolveProperties(nacosPropertiesAttributes, environment,
globalNacosProperties);
}
/** private Properties resolveGlobalNacosProperties() {
* Subtype would implement this method to create target Nacos Service return source.getMergedGlobalProperties(beanFactory);
* }
* @param nacosServiceFactory {@link NacosServiceFactory}
* @param properties {@link Properties}
* @return target Nacos Service instance
* @throws NacosException When Nacos Service creation is failed
*/
protected abstract S createService(NacosServiceFactory nacosServiceFactory, Properties properties) throws NacosException;
/** final Class<?> getType() {
* Resolve Nacos {@link Properties} from {@link NacosProperties @NacosProperties} return type;
* }
* @param nacosProperties {@link NacosProperties @NacosProperties}
* @return non-null
*/
public final Properties resolveProperties(NacosProperties nacosProperties) {
Properties globalNacosProperties = resolveGlobalNacosProperties();
return NacosUtils.resolveProperties(nacosProperties, environment, globalNacosProperties);
}
/** @Override
* Resolve Nacos {@link Properties} from {@link NacosProperties @NacosProperties} public void setBeanFactory(BeanFactory beanFactory) {
* this.beanFactory = beanFactory;
* @param nacosPropertiesAttributes {@link NacosProperties Nacos Properties}'s attributes }
* @return non-null
*/
public final Properties resolveProperties(Map<String, Object> nacosPropertiesAttributes) {
Properties globalNacosProperties = resolveGlobalNacosProperties();
return NacosUtils.resolveProperties(nacosPropertiesAttributes, environment, globalNacosProperties);
}
private Properties resolveGlobalNacosProperties() { @Override
return source.getMergedGlobalProperties(beanFactory); public void setEnvironment(Environment environment) {
} this.environment = environment;
}
final Class<?> getType() {
return type;
}
@Override
public void setBeanFactory(BeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
@Override
public void setEnvironment(Environment environment) {
this.environment = environment;
}
} }

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,97 +25,122 @@ 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}
*/ */
public static final String BEAN_NAME = "annotationNacosInjectedBeanPostProcessor"; public static final String BEAN_NAME = "annotationNacosInjectedBeanPostProcessor";
private Map<Class<?>, AbstractNacosServiceBeanBuilder> nacosServiceBeanBuilderMap; private Map<Class<?>, AbstractNacosServiceBeanBuilder> nacosServiceBeanBuilderMap;
@Override public AnnotationNacosInjectedBeanPostProcessor() {
public final void afterPropertiesSet() { super(NacosInjected.class);
// Get beanFactory from super }
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
initNacosServiceBeanBuilderMap(beanFactory); @Override
} public final void afterPropertiesSet() {
// Get beanFactory from super
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
private void initNacosServiceBeanBuilderMap(ConfigurableListableBeanFactory beanFactory) { initNacosServiceBeanBuilderMap(beanFactory);
}
Class<AbstractNacosServiceBeanBuilder> builderClass = AbstractNacosServiceBeanBuilder.class; private void initNacosServiceBeanBuilderMap(
ConfigurableListableBeanFactory beanFactory) {
String[] beanNames = BeanUtils.getBeanNames(beanFactory, builderClass); Class<AbstractNacosServiceBeanBuilder> builderClass = AbstractNacosServiceBeanBuilder.class;
if (beanNames.length == 0) {
throw new NoSuchBeanDefinitionException(builderClass,
format("Please check the BeanDefinition of %s in Spring BeanFactory", builderClass));
}
Collection<AbstractNacosServiceBeanBuilder> serviceBeanBuilders String[] beanNames = BeanUtils.getBeanNames(beanFactory, builderClass);
= new ArrayList<AbstractNacosServiceBeanBuilder>(beanNames.length); if (beanNames.length == 0) {
for (String beanName : beanNames) { throw new NoSuchBeanDefinitionException(builderClass,
serviceBeanBuilders.add(beanFactory.getBean(beanName, builderClass)); format("Please check the BeanDefinition of %s in Spring BeanFactory",
} builderClass));
}
if (serviceBeanBuilders.isEmpty()) { Collection<AbstractNacosServiceBeanBuilder> serviceBeanBuilders = new ArrayList<AbstractNacosServiceBeanBuilder>(
throw new NoSuchBeanDefinitionException(builderClass, beanNames.length);
format("Please check the BeanDefinition of %s in Spring BeanFactory", builderClass)); for (String beanName : beanNames) {
} serviceBeanBuilders.add(beanFactory.getBean(beanName, builderClass));
}
Map<Class<?>, AbstractNacosServiceBeanBuilder> builderMap = if (serviceBeanBuilders.isEmpty()) {
new HashMap<Class<?>, AbstractNacosServiceBeanBuilder>(serviceBeanBuilders.size()); throw new NoSuchBeanDefinitionException(builderClass,
format("Please check the BeanDefinition of %s in Spring BeanFactory",
builderClass));
}
for (AbstractNacosServiceBeanBuilder serviceBeanBuilder : serviceBeanBuilders) { Map<Class<?>, AbstractNacosServiceBeanBuilder> builderMap = new HashMap<Class<?>, AbstractNacosServiceBeanBuilder>(
Class<?> type = serviceBeanBuilder.getType(); serviceBeanBuilders.size());
builderMap.put(type, serviceBeanBuilder);
}
// Should not be modified in future for (AbstractNacosServiceBeanBuilder serviceBeanBuilder : serviceBeanBuilders) {
this.nacosServiceBeanBuilderMap = unmodifiableMap(builderMap); Class<?> type = serviceBeanBuilder.getType();
} builderMap.put(type, serviceBeanBuilder);
}
@Override // Should not be modified in future
protected Object doGetInjectedBean(NacosInjected annotation, Object bean, String beanName, Class<?> injectedType, this.nacosServiceBeanBuilderMap = unmodifiableMap(builderMap);
InjectionMetadata.InjectedElement injectedElement) { }
AbstractNacosServiceBeanBuilder serviceBeanBuilder = nacosServiceBeanBuilderMap.get(injectedType); @Override
protected Object doGetInjectedBean(AnnotationAttributes attributes, Object bean,
String beanName, Class<?> injectedType,
InjectionMetadata.InjectedElement injectedElement) throws Exception {
AbstractNacosServiceBeanBuilder serviceBeanBuilder = nacosServiceBeanBuilderMap
.get(injectedType);
return serviceBeanBuilder.build(annotation.properties()); Map<String, Object> nacosProperties = getNacosProperties(attributes);
} 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) {
throw new UnsupportedOperationException(format(
"Only support to inject types[%s] instance , however actual injected type [%s] in member[%s]",
nacosServiceBeanBuilderMap.keySet(), injectedType,
injectedElement.getMember()));
}
if (serviceBeanBuilder == null) { Map<String, Object> nacosProperties = getNacosProperties(attributes);
throw new UnsupportedOperationException(
format("Only support to inject types[%s] instance , however actual injected type [%s] in member[%s]",
nacosServiceBeanBuilderMap.keySet(), injectedType, injectedElement.getMember()));
}
Properties properties = serviceBeanBuilder.resolveProperties(annotation.properties()); 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,33 +16,34 @@
*/ */
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}
*/ */
public static final String BEAN_NAME = "configServiceBeanBuilder"; public static final String BEAN_NAME = "configServiceBeanBuilder";
protected ConfigServiceBeanBuilder() { protected ConfigServiceBeanBuilder() {
super(GlobalNacosPropertiesSource.CONFIG); super(GlobalNacosPropertiesSource.CONFIG);
} }
@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,33 +16,34 @@
*/ */
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}
*/ */
public static final String BEAN_NAME = "namingServiceBeanBuilder"; public static final String BEAN_NAME = "namingServiceBeanBuilder";
public NamingServiceBeanBuilder() { public NamingServiceBeanBuilder() {
super(GlobalNacosPropertiesSource.DISCOVERY); super(GlobalNacosPropertiesSource.DISCOVERY);
} }
@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.
@ -31,19 +36,19 @@ import java.lang.annotation.*;
* @see NacosBeanDefinitionRegistrar * @see NacosBeanDefinitionRegistrar
* @since 0.1.0 * @since 0.1.0
*/ */
@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 {
/** /**
* Global {@link NacosProperties Nacos Properties} * Global {@link NacosProperties Nacos Properties}
* *
* @return required * @return required
* @see NacosInjected#properties() * @see NacosInjected#properties()
* @see NacosConfigListener#properties() * @see NacosConfigListener#properties()
* @see NacosConfigurationProperties#properties() * @see NacosConfigurationProperties#properties()
*/ */
NacosProperties globalProperties(); NacosProperties globalProperties();
} }

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,43 +43,50 @@ 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,
// Register Nacos Annotation Beans GLOBAL_NACOS_PROPERTIES_BEAN_NAME);
registerNacosAnnotationBeans(registry); // Register Nacos Annotation Beans
// Invoke NacosPropertySourcePostProcessor immediately registerNacosAnnotationBeans(registry);
// in order to enhance the precedence of @NacosPropertySource process // Invoke NacosPropertySourcePostProcessor immediately
invokeNacosPropertySourcePostProcessor(beanFactory); // in order to enhance the precedence of @NacosPropertySource process
} invokeNacosPropertySourcePostProcessor(beanFactory);
}
@Override @Override
public void setEnvironment(Environment environment) { public void setEnvironment(Environment environment) {
this.environment = environment; this.environment = environment;
} }
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);
} }
@Override @Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException { public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory; this.beanFactory = beanFactory;
} }
} }

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.
@ -34,82 +51,103 @@ import static com.alibaba.nacos.api.annotation.NacosProperties.*;
* @see NacosBeanDefinitionRegistrar * @see NacosBeanDefinitionRegistrar
* @since 0.1.0 * @since 0.1.0
*/ */
@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
* <code>"${nacos.config.endpoint:${nacos.endpoint:}}"</code>
*/
String ENDPOINT_PLACEHOLDER = "${" + CONFIG_PREFIX + ENDPOINT + ":"
+ NacosProperties.ENDPOINT_PLACEHOLDER + "}";
/**
* The placeholder of endpoint, the value is
* <code>"${nacos.config.namespace:${nacos.namespace:}}"</code>
*/
String NAMESPACE_PLACEHOLDER = "${" + CONFIG_PREFIX + NAMESPACE + ":"
+ NacosProperties.NAMESPACE_PLACEHOLDER + "}";
/**
* The placeholder of endpoint, the value is
* <code>"${nacos.config.access-key:${nacos.access-key:}}"</code>
*/
String ACCESS_KEY_PLACEHOLDER = "${" + CONFIG_PREFIX + ACCESS_KEY + ":"
+ NacosProperties.ACCESS_KEY_PLACEHOLDER + "}";
/**
* The placeholder of endpoint, the value is
* <code>"${nacos.config.secret-key:${nacos.secret-key:}}"</code>
*/
String SECRET_KEY_PLACEHOLDER = "${" + CONFIG_PREFIX + SECRET_KEY + ":"
+ NacosProperties.SECRET_KEY_PLACEHOLDER + "}";
/**
* The placeholder of endpoint, the value is
* <code>"${nacos.config.server-addr:${nacos.server-addr:}}"</code>
*/
String SERVER_ADDR_PLACEHOLDER = "${" + CONFIG_PREFIX + SERVER_ADDR + ":"
+ NacosProperties.SERVER_ADDR_PLACEHOLDER + "}";
/**
* The placeholder of endpoint, the value is
* <code>"${nacos.config.context-path:${nacos.context-path:}}"</code>
*/
String CONTEXT_PATH_PLACEHOLDER = "${" + CONFIG_PREFIX + CONTEXT_PATH + ":"
+ NacosProperties.CONTEXT_PATH_PLACEHOLDER + "}";
/**
* The placeholder of endpoint, the value is
* <code>"${nacos.config.cluster-name:${nacos.cluster-name:}}"</code>
*/
String CLUSTER_NAME_PLACEHOLDER = "${" + CONFIG_PREFIX + CLUSTER_NAME + ":"
+ NacosProperties.CLUSTER_NAME_PLACEHOLDER + "}";
/**
* The placeholder of {@link NacosProperties#ENCODE encode}, the value is
* <code>"${nacos.config.encode:${nacos.encode:UTF-8}}"</code>
*/
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 + "}";
/** /**
* The placeholder of endpoint, the value is * Global {@link NacosProperties Nacos Properties}
* <code>"${nacos.config.endpoint:${nacos.endpoint:}}"</code> *
*/ * @return required
String ENDPOINT_PLACEHOLDER = "${" + CONFIG_PREFIX + ENDPOINT + ":" + NacosProperties.ENDPOINT_PLACEHOLDER + "}"; * @see NacosInjected#properties()
* @see NacosConfigListener#properties()
/** * @see NacosConfigurationProperties#properties()
* The placeholder of endpoint, the value is */
* <code>"${nacos.config.namespace:${nacos.namespace:}}"</code> 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);
*/
String NAMESPACE_PLACEHOLDER = "${" + CONFIG_PREFIX + NAMESPACE + ":" + NacosProperties.NAMESPACE_PLACEHOLDER + "}";
/**
* The placeholder of endpoint, the value is
* <code>"${nacos.config.access-key:${nacos.access-key:}}"</code>
*/
String ACCESS_KEY_PLACEHOLDER = "${" + CONFIG_PREFIX + ACCESS_KEY + ":" + NacosProperties.ACCESS_KEY_PLACEHOLDER + "}";
/**
* The placeholder of endpoint, the value is
* <code>"${nacos.config.secret-key:${nacos.secret-key:}}"</code>
*/
String SECRET_KEY_PLACEHOLDER = "${" + CONFIG_PREFIX + SECRET_KEY + ":" + NacosProperties.SECRET_KEY_PLACEHOLDER + "}";
/**
* The placeholder of endpoint, the value is
* <code>"${nacos.config.server-addr:${nacos.server-addr:}}"</code>
*/
String SERVER_ADDR_PLACEHOLDER = "${" + CONFIG_PREFIX + SERVER_ADDR + ":" + NacosProperties.SERVER_ADDR_PLACEHOLDER + "}";
/**
* The placeholder of endpoint, the value is
* <code>"${nacos.config.context-path:${nacos.context-path:}}"</code>
*/
String CONTEXT_PATH_PLACEHOLDER = "${" + CONFIG_PREFIX + CONTEXT_PATH + ":" + NacosProperties.CONTEXT_PATH_PLACEHOLDER + "}";
/**
* The placeholder of endpoint, the value is
* <code>"${nacos.config.cluster-name:${nacos.cluster-name:}}"</code>
*/
String CLUSTER_NAME_PLACEHOLDER = "${" + CONFIG_PREFIX + CLUSTER_NAME + ":" + NacosProperties.CLUSTER_NAME_PLACEHOLDER + "}";
/**
* The placeholder of {@link NacosProperties#ENCODE encode}, the value is
* <code>"${nacos.config.encode:${nacos.encode:UTF-8}}"</code>
*/
String ENCODE_PLACEHOLDER = "${" + CONFIG_PREFIX + ENCODE + ":" + NacosProperties.ENCODE_PLACEHOLDER + "}";
/**
* Global {@link NacosProperties Nacos Properties}
*
* @return required
* @see NacosInjected#properties()
* @see NacosConfigListener#properties()
* @see NacosConfigurationProperties#properties()
*/
NacosProperties globalProperties() default
@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,51 +34,53 @@ 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) {
// Register Global Nacos Properties Bean AnnotationAttributes attributes = fromMap(
registerGlobalNacosProperties(attributes, registry, environment, CONFIG_GLOBAL_NACOS_PROPERTIES_BEAN_NAME); metadata.getAnnotationAttributes(EnableNacosConfig.class.getName()));
// Register Nacos Common Beans
registerNacosCommonBeans(registry);
// Register Nacos Config Beans
registerNacosConfigBeans(registry, environment);
// Invoke NacosPropertySourcePostProcessor immediately
// in order to enhance the precedence of @NacosPropertySource process
invokeNacosPropertySourcePostProcessor(beanFactory);
}
@Override // Register Global Nacos Properties Bean
public void setEnvironment(Environment environment) { registerGlobalNacosProperties(attributes, registry, environment,
this.environment = environment; CONFIG_GLOBAL_NACOS_PROPERTIES_BEAN_NAME);
} // Register Nacos Common Beans
registerNacosCommonBeans(registry);
// Register Nacos Config Beans
registerNacosConfigBeans(registry, environment, beanFactory);
// Invoke NacosPropertySourcePostProcessor immediately
// in order to enhance the precedence of @NacosPropertySource process
@Override invokeNacosPropertySourcePostProcessor(beanFactory);
public void setBeanFactory(BeanFactory beanFactory) throws BeansException { }
this.beanFactory = beanFactory;
} @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,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,185 +63,200 @@ 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}
*/ */
public static final String BEAN_NAME = "nacosConfigListenerMethodProcessor"; public static final String BEAN_NAME = "nacosConfigListenerMethodProcessor";
/** /**
* The bean name of {@link ConversionService} for Nacos Configuration * The bean name of {@link ConversionService} for Nacos Configuration
*/ */
public static final String NACOS_CONFIG_CONVERSION_SERVICE_BEAN_NAME = "nacosConfigConversionService"; public static final String NACOS_CONFIG_CONVERSION_SERVICE_BEAN_NAME = "nacosConfigConversionService";
private Properties globalNacosProperties; private Properties globalNacosProperties;
private NacosServiceFactory nacosServiceFactory; private NacosServiceFactory nacosServiceFactory;
private ConversionService conversionService; private ConversionService conversionService;
private ConfigServiceBeanBuilder configServiceBeanBuilder; private ConfigServiceBeanBuilder configServiceBeanBuilder;
private Environment environment; private Environment environment;
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);
long timeout = listener.timeout(); 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();
}
Assert.isTrue(StringUtils.hasText(dataId), "dataId must have content"); long timeout = listener.timeout();
Assert.isTrue(StringUtils.hasText(groupId), "groupId must have content");
Assert.isTrue(timeout > 0, "timeout must be greater than zero");
ConfigService configService = configServiceBeanBuilder.build(listener.properties()); Assert.isTrue(StringUtils.hasText(dataId), "dataId must have content");
Assert.isTrue(StringUtils.hasText(groupId), "groupId must have content");
Assert.isTrue(timeout > 0, "timeout must be greater than zero");
try { ConfigService configService = configServiceBeanBuilder
.build(listener.properties());
configService.addListener(dataId, groupId, new TimeoutNacosConfigListener(dataId, groupId, timeout) { try {
configService.addListener(dataId, groupId,
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(
Object parameterValue = configConverter.convert(config); targetType, listener, type);
// Execute target method Object parameterValue = configConverter.convert(config);
ReflectionUtils.invokeMethod(method, bean, parameterValue); // Execute target method
} 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);
// Nacos Metadata // Nacos Metadata
metadataEvent.setDataId(dataId); metadataEvent.setDataId(dataId);
metadataEvent.setGroupId(groupId); metadataEvent.setGroupId(groupId);
Map<String, Object> nacosPropertiesAttributes = getAnnotationAttributes(nacosProperties); Map<String, Object> nacosPropertiesAttributes = getAnnotationAttributes(
metadataEvent.setNacosPropertiesAttributes(nacosPropertiesAttributes); nacosProperties);
metadataEvent.setNacosProperties(resolvedNacosProperties); metadataEvent.setNacosPropertiesAttributes(nacosPropertiesAttributes);
metadataEvent.setNacosProperties(resolvedNacosProperties);
// Bean Metadata // Bean Metadata
metadataEvent.setBeanName(beanName); metadataEvent.setBeanName(beanName);
metadataEvent.setBean(bean); metadataEvent.setBean(bean);
metadataEvent.setBeanType(beanClass); metadataEvent.setBeanType(beanClass);
metadataEvent.setAnnotatedElement(method); metadataEvent.setAnnotatedElement(method);
// Publish event // Publish event
applicationEventPublisher.publishEvent(metadataEvent); applicationEventPublisher.publishEvent(metadataEvent);
} }
private ConfigService resolveConfigService(Properties nacosProperties, ApplicationContext applicationContext) @Override
throws BeansException { protected boolean isCandidateMethod(Object bean, Class<?> beanClass,
NacosConfigListener listener, Method method,
ApplicationContext applicationContext) {
Class<?>[] parameterTypes = method.getParameterTypes();
ConfigService configService = null; if (parameterTypes.length != 1) { // Only one argument on method
if (logger.isWarnEnabled()) {
logger.warn("Listener method [" + method
+ "] parameters' count must be one !");
}
return false;
}
try { Class<?> targetType = parameterTypes[0];
configService = nacosServiceFactory.createConfigService(nacosProperties);
} catch (NacosException e) {
throw new BeanCreationException(e.getErrMsg(), e);
}
return configService; NacosConfigConverter configConverter = determineNacosConfigConverter(targetType,
} listener, listener.type().getType());
@Override if (!configConverter.canConvert(targetType)) {
protected boolean isCandidateMethod(Object bean, Class<?> beanClass, NacosConfigListener listener, Method method, if (logger.isWarnEnabled()) {
ApplicationContext applicationContext) { logger.warn("Listener method [" + method
Class<?>[] parameterTypes = method.getParameterTypes(); + "] is not a candidate , thus its parameter type [" + targetType
+ "] can't be converted , please check NacosConfigConverter implementation : "
+ configConverter.getClass().getName());
}
}
if (parameterTypes.length != 1) { // Only one argument on method return true;
if (logger.isWarnEnabled()) { }
logger.warn("Listener method [" + method + "] parameters' count must be one !");
}
return false;
}
Class<?> targetType = parameterTypes[0]; private NacosConfigConverter determineNacosConfigConverter(Class<?> targetType,
NacosConfigListener listener, String type) {
NacosConfigConverter configConverter = determineNacosConfigConverter(targetType, listener); Class<?> converterClass = listener.converter();
if (!configConverter.canConvert(targetType)) { NacosConfigConverter configConverter = null;
if (logger.isWarnEnabled()) {
logger.warn("Listener method [" + method + "] is not a candidate , thus its parameter type ["
+ targetType + "] can't be converted , please check NacosConfigConverter implementation : "
+ configConverter.getClass().getName());
}
}
return true; // Use default implementation
} if (NacosConfigConverter.class.equals(converterClass)) {
configConverter = new DefaultNacosConfigConverter(targetType,
conversionService, type);
private NacosConfigConverter determineNacosConfigConverter(Class<?> targetType, NacosConfigListener listener) { }
else {
// Use customized implementation
configConverter = (NacosConfigConverter) instantiateClass(converterClass);
Class<?> converterClass = listener.converter(); }
NacosConfigConverter configConverter = null; return configConverter;
}
if (NacosConfigConverter.class.equals(converterClass)) { // Use default implementation @Override
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
globalNacosProperties = CONFIG.getMergedGlobalProperties(applicationContext);
nacosServiceFactory = getNacosServiceFactoryBean(applicationContext);
conversionService = determineConversionService(applicationContext);
configServiceBeanBuilder = getConfigServiceBeanBuilder(applicationContext);
}
configConverter = new DefaultNacosConfigConverter(targetType, conversionService); private ConversionService determineConversionService(
ApplicationContext applicationContext) {
} else { // Use customized implementation String beanName = NACOS_CONFIG_CONVERSION_SERVICE_BEAN_NAME;
configConverter = (NacosConfigConverter) instantiateClass(converterClass); ConversionService conversionService = applicationContext.containsBean(beanName)
? applicationContext.getBean(beanName, ConversionService.class)
: null;
} if (conversionService == null) {
conversionService = new DefaultFormattingConversionService();
}
return configConverter; return conversionService;
} }
@Override @Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { public void setApplicationEventPublisher(
globalNacosProperties = CONFIG.getMergedGlobalProperties(applicationContext); ApplicationEventPublisher applicationEventPublisher) {
nacosServiceFactory = getNacosServiceFactoryBean(applicationContext); this.applicationEventPublisher = applicationEventPublisher;
conversionService = determineConversionService(applicationContext); }
configServiceBeanBuilder = getConfigServiceBeanBuilder(applicationContext);
}
private ConversionService determineConversionService(ApplicationContext applicationContext) { @Override
public void setEnvironment(Environment environment) {
String beanName = NACOS_CONFIG_CONVERSION_SERVICE_BEAN_NAME; this.environment = environment;
}
ConversionService conversionService = applicationContext.containsBean(beanName) ?
applicationContext.getBean(beanName, ConversionService.class) : null;
if (conversionService == null) {
conversionService = new DefaultFormattingConversionService();
}
return conversionService;
}
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
this.applicationEventPublisher = applicationEventPublisher;
}
@Override
public void setEnvironment(Environment environment) {
this.environment = environment;
}
} }

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}
* *
@ -37,122 +44,133 @@ import static com.alibaba.nacos.spring.util.NacosUtils.DEFAULT_STRING_ATTRIBUTE_
* @see org.springframework.context.annotation.PropertySource * @see org.springframework.context.annotation.PropertySource
* @since 0.1.0 * @since 0.1.0
*/ */
@Target({ElementType.TYPE}) @Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Documented @Documented
@Repeatable(NacosPropertySources.class) @Repeatable(NacosPropertySources.class)
public @interface NacosPropertySource { public @interface NacosPropertySource {
/** /**
* The attribute name of {@link NacosPropertySource#name()} * The attribute name of {@link NacosPropertySource#name()}
*/ */
String NAME_ATTRIBUTE_NAME = "name"; String NAME_ATTRIBUTE_NAME = "name";
/** /**
* The attribute name of {@link NacosPropertySource#groupId()} * The attribute name of {@link NacosPropertySource#groupId()}
*/ */
String GROUP_ID_ATTRIBUTE_NAME = "groupId"; String GROUP_ID_ATTRIBUTE_NAME = "groupId";
/** /**
* The attribute name of {@link NacosPropertySource#dataId()} * The attribute name of {@link NacosPropertySource#dataId()}
*/ */
String DATA_ID_ATTRIBUTE_NAME = "dataId"; String DATA_ID_ATTRIBUTE_NAME = "dataId";
/** /**
* The attribute name of {@link NacosPropertySource#autoRefreshed()} * The attribute name of {@link NacosPropertySource#autoRefreshed()}
*/ */
String AUTO_REFRESHED_ATTRIBUTE_NAME = "autoRefreshed"; String AUTO_REFRESHED_ATTRIBUTE_NAME = "autoRefreshed";
/** /**
* The attribute name of {@link NacosPropertySource#first()} * The attribute name of {@link NacosPropertySource#first()}
*/ */
String FIRST_ATTRIBUTE_NAME = "first"; String FIRST_ATTRIBUTE_NAME = "first";
/** /**
* The attribute name of {@link NacosPropertySource#before()} * The attribute name of {@link NacosPropertySource#before()}
*/ */
String BEFORE_ATTRIBUTE_NAME = "before"; String BEFORE_ATTRIBUTE_NAME = "before";
/** /**
* The attribute name of {@link NacosPropertySource#after()} * The attribute name of {@link NacosPropertySource#after()}
*/ */
String AFTER_ATTRIBUTE_NAME = "after"; String AFTER_ATTRIBUTE_NAME = "after";
/** /**
* The attribute name of {@link NacosPropertySource#properties()} * The attribute name of {@link NacosPropertySource#properties()}
*/ */
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";
* {@link NacosUtils#buildDefaultPropertySourceName(String, String, Map)} method
*
* @return default value is ""
*/
String name() default DEFAULT_STRING_ATTRIBUTE_VALUE;
/** /**
* Nacos Group ID * The name of Nacos {@link PropertySource} If absent , the default name will be built
* * from {@link #dataId() dataId}, {@link #groupId() groupid} and {@link #properties()
* @return default value {@link Constants#DEFAULT_GROUP}; * properties} by
*/ * {@link NacosUtils#buildDefaultPropertySourceName(String, String, Map)} method
String groupId() default DEFAULT_GROUP; *
* @return default value is ""
*/
String name() default DEFAULT_STRING_ATTRIBUTE_VALUE;
/** /**
* Nacos Data ID * Nacos Group ID
* *
* @return required value. * @return default value {@link Constants#DEFAULT_GROUP};
*/ */
String dataId(); String groupId() default DEFAULT_GROUP;
/** /**
* It indicates the property source is auto-refreshed when Nacos configuration is changed. * Nacos Data ID
* *
* @return default value is <code>false</code> * @return required value.
*/ */
boolean autoRefreshed() default DEFAULT_BOOLEAN_ATTRIBUTE_VALUE; String dataId();
/** /**
* Indicates current Nacos {@link PropertySource} is first order or not * It indicates the property source is auto-refreshed when Nacos configuration is
* If specified , {@link #before()} and {@link #after()} will be ignored, or * changed.
* last order. *
* * @return default value is <code>false</code>
* @return default value is <code>false</code> */
*/ boolean autoRefreshed() default DEFAULT_BOOLEAN_ATTRIBUTE_VALUE;
boolean first() default DEFAULT_BOOLEAN_ATTRIBUTE_VALUE;
/** /**
* The relative order before specified {@link PropertySource} * Indicates current Nacos {@link PropertySource} is first order or not If specified ,
* <p> * {@link #before()} and {@link #after()} will be ignored, or last order.
* If not specified , current Nacos {@link PropertySource} will be added last. *
* <p> * @return default value is <code>false</code>
* If {@link #first()} specified , current attribute will be ignored. */
* boolean first() default DEFAULT_BOOLEAN_ATTRIBUTE_VALUE;
* @return the name of {@link PropertySource}
*/
String before() default DEFAULT_STRING_ATTRIBUTE_VALUE;
/** /**
* The relative order after specified {@link PropertySource} * The relative order before specified {@link PropertySource}
* <p> * <p>
* If not specified , current Nacos {@link PropertySource} will be added last. * If not specified , current Nacos {@link PropertySource} will be added last.
* <p> * <p>
* If {@link #first()} specified , current attribute will be ignored. * If {@link #first()} specified , current attribute will be ignored.
* *
* @return the name of {@link PropertySource} * @return the name of {@link PropertySource}
*/ */
String after() default DEFAULT_STRING_ATTRIBUTE_VALUE; String before() default DEFAULT_STRING_ATTRIBUTE_VALUE;
/** /**
* The {@link NacosProperties} attribute, If not specified, it will use * The relative order after specified {@link PropertySource}
* {@link EnableNacos#globalProperties() global Nacos Properties}. * <p>
* * If not specified , current Nacos {@link PropertySource} will be added last.
* @return the default value is {@link NacosProperties} * <p>
* @see EnableNacos#globalProperties() * If {@link #first()} specified , current attribute will be ignored.
*/ *
NacosProperties properties() default @NacosProperties; * @return the name of {@link PropertySource}
*/
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
* {@link EnableNacos#globalProperties() global Nacos Properties}.
*
* @return the default value is {@link NacosProperties}
* @see EnableNacos#globalProperties()
*/
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
* *
@ -42,88 +44,94 @@ import static java.lang.String.format;
*/ */
class NacosPropertySourceBuilder { class NacosPropertySourceBuilder {
private final Logger logger = LoggerFactory.getLogger(getClass()); private final Logger logger = LoggerFactory.getLogger(getClass());
private String name; private String name;
private String dataId; private String dataId;
private String groupId; private String groupId;
private Properties properties; private String type;
private ConfigurableEnvironment environment; private Properties properties;
private BeanFactory beanFactory; private ConfigurableEnvironment environment;
private NacosConfigLoader nacosConfigLoader; private BeanFactory beanFactory;
public NacosPropertySourceBuilder name(String name) { private NacosConfigLoader nacosConfigLoader;
this.name = name;
return this;
}
public NacosPropertySourceBuilder dataId(String dataId) { public NacosPropertySourceBuilder name(String name) {
this.dataId = dataId; this.name = name;
return this; return this;
} }
public NacosPropertySourceBuilder groupId(String groupId) { public NacosPropertySourceBuilder dataId(String dataId) {
this.groupId = groupId; this.dataId = dataId;
return this; return this;
} }
public NacosPropertySourceBuilder properties(Properties properties) { public NacosPropertySourceBuilder groupId(String groupId) {
this.properties = properties; this.groupId = groupId;
return this; return this;
} }
public NacosPropertySourceBuilder environment(ConfigurableEnvironment environment) { public NacosPropertySourceBuilder properties(Properties properties) {
this.environment = environment; this.properties = properties;
return this; return this;
} }
public NacosPropertySourceBuilder beanFactory(BeanFactory beanFactory) { public NacosPropertySourceBuilder type(String type) {
this.beanFactory = beanFactory; this.type = type;
return this; return this;
} }
/** public NacosPropertySourceBuilder environment(ConfigurableEnvironment environment) {
* Build Nacos {@link PropertySource} this.environment = environment;
* return this;
* @return if Nacos config is absent , return <code>null</code> }
*/
public PropertySource build() {
nacosConfigLoader = new NacosConfigLoader(environment); public NacosPropertySourceBuilder beanFactory(BeanFactory beanFactory) {
this.beanFactory = beanFactory;
return this;
}
NacosServiceFactory nacosServiceFactory = getNacosServiceFactoryBean(beanFactory); /**
* Build Nacos {@link PropertySource}
*
* @return if Nacos config is absent , return <code>null</code>
*/
public PropertySource build() {
nacosConfigLoader.setNacosServiceFactory(nacosServiceFactory); nacosConfigLoader = new NacosConfigLoader(environment);
String config = nacosConfigLoader.load(dataId, groupId, properties); NacosServiceFactory nacosServiceFactory = getNacosServiceFactoryBean(beanFactory);
if (!StringUtils.hasText(config)) { nacosConfigLoader.setNacosServiceFactory(nacosServiceFactory);
if (logger.isWarnEnabled()) {
logger.warn(format("There is no content for Nacos PropertySource from dataId[%s] , groupId[%s] , properties[%s].",
dataId,
groupId,
properties));
}
return null;
}
Properties properties = toProperties(config); String config = nacosConfigLoader.load(dataId, groupId, properties);
if (!StringUtils.hasText(name)) { if (!StringUtils.hasText(config)) {
name = buildDefaultPropertySourceName(dataId, groupId, properties); if (logger.isWarnEnabled()) {
} logger.warn(format(
"There is no content for Nacos PropertySource from dataId[%s] , groupId[%s] , properties[%s].",
dataId, groupId, properties));
}
return null;
}
return new PropertiesPropertySource(name, properties); Map<String, Object> properties = toProperties(dataId, groupId, config, type);
}
public NacosConfigLoader getNacosConfigLoader() { if (!StringUtils.hasText(name)) {
return nacosConfigLoader; name = buildDefaultPropertySourceName(dataId, groupId, properties);
} }
return new MapPropertySource(name, properties);
}
public NacosConfigLoader getNacosConfigLoader() {
return nacosConfigLoader;
}
} }

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.
@ -24,15 +28,15 @@ import java.lang.annotation.*;
* @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
*/ */
@Target({ElementType.TYPE}) @Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Documented @Documented
public @interface NacosPropertySources { public @interface NacosPropertySources {
/** /**
* Multiple {@link NacosPropertySource @NacosPropertySource} * Multiple {@link NacosPropertySource @NacosPropertySource}
* *
* @return {@link NacosPropertySource @NacosPropertySource} array * @return {@link NacosPropertySource @NacosPropertySource} array
*/ */
NacosPropertySource[] value(); NacosPropertySource[] value();
} }

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,271 +27,384 @@ 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.
*/
public static final String BEAN_NAME = "nacosValueAnnotationBeanPostProcessor";
/** private static final String SPEL_PREFIX = "#{";
* The name of {@link NacosValueAnnotationBeanPostProcessor} bean
*/
public static final String BEAN_NAME = "nacosValueAnnotationBeanPostProcessor";
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 String VALUE_SEPARATOR = ":"; private static final char PLACEHOLDER_MATCH_PREFIX = '{';
/** private static final char PLACEHOLDER_MATCH_SUFFIX = '}';
* placeholder, nacosValueTarget
*/
private Map<String, List<NacosValueTarget>> placeholderNacosValueTargetMap
= new HashMap<String, List<NacosValueTarget>>();
private ConfigurableListableBeanFactory beanFactory; private static final String VALUE_SEPARATOR = ":";
@Override private final Logger logger = LoggerFactory.getLogger(getClass());
protected Object doGetInjectedBean(NacosValue annotation, Object bean, String beanName, Class<?> injectedType,
InjectionMetadata.InjectedElement injectedElement) {
String annotationValue = annotation.value();
String value = beanFactory.resolveEmbeddedValue(annotationValue);
/**
* placeholder, nacosValueTarget.
*/
private Map<String, List<NacosValueTarget>> placeholderNacosValueTargetMap = new HashMap<String, List<NacosValueTarget>>();
private ConfigurableListableBeanFactory beanFactory;
private Environment environment;
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);
}
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) {
// In to this event receiver, the environment has been updated the
// latest configuration information, pull directly from the environment
// fix issue #142
for (Map.Entry<String, List<NacosValueTarget>> entry : placeholderNacosValueTargetMap
.entrySet()) {
String key = environment.resolvePlaceholders(entry.getKey());
String newValue = environment.getProperty(key);
if (newValue == null) {
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);
}
}
}
}
}
private Object resolveNotifyValue(String nacosValueExpr, String key, String newValue) {
String spelExpr = StringUtils.replace(nacosValueExpr, PLACEHOLDER_PREFIX + key + PLACEHOLDER_SUFFIX, newValue);
return resolveStringValue(spelExpr);
}
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 {
NacosValue annotation = getAnnotation(field, NacosValue.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 {
NacosValue annotation = getAnnotation(method, NacosValue.class);
doWithAnnotation(beanName, bean, annotation,
method.getModifiers(), method, null);
}
});
}
private void doWithAnnotation(String beanName, Object bean, NacosValue annotation,
int modifiers, Method method, Field field) {
if (annotation != null) {
if (Modifier.isStatic(modifiers)) {
return;
}
if (annotation.autoRefreshed()) {
String placeholder = resolvePlaceholder(annotation.value());
if (placeholder == null) {
return;
}
NacosValueTarget nacosValueTarget = new NacosValueTarget(bean, beanName,
method, field, annotation.value());
put2ListMap(placeholderNacosValueTargetMap, placeholder,
nacosValueTarget);
}
}
}
private String resolvePlaceholder(String placeholder) {
if (!placeholder.startsWith(PLACEHOLDER_PREFIX) && !placeholder.startsWith(SPEL_PREFIX)) {
return null;
}
if (!placeholder.endsWith(PLACEHOLDER_SUFFIX)) {
return null;
}
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();
if (member instanceof Method) { int endIndex = placeholder.indexOf(PLACEHOLDER_SUFFIX, beginIndex);
return convertIfNecessary((Method)member, value); if (endIndex == -1) {
return null;
} }
placeholder = placeholder.substring(beginIndex, endIndex);
return null; int separatorIndex = placeholder.indexOf(VALUE_SEPARATOR);
} if (separatorIndex != -1) {
return placeholder.substring(0, separatorIndex);
}
@Override return placeholder;
protected String buildInjectedObjectCacheKey(NacosValue annotation, Object bean, String beanName, }
Class<?> injectedType,
InjectionMetadata.InjectedElement injectedElement) {
return bean.getClass().getName() + annotation;
}
@Override private <K, V> void put2ListMap(Map<K, List<V>> map, K key, V value) {
public void setBeanFactory(BeanFactory beanFactory) throws BeansException { List<V> valueList = map.get(key);
if (!(beanFactory instanceof ConfigurableListableBeanFactory)) { if (valueList == null) {
throw new IllegalArgumentException( valueList = new ArrayList<V>();
"NacosValueAnnotationBeanPostProcessor requires a ConfigurableListableBeanFactory"); }
} valueList.add(value);
this.beanFactory = (ConfigurableListableBeanFactory)beanFactory; map.put(key, valueList);
} }
@Override private void setMethod(NacosValueTarget nacosValueTarget, Object propertyValue) {
public Object postProcessBeforeInitialization(Object bean, final String beanName) Method method = nacosValueTarget.method;
throws BeansException { ReflectionUtils.makeAccessible(method);
try {
method.invoke(nacosValueTarget.bean,
convertIfNecessary(method, propertyValue));
doWithFields(bean, beanName); if (logger.isDebugEnabled()) {
logger.debug("Update value with {} (method) in {} (bean) with {}",
method.getName(), nacosValueTarget.beanName, propertyValue);
}
}
catch (Throwable e) {
if (logger.isErrorEnabled()) {
logger.error("Can't update value with " + method.getName()
+ " (method) in " + nacosValueTarget.beanName + " (bean)", e);
}
}
}
doWithMethods(bean, beanName); private void setField(final NacosValueTarget nacosValueTarget,
final Object propertyValue) {
final Object bean = nacosValueTarget.bean;
return super.postProcessBeforeInitialization(bean, beanName); Field field = nacosValueTarget.field;
}
@Override String fieldName = field.getName();
public void onApplicationEvent(NacosConfigReceivedEvent event) {
String content = event.getContent();
if (content != null) {
Properties configProperties = toProperties(content);
for (Object key : configProperties.keySet()) { try {
String propertyKey = (String)key; ReflectionUtils.makeAccessible(field);
field.set(bean, convertIfNecessary(field, propertyValue));
List<NacosValueTarget> beanPropertyList = placeholderNacosValueTargetMap.get(propertyKey); if (logger.isDebugEnabled()) {
if (beanPropertyList == null) { logger.debug("Update value of the {}" + " (field) in {} (bean) with {}",
continue; fieldName, nacosValueTarget.beanName, propertyValue);
} }
}
catch (Throwable e) {
if (logger.isErrorEnabled()) {
logger.error("Can't update value of the " + fieldName + " (field) in "
+ nacosValueTarget.beanName + " (bean)", e);
}
}
}
String propertyValue = configProperties.getProperty(propertyKey); private static class NacosValueTarget {
for (NacosValueTarget nacosValueTarget : beanPropertyList) {
if (nacosValueTarget.method == null) {
setField(nacosValueTarget, propertyValue);
} else {
setMethod(nacosValueTarget, propertyValue);
}
}
}
}
}
private Object convertIfNecessary(Field field, Object value) { private final Object bean;
TypeConverter converter = beanFactory.getTypeConverter();
return converter.convertIfNecessary(value, field.getType(), field);
}
private Object convertIfNecessary(Method method, Object value) { private final String beanName;
Class<?>[] paramTypes = method.getParameterTypes();
Object[] arguments = new Object[paramTypes.length];
TypeConverter converter = beanFactory.getTypeConverter(); private final Method method;
if (arguments.length == 1) { private final Field field;
return converter.convertIfNecessary(value, paramTypes[0], new MethodParameter(method, 0));
}
for (int i = 0; i < arguments.length; i++) { private String lastMD5;
arguments[i] = converter.convertIfNecessary(value, paramTypes[i], new MethodParameter(method, i));
}
return arguments; private final String nacosValueExpr;
}
private void doWithFields(final Object bean, final String beanName) { NacosValueTarget(Object bean, String beanName, Method method, Field field, String nacosValueExpr) {
ReflectionUtils.doWithFields(bean.getClass(), new ReflectionUtils.FieldCallback() { this.bean = bean;
@Override
public void doWith(Field field) throws IllegalArgumentException {
NacosValue annotation = getAnnotation(field, NacosValue.class);
doWithAnnotation(beanName, bean, annotation, field.getModifiers(), null, field);
}
});
}
private void doWithMethods(final Object bean, final String beanName) { this.beanName = beanName;
ReflectionUtils.doWithMethods(bean.getClass(), new ReflectionUtils.MethodCallback() {
@Override
public void doWith(Method method) throws IllegalArgumentException {
NacosValue annotation = getAnnotation(method, NacosValue.class);
doWithAnnotation(beanName, bean, annotation, method.getModifiers(), method, null);
}
});
}
private void doWithAnnotation(String beanName, Object bean, NacosValue annotation, int modifiers, Method method, this.method = method;
Field field) {
if (annotation != null) {
if (Modifier.isStatic(modifiers)) {
return;
}
if (annotation.autoRefreshed()) { this.field = field;
String placeholder = resolvePlaceholder(annotation.value());
if (placeholder == null) { this.lastMD5 = "";
return;
}
NacosValueTarget nacosValueTarget = new NacosValueTarget(bean, beanName, method, field); this.nacosValueExpr = resolveExpr(nacosValueExpr);
put2ListMap(placeholderNacosValueTargetMap, placeholder, nacosValueTarget); }
}
}
}
private String resolvePlaceholder(String placeholder) { private String resolveExpr(String nacosValueExpr) {
if (!placeholder.startsWith(PLACEHOLDER_PREFIX)) { try {
return null; 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);
}
}
if (!placeholder.endsWith(PLACEHOLDER_SUFFIX)) { protected void updateLastMD5(String newMD5) {
return null; this.lastMD5 = newMD5;
} }
if (placeholder.length() <= PLACEHOLDER_PREFIX.length() + PLACEHOLDER_SUFFIX.length()) { }
return null;
}
int beginIndex = PLACEHOLDER_PREFIX.length();
int endIndex = placeholder.length() - PLACEHOLDER_PREFIX.length() + 1;
placeholder = placeholder.substring(beginIndex, endIndex);
int separatorIndex = placeholder.indexOf(VALUE_SEPARATOR);
if (separatorIndex != -1) {
return placeholder.substring(0, separatorIndex);
}
return placeholder;
}
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(NacosValueTarget nacosValueTarget, String propertyValue) {
Method method = nacosValueTarget.method;
ReflectionUtils.makeAccessible(method);
try {
method.invoke(nacosValueTarget.bean, convertIfNecessary(method, propertyValue));
if (logger.isDebugEnabled()) {
logger.debug("Update value with {} (method) in {} (bean) with {}",
method.getName(), nacosValueTarget.beanName, propertyValue);
}
} catch (Throwable e) {
if (logger.isErrorEnabled()) {
logger.error(
"Can't update value with " + method.getName() + " (method) in "
+ nacosValueTarget.beanName + " (bean)", e);
}
}
}
private void setField(final NacosValueTarget nacosValueTarget, final String propertyValue) {
final Object bean = nacosValueTarget.bean;
Field field = nacosValueTarget.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, nacosValueTarget.beanName, propertyValue);
}
} catch (Throwable e) {
if (logger.isErrorEnabled()) {
logger.error(
"Can't update value of the " + fieldName + " (field) in "
+ nacosValueTarget.beanName + " (bean)", e);
}
}
}
private static class NacosValueTarget {
private Object bean;
private String beanName;
private Method method;
private Field field;
NacosValueTarget(Object bean, String beanName, Method method, Field field) {
this.bean = bean;
this.beanName = beanName;
this.method = method;
this.field = field;
}
}
} }

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.
@ -32,81 +46,91 @@ import static com.alibaba.nacos.api.annotation.NacosProperties.*;
* @see NacosBeanDefinitionRegistrar * @see NacosBeanDefinitionRegistrar
* @since 0.1.0 * @since 0.1.0
*/ */
@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
*/
String DISCOVERY_PREFIX = NacosProperties.PREFIX + "discovery.";
/** /**
* The prefix of property name of Nacos discovery * The placeholder of endpoint, the value is
*/ * <code>"${nacos.discovery.endpoint:${nacos.endpoint:}}"</code>
String DISCOVERY_PREFIX = NacosProperties.PREFIX + "discovery."; */
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.endpoint:${nacos.endpoint:}}"</code> * <code>"${nacos.discovery.namespace:${nacos.namespace:}}"</code>
*/ */
String ENDPOINT_PLACEHOLDER = "${" + DISCOVERY_PREFIX + ENDPOINT + ":" + NacosProperties.ENDPOINT_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.namespace:${nacos.namespace:}}"</code> * <code>"${nacos.discovery.access-key:${nacos.access-key:}}"</code>
*/ */
String NAMESPACE_PLACEHOLDER = "${" + DISCOVERY_PREFIX + NAMESPACE + ":" + NacosProperties.NAMESPACE_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.access-key:${nacos.access-key:}}"</code> * <code>"${nacos.discovery.secret-key:${nacos.secret-key:}}"</code>
*/ */
String ACCESS_KEY_PLACEHOLDER = "${" + DISCOVERY_PREFIX + ACCESS_KEY +":" + NacosProperties.ACCESS_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.secret-key:${nacos.secret-key:}}"</code> * <code>"${nacos.discovery.server-addr:${nacos.server-addr:}}"</code>
*/ */
String SECRET_KEY_PLACEHOLDER = "${" + DISCOVERY_PREFIX + SECRET_KEY + ":" + NacosProperties.SECRET_KEY_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.server-addr:${nacos.server-addr:}}"</code> * <code>"${nacos.discovery.context-path:${nacos.context-path:}}"</code>
*/ */
String SERVER_ADDR_PLACEHOLDER = "${" + DISCOVERY_PREFIX + SERVER_ADDR + ":" + NacosProperties.SERVER_ADDR_PLACEHOLDER + "}"; String CONTEXT_PATH_PLACEHOLDER = "${" + DISCOVERY_PREFIX + CONTEXT_PATH + ":"
+ NacosProperties.CONTEXT_PATH_PLACEHOLDER + "}";
/**
* The placeholder of endpoint, the value is
* <code>"${nacos.discovery.cluster-name:${nacos.cluster-name:}}"</code>
*/
String CLUSTER_NAME_PLACEHOLDER = "${" + DISCOVERY_PREFIX + CLUSTER_NAME + ":"
+ NacosProperties.CLUSTER_NAME_PLACEHOLDER + "}";
/** /**
* The placeholder of endpoint, the value is * The placeholder of {@link NacosProperties#ENCODE encode}, the value is
* <code>"${nacos.discovery.context-path:${nacos.context-path:}}"</code> * <code>"${nacos.discovery.encode:${nacos.encode:UTF-8}}"</code>
*/ */
String CONTEXT_PATH_PLACEHOLDER = "${" + DISCOVERY_PREFIX + CONTEXT_PATH + ":" + NacosProperties.CONTEXT_PATH_PLACEHOLDER + "}"; String ENCODE_PLACEHOLDER = "${" + DISCOVERY_PREFIX + ENCODE + ":"
+ NacosProperties.ENCODE_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.username:${nacos.username:}}"</code>
*/ */
String CLUSTER_NAME_PLACEHOLDER = "${" + DISCOVERY_PREFIX + CLUSTER_NAME + ":" + NacosProperties.CLUSTER_NAME_PLACEHOLDER + "}"; String USERNAME_PLACEHOLDER = "${" + DISCOVERY_PREFIX + USERNAME + ":"
+ NacosProperties.USERNAME_PLACEHOLDER + "}";
/** /**
* The placeholder of {@link NacosProperties#ENCODE encode}, the value is * The placeholder of endpoint, the value is
* <code>"${nacos.discovery.encode:${nacos.encode:UTF-8}}"</code> * <code>"${nacos.discovery.password:${nacos.password:}}"</code>
*/ */
String ENCODE_PLACEHOLDER = "${" + DISCOVERY_PREFIX + ENCODE + ":" + NacosProperties.ENCODE_PLACEHOLDER + "}"; String PASSWORD_PLACEHOLDER = "${" + DISCOVERY_PREFIX + PASSWORD + ":"
+ NacosProperties.PASSWORD_PLACEHOLDER + "}";
/** /**
* Global {@link NacosProperties Nacos Properties} * Global {@link NacosProperties Nacos Properties}
* *
* @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,36 +30,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.*; 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
// Register Global Nacos Properties Bean .fromMap(importingClassMetadata
registerGlobalNacosProperties(attributes, registry, environment, DISCOVERY_GLOBAL_NACOS_PROPERTIES_BEAN_NAME); .getAnnotationAttributes(EnableNacosDiscovery.class.getName()));
// Register Nacos Common Beans // Register Global Nacos Properties Bean
registerNacosCommonBeans(registry); registerGlobalNacosProperties(attributes, registry, environment,
// Register Nacos Discovery Beans DISCOVERY_GLOBAL_NACOS_PROPERTIES_BEAN_NAME);
registerNacosDiscoveryBeans(registry); registerGlobalNacosProperties(attributes, registry, environment,
} MAINTAIN_GLOBAL_NACOS_PROPERTIES_BEAN_NAME);
// Register Nacos Common Beans
registerNacosCommonBeans(registry);
// Register Nacos Discovery Beans
registerNacosDiscoveryBeans(registry);
}
@Override @Override
public void setEnvironment(Environment environment) { public void setEnvironment(Environment environment) {
this.environment = environment; this.environment = environment;
} }
} }

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
@ -43,27 +53,36 @@ import static com.alibaba.nacos.spring.util.NacosBeanUtils.registerGlobalNacosPr
*/ */
public class GlobalNacosPropertiesBeanDefinitionParser implements BeanDefinitionParser { public class GlobalNacosPropertiesBeanDefinitionParser implements BeanDefinitionParser {
@Override @Override
public BeanDefinition parse(Element element, ParserContext parserContext) { public BeanDefinition parse(Element element, ParserContext parserContext) {
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,
properties.setProperty(PropertyKeyConst.ENCODE, element.getAttribute(ENCODE)); 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.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
@ -33,16 +35,18 @@ import org.w3c.dom.Element;
*/ */
public class NacosAnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser { public class NacosAnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
@Override @Override
public BeanDefinition parse(Element element, ParserContext parserContext) { public BeanDefinition parse(Element element, ParserContext parserContext) {
// Get Environment
Environment environment = parserContext.getDelegate().getEnvironment(); // Get Environment
// Get BeanDefinitionRegistry Environment environment = parserContext.getDelegate().getReaderContext()
BeanDefinitionRegistry registry = parserContext.getRegistry(); .getReader().getEnvironment();
// Register Nacos Annotation Beans // Get BeanDefinitionRegistry
NacosBeanDefinitionRegistrar registrar = new NacosBeanDefinitionRegistrar(); BeanDefinitionRegistry registry = parserContext.getRegistry();
registrar.setEnvironment(environment); // Register Nacos Annotation Beans
registrar.registerNacosAnnotationBeans(registry); NacosBeanDefinitionRegistrar registrar = new NacosBeanDefinitionRegistrar();
return null; registrar.setEnvironment(environment);
} registrar.registerNacosAnnotationBeans(registry);
return null;
}
} }

View File

@ -28,10 +28,13 @@ import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
*/ */
public class NacosNamespaceHandler extends NamespaceHandlerSupport { 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,39 +28,41 @@ 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
registerNacosPropertySourcePostProcessor(registry); registerNacosPropertySourcePostProcessor(registry);
registerXmlNacosPropertySourceBuilder(registry); registerXmlNacosPropertySourceBuilder(registry);
NacosPropertySourceXmlBeanDefinition beanDefinition = new NacosPropertySourceXmlBeanDefinition(); NacosPropertySourceXmlBeanDefinition beanDefinition = new NacosPropertySourceXmlBeanDefinition();
beanDefinition.setElement(element); beanDefinition.setElement(element);
beanDefinition.setXmlReaderContext(parserContext.getReaderContext()); beanDefinition.setXmlReaderContext(parserContext.getReaderContext());
return beanDefinition; return beanDefinition;
} }
@Override @Override
protected boolean shouldGenerateId() { protected boolean shouldGenerateId() {
return true; return true;
} }
} }

View File

@ -30,29 +30,29 @@ import org.w3c.dom.Element;
*/ */
public class NacosPropertySourceXmlBeanDefinition extends GenericBeanDefinition { public class NacosPropertySourceXmlBeanDefinition extends GenericBeanDefinition {
private Element element; private Element element;
private XmlReaderContext xmlReaderContext; private XmlReaderContext xmlReaderContext;
public NacosPropertySourceXmlBeanDefinition() { public NacosPropertySourceXmlBeanDefinition() {
// Self type as Bean Class // Self type as Bean Class
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() { public XmlReaderContext getXmlReaderContext() {
return element; return xmlReaderContext;
} }
public XmlReaderContext getXmlReaderContext() { void setXmlReaderContext(XmlReaderContext xmlReaderContext) {
return xmlReaderContext; this.xmlReaderContext = xmlReaderContext;
} }
} }

View File

@ -26,14 +26,16 @@ import com.alibaba.nacos.api.annotation.NacosProperties;
*/ */
public interface NacosConstants { 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,125 +51,131 @@ 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() {
this.annotationType = resolveGenericType(getClass()); this.annotationType = resolveGenericType(getClass());
} }
/** /**
* Must be * Must be
* <ul> * <ul>
* <li><code>public</code></li> * <li><code>public</code></li>
* <li>not <code>static</code></li> * <li>not <code>static</code></li>
* <li>not <code>abstract</code></li> * <li>not <code>abstract</code></li>
* <li>not <code>native</code></li> * <li>not <code>native</code></li>
* <li><code>void</code></li> * <li><code>void</code></li>
* </ul> * </ul>
* *
* @param method {@link Method} * @param method {@link Method}
* @return if obey above rules , return <code>true</code> * @return if obey above rules , return <code>true</code>
*/ */
static boolean isListenerMethod(Method method) { static boolean isListenerMethod(Method method) {
int modifiers = method.getModifiers(); int modifiers = method.getModifiers();
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
public final void onApplicationEvent(ContextRefreshedEvent event) { public final void onApplicationEvent(ContextRefreshedEvent event) {
// Retrieve ApplicationContext from ContextRefreshedEvent // Retrieve ApplicationContext from ContextRefreshedEvent
ApplicationContext applicationContext = event.getApplicationContext(); ApplicationContext applicationContext = event.getApplicationContext();
// Select those methods from all beans that annotated // Select those methods from all beans that annotated
processBeans(applicationContext); processBeans(applicationContext);
} }
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();
Object bean = entry.getValue(); Object bean = entry.getValue();
// Bean type // Bean type
if (bean != null) { if (bean != null) {
Class<?> beanClass = AopUtils.getTargetClass(bean); Class<?> beanClass = AopUtils.getTargetClass(bean);
processBean(beanName, bean, beanClass, applicationContext); processBean(beanName, bean, beanClass, applicationContext);
} }
} }
} }
/** /**
* Select those methods from bean that annotated * Select those methods from bean that annotated
* *
* @param beanName Bean name * @param beanName Bean name
* @param bean Bean object * @param bean Bean object
* @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)
A annotation = AnnotationUtils.getAnnotation(method, annotationType); throws IllegalArgumentException, IllegalAccessException {
if (annotation != null && isCandidateMethod(bean, beanClass, annotation, method, applicationContext)) { A annotation = AnnotationUtils.getAnnotation(method, annotationType);
processListenerMethod(beanName, bean, beanClass, annotation, method, applicationContext); if (annotation != null && isCandidateMethod(bean, beanClass, annotation,
} method, applicationContext)) {
} processListenerMethod(beanName, bean, beanClass, annotation, method,
applicationContext);
}
}
}, new ReflectionUtils.MethodFilter() { }, new ReflectionUtils.MethodFilter() {
@Override @Override
public boolean matches(Method method) { public boolean matches(Method method) {
return isListenerMethod(method); return isListenerMethod(method);
} }
}); });
} }
/** /**
* 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)}
* @param beanName Bean name * returns <code>true</code>
* @param bean Bean object *
* @param beanClass Bean Class * @param beanName Bean name
* @param annotation Annotation object * @param bean Bean object
* @param method Method * @param beanClass Bean Class
* @param applicationContext ApplicationContext * @param annotation Annotation object
*/ * @param method Method
protected abstract void processListenerMethod(String beanName, Object bean, Class<?> beanClass, A annotation, Method method, * @param applicationContext ApplicationContext
ApplicationContext applicationContext); */
protected abstract void processListenerMethod(String beanName, Object bean,
Class<?> beanClass, A annotation, Method method,
ApplicationContext applicationContext);
/** /**
* Subclass could override this method to determine current method is candidate or not * Subclass could override this method to determine current method is candidate or not
* *
* @param bean Bean object * @param bean Bean object
* @param beanClass Bean Class * @param beanClass Bean Class
* @param annotation Annotation object * @param annotation Annotation object
* @param method Method * @param method Method
* @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,65 +16,80 @@
*/ */
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;
this.context.addApplicationListener(this); this.context.addApplicationListener(this);
} }
@Override @Override
public void publishEvent(ApplicationEvent event) { public void publishEvent(ApplicationEvent event) {
if (context.isRunning()) { try {
context.publishEvent(event); if (context.isRunning()) {
} else { context.publishEvent(event);
deferredEvents.add(event); }
} else {
deferredEvents.add(event);
}
}
catch (Exception ignore) {
deferredEvents.add(event);
}
}
} public void publishEvent(Object event) {
// TODO
}
@Override @Override
public void onApplicationEvent(ContextRefreshedEvent event) { public void onApplicationEvent(ContextRefreshedEvent event) {
ApplicationContext currentContext = event.getApplicationContext(); ApplicationContext currentContext = event.getApplicationContext();
if (!currentContext.equals(context)) { if (!currentContext.equals(context)) {
// prevent multiple event multi-casts in hierarchical contexts // prevent multiple event multi-casts in hierarchical contexts
return; return;
} }
replayDeferredEvents(); replayDeferredEvents();
} }
private void replayDeferredEvents() { private void replayDeferredEvents() {
Iterator<ApplicationEvent> iterator = deferredEvents.iterator(); Iterator<ApplicationEvent> iterator = deferredEvents.iterator();
while (iterator.hasNext()) { while (iterator.hasNext()) {
ApplicationEvent event = iterator.next(); ApplicationEvent event = iterator.next();
publishEvent(event); publishEvent(event);
iterator.remove(); // remove if published iterator.remove(); // remove if published
} }
} }
} }

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()); @Override
public void onApplicationEvent(NacosConfigMetadataEvent event) {
private final static String LOGGING_MESSAGE = "Nacos Config Metadata : " + if (!logger.isInfoEnabled()) {
"dataId='{}'" + return;
", groupId='{}'" + }
", beanName='{}'" + logger.info(LOGGING_MESSAGE, event.getDataId(), event.getGroupId(),
", bean='{}'" + event.getBeanName(), event.getBean(), event.getBeanType(),
", beanType='{}'" + event.getAnnotatedElement(), event.getXmlResource(),
", annotatedElement='{}'" + obscuresNacosProperties(event.getNacosProperties()), event.getNacosPropertiesAttributes(),
", xmlResource='{}'" + event.getSource(), event.getTimestamp());
", nacosProperties='{}'" + }
", nacosPropertiesAttributes='{}'" +
", source='{}'" + /**
", timestamp='{}'"; * obscures some private field like password in {@link com.alibaba.nacos.api.annotation.NacosProperties}
* @param nacosProperties {@link com.alibaba.nacos.api.annotation.NacosProperties}
@Override * @return the properties String after obscures
public void onApplicationEvent(NacosConfigMetadataEvent event) { */
if (logger.isInfoEnabled()) { private String obscuresNacosProperties(Map<Object, Object> nacosProperties) {
logger.info(LOGGING_MESSAGE, String nacosPropertyStr;
event.getDataId(), if (nacosProperties != null && nacosProperties.size() > 0) {
event.getGroupId(), StringBuilder sb = new StringBuilder("{");
event.getBeanName(), int size = nacosProperties.size();
event.getBean(), int idx = 0;
event.getBeanType(), for (Map.Entry<Object, Object> e : nacosProperties.entrySet()) {
event.getAnnotatedElement(), Object key = e.getKey();
event.getXmlResource(), Object value = e.getValue();
event.getNacosProperties(), sb.append(key);
event.getNacosPropertiesAttributes(), sb.append('=');
event.getSource(), // hide some private messages
event.getTimestamp() 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,57 +36,69 @@ 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;
private final String dataId; private final String dataId;
private final String groupId; private final String groupId;
private final ApplicationEventPublisher applicationEventPublisher; private final ApplicationEventPublisher applicationEventPublisher;
private final Executor executor; private final String configType;
private final Listener delegate; private final Executor executor;
DelegatingEventPublishingListener(ConfigService configService, String dataId, String groupId, private final Listener delegate;
ApplicationEventPublisher applicationEventPublisher,
Executor executor, Listener delegate) {
this.configService = configService;
this.dataId = dataId;
this.groupId = groupId;
this.applicationEventPublisher = applicationEventPublisher;
this.executor = executor;
this.delegate = delegate;
}
@Override DelegatingEventPublishingListener(ConfigService configService, String dataId,
public Executor getExecutor() { String groupId, ApplicationEventPublisher applicationEventPublisher,
Executor executor = delegate.getExecutor(); Executor executor, Listener delegate) {
if (executor == null) { this(configService, dataId, groupId, ConfigType.PROPERTIES.getType(),
executor = this.executor; applicationEventPublisher, executor, delegate);
} }
return executor;
}
/** DelegatingEventPublishingListener(ConfigService configService, String dataId,
* Callback method on Nacos config received String groupId, String configType,
* ApplicationEventPublisher applicationEventPublisher, Executor executor,
* @param content Nacos config Listener delegate) {
*/ this.configService = configService;
@Override this.dataId = dataId;
public void receiveConfigInfo(String content) { this.groupId = groupId;
publishEvent(content); this.configType = configType;
onReceived(content); this.applicationEventPublisher = applicationEventPublisher;
} this.executor = executor;
this.delegate = delegate;
}
private void publishEvent(String content) { @Override
NacosConfigReceivedEvent event = new NacosConfigReceivedEvent(configService, dataId, groupId, content); public Executor getExecutor() {
applicationEventPublisher.publishEvent(event); Executor executor = delegate.getExecutor();
} if (executor == null) {
executor = this.executor;
}
return executor;
}
private void onReceived(String content) { /**
delegate.receiveConfigInfo(content); * Callback method on Nacos config received
} *
* @param content Nacos config
*/
@Override
public void receiveConfigInfo(String content) {
onReceived(content);
publishEvent(content);
}
private void publishEvent(String content) {
NacosConfigReceivedEvent event = new NacosConfigReceivedEvent(configService,
dataId, groupId, content, configType);
applicationEventPublisher.publishEvent(event);
}
private void onReceived(String content) {
delegate.receiveConfigInfo(content);
}
} }

View File

@ -14,93 +14,171 @@
* 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;
private final ApplicationEventPublisher applicationEventPublisher; private final ApplicationEventPublisher applicationEventPublisher;
private final Executor executor; private final Executor executor;
private final Properties properties; private final Properties properties;
public EventPublishingConfigService(ConfigService configService, Properties properties, ConfigurableApplicationContext context, public EventPublishingConfigService(ConfigService configService,
Executor executor) { Properties properties, ConfigurableApplicationContext context,
this.configService = configService; Executor executor) {
this.properties = properties; this.configService = configService;
this.applicationEventPublisher = new DeferredApplicationEventPublisher(context); this.properties = properties;
this.executor = executor; this.applicationEventPublisher = new DeferredApplicationEventPublisher(context);
} this.executor = executor;
}
@Override @Override
public String getConfig(String dataId, String group, long timeoutMs) throws NacosException { public String getConfig(String dataId, String group, long timeoutMs)
try { throws NacosException {
return configService.getConfig(dataId, group, timeoutMs); try {
} catch (NacosException e) { return configService.getConfig(dataId, group, timeoutMs);
if (NacosException.SERVER_ERROR == e.getErrCode()) { // timeout error }
publishEvent(new NacosConfigTimeoutEvent(configService, dataId, group, timeoutMs, e.getErrMsg())); catch (NacosException e) {
} if (NacosException.SERVER_ERROR == e.getErrCode()) { // timeout error
throw e; // re-throw NacosException publishEvent(new NacosConfigTimeoutEvent(configService, dataId, group,
} timeoutMs, e.getErrMsg()));
} }
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);
}
@Override /**
public boolean publishConfig(String dataId, String group, String content) throws NacosException { * Implementation of the new version of support for multiple configuration file type
boolean published = configService.publishConfig(dataId, group, content); * resolution.
publishEvent(new NacosConfigPublishedEvent(configService, dataId, group, content, published)); *
return published; * @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 removeConfig(String dataId, String group) throws NacosException { public void addListener(String dataId, String group, Listener listener)
boolean removed = configService.removeConfig(dataId, group); throws NacosException {
publishEvent(new NacosConfigRemovedEvent(configService, dataId, group, removed)); configService.addListener(dataId, group, listener);
return removed; publishEvent(new NacosConfigListenerRegisteredEvent(configService, dataId, group,
} listener, true));
}
@Override @Override
public void removeListener(String dataId, String group, Listener listener) { public boolean publishConfig(String dataId, String group, String content)
configService.removeListener(dataId, group, listener); throws NacosException {
publishEvent(new NacosConfigListenerRegisteredEvent(configService, dataId, group, listener, false)); boolean published = configService.publishConfig(dataId, group, content);
} 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;
}
@Override
public boolean removeConfig(String dataId, String group) throws NacosException {
boolean removed = configService.removeConfig(dataId, group);
publishEvent(new NacosConfigRemovedEvent(configService, dataId, group, removed));
return removed;
}
@Override @Override
public String getServerStatus() { public void removeListener(String dataId, String group, Listener listener) {
return configService.getServerStatus(); configService.removeListener(dataId, group, listener);
} publishEvent(new NacosConfigListenerRegisteredEvent(configService, dataId, group,
listener, false));
}
private void publishEvent(NacosConfigEvent nacosConfigEvent) { @Override
applicationEventPublisher.publishEvent(nacosConfigEvent); public String getServerStatus() {
} return configService.getServerStatus();
}
@Override @Override
public Properties getProperties() { public void shutDown() throws NacosException {
return properties; configService.shutDown();
} }
private void publishEvent(NacosConfigEvent nacosConfigEvent) {
applicationEventPublisher.publishEvent(nacosConfigEvent);
}
@Override
public Properties getProperties() {
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
* *
@ -27,40 +28,40 @@ import org.springframework.context.ApplicationEvent;
*/ */
public abstract class NacosConfigEvent extends ApplicationEvent { public abstract class NacosConfigEvent extends ApplicationEvent {
private final String dataId; private final String dataId;
private final String groupId; private final String groupId;
/** /**
* @param configService Nacos {@link ConfigService} * @param configService Nacos {@link ConfigService}
* @param dataId data ID * @param dataId data ID
* @param groupId group ID * @param groupId group ID
*/ */
public NacosConfigEvent(ConfigService configService, String dataId, String groupId) { public NacosConfigEvent(ConfigService configService, String dataId, String groupId) {
super(configService); super(configService);
this.dataId = dataId; this.dataId = dataId;
this.groupId = groupId; this.groupId = groupId;
} }
@Override @Override
public final ConfigService getSource() { public final ConfigService getSource() {
return (ConfigService) super.getSource(); return (ConfigService) super.getSource();
} }
/** /**
* Get {@link ConfigService} * Get {@link ConfigService}
* *
* @return {@link ConfigService} * @return {@link ConfigService}
*/ */
public final ConfigService getConfigService() { public final ConfigService getConfigService() {
return getSource(); return getSource();
} }
public final String getDataId() { public final String getDataId() {
return dataId; return dataId;
} }
public final String getGroupId() { public final String getGroupId() {
return groupId; return groupId;
} }
} }

View File

@ -28,29 +28,29 @@ import com.alibaba.nacos.api.config.listener.Listener;
*/ */
public class NacosConfigListenerRegisteredEvent extends NacosConfigEvent { public class NacosConfigListenerRegisteredEvent extends NacosConfigEvent {
private final Listener listener; private final Listener listener;
private final boolean registered; private final boolean registered;
/** /**
* @param configService Nacos {@link ConfigService} * @param configService Nacos {@link ConfigService}
* @param dataId data ID * @param dataId data ID
* @param groupId group ID * @param groupId group ID
* @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;
} }
public Listener getListener() { public Listener getListener() {
return listener; return listener;
} }
public boolean isRegistered() { public boolean isRegistered() {
return registered; return 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}
@ -37,129 +37,131 @@ import java.util.Properties;
*/ */
public class NacosConfigMetadataEvent extends ApplicationEvent { public class NacosConfigMetadataEvent extends ApplicationEvent {
private String dataId; private String dataId;
private String groupId; private String groupId;
private String beanName; private String beanName;
private Object bean; private Object bean;
private Class<?> beanType; private Class<?> beanType;
private AnnotatedElement annotatedElement; private AnnotatedElement annotatedElement;
private Resource xmlResource; private Resource xmlResource;
private Properties nacosProperties; private Map<Object, Object> nacosProperties;
private Map<String, Object> nacosPropertiesAttributes; private Map<String, Object> nacosPropertiesAttributes;
/** /**
* Create a new ApplicationEvent. * Create a new ApplicationEvent.
* *
* @param source maybe {@link Annotation} or {@link Element XML element} * @param source maybe {@link Annotation} or {@link Element XML element}
* @see NacosConfigListener * @see NacosConfigListener
* @see NacosConfigurationProperties * @see NacosConfigurationProperties
* @see NacosPropertySource * @see NacosPropertySource
* @see Element * @see Element
*/ */
public NacosConfigMetadataEvent(Object source) { public NacosConfigMetadataEvent(Object source) {
super(source); super(source);
} }
public String getDataId() { public String getDataId() {
return dataId; return dataId;
} }
public void setDataId(String dataId) { public void setDataId(String dataId) {
this.dataId = dataId; this.dataId = dataId;
} }
public String getGroupId() { public String getGroupId() {
return groupId; return groupId;
} }
public void setGroupId(String groupId) { public void setGroupId(String groupId) {
this.groupId = groupId; this.groupId = groupId;
} }
public String getBeanName() { public String getBeanName() {
return beanName; return beanName;
} }
public void setBeanName(String beanName) { public void setBeanName(String beanName) {
this.beanName = beanName; this.beanName = beanName;
} }
public Object getBean() { public Object getBean() {
return bean; return bean;
} }
public void setBean(Object bean) { public void setBean(Object bean) {
this.bean = bean; this.bean = bean;
} }
public Class<?> getBeanType() { public Class<?> getBeanType() {
return beanType; return beanType;
} }
public void setBeanType(Class<?> beanType) { public void setBeanType(Class<?> beanType) {
this.beanType = beanType; this.beanType = beanType;
} }
/** /**
* {@link AnnotatedElement} maybe {@link Class}, {@link Method} * {@link AnnotatedElement} maybe {@link Class}, {@link Method}
* *
* @return maybe <code>null</code> if source from XML configuration * @return maybe <code>null</code> if source from XML configuration
* @see NacosConfigListener * @see NacosConfigListener
* @see NacosConfigurationProperties * @see NacosConfigurationProperties
* @see NacosPropertySource * @see NacosPropertySource
*/ */
public AnnotatedElement getAnnotatedElement() { public AnnotatedElement getAnnotatedElement() {
return annotatedElement; return annotatedElement;
} }
public void setAnnotatedElement(AnnotatedElement annotatedElement) { public void setAnnotatedElement(AnnotatedElement annotatedElement) {
this.annotatedElement = annotatedElement; this.annotatedElement = annotatedElement;
} }
/** /**
* {@link Resource} for XML configuration * {@link Resource} for XML configuration
* *
* @return maybe <code>null</code> if Annotated by somewhere * @return maybe <code>null</code> if Annotated by somewhere
*/ */
public Resource getXmlResource() { public Resource getXmlResource() {
return xmlResource; return xmlResource;
} }
public void setXmlResource(Resource xmlResource) { public void setXmlResource(Resource xmlResource) {
this.xmlResource = xmlResource; this.xmlResource = xmlResource;
} }
/** /**
* 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
public Map<String, Object> getNacosPropertiesAttributes() { */
return nacosPropertiesAttributes; public Map<String, Object> getNacosPropertiesAttributes() {
} return nacosPropertiesAttributes;
}
public void setNacosPropertiesAttributes(Map<String, Object> nacosPropertiesAttributes) { public void setNacosPropertiesAttributes(
this.nacosPropertiesAttributes = nacosPropertiesAttributes; Map<String, Object> nacosPropertiesAttributes) {
} this.nacosPropertiesAttributes = nacosPropertiesAttributes;
}
} }

View File

@ -26,32 +26,34 @@ import com.alibaba.nacos.api.config.ConfigService;
*/ */
public class NacosConfigPublishedEvent extends NacosConfigEvent { public class NacosConfigPublishedEvent extends NacosConfigEvent {
private final String content; private final String content;
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;
} }
/** /**
* Get Content of published Nacos Configuration * Get Content of published Nacos Configuration
* *
* @return content * @return content
*/ */
public String getContent() { public String getContent() {
return content; return content;
} }
/** /**
* 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
* @return if published , return <code>true</code> * result.
*/ *
public boolean isPublished() { * @return if published , return <code>true</code>
return published; */
} public boolean isPublished() {
return published;
}
} }

View File

@ -26,19 +26,27 @@ 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,
super(configService, dataId, groupId); String groupId, String content, String type) {
this.content = content; super(configService, dataId, groupId);
} this.content = content;
this.type = type;
}
/**
* Get Content of published Nacos Configuration
*
* @return content
*/
public String getContent() {
return content;
}
public String getType() {
return type;
}
/**
* Get Content of published Nacos Configuration
*
* @return content
*/
public String getContent() {
return content;
}
} }

View File

@ -26,19 +26,21 @@ import com.alibaba.nacos.api.config.ConfigService;
*/ */
public class NacosConfigRemovedEvent extends NacosConfigEvent { 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,
super(configService, dataId, groupId); String groupId, boolean removed) {
this.removed = removed; super(configService, dataId, groupId);
} 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>
public boolean isRemoved() { */
return removed; public boolean isRemoved() {
} return removed;
}
} }

View File

@ -19,45 +19,47 @@ 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
*/ */
public class NacosConfigTimeoutEvent extends NacosConfigEvent { public class NacosConfigTimeoutEvent extends NacosConfigEvent {
private final long timeout; private final long timeout;
private final String errorMessage; private final String errorMessage;
/** /**
* @param configService Nacos {@link ConfigService} * @param configService Nacos {@link ConfigService}
* @param dataId data ID * @param dataId data ID
* @param groupId group ID * @param groupId group ID
* @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,
super(configService, dataId, groupId); String groupId, long timeout, String errorMessage) {
this.timeout = timeout; super(configService, dataId, groupId);
this.errorMessage = errorMessage; this.timeout = timeout;
} this.errorMessage = errorMessage;
}
/** /**
* Get timeout in Millis. * Get timeout in Millis.
* *
* @return timeout in Millis * @return timeout in Millis
*/ */
public long getTimeout() { public long getTimeout() {
return timeout; return timeout;
} }
/** /**
* get error message * get error message
* *
* @return error message * @return error message
*/ */
public String getErrorMessage() { public String getErrorMessage() {
return errorMessage; return 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}.
* *
@ -29,50 +29,46 @@ import java.util.EventObject;
*/ */
public class NacosConfigurationPropertiesBeanBoundEvent extends NacosConfigEvent { public class NacosConfigurationPropertiesBeanBoundEvent extends NacosConfigEvent {
private final Object bean; private final Object bean;
private final String beanName; private final String beanName;
private final NacosConfigurationProperties properties; private final NacosConfigurationProperties properties;
private final String content; private final String content;
/** /**
* @param configService Nacos {@link ConfigService} * @param configService Nacos {@link ConfigService}
* @param dataId data ID * @param dataId data ID
* @param groupId group ID * @param groupId group ID
* @param bean annotated {@link NacosConfigurationProperties} bean * @param bean annotated {@link NacosConfigurationProperties} bean
* @param beanName the name of annotated {@link NacosConfigurationProperties} bean * @param beanName the name of annotated {@link NacosConfigurationProperties} bean
* @param properties {@link NacosConfigurationProperties} object * @param properties {@link NacosConfigurationProperties} object
* @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, super(configService, dataId, groupId);
String beanName, this.bean = bean;
NacosConfigurationProperties properties, this.beanName = beanName;
String content) { this.properties = properties;
super(configService, dataId, groupId); this.content = content;
this.bean = bean; }
this.beanName = beanName;
this.properties = properties;
this.content = content;
}
public Object getBean() { public Object getBean() {
return bean; return bean;
} }
public String getBeanName() { public String getBeanName() {
return beanName; return beanName;
} }
public NacosConfigurationProperties getProperties() { public NacosConfigurationProperties getProperties() {
return properties; return properties;
} }
public String getContent() { public String getContent() {
return content; return content;
} }
} }

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,62 +39,74 @@ import java.util.concurrent.*;
*/ */
public abstract class TimeoutNacosConfigListener extends AbstractListener { public abstract class TimeoutNacosConfigListener extends AbstractListener {
private final Logger logger = LoggerFactory.getLogger(getClass()); private static AtomicInteger id = new AtomicInteger(0);
private final String dataId; 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 String groupId; private final Logger logger = LoggerFactory.getLogger(getClass());
private final long timeout; private final String dataId;
public TimeoutNacosConfigListener(String dataId, String groupId, long timeout) { private final String groupId;
this.dataId = dataId;
this.groupId = groupId;
this.timeout = timeout;
}
public final void receiveConfigInfo(final String content) { private final long timeout;
ExecutorService executorService = Executors.newSingleThreadExecutor(); public TimeoutNacosConfigListener(String dataId, String groupId, long timeout) {
this.dataId = dataId;
this.groupId = groupId;
this.timeout = timeout;
}
Future future = executorService.submit(new Runnable() { @Override
@Override public void receiveConfigInfo(final String content) {
public void run() { Future future = executorService.submit(new Runnable() {
onReceived(content); @Override
} public void run() {
}); onReceived(content);
}
});
try {
future.get(timeout, TimeUnit.MILLISECONDS);
}
catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new RuntimeException(e);
}
catch (ExecutionException e) {
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);
}
}
try { /**
future.get(timeout, TimeUnit.MILLISECONDS); * process Nacos Config when received.
} catch (InterruptedException e) { *
Thread.currentThread().interrupt(); * @param content Nacos Config
throw new RuntimeException(e); */
} catch (ExecutionException e) { protected abstract void onReceived(String content);
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 {
executorService.shutdown();
}
}
/** /**
* process Nacos Config when received. * Get timeout in milliseconds
* *
* @param content Nacos Config * @return timeout in milliseconds
*/ */
protected abstract void onReceived(String content); public long getTimeout() {
return timeout;
/** }
* Get timeout in milliseconds
*
* @return timeout in milliseconds
*/
public long getTimeout() {
return timeout;
}
} }

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,143 +55,155 @@ 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 final ConfigurableApplicationContext applicationContext; private static final Logger logger = LoggerFactory
.getLogger(NacosConfigurationPropertiesBinder.class);
private final Environment environment; private final ConfigurableApplicationContext applicationContext;
private final ApplicationEventPublisher applicationEventPublisher; private final Environment environment;
private final ConfigServiceBeanBuilder configServiceBeanBuilder; private final ApplicationEventPublisher applicationEventPublisher;
NacosConfigurationPropertiesBinder(ConfigurableApplicationContext applicationContext) { private final ConfigServiceBeanBuilder configServiceBeanBuilder;
Assert.notNull(applicationContext, "ConfigurableApplicationContext must not be null!");
this.applicationContext = applicationContext;
this.environment = applicationContext.getEnvironment();
this.applicationEventPublisher = applicationContext;
this.configServiceBeanBuilder = getConfigServiceBeanBuilder(applicationContext);
}
protected void bind(Object bean, String beanName) { protected NacosConfigurationPropertiesBinder(
ConfigurableApplicationContext applicationContext) {
Assert.notNull(applicationContext,
"ConfigurableApplicationContext must not be null!");
this.applicationContext = applicationContext;
this.environment = applicationContext.getEnvironment();
this.applicationEventPublisher = applicationContext;
this.configServiceBeanBuilder = getConfigServiceBeanBuilder(applicationContext);
}
NacosConfigurationProperties properties = findAnnotation(bean.getClass(), NacosConfigurationProperties.class); protected void bind(Object bean, String beanName) {
bind(bean, beanName, properties); NacosConfigurationProperties properties = findAnnotation(bean.getClass(),
NacosConfigurationProperties.class);
} bind(bean, beanName, properties);
protected void bind(final Object bean, final String beanName, final NacosConfigurationProperties properties) { }
Assert.notNull(bean, "Bean must not be null!"); protected void bind(final Object bean, final String beanName,
final NacosConfigurationProperties properties) {
Assert.notNull(properties, "NacosConfigurationProperties must not be null!"); Assert.notNull(bean, "Bean must not be null!");
final String dataId = properties.dataId(); Assert.notNull(properties, "NacosConfigurationProperties must not be null!");
final String groupId = properties.groupId(); // 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;
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()) {
String content = getContent(configService, dataId, groupId);
if (hasText(content)) {
doBind(bean, beanName, dataId, groupId, type, properties, content,
configService);
}
try { Listener listener = new AbstractListener() {
configService.addListener(dataId, groupId, new AbstractListener() { @Override
@Override public void receiveConfigInfo(String config) {
public void receiveConfigInfo(String config) { doBind(bean, beanName, dataId, groupId, type, properties, config,
doBind(bean, beanName, dataId, groupId, properties, config, configService); configService);
} }
}); };
} catch (NacosException e) { try {//
if (logger.isErrorEnabled()) { if (configService instanceof EventPublishingConfigService) {
logger.error(e.getMessage(), e); ((EventPublishingConfigService) configService).addListener(dataId,
} groupId, type, listener);
} }
} else {
configService.addListener(dataId, groupId, listener);
}
}
catch (NacosException e) {
if (logger.isErrorEnabled()) {
logger.error(e.getMessage(), e);
}
}
}
}
String content = getContent(configService, dataId, groupId); protected void doBind(Object bean, String beanName, String dataId, String groupId,
String type, NacosConfigurationProperties properties, String content,
ConfigService configService) {
final String prefix = properties.prefix();
PropertyValues propertyValues = NacosUtils.resolvePropertyValues(bean, prefix,
dataId, groupId, content, type);
doBind(bean, properties, propertyValues);
publishBoundEvent(bean, beanName, dataId, groupId, properties, content,
configService);
publishMetadataEvent(bean, beanName, dataId, groupId, properties);
}
if (hasText(content)) { protected void publishMetadataEvent(Object bean, String beanName, String dataId,
doBind(bean, beanName, dataId, groupId, properties, content, configService); String groupId, NacosConfigurationProperties properties) {
}
}
private void doBind(Object bean, String beanName, String dataId, String groupId, NacosProperties nacosProperties = properties.properties();
NacosConfigurationProperties properties, String content, ConfigService configService) {
PropertyValues propertyValues = resolvePropertyValues(bean, content);
doBind(bean, properties, propertyValues);
publishBoundEvent(bean, beanName, dataId, groupId, properties, content, configService);
publishMetadataEvent(bean, beanName, dataId, groupId, properties);
}
private void publishMetadataEvent(Object bean, String beanName, String dataId, String groupId, NacosConfigMetadataEvent metadataEvent = new NacosConfigMetadataEvent(properties);
NacosConfigurationProperties properties) {
NacosProperties nacosProperties = properties.properties(); // Nacos Metadata
metadataEvent.setDataId(dataId);
metadataEvent.setGroupId(groupId);
Properties resolvedNacosProperties = configServiceBeanBuilder
.resolveProperties(nacosProperties);
Map<String, Object> nacosPropertiesAttributes = getAnnotationAttributes(
nacosProperties);
metadataEvent.setNacosPropertiesAttributes(nacosPropertiesAttributes);
metadataEvent.setNacosProperties(resolvedNacosProperties);
NacosConfigMetadataEvent metadataEvent = new NacosConfigMetadataEvent(properties); // Bean Metadata
Class<?> beanClass = bean.getClass();
metadataEvent.setBeanName(beanName);
metadataEvent.setBean(bean);
metadataEvent.setBeanType(beanClass);
metadataEvent.setAnnotatedElement(beanClass);
// Nacos Metadata // Publish event
metadataEvent.setDataId(dataId); applicationEventPublisher.publishEvent(metadataEvent);
metadataEvent.setGroupId(groupId); }
Properties resolvedNacosProperties = configServiceBeanBuilder.resolveProperties(nacosProperties);
Map<String, Object> nacosPropertiesAttributes = getAnnotationAttributes(nacosProperties);
metadataEvent.setNacosPropertiesAttributes(nacosPropertiesAttributes);
metadataEvent.setNacosProperties(resolvedNacosProperties);
// Bean Metadata protected void publishBoundEvent(Object bean, String beanName, String dataId,
Class<?> beanClass = bean.getClass(); String groupId, NacosConfigurationProperties properties, String content,
metadataEvent.setBeanName(beanName); ConfigService configService) {
metadataEvent.setBean(bean); NacosConfigEvent event = new NacosConfigurationPropertiesBeanBoundEvent(
metadataEvent.setBeanType(beanClass); configService, dataId, groupId, bean, beanName, properties, content);
metadataEvent.setAnnotatedElement(beanClass); applicationEventPublisher.publishEvent(event);
}
// Publish event private void doBind(Object bean, NacosConfigurationProperties properties,
applicationEventPublisher.publishEvent(metadataEvent); PropertyValues propertyValues) {
} ObjectUtils.cleanMapOrCollectionField(bean);
DataBinder dataBinder = new DataBinder(bean);
private void publishBoundEvent(Object bean, String beanName, String dataId, String groupId, dataBinder.setAutoGrowNestedPaths(properties.ignoreNestedProperties());
NacosConfigurationProperties properties, String content, ConfigService configService) { dataBinder.setIgnoreInvalidFields(properties.ignoreInvalidFields());
NacosConfigEvent event = new NacosConfigurationPropertiesBeanBoundEvent(configService, dataId, groupId, bean, dataBinder.setIgnoreUnknownFields(properties.ignoreUnknownFields());
beanName, properties, content); dataBinder.bind(propertyValues);
applicationEventPublisher.publishEvent(event); }
}
private void doBind(Object bean, NacosConfigurationProperties properties,
PropertyValues propertyValues) {
DataBinder dataBinder = new DataBinder(bean);
dataBinder.setAutoGrowNestedPaths(properties.ignoreNestedProperties());
dataBinder.setIgnoreInvalidFields(properties.ignoreInvalidFields());
dataBinder.setIgnoreUnknownFields(properties.ignoreUnknownFields());
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,51 +39,68 @@ 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
*/ */
public static final String BEAN_NAME = "nacosConfigurationPropertiesBindingPostProcessor"; public static final String BEAN_NAME = "nacosConfigurationPropertiesBindingPostProcessor";
private Properties globalNacosProperties; private Properties globalNacosProperties;
private NacosServiceFactory nacosServiceFactory; private NacosServiceFactory nacosServiceFactory;
private Environment environment; private Environment environment;
private ApplicationEventPublisher applicationEventPublisher; private ApplicationEventPublisher applicationEventPublisher;
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);
} }
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);
}
binder.bind(bean, beanName, nacosConfigurationProperties); }
catch (Exception e) {
binder = new NacosConfigurationPropertiesBinder(applicationContext);
}
} binder.bind(bean, beanName, nacosConfigurationProperties);
}
@Override @Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { public Object postProcessAfterInitialization(Object bean, String beanName)
return bean; throws BeansException {
} return bean;
}
@Override @Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { public void setApplicationContext(ApplicationContext applicationContext)
this.applicationContext = (ConfigurableApplicationContext) applicationContext; throws BeansException {
} 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
* *
@ -28,29 +32,40 @@ import org.springframework.format.support.DefaultFormattingConversionService;
*/ */
public class DefaultNacosConfigConverter<T> implements NacosConfigConverter<T> { public class DefaultNacosConfigConverter<T> implements NacosConfigConverter<T> {
private final Class<T> targetType; private final Class<T> targetType;
private final ConversionService conversionService; private final ConversionService conversionService;
public DefaultNacosConfigConverter(Class<T> targetType) { private final String type;
this(targetType, new DefaultFormattingConversionService());
}
public DefaultNacosConfigConverter(Class<T> targetType, ConversionService conversionService) { public DefaultNacosConfigConverter(Class<T> targetType) {
this.targetType = targetType; this(targetType, new DefaultFormattingConversionService(), "properties");
this.conversionService = conversionService; }
}
@Override public DefaultNacosConfigConverter(Class<T> targetType,
public T convert(String source) { ConversionService conversionService, String type) {
if (conversionService.canConvert(source.getClass(), targetType)) { this.targetType = targetType;
return conversionService.convert(source, targetType); this.conversionService = conversionService;
} this.type = type;
return null; }
}
@Override @Override
public boolean canConvert(Class<T> targetType) { public T convert(String source) {
return conversionService.canConvert(String.class, targetType);
} // 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)) {
return conversionService.convert(source, targetType);
}
return null;
}
@Override
public boolean canConvert(Class<T> targetType) {
return conversionService.canConvert(String.class, 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,200 +68,230 @@ 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());
private final Class<T> beanDefinitionType;
protected ConfigurableEnvironment environment;
protected BeanFactory beanFactory;
private NacosConfigLoader nacosConfigLoader;
private Properties globalNacosProperties;
private ClassLoader classLoader;
protected ConfigurableEnvironment environment; private ApplicationEventPublisher applicationEventPublisher;
protected BeanFactory beanFactory; public AbstractNacosPropertySourceBuilder() {
beanDefinitionType = resolveGenericType(getClass());
}
private NacosConfigLoader nacosConfigLoader; /**
* Build {@link NacosPropertySource} from {@link BeanDefinition}
*
* @param beanName Bean name
* @param beanDefinition {@link BeanDefinition}
* @return a {@link NacosPropertySource} instance
*/
public List<NacosPropertySource> build(String beanName, T beanDefinition) {
private Properties globalNacosProperties; Map<String, Object>[] attributesArray = resolveRuntimeAttributesArray(
beanDefinition, globalNacosProperties);
private final Class<T> beanDefinitionType; int size = attributesArray == null ? 0 : attributesArray.length;
private ClassLoader classLoader; if (size == 0) {
return Collections.emptyList();
}
private ApplicationEventPublisher applicationEventPublisher; List<NacosPropertySource> nacosPropertySources = new ArrayList<NacosPropertySource>(
size);
public AbstractNacosPropertySourceBuilder() { for (int i = 0; i < size; i++) {
beanDefinitionType = resolveGenericType(getClass()); Map<String, Object> attributes = attributesArray[i];
} if (!CollectionUtils.isEmpty(attributes)) {
/** NacosPropertySource nacosPropertySource = doBuild(beanName,
* Build {@link NacosPropertySource} from {@link BeanDefinition} beanDefinition, attributesArray[i]);
*
* @param beanName Bean name
* @param beanDefinition {@link BeanDefinition}
* @return a {@link NacosPropertySource} instance
*/
public List<NacosPropertySource> build(String beanName, T beanDefinition) {
Map<String, Object>[] attributesArray = resolveRuntimeAttributesArray(beanDefinition, globalNacosProperties); NacosConfigMetadataEvent metadataEvent = createMetaEvent(
nacosPropertySource, beanDefinition);
int size = attributesArray == null ? 0 : attributesArray.length; initMetadataEvent(nacosPropertySource, beanDefinition, metadataEvent);
if (size == 0) { publishMetadataEvent(metadataEvent);
return Collections.emptyList();
}
List<NacosPropertySource> nacosPropertySources = new ArrayList<NacosPropertySource>(size); nacosPropertySources.add(nacosPropertySource);
for (int i = 0; i < size; i++) { }
Map<String, Object> attributes = attributesArray[i]; }
if (!CollectionUtils.isEmpty(attributes)) {
NacosPropertySource nacosPropertySource = doBuild(beanName, beanDefinition, attributesArray[i]); return nacosPropertySources;
}
NacosConfigMetadataEvent metadataEvent = createMetaEvent(nacosPropertySource, beanDefinition); protected abstract NacosConfigMetadataEvent createMetaEvent(
NacosPropertySource nacosPropertySource, T beanDefinition);
initMetadataEvent(nacosPropertySource, beanDefinition, metadataEvent); private void initMetadataEvent(NacosPropertySource nacosPropertySource,
T beanDefinition, NacosConfigMetadataEvent metadataEvent) {
metadataEvent.setDataId(nacosPropertySource.getDataId());
metadataEvent.setGroupId(nacosPropertySource.getGroupId());
metadataEvent.setBeanName(nacosPropertySource.getBeanName());
metadataEvent.setBeanType(nacosPropertySource.getBeanType());
metadataEvent.setNacosProperties(nacosPropertySource.getProperties());
Map<String, Object> attributesMetadata = nacosPropertySource
.getAttributesMetadata();
Map<String, Object> nacosPropertiesAttributes = (Map<String, Object>) attributesMetadata
.get(PROPERTIES_ATTRIBUTE_NAME);
metadataEvent.setNacosPropertiesAttributes(nacosPropertiesAttributes);
doInitMetadataEvent(nacosPropertySource, beanDefinition, metadataEvent);
}
publishMetadataEvent(metadataEvent); private void publishMetadataEvent(NacosConfigMetadataEvent metadataEvent) {
applicationEventPublisher.publishEvent(metadataEvent);
}
nacosPropertySources.add(nacosPropertySource); protected abstract void doInitMetadataEvent(NacosPropertySource nacosPropertySource,
T beanDefinition, NacosConfigMetadataEvent metadataEvent);
} protected NacosPropertySource doBuild(String beanName, T beanDefinition,
} Map<String, Object> runtimeAttributes) {
return nacosPropertySources; // Get annotation metadata
} String name = (String) runtimeAttributes.get(NAME_ATTRIBUTE_NAME);
String dataId = (String) runtimeAttributes.get(DATA_ID_ATTRIBUTE_NAME);
String groupId = (String) runtimeAttributes.get(GROUP_ID_ATTRIBUTE_NAME);
protected abstract NacosConfigMetadataEvent createMetaEvent(NacosPropertySource nacosPropertySource, T beanDefinition); 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();
}
private void initMetadataEvent(NacosPropertySource nacosPropertySource, T beanDefinition, Map<String, Object> nacosPropertiesAttributes = (Map<String, Object>) runtimeAttributes
NacosConfigMetadataEvent metadataEvent) { .get(PROPERTIES_ATTRIBUTE_NAME);
metadataEvent.setDataId(nacosPropertySource.getDataId());
metadataEvent.setGroupId(nacosPropertySource.getGroupId());
metadataEvent.setBeanName(nacosPropertySource.getBeanName());
metadataEvent.setBeanType(nacosPropertySource.getBeanType());
metadataEvent.setNacosProperties(nacosPropertySource.getProperties());
Map<String, Object> attributesMetadata = nacosPropertySource.getAttributesMetadata();
Map<String, Object> nacosPropertiesAttributes = (Map<String, Object>) attributesMetadata.get(PROPERTIES_ATTRIBUTE_NAME);
metadataEvent.setNacosPropertiesAttributes(nacosPropertiesAttributes);
doInitMetadataEvent(nacosPropertySource, beanDefinition, metadataEvent);
}
private void publishMetadataEvent(NacosConfigMetadataEvent metadataEvent) { Properties nacosProperties = resolveProperties(nacosPropertiesAttributes,
applicationEventPublisher.publishEvent(metadataEvent); environment, globalNacosProperties);
}
String nacosConfig = nacosConfigLoader.load(dataId, groupId, nacosProperties);
protected abstract void doInitMetadataEvent(NacosPropertySource nacosPropertySource, T beanDefinition, if (!StringUtils.hasText(nacosConfig)) {
NacosConfigMetadataEvent metadataEvent); if (logger.isWarnEnabled()) {
logger.warn(format(
"There is no content for NacosPropertySource from dataId[%s] , groupId[%s] , properties[%s].",
dataId, groupId, nacosPropertiesAttributes));
}
}
if (!StringUtils.hasText(name)) {
name = buildDefaultPropertySourceName(dataId, groupId, nacosProperties);
}
protected NacosPropertySource doBuild(String beanName, T beanDefinition, Map<String, Object> runtimeAttributes) { NacosPropertySource nacosPropertySource = new NacosPropertySource(dataId, groupId,
name, nacosConfig, type);
// Get annotation metadata nacosPropertySource.setBeanName(beanName);
String name = (String) runtimeAttributes.get(NAME_ATTRIBUTE_NAME);
String dataId = (String) runtimeAttributes.get(DATA_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); String beanClassName = beanDefinition.getBeanClassName();
if (StringUtils.hasText(beanClassName)) {
nacosPropertySource.setBeanType(resolveClassName(beanClassName, classLoader));
}
nacosPropertySource.setGroupId(groupId);
nacosPropertySource.setDataId(dataId);
nacosPropertySource.setProperties(nacosProperties);
String nacosConfig = nacosConfigLoader.load(dataId, groupId, nacosProperties); initNacosPropertySource(nacosPropertySource, beanDefinition, runtimeAttributes);
if (!StringUtils.hasText(nacosConfig)) { return nacosPropertySource;
if (logger.isWarnEnabled()) {
logger.warn(format("There is no content for NacosPropertySource from dataId[%s] , groupId[%s] , properties[%s].",
dataId,
groupId,
valueOf(nacosPropertiesAttributes)));
}
}
if (!StringUtils.hasText(name)) { }
name = buildDefaultPropertySourceName(dataId, groupId, nacosProperties);
}
NacosPropertySource nacosPropertySource = new NacosPropertySource(name, nacosConfig); /**
* Runtime attributes must contain those:
* <ul>
* <li>{@link com.alibaba.nacos.spring.context.annotation.config.NacosPropertySource#NAME_ATTRIBUTE_NAME}</li>
* <li>{@link com.alibaba.nacos.spring.context.annotation.config.NacosPropertySource#DATA_ID_ATTRIBUTE_NAME}</li>
* <li>{@link com.alibaba.nacos.spring.context.annotation.config.NacosPropertySource#GROUP_ID_ATTRIBUTE_NAME}</li>
* <li>{@link com.alibaba.nacos.spring.context.annotation.config.NacosPropertySource#PROPERTIES_ATTRIBUTE_NAME}</li>
* </ul>
*
* @param beanDefinition Bean Definition
* @param globalNacosProperties Global Nacos {@link Properties}
* @return a non-null attributes array
*/
protected abstract Map<String, Object>[] resolveRuntimeAttributesArray(
T beanDefinition, Properties globalNacosProperties);
nacosPropertySource.setBeanName(beanName); protected abstract void initNacosPropertySource(
NacosPropertySource nacosPropertySource, T beanDefinition,
Map<String, Object> attributes);
String beanClassName = beanDefinition.getBeanClassName(); /**
if (StringUtils.hasText(beanClassName)) { * Whether target {@link BeanDefinition} supports or not
nacosPropertySource.setBeanType(resolveClassName(beanClassName, classLoader)); *
} * @param beanDefinition {@link BeanDefinition}
nacosPropertySource.setGroupId(groupId); * @return If supports, return <code>true</code>, or <code>false</code>
nacosPropertySource.setDataId(dataId); */
nacosPropertySource.setProperties(nacosProperties); public boolean supports(BeanDefinition beanDefinition) {
Class<?> beanDefinitionClass = beanDefinition.getClass();
return beanDefinitionType.isAssignableFrom(beanDefinitionClass);
}
initNacosPropertySource(nacosPropertySource, beanDefinition, runtimeAttributes); @Override
public void setEnvironment(Environment environment) {
if (environment instanceof ConfigurableEnvironment) {
this.environment = (ConfigurableEnvironment) environment;
}
}
return nacosPropertySource; @Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
} @Override
public void setBeanClassLoader(ClassLoader classLoader) {
this.classLoader = classLoader;
}
/** @Override
* Runtime attributes must contain those: public void setApplicationContext(ApplicationContext applicationContext) {
* <ul> ConfigurableApplicationContext context = (ConfigurableApplicationContext) applicationContext;
* <li>{@link com.alibaba.nacos.spring.context.annotation.config.NacosPropertySource#NAME_ATTRIBUTE_NAME}</li> this.applicationEventPublisher = new DeferredApplicationEventPublisher(context);
* <li>{@link com.alibaba.nacos.spring.context.annotation.config.NacosPropertySource#DATA_ID_ATTRIBUTE_NAME}</li> }
* <li>{@link com.alibaba.nacos.spring.context.annotation.config.NacosPropertySource#GROUP_ID_ATTRIBUTE_NAME}</li>
* <li>{@link com.alibaba.nacos.spring.context.annotation.config.NacosPropertySource#PROPERTIES_ATTRIBUTE_NAME}</li>
* </ul>
*
* @param beanDefinition Bean Definition
* @param globalNacosProperties Global Nacos {@link Properties}
* @return a non-null attributes array
*/
protected abstract Map<String, Object>[] resolveRuntimeAttributesArray(T beanDefinition, Properties globalNacosProperties);
protected abstract void initNacosPropertySource(NacosPropertySource nacosPropertySource, T beanDefinition, @Override
Map<String, Object> attributes); public void afterPropertiesSet() throws Exception {
nacosConfigLoader = new NacosConfigLoader(environment);
nacosConfigLoader.setNacosServiceFactory(getNacosServiceFactoryBean(beanFactory));
globalNacosProperties = CONFIG.getMergedGlobalProperties(beanFactory);
}
/** @Override
* Whether target {@link BeanDefinition} supports or not public void destroy() throws Exception {
* if (nacosConfigLoader == null) {
* @param beanDefinition {@link BeanDefinition} return;
* @return If supports, return <code>true</code>, or <code>false</code> }
*/ ConfigService configService = nacosConfigLoader.getConfigService();
public boolean supports(BeanDefinition beanDefinition) { if (configService != null) {
Class<?> beanDefinitionClass = beanDefinition.getClass(); configService.shutDown();
return beanDefinitionType.isAssignableFrom(beanDefinitionClass); }
} }
@Override /**
public void setEnvironment(Environment environment) { * The type of {@link T Bean Definition}
if (environment instanceof ConfigurableEnvironment) { *
this.environment = (ConfigurableEnvironment) environment; * @return type of {@link T Bean Definition}
} */
} public final Class<T> getBeanDefinitionType() {
return beanDefinitionType;
@Override }
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
this.classLoader = classLoader;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
ConfigurableApplicationContext context = (ConfigurableApplicationContext) applicationContext;
this.applicationEventPublisher = new DeferredApplicationEventPublisher(context);
}
@Override
public void afterPropertiesSet() throws Exception {
nacosConfigLoader = new NacosConfigLoader(environment);
nacosConfigLoader.setNacosServiceFactory(getNacosServiceFactoryBean(beanFactory));
globalNacosProperties = CONFIG.getMergedGlobalProperties(beanFactory);
}
/**
* The type of {@link T Bean Definition}
*
* @return type of {@link T Bean Definition}
*/
public final Class<T> getBeanDefinitionType() {
return beanDefinitionType;
}
} }

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,91 +44,109 @@ 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}
*/ */
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(
// Get AnnotationMetadata AnnotatedBeanDefinition beanDefinition, Properties globalNacosProperties) {
AnnotationMetadata metadata = beanDefinition.getMetadata(); // Get AnnotationMetadata
AnnotationMetadata metadata = beanDefinition.getMetadata();
Set<String> annotationTypes = metadata.getAnnotationTypes(); Set<String> annotationTypes = metadata.getAnnotationTypes();
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
if (annotationAttributes != null) { .getAnnotationAttributes(annotationType);
annotationAttributesList.addAll(Arrays.asList((Map<String, Object>[]) annotationAttributes.get("value"))); if (annotationAttributes != null) {
} annotationAttributesList.addAll(Arrays.asList(
} else if (com.alibaba.nacos.spring.context.annotation.config.NacosPropertySource.class.getName().equals(annotationType)) { (Map<String, Object>[]) annotationAttributes.get("value")));
annotationAttributesList.add(metadata.getAnnotationAttributes(annotationType)); }
} }
return annotationAttributesList; else if (com.alibaba.nacos.spring.context.annotation.config.NacosPropertySource.class
} .getName().equals(annotationType)) {
annotationAttributesList
.add(metadata.getAnnotationAttributes(annotationType));
}
return annotationAttributesList;
}
@Override @Override
protected void initNacosPropertySource(NacosPropertySource nacosPropertySource, AnnotatedBeanDefinition beanDefinition, protected void initNacosPropertySource(NacosPropertySource nacosPropertySource,
Map<String, Object> annotationAttributes) { AnnotatedBeanDefinition beanDefinition,
// AttributesMetadata Map<String, Object> annotationAttributes) {
initAttributesMetadata(nacosPropertySource, annotationAttributes); // AttributesMetadata
// Auto-Refreshed initAttributesMetadata(nacosPropertySource, annotationAttributes);
initAutoRefreshed(nacosPropertySource, annotationAttributes); // Auto-Refreshed
// Origin initAutoRefreshed(nacosPropertySource, annotationAttributes);
initOrigin(nacosPropertySource, beanDefinition); // Origin
// Order initOrigin(nacosPropertySource, beanDefinition);
initOrder(nacosPropertySource, annotationAttributes); // Order
initOrder(nacosPropertySource, annotationAttributes);
} }
private void initAttributesMetadata(NacosPropertySource nacosPropertySource, Map<String, Object> annotationAttributes) { private void initAttributesMetadata(NacosPropertySource nacosPropertySource,
nacosPropertySource.setAttributesMetadata(annotationAttributes); Map<String, Object> 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) {
nacosPropertySource.setAutoRefreshed(autoRefreshed); boolean autoRefreshed = Boolean.TRUE
} .equals(annotationAttributes.get(AUTO_REFRESHED_ATTRIBUTE_NAME));
nacosPropertySource.setAutoRefreshed(autoRefreshed);
}
private void initOrigin(NacosPropertySource nacosPropertySource, AnnotatedBeanDefinition beanDefinition) { private void initOrigin(NacosPropertySource nacosPropertySource,
AnnotationMetadata metadata = beanDefinition.getMetadata(); AnnotatedBeanDefinition beanDefinition) {
nacosPropertySource.setOrigin(metadata.getClassName()); AnnotationMetadata metadata = beanDefinition.getMetadata();
} 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) {
String before = (String) annotationAttributes.get(BEFORE_ATTRIBUTE_NAME); boolean first = Boolean.TRUE
String after = (String) annotationAttributes.get(AFTER_ATTRIBUTE_NAME); .equals(annotationAttributes.get(FIRST_ATTRIBUTE_NAME));
nacosPropertySource.setFirst(first); String before = (String) annotationAttributes.get(BEFORE_ATTRIBUTE_NAME);
nacosPropertySource.setBefore(before); String after = (String) annotationAttributes.get(AFTER_ATTRIBUTE_NAME);
nacosPropertySource.setAfter(after); nacosPropertySource.setFirst(first);
} nacosPropertySource.setBefore(before);
nacosPropertySource.setAfter(after);
}
@Override @Override
protected NacosConfigMetadataEvent createMetaEvent(NacosPropertySource nacosPropertySource, protected NacosConfigMetadataEvent createMetaEvent(
AnnotatedBeanDefinition beanDefinition) { NacosPropertySource nacosPropertySource,
return new NacosConfigMetadataEvent(beanDefinition.getMetadata()); AnnotatedBeanDefinition beanDefinition) {
} return new NacosConfigMetadataEvent(beanDefinition.getMetadata());
}
@Override @Override
protected void doInitMetadataEvent(NacosPropertySource nacosPropertySource, AnnotatedBeanDefinition beanDefinition, protected void doInitMetadataEvent(NacosPropertySource nacosPropertySource,
NacosConfigMetadataEvent metadataEvent) { AnnotatedBeanDefinition beanDefinition,
metadataEvent.setAnnotatedElement(metadataEvent.getAnnotatedElement()); NacosConfigMetadataEvent metadataEvent) {
} 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,153 +31,163 @@ 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;
private String dataId; private String dataId;
private boolean autoRefreshed; private boolean autoRefreshed;
private boolean first; private boolean first;
private String before; private String before;
private String after; private String after;
private Properties properties; private String type;
private Map<String, Object> attributesMetadata; private Map<Object, Object> properties;
private Object origin; private Map<String, Object> attributesMetadata;
private String beanName; private Object origin;
private Class<?> beanType; private String beanName;
/** private Class<?> beanType;
* @param name the name of Nacos {@link PropertySource}
* @param nacosConfig the Nacos Config with {@link Properties} format
*/
public NacosPropertySource(String name, String nacosConfig) {
super(name, toProperties(nacosConfig));
}
public String getGroupId() { public NacosPropertySource(String dataId, String groupId, String name,
return groupId; String nacosConfig, String type) {
} super(name, toProperties(dataId, groupId, nacosConfig, type));
this.type = type;
}
public void setGroupId(String groupId) { public String getGroupId() {
this.groupId = groupId; return groupId;
} }
public String getDataId() { public void setGroupId(String groupId) {
return dataId; this.groupId = groupId;
} }
public void setDataId(String dataId) { public String getDataId() {
this.dataId = dataId; return dataId;
} }
public boolean isAutoRefreshed() { public void setDataId(String dataId) {
return autoRefreshed; this.dataId = dataId;
} }
public void setAutoRefreshed(boolean autoRefreshed) { public boolean isAutoRefreshed() {
this.autoRefreshed = autoRefreshed; return autoRefreshed;
} }
public boolean isFirst() { public void setAutoRefreshed(boolean autoRefreshed) {
return first; this.autoRefreshed = autoRefreshed;
} }
public void setFirst(boolean first) { public boolean isFirst() {
this.first = first; return first;
} }
public String getBefore() { public void setFirst(boolean first) {
return before; this.first = first;
} }
public void setBefore(String before) { public String getBefore() {
this.before = before; return before;
} }
public String getAfter() { public void setBefore(String before) {
return after; this.before = before;
} }
public void setAfter(String after) { public String getAfter() {
this.after = after; return after;
} }
public Properties getProperties() { public void setAfter(String after) {
return properties; this.after = after;
} }
public void setProperties(Properties properties) { public String getType() {
this.properties = properties; return type;
} }
/** public void setType(String type) {
* @param attributesMetadata the attributesMetadata of attributes from this.type = type;
* {@link com.alibaba.nacos.spring.context.annotation.config.NacosPropertySource @NacosPropertySource} }
* or &lt;nacos:property-source ... &gt;
*/
public void setAttributesMetadata(Map<String, Object> attributesMetadata) {
this.attributesMetadata = attributesMetadata;
}
/** public Map<Object, Object> getProperties() {
* @param origin where Nacos {@link PropertySource} comes from return properties;
*/ }
public void setOrigin(Object origin) {
this.origin = origin;
}
/** public void setProperties(Map<Object, Object> properties) {
* @return the attributesMetadata of attributes from this.properties = properties;
* {@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 the attributesMetadata of attributes from
*/ * {@link com.alibaba.nacos.spring.context.annotation.config.NacosPropertySource @NacosPropertySource}
public Object getOrigin() { * or &lt;nacos:property-source ... &gt;
return origin; */
} public Map<String, Object> getAttributesMetadata() {
return attributesMetadata != null ? attributesMetadata
: Collections.<String, Object> emptyMap();
}
public String getBeanName() { /**
return beanName; * @param attributesMetadata the attributesMetadata of attributes from
} * {@link com.alibaba.nacos.spring.context.annotation.config.NacosPropertySource @NacosPropertySource}
* or &lt;nacos:property-source ... &gt;
*/
public void setAttributesMetadata(Map<String, Object> attributesMetadata) {
this.attributesMetadata = attributesMetadata;
}
public void setBeanName(String beanName) { /**
this.beanName = beanName; * @return where Nacos {@link PropertySource} comes from
} */
public Object getOrigin() {
return origin;
}
public Class<?> getBeanType() { /**
return beanType; * @param origin where Nacos {@link PropertySource} comes from
} */
public void setOrigin(Object origin) {
this.origin = origin;
}
public void setBeanType(Class<?> beanType) { public String getBeanName() {
this.beanType = beanType; return beanName;
} }
protected void copy(NacosPropertySource original) { public void setBeanName(String beanName) {
this.groupId = original.groupId; this.beanName = beanName;
this.dataId = original.dataId; }
this.autoRefreshed = original.autoRefreshed;
this.first = original.first; public Class<?> getBeanType() {
this.before = original.before; return beanType;
this.after = original.after; }
this.properties = original.properties;
this.attributesMetadata = original.attributesMetadata; public void setBeanType(Class<?> beanType) {
this.origin = original.origin; this.beanType = beanType;
this.beanName = original.beanName; }
this.beanType = original.beanType;
} protected void copy(NacosPropertySource original) {
this.groupId = original.groupId;
this.dataId = original.dataId;
this.autoRefreshed = original.autoRefreshed;
this.first = original.first;
this.before = original.before;
this.after = original.after;
this.type = original.type;
this.properties = original.properties;
this.attributesMetadata = original.attributesMetadata;
this.origin = original.origin;
this.beanName = original.beanName;
this.beanType = original.beanType;
}
} }

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,150 +73,187 @@ 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
EnvironmentAware, Ordered { implements BeanDefinitionRegistryPostProcessor, BeanFactoryPostProcessor,
EnvironmentAware, Ordered {
/** /**
* The bean name of {@link NacosPropertySourcePostProcessor} * The bean name of {@link NacosPropertySourcePostProcessor}
*/ */
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;
private ConfigurableEnvironment environment; protected final Set<String> processedBeanNames = new LinkedHashSet<String>();
private Collection<AbstractNacosPropertySourceBuilder> nacosPropertySourceBuilders; private ConfigurableEnvironment environment;
private ConfigServiceBeanBuilder configServiceBeanBuilder; protected Collection<AbstractNacosPropertySourceBuilder> nacosPropertySourceBuilders;
@Override protected ConfigServiceBeanBuilder configServiceBeanBuilder;
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
}
@Override public static void addListenerIfAutoRefreshed(
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { final NacosPropertySource nacosPropertySource, final Properties properties,
String[] abstractNacosPropertySourceBuilderBeanNames = BeanUtils.getBeanNames(beanFactory, final ConfigurableEnvironment environment) {
AbstractNacosPropertySourceBuilder.class);
this.nacosPropertySourceBuilders = new ArrayList<AbstractNacosPropertySourceBuilder>( if (!nacosPropertySource.isAutoRefreshed()) { // Disable Auto-Refreshed
abstractNacosPropertySourceBuilderBeanNames.length); return;
}
for (String beanName : abstractNacosPropertySourceBuilderBeanNames) { final String dataId = nacosPropertySource.getDataId();
this.nacosPropertySourceBuilders.add( final String groupId = nacosPropertySource.getGroupId();
beanFactory.getBean(beanName, AbstractNacosPropertySourceBuilder.class)); final String type = nacosPropertySource.getType();
} final NacosServiceFactory nacosServiceFactory = getNacosServiceFactoryBean(
beanFactory);
this.configServiceBeanBuilder = getConfigServiceBeanBuilder(beanFactory); try {
String[] beanNames = beanFactory.getBeanDefinitionNames(); ConfigService configService = nacosServiceFactory
.createConfigService(properties);
for (String beanName : beanNames) { Listener listener = new AbstractListener() {
processPropertySource(beanName, beanFactory);
}
} @Override
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);
}
};
private void processPropertySource(String beanName, ConfigurableListableBeanFactory beanFactory) { if (configService instanceof EventPublishingConfigService) {
((EventPublishingConfigService) configService).addListener(dataId,
groupId, type, listener);
}
else {
configService.addListener(dataId, groupId, listener);
}
if (processedBeanNames.contains(beanName)) { }
return; catch (NacosException e) {
} throw new RuntimeException(
"ConfigService can't add Listener with properties : " + properties,
e);
}
}
BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName); @Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry)
throws BeansException {
}
// Build multiple instance if possible @Override
List<NacosPropertySource> nacosPropertySources = buildNacosPropertySources(beanName, beanDefinition); public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
throws BeansException {
String[] abstractNacosPropertySourceBuilderBeanNames = BeanUtils
.getBeanNames(beanFactory, AbstractNacosPropertySourceBuilder.class);
// Add Orderly this.nacosPropertySourceBuilders = new ArrayList<AbstractNacosPropertySourceBuilder>(
for (NacosPropertySource nacosPropertySource : nacosPropertySources) { abstractNacosPropertySourceBuilderBeanNames.length);
addNacosPropertySource(nacosPropertySource);
addListenerIfAutoRefreshed(nacosPropertySource);
}
processedBeanNames.add(beanName); for (String beanName : abstractNacosPropertySourceBuilderBeanNames) {
} this.nacosPropertySourceBuilders.add(beanFactory.getBean(beanName,
AbstractNacosPropertySourceBuilder.class));
}
private List<NacosPropertySource> buildNacosPropertySources(String beanName, BeanDefinition beanDefinition) { NacosPropertySourcePostProcessor.beanFactory = beanFactory;
for (AbstractNacosPropertySourceBuilder builder : nacosPropertySourceBuilders) { this.configServiceBeanBuilder = getConfigServiceBeanBuilder(beanFactory);
if (builder.supports(beanDefinition)) {
return builder.build(beanName, beanDefinition);
}
}
return Collections.emptyList();
}
private void addNacosPropertySource(NacosPropertySource nacosPropertySource) { String[] beanNames = beanFactory.getBeanDefinitionNames();
MutablePropertySources propertySources = environment.getPropertySources(); for (String beanName : beanNames) {
processPropertySource(beanName, beanFactory);
}
boolean first = nacosPropertySource.isFirst(); }
String before = nacosPropertySource.getBefore();
String after = nacosPropertySource.getAfter();
boolean hasBefore = !nullSafeEquals(DEFAULT_STRING_ATTRIBUTE_VALUE, before); protected void processPropertySource(String beanName,
boolean hasAfter = !nullSafeEquals(DEFAULT_STRING_ATTRIBUTE_VALUE, after); ConfigurableListableBeanFactory beanFactory) {
boolean isRelative = hasBefore || hasAfter; if (processedBeanNames.contains(beanName)) {
return;
}
if (first) { // If First BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);
propertySources.addFirst(nacosPropertySource);
} else if (isRelative) { // If relative
if (hasBefore) {
propertySources.addBefore(before, nacosPropertySource);
}
if (hasAfter) {
propertySources.addAfter(after, nacosPropertySource);
}
} else {
propertySources.addLast(nacosPropertySource); // default add last
}
}
private void addListenerIfAutoRefreshed(final NacosPropertySource nacosPropertySource) { doProcessPropertySource(beanName, beanDefinition);
if (!nacosPropertySource.isAutoRefreshed()) { // Disable Auto-Refreshed processedBeanNames.add(beanName);
return; }
}
final String dataId = nacosPropertySource.getDataId(); protected void doProcessPropertySource(String beanName, BeanDefinition beanDefinition) {
final String groupId = nacosPropertySource.getGroupId(); // Build multiple instance if possible
final Map<String, Object> nacosPropertiesAttributes = nacosPropertySource.getAttributesMetadata(); List<NacosPropertySource> nacosPropertySources = buildNacosPropertySources(
final ConfigService configService = configServiceBeanBuilder.build(nacosPropertiesAttributes); beanName, beanDefinition);
try { // Add Orderly
configService.addListener(dataId, groupId, new AbstractListener() { for (NacosPropertySource nacosPropertySource : nacosPropertySources) {
addNacosPropertySource(nacosPropertySource);
Properties properties = configServiceBeanBuilder
.resolveProperties(nacosPropertySource.getAttributesMetadata());
addListenerIfAutoRefreshed(nacosPropertySource, properties, environment);
}
}
@Override private List<NacosPropertySource> buildNacosPropertySources(String beanName,
public void receiveConfigInfo(String config) { BeanDefinition beanDefinition) {
String name = nacosPropertySource.getName(); for (AbstractNacosPropertySourceBuilder builder : nacosPropertySourceBuilders) {
NacosPropertySource newNacosPropertySource = new NacosPropertySource(name, config); if (builder.supports(beanDefinition)) {
newNacosPropertySource.copy(nacosPropertySource); return builder.build(beanName, beanDefinition);
MutablePropertySources propertySources = environment.getPropertySources(); }
// replace NacosPropertySource }
propertySources.replace(name, newNacosPropertySource); return Collections.emptyList();
} }
});
} catch (NacosException e) {
throw new RuntimeException("ConfigService can't add Listener with properties : " + nacosPropertiesAttributes, e);
}
}
private void addNacosPropertySource(NacosPropertySource nacosPropertySource) {
/** MutablePropertySources propertySources = environment.getPropertySources();
* The order is closed to {@link ConfigurationClassPostProcessor#getOrder() HIGHEST_PRECEDENCE} almost.
*
* @return <code>Ordered.HIGHEST_PRECEDENCE + 1</code>
* @see ConfigurationClassPostProcessor#getOrder()
*/
@Override
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE + 1;
}
boolean first = nacosPropertySource.isFirst();
String before = nacosPropertySource.getBefore();
String after = nacosPropertySource.getAfter();
@Override boolean hasBefore = !nullSafeEquals(DEFAULT_STRING_ATTRIBUTE_VALUE, before);
public void setEnvironment(Environment environment) { boolean hasAfter = !nullSafeEquals(DEFAULT_STRING_ATTRIBUTE_VALUE, after);
this.environment = (ConfigurableEnvironment) environment;
} boolean isRelative = hasBefore || hasAfter;
if (first) { // If First
propertySources.addFirst(nacosPropertySource);
}
else if (isRelative) { // If relative
if (hasBefore) {
propertySources.addBefore(before, nacosPropertySource);
}
if (hasAfter) {
propertySources.addAfter(after, nacosPropertySource);
}
}
else {
propertySources.addLast(nacosPropertySource); // default add last
}
}
/**
* The order is closed to {@link ConfigurationClassPostProcessor#getOrder()
* HIGHEST_PRECEDENCE} almost.
*
* @return <code>Ordered.HIGHEST_PRECEDENCE + 1</code>
* @see ConfigurationClassPostProcessor#getOrder()
*/
@Override
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE + 1;
}
@Override
public void setEnvironment(Environment 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,92 +51,129 @@ 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}
*/ */
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(
Properties globalNacosProperties) { NacosPropertySourceXmlBeanDefinition beanDefinition,
Element element = beanDefinition.getElement(); Properties globalNacosProperties) {
Map<String, Object> runtimeAttributes = new HashMap<String, Object>(4); Element element = beanDefinition.getElement();
// Nacos Metadata Map<String, Object> runtimeAttributes = new HashMap<String, Object>(4);
runtimeAttributes.put(DATA_ID_ATTRIBUTE_NAME, getAttribute(element, "data-id", DEFAULT_STRING_ATTRIBUTE_VALUE)); // Nacos Metadata
runtimeAttributes.put(GROUP_ID_ATTRIBUTE_NAME, getAttribute(element, "group-id", DEFAULT_GROUP)); runtimeAttributes.put(DATA_ID_ATTRIBUTE_NAME,
// PropertySource Name getAttribute(element, "data-id", DEFAULT_STRING_ATTRIBUTE_VALUE));
runtimeAttributes.put(NAME_ATTRIBUTE_NAME, getAttribute(element, NAME_ATTRIBUTE_NAME, DEFAULT_STRING_ATTRIBUTE_VALUE)); runtimeAttributes.put(GROUP_ID_ATTRIBUTE_NAME,
// TODO support nested properties getAttribute(element, "group-id", DEFAULT_GROUP));
runtimeAttributes.put(PROPERTIES_ATTRIBUTE_NAME, new Properties()); // PropertySource Name
return new Map[]{runtimeAttributes}; 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);
@Override try {
protected void initNacosPropertySource(NacosPropertySource nacosPropertySource, runtimeAttributes.put(CONFIG_TYPE_ATTRIBUTE_NAME,
NacosPropertySourceXmlBeanDefinition beanDefinition, Map<String, Object> attributes) { ConfigType.valueOf(type.toUpperCase()));
Element element = beanDefinition.getElement(); // TODO support nested properties
runtimeAttributes.put(PROPERTIES_ATTRIBUTE_NAME, new Properties());
return new Map[] { runtimeAttributes };
}
catch (IllegalArgumentException e) {
throw new IllegalArgumentException(
"Now the config type just support [properties, json, yaml, xml, text, html]");
}
// Attributes Metadata }
initAttributesMetadata(nacosPropertySource, element);
// Origin
initOrigin(nacosPropertySource, beanDefinition.getXmlReaderContext());
// Auto-refreshed
initAutoRefreshed(nacosPropertySource, element);
// PropertySource Order
initOrder(nacosPropertySource, element);
}
private void initOrigin(NacosPropertySource nacosPropertySource, XmlReaderContext xmlReaderContext) { @Override
// Resource protected void initNacosPropertySource(NacosPropertySource nacosPropertySource,
Resource resource = xmlReaderContext.getResource(); NacosPropertySourceXmlBeanDefinition beanDefinition,
Map<String, Object> attributes) {
Element element = beanDefinition.getElement();
nacosPropertySource.setOrigin(resource); // Attributes Metadata
} initAttributesMetadata(nacosPropertySource, element);
// Origin
initOrigin(nacosPropertySource, beanDefinition.getXmlReaderContext());
// Auto-refreshed
initAutoRefreshed(nacosPropertySource, element);
// PropertySource Order
initOrder(nacosPropertySource, element);
}
private void initAutoRefreshed(NacosPropertySource nacosPropertySource, Element element) { private void initOrigin(NacosPropertySource nacosPropertySource,
boolean autoRefreshed = getAttribute(element, "auto-refreshed", DEFAULT_BOOLEAN_ATTRIBUTE_VALUE); XmlReaderContext xmlReaderContext) {
nacosPropertySource.setAutoRefreshed(autoRefreshed); // Resource
} Resource resource = xmlReaderContext.getResource();
private void initAttributesMetadata(NacosPropertySource nacosPropertySource, Element element) { nacosPropertySource.setOrigin(resource);
NamedNodeMap elementAttributes = element.getAttributes(); }
int length = elementAttributes.getLength();
}
private void initOrder(NacosPropertySource nacosPropertySource, Element element) { private void initAutoRefreshed(NacosPropertySource nacosPropertySource,
// Order Element element) {
boolean first = getAttribute(element, FIRST_ATTRIBUTE_NAME, DEFAULT_BOOLEAN_ATTRIBUTE_VALUE); boolean autoRefreshed = getAttribute(element, "auto-refreshed",
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); nacosPropertySource.setAutoRefreshed(autoRefreshed);
nacosPropertySource.setFirst(first); }
nacosPropertySource.setBefore(before);
nacosPropertySource.setAfter(after);
}
private void initAttributesMetadata(NacosPropertySource nacosPropertySource,
Element element) {
NamedNodeMap elementAttributes = element.getAttributes();
int length = elementAttributes.getLength();
}
private <T> T getAttribute(Element element, String name, T defaultValue) { private void initOrder(NacosPropertySource nacosPropertySource, Element element) {
ConversionService conversionService = environment.getConversionService(); // Order
String value = element.getAttribute(name); boolean first = getAttribute(element, FIRST_ATTRIBUTE_NAME,
String resolvedValue = environment.resolvePlaceholders(value); DEFAULT_BOOLEAN_ATTRIBUTE_VALUE);
T attributeValue = StringUtils.hasText(resolvedValue) ? String before = getAttribute(element, BEFORE_ATTRIBUTE_NAME,
(T) conversionService.convert(resolvedValue, defaultValue.getClass()) : DEFAULT_STRING_ATTRIBUTE_VALUE);
defaultValue; String after = getAttribute(element, AFTER_ATTRIBUTE_NAME,
return attributeValue; DEFAULT_STRING_ATTRIBUTE_VALUE);
} nacosPropertySource.setFirst(first);
nacosPropertySource.setBefore(before);
nacosPropertySource.setAfter(after);
}
private <T> T getAttribute(Element element, String name, T defaultValue) {
ConversionService conversionService = environment.getConversionService();
String value = element.getAttribute(name);
String resolvedValue = environment.resolvePlaceholders(value);
T attributeValue = StringUtils.hasText(resolvedValue)
? (T) conversionService.convert(resolvedValue, defaultValue.getClass())
: defaultValue;
return attributeValue;
}
@Override @Override
protected NacosConfigMetadataEvent createMetaEvent(NacosPropertySource nacosPropertySource, protected NacosConfigMetadataEvent createMetaEvent(
NacosPropertySourceXmlBeanDefinition beanDefinition) { NacosPropertySource nacosPropertySource,
return new NacosConfigMetadataEvent(beanDefinition.getElement()); NacosPropertySourceXmlBeanDefinition beanDefinition) {
} return new NacosConfigMetadataEvent(beanDefinition.getElement());
}
@Override @Override
protected void doInitMetadataEvent(NacosPropertySource nacosPropertySource, protected void doInitMetadataEvent(NacosPropertySource nacosPropertySource,
NacosPropertySourceXmlBeanDefinition beanDefinition, NacosConfigMetadataEvent metadataEvent) { NacosPropertySourceXmlBeanDefinition beanDefinition,
metadataEvent.setXmlResource(beanDefinition.getXmlReaderContext().getResource()); NacosConfigMetadataEvent metadataEvent) {
} 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,72 +45,263 @@ 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 ConfigurableApplicationContext context; private final Map<String, NamingService> namingServicesCache = new LinkedHashMap<String, NamingService>(
2);
private ExecutorService nacosConfigListenerExecutor; private final Map<String, NamingMaintainService> maintainServiceCache = new LinkedHashMap<String, NamingMaintainService>(
2);
@Override private final LinkedList<DeferServiceHolder> deferServiceCache = new LinkedList<DeferServiceHolder>();
public ConfigService createConfigService(Properties properties) throws NacosException {
Properties copy = new Properties(); private ConfigurableApplicationContext context;
copy.putAll(properties); private ExecutorService nacosConfigListenerExecutor;
String cacheKey = identify(copy); private Map<ServiceType, AbstractCreateWorker> createWorkerManager = new HashMap<ServiceType, AbstractCreateWorker>(
3);
ConfigService configService = configServicesCache.get(cacheKey); public CacheableEventPublishingNacosServiceFactory() {
createWorkerManager.put(ServiceType.CONFIG, new ConfigCreateWorker());
createWorkerManager.put(ServiceType.NAMING, new NamingCreateWorker());
createWorkerManager.put(ServiceType.MAINTAIN, new MaintainCreateWorker());
createWorkerManager = Collections.unmodifiableMap(createWorkerManager);
}
if (configService == null) { public static CacheableEventPublishingNacosServiceFactory getSingleton() {
configService = doCreateConfigService(copy); return SINGLETON;
configServicesCache.put(cacheKey, configService); }
}
return configService; @Override
} public ConfigService createConfigService(Properties properties)
throws NacosException {
Properties copy = new Properties();
copy.putAll(properties);
return (ConfigService) createWorkerManager.get(ServiceType.CONFIG).run(copy,
null);
}
private ConfigService doCreateConfigService(Properties properties) throws NacosException { @Override
ConfigService configService = NacosFactory.createConfigService(properties); public NamingService createNamingService(Properties properties)
return new EventPublishingConfigService(configService, properties, context, nacosConfigListenerExecutor); throws NacosException {
} Properties copy = new Properties();
copy.putAll(properties);
return (NamingService) createWorkerManager.get(ServiceType.NAMING).run(copy,
null);
}
@Override // Exist some cases need to create the ConfigService | NamingService |
public NamingService createNamingService(Properties properties) throws NacosException { // NamingMaintainService
// before loading the Context object, lazy loading
Properties copy = new Properties(); @Override
public NamingMaintainService createNamingMaintainService(Properties properties)
throws NacosException {
Properties copy = new Properties();
copy.putAll(properties);
return (NamingMaintainService) createWorkerManager.get(ServiceType.MAINTAIN)
.run(copy, null);
}
copy.putAll(properties); public <T> T deferCreateService(T service, Properties properties) {
DeferServiceHolder serviceHolder = new DeferServiceHolder();
serviceHolder.setHolder(service);
serviceHolder.setProperties(properties);
deferServiceCache.add(serviceHolder);
return service;
}
String cacheKey = identify(copy); @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();
}
NamingService namingService = namingServicesCache.get(cacheKey); public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
this.context = (ConfigurableApplicationContext) applicationContext;
this.nacosConfigListenerExecutor = getSingleton().nacosConfigListenerExecutor == null
? getNacosConfigListenerExecutorIfPresent(applicationContext)
: getSingleton().nacosConfigListenerExecutor;
}
if (namingService == null) { @Override
namingService = new DelegatingNamingService(NacosFactory.createNamingService(copy), properties); public Collection<ConfigService> getConfigServices() {
namingServicesCache.put(cacheKey, namingService); return configServicesCache.values();
} }
return namingService; @Override
} public Collection<NamingService> getNamingServices() {
return namingServicesCache.values();
}
@Override @Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { public Collection<NamingMaintainService> getNamingMaintainService() {
this.context = (ConfigurableApplicationContext) applicationContext; return maintainServiceCache.values();
this.nacosConfigListenerExecutor = getNacosConfigListenerExecutorIfPresent(applicationContext); }
}
@Override private static enum ServiceType {
public Collection<ConfigService> getConfigServices() {
return configServicesCache.values(); /**
} * 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;
}
}
@Override
public Collection<NamingService> getNamingServices() {
return namingServicesCache.values();
}
} }

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,130 +14,371 @@
* 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;
private final Properties properties; private final Properties properties;
DelegatingNamingService(NamingService delegate, Properties properties) { DelegatingNamingService(NamingService delegate, Properties properties) {
this.delegate = delegate; this.delegate = delegate;
this.properties = properties; this.properties = properties;
} }
@Override @Override
public void registerInstance(String serviceName, String ip, int port) throws NacosException { public void registerInstance(String serviceName, String ip, int port)
delegate.registerInstance(serviceName, ip, port); throws NacosException {
} 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,
delegate.registerInstance(serviceName, ip, port, clusterName); int port) throws NacosException {
} delegate.registerInstance(serviceName, groupName, ip, port);
}
@Override @Override
public void registerInstance(String serviceName, Instance instance) throws NacosException { public void registerInstance(String serviceName, String ip, int port,
delegate.registerInstance(serviceName, instance); String clusterName) throws NacosException {
} delegate.registerInstance(serviceName, ip, port, clusterName);
}
@Override @Override
public void deregisterInstance(String serviceName, String ip, int port) throws NacosException { public void registerInstance(String serviceName, String groupName, String ip,
delegate.deregisterInstance(serviceName, ip, port); int port, String clusterName) throws NacosException {
} delegate.registerInstance(serviceName, groupName, ip, port, clusterName);
}
@Override @Override
public void deregisterInstance(String serviceName, String ip, int port, String clusterName) throws NacosException { public void registerInstance(String serviceName, Instance instance)
delegate.deregisterInstance(serviceName, ip, port, clusterName); throws NacosException {
} delegate.registerInstance(serviceName, instance);
}
@Override @Override
public List<Instance> getAllInstances(String serviceName) throws NacosException { public void registerInstance(String serviceName, String groupName, Instance instance)
return delegate.getAllInstances(serviceName); 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);
}
@Override @Override
public List<Instance> getAllInstances(String serviceName, List<String> clusters) throws NacosException { public void deregisterInstance(String serviceName, String groupName, String ip,
return delegate.getAllInstances(serviceName, clusters); int port) throws NacosException {
} delegate.deregisterInstance(serviceName, groupName, ip, port);
}
@Override @Override
public List<Instance> selectInstances(String serviceName, boolean healthy) throws NacosException { public void deregisterInstance(String serviceName, String ip, int port,
return delegate.selectInstances(serviceName, healthy); String clusterName) throws NacosException {
} delegate.deregisterInstance(serviceName, ip, port, clusterName);
}
@Override @Override
public List<Instance> selectInstances(String serviceName, List<String> clusters, boolean healthy) throws NacosException { public void deregisterInstance(String serviceName, String groupName, String ip,
return delegate.selectInstances(serviceName, clusters, healthy); int port, String clusterName) throws NacosException {
} delegate.deregisterInstance(serviceName, groupName, ip, port, clusterName);
}
@Override @Override
public Instance selectOneHealthyInstance(String serviceName) throws NacosException { public void deregisterInstance(String serviceName, Instance instance)
return delegate.selectOneHealthyInstance(serviceName); throws NacosException {
} delegate.deregisterInstance(serviceName, instance);
}
@Override @Override
public Instance selectOneHealthyInstance(String serviceName, List<String> clusters) throws NacosException { public void deregisterInstance(String serviceName, String groupName,
return delegate.selectOneHealthyInstance(serviceName, clusters); Instance instance) throws NacosException {
} delegate.deregisterInstance(serviceName, groupName, instance);
}
@Override @Override
public void subscribe(String serviceName, EventListener listener) throws NacosException { public List<Instance> getAllInstances(String serviceName) throws NacosException {
delegate.subscribe(serviceName, listener); return delegate.getAllInstances(serviceName);
} }
@Override @Override
public void subscribe(String serviceName, List<String> clusters, EventListener listener) throws NacosException { public List<Instance> getAllInstances(String serviceName, String groupName)
delegate.subscribe(serviceName, clusters, listener); throws NacosException {
} return delegate.getAllInstances(serviceName, groupName);
}
@Override @Override
public void unsubscribe(String serviceName, EventListener listener) throws NacosException { public List<Instance> getAllInstances(String serviceName, boolean subscribe)
delegate.unsubscribe(serviceName, listener); throws NacosException {
} return delegate.getAllInstances(serviceName, subscribe);
}
@Override @Override
public void unsubscribe(String serviceName, List<String> clusters, EventListener listener) throws NacosException { public List<Instance> getAllInstances(String serviceName, String groupName,
delegate.unsubscribe(serviceName, clusters, listener); boolean subscribe) throws NacosException {
} return delegate.getAllInstances(serviceName, groupName, subscribe);
}
@Override @Override
public ListView<String> getServicesOfServer(int pageNo, int pageSize) throws NacosException { public List<Instance> getAllInstances(String serviceName, List<String> clusters)
return delegate.getServicesOfServer(pageNo, pageSize); throws NacosException {
} return delegate.getAllInstances(serviceName, clusters);
}
@Override @Override
public List<ServiceInfo> getSubscribeServices() throws NacosException { public List<Instance> getAllInstances(String serviceName, String groupName,
return delegate.getSubscribeServices(); List<String> clusters) throws NacosException {
} return delegate.getAllInstances(serviceName, groupName, clusters);
}
@Override @Override
public String getServerStatus() { public List<Instance> getAllInstances(String serviceName, List<String> clusters,
return delegate.getServerStatus(); boolean subscribe) throws NacosException {
} return delegate.getAllInstances(serviceName, clusters, subscribe);
}
@Override @Override
public Properties getProperties() { public List<Instance> getAllInstances(String serviceName, String groupName,
return properties; 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);
}
@Override
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);
}
@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
public Instance selectOneHealthyInstance(String serviceName) throws NacosException {
return delegate.selectOneHealthyInstance(serviceName);
}
@Override
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);
}
@Override
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);
}
@Override
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);
}
@Override
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);
}
@Override
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);
}
@Override
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);
}
@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
public List<ServiceInfo> getSubscribeServices() throws NacosException {
return delegate.getSubscribeServices();
}
@Override
public String getServerStatus() {
return delegate.getServerStatus();
}
@Override
public void shutDown() throws NacosException {
delegate.shutDown();
}
@Override
public Properties getProperties() {
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
* *
@ -33,43 +34,61 @@ import java.util.Properties;
*/ */
public interface NacosServiceFactory { public interface NacosServiceFactory {
/** /**
* The bean name of {@link NacosServiceFactory} * The bean name of {@link NacosServiceFactory}
*/ */
String BEAN_NAME = "nacosServiceFactory"; String BEAN_NAME = "nacosServiceFactory";
/** /**
* Create {@link ConfigService} instance * Create {@link ConfigService} instance
* *
* @param properties init param * @param properties init param
* @return a {@link ConfigService} instance * @return a {@link ConfigService} instance
* @throws NacosException If creation is failed. * @throws NacosException If creation is failed.
* @see NacosFactory#createConfigService(Properties) * @see NacosFactory#createConfigService(Properties)
*/ */
ConfigService createConfigService(Properties properties) throws NacosException; ConfigService createConfigService(Properties properties) throws NacosException;
/** /**
* Create {@link NamingService} instance * Create {@link NamingService} instance
* *
* @param properties init param * @param properties init param
* @return a {@link NamingService} instance * @return a {@link NamingService} instance
* @throws NacosException If creation is failed. * @throws NacosException If creation is failed.
* @see NacosFactory#createNamingService(Properties) * @see NacosFactory#createNamingService(Properties)
*/ */
NamingService createNamingService(Properties properties) throws NacosException; NamingService createNamingService(Properties properties) throws NacosException;
/** /**
* Get all instances of {@link ConfigService} * Create {@link NamingMaintainService} instance
* *
* @return read-only {@link Collection} * @param properties init param
*/ * @return a {@link NamingMaintainService} instance
Collection<ConfigService> getConfigServices(); * @throws NacosException If creation is failed.
* @see NacosFactory#createNamingService(Properties)
*/
NamingMaintainService createNamingMaintainService(Properties properties)
throws NacosException;
/** /**
* Get all instances of {@link NamingService} * Get all instances of {@link ConfigService}
* *
* @return read-only {@link Collection} * @return read-only {@link Collection}
*/ */
Collection<NamingService> getNamingServices(); Collection<ConfigService> getConfigServices();
/**
* Get all instances of {@link NamingService}
*
* @return read-only {@link Collection}
*/
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
* *
@ -33,11 +33,11 @@ import java.util.Properties;
*/ */
public interface NacosServiceMetaData { public interface NacosServiceMetaData {
/** /**
* Get the {@link Properties} for Nacos Service * Get the {@link Properties} for Nacos Service
* *
* @return non-null * @return non-null
* @see NacosProperties * @see NacosProperties
*/ */
Properties getProperties(); Properties getProperties();
} }

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}
@ -34,49 +38,54 @@ import static java.util.Collections.emptyMap;
*/ */
public enum GlobalNacosPropertiesSource { public enum GlobalNacosPropertiesSource {
/** /**
* Default Global {@link NacosProperties} * Default Global {@link NacosProperties}
*/ */
DEFAULT(GLOBAL_NACOS_PROPERTIES_BEAN_NAME), DEFAULT(GLOBAL_NACOS_PROPERTIES_BEAN_NAME),
/** /**
* Global {@link NacosProperties} for Nacos Config * Global {@link NacosProperties} for Nacos Config
*/ */
CONFIG(CONFIG_GLOBAL_NACOS_PROPERTIES_BEAN_NAME), CONFIG(CONFIG_GLOBAL_NACOS_PROPERTIES_BEAN_NAME),
/** /**
* 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;
GlobalNacosPropertiesSource(String beanName) { GlobalNacosPropertiesSource(String beanName) {
this.beanName = beanName; this.beanName = beanName;
} }
/** /**
* Get Merged {@link Properties} from {@link BeanFactory} * Get Merged {@link Properties} from {@link BeanFactory}
* *
* @param beanFactory {@link BeanFactory} * @param beanFactory {@link BeanFactory}
* @return Global {@link Properties} Bean * @return Global {@link Properties} Bean
*/ */
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,
// merge GLOBAL_NACOS_PROPERTIES_BEAN_NAME);
merge(globalProperties, currentProperties); // merge
return globalProperties; merge(globalProperties, currentProperties);
} 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)
beanFactory.getBean(beanName, Properties.class) : emptyMap(); : 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
@ -65,380 +69,513 @@ import static com.alibaba.nacos.spring.util.NacosUtils.resolveProperties;
*/ */
public abstract class NacosBeanUtils { public abstract class NacosBeanUtils {
/** /**
* The bean name of {@link PropertySourcesPlaceholderConfigurer} * The bean name of {@link PropertySourcesPlaceholderConfigurer}
*/ */
public static final String PLACEHOLDER_CONFIGURER_BEAN_NAME = "propertySourcesPlaceholderConfigurer"; public static final String PLACEHOLDER_CONFIGURER_BEAN_NAME = "propertySourcesPlaceholderConfigurer";
/** /**
* The bean name of global Nacos {@link Properties} * The bean name of global Nacos {@link Properties}
*/ */
public static final String GLOBAL_NACOS_PROPERTIES_BEAN_NAME = "globalNacosProperties"; public static final String GLOBAL_NACOS_PROPERTIES_BEAN_NAME = "globalNacosProperties";
/** /**
* The bean name of global Nacos {@link Properties} for config * The bean name of global Nacos {@link Properties} for config
*/ */
public static final String CONFIG_GLOBAL_NACOS_PROPERTIES_BEAN_NAME = GLOBAL_NACOS_PROPERTIES_BEAN_NAME public static final String CONFIG_GLOBAL_NACOS_PROPERTIES_BEAN_NAME = GLOBAL_NACOS_PROPERTIES_BEAN_NAME
+ "$config"; + "$config";
/** /**
* 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 {@link Executor} for Nacos Config Listener * The bean name of global Nacos {@link Properties} for maintain
*/ */
public static final String NACOS_CONFIG_LISTENER_EXECUTOR_BEAN_NAME = "nacosConfigListenerExecutor"; public static final String MAINTAIN_GLOBAL_NACOS_PROPERTIES_BEAN_NAME = GLOBAL_NACOS_PROPERTIES_BEAN_NAME
+ "$maintain";
/** /**
* Register an object to be Singleton Bean * The bean name of {@link Executor} for Nacos Config Listener
* */
* @param registry {@link BeanDefinitionRegistry} public static final String NACOS_CONFIG_LISTENER_EXECUTOR_BEAN_NAME = "nacosConfigListenerExecutor";
* @param beanName bean name
* @param singletonObject singleton object
*/
public static void registerSingleton(BeanDefinitionRegistry registry, String beanName, Object singletonObject) {
SingletonBeanRegistry beanRegistry = null;
if (registry instanceof SingletonBeanRegistry) {
beanRegistry = (SingletonBeanRegistry) registry;
} else if (registry instanceof AbstractApplicationContext) {
// Maybe AbstractApplicationContext or its sub-classes
beanRegistry = ((AbstractApplicationContext) registry).getBeanFactory();
}
// Register Singleton Object if possible
if (beanRegistry != null) {
beanRegistry.registerSingleton(beanName, singletonObject);
}
}
/** /**
* Register Infrastructure Bean * the ignoreResourceNotFound property for propertySourcesPlaceholderConfigurer
* */
* @param registry {@link BeanDefinitionRegistry} public static final String IGNORE_RESOURCE_NOT_FOUND = "ignoreResourceNotFound";
* @param beanName the name of bean
* @param beanClass the class of bean
* @param constructorArgs the arguments of {@link Constructor}
*/
public static void registerInfrastructureBean(BeanDefinitionRegistry registry, String beanName, Class<?> beanClass,
Object... constructorArgs) {
// Build a BeanDefinition for NacosServiceFactory class
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.rootBeanDefinition(beanClass);
for (Object constructorArg : constructorArgs) {
beanDefinitionBuilder.addConstructorArgValue(constructorArg);
}
// ROLE_INFRASTRUCTURE
beanDefinitionBuilder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
// Register
registry.registerBeanDefinition(beanName, beanDefinitionBuilder.getBeanDefinition());
}
/** /**
* Register Infrastructure Bean if absent * the ignoreUnresolvablePlaceholders property for
* * propertySourcesPlaceholderConfigurer
* @param registry {@link BeanDefinitionRegistry} */
* @param beanName the name of bean public static final String IGNORE_UNRESOLVABLE_PLACEHOLDERS = "ignoreUnresolvablePlaceholders";
* @param beanClass the class of bean
* @param constructorArgs the arguments of {@link Constructor}
*/
public static void registerInfrastructureBeanIfAbsent(BeanDefinitionRegistry registry, String beanName, Class<?> beanClass,
Object... constructorArgs) {
if (!isBeanDefinitionPresent(registry, beanName, beanClass) && !registry.containsBeanDefinition(beanName)) {
registerInfrastructureBean(registry, beanName, beanClass, constructorArgs);
}
}
/** /**
* Resolve {@link BeanFactory} from {@link BeanDefinitionRegistry} * Register an object to be Singleton Bean
* *
* @param registry {@link BeanDefinitionRegistry} * @param registry {@link BeanDefinitionRegistry}
* @return {@link BeanFactory} if resolved * @param beanName bean name
*/ * @param singletonObject singleton object
public static BeanFactory resolveBeanFactory(BeanDefinitionRegistry registry) { */
if (registry instanceof BeanFactory) { public static void registerSingleton(BeanDefinitionRegistry registry, String beanName,
return (BeanFactory) registry; Object singletonObject) {
} SingletonBeanRegistry beanRegistry = null;
if (registry instanceof SingletonBeanRegistry) {
beanRegistry = (SingletonBeanRegistry) registry;
}
else if (registry instanceof AbstractApplicationContext) {
// Maybe AbstractApplicationContext or its sub-classes
beanRegistry = ((AbstractApplicationContext) registry).getBeanFactory();
}
// Register Singleton Object if possible
if (beanRegistry != null) {
// Determine in advance whether injected with beans
if (!beanRegistry.containsSingleton(beanName)) {
beanRegistry.registerSingleton(beanName, singletonObject);
}
}
}
if (registry instanceof AbstractApplicationContext) { /**
return ((AbstractApplicationContext) registry).getBeanFactory(); * Register Infrastructure Bean
} *
return null; * @param registry {@link BeanDefinitionRegistry}
} * @param beanName the name of bean
* @param beanClass the class of bean
* @param constructorArgs the arguments of {@link Constructor}
*/
public static void registerInfrastructureBean(BeanDefinitionRegistry registry,
String beanName, Class<?> beanClass, Object... constructorArgs) {
// Build a BeanDefinition for NacosServiceFactory class
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder
.rootBeanDefinition(beanClass);
for (Object constructorArg : constructorArgs) {
beanDefinitionBuilder.addConstructorArgValue(constructorArg);
}
// ROLE_INFRASTRUCTURE
beanDefinitionBuilder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
// Register
registry.registerBeanDefinition(beanName,
beanDefinitionBuilder.getBeanDefinition());
}
/** /**
* Is {@link BeanDefinition} present in {@link BeanDefinitionRegistry} * Register Infrastructure Bean if absent
* *
* @param registry {@link BeanDefinitionRegistry} * @param registry {@link BeanDefinitionRegistry}
* @param beanName the name of bean * @param beanName the name of bean
* @param targetBeanClass the type of bean * @param beanClass the class of bean
* @return If Present , return <code>true</code> * @param constructorArgs the arguments of {@link Constructor}
*/ */
public static boolean isBeanDefinitionPresent(BeanDefinitionRegistry registry, String beanName, Class<?> targetBeanClass) { public static void registerInfrastructureBeanIfAbsent(BeanDefinitionRegistry registry,
String[] beanNames = BeanUtils.getBeanNames((ListableBeanFactory) registry, targetBeanClass); String beanName, Class<?> beanClass, Object... constructorArgs) {
return ArrayUtils.contains(beanNames, beanName); if (!isBeanDefinitionPresent(registry, beanName, beanClass)
} && !registry.containsBeanDefinition(beanName)) {
registerInfrastructureBean(registry, beanName, beanClass, constructorArgs);
}
}
/** /**
* Register {@link PropertySourcesPlaceholderConfigurer} Bean * Resolve {@link BeanFactory} from {@link BeanDefinitionRegistry}
* *
* @param registry {@link BeanDefinitionRegistry} * @param registry {@link BeanDefinitionRegistry}
*/ * @return {@link BeanFactory} if resolved
public static void registerPropertySourcesPlaceholderConfigurer(BeanDefinitionRegistry registry) { */
registerInfrastructureBeanIfAbsent(registry, PLACEHOLDER_CONFIGURER_BEAN_NAME, public static BeanFactory resolveBeanFactory(BeanDefinitionRegistry registry) {
PropertySourcesPlaceholderConfigurer.class); if (registry instanceof BeanFactory) {
} return (BeanFactory) registry;
}
if (registry instanceof AbstractApplicationContext) {
return ((AbstractApplicationContext) registry).getBeanFactory();
}
return null;
}
/** /**
* Register Global Nacos Properties Bean with specified name * Is {@link BeanDefinition} present in {@link BeanDefinitionRegistry}
* *
* @param attributes the attributes of Global Nacos Properties may contain placeholders * @param registry {@link BeanDefinitionRegistry}
* @param registry {@link BeanDefinitionRegistry} * @param beanName the name of bean
* @param propertyResolver {@link PropertyResolver} * @param targetBeanClass the type of bean
* @param beanName Bean name * @return If Present , return <code>true</code>
*/ */
public static void registerGlobalNacosProperties(AnnotationAttributes attributes, public static boolean isBeanDefinitionPresent(BeanDefinitionRegistry registry,
BeanDefinitionRegistry registry, String beanName, Class<?> targetBeanClass) {
PropertyResolver propertyResolver, String[] beanNames = BeanUtils.getBeanNames((ListableBeanFactory) registry,
String beanName) { targetBeanClass);
if (attributes == null) { return ArrayUtils.contains(beanNames, beanName);
return; // Compatible with null }
}
AnnotationAttributes globalPropertiesAttributes = attributes.getAnnotation("globalProperties");
registerGlobalNacosProperties((Map<?, ?>) globalPropertiesAttributes, registry, propertyResolver,
beanName);
}
/** /**
* Register Global Nacos Properties Bean with specified name * Register {@link PropertySourcesPlaceholderConfigurer} Bean
* *
* @param globalPropertiesAttributes the attributes of Global Nacos Properties may contain placeholders * @param registry {@link BeanDefinitionRegistry}
* @param registry {@link BeanDefinitionRegistry} * @param beanFactory {@link BeanFactory}
* @param propertyResolver {@link PropertyResolver} */
* @param beanName Bean name public static void registerPropertySourcesPlaceholderConfigurer(
*/ BeanDefinitionRegistry registry, BeanFactory beanFactory) {
public static void registerGlobalNacosProperties(Map<?, ?> globalPropertiesAttributes, registerInfrastructureBeanIfAbsent(registry, PLACEHOLDER_CONFIGURER_BEAN_NAME,
BeanDefinitionRegistry registry, PropertySourcesPlaceholderConfigurer.class);
PropertyResolver propertyResolver,
String beanName) {
Properties globalProperties = resolveProperties(globalPropertiesAttributes, propertyResolver);
registerSingleton(registry, beanName, globalProperties);
}
/*
* 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
* Register {@link CacheableEventPublishingNacosServiceFactory NacosServiceFactory} .parseBoolean(System.getProperty(IGNORE_RESOURCE_NOT_FOUND));
* boolean ignoreUnresolvablePlaceholders = Boolean
* @param registry {@link BeanDefinitionRegistry} .parseBoolean(System.getProperty(IGNORE_UNRESOLVABLE_PLACEHOLDERS));
*/ if (ignoreResourceNotFound || ignoreUnresolvablePlaceholders) {
public static void registerNacosServiceFactory(BeanDefinitionRegistry registry) { PropertySourcesPlaceholderConfigurer configurer = (PropertySourcesPlaceholderConfigurer) beanFactory
registerInfrastructureBeanIfAbsent(registry, CacheableEventPublishingNacosServiceFactory.BEAN_NAME, .getBean(NacosBeanUtils.PLACEHOLDER_CONFIGURER_BEAN_NAME);
CacheableEventPublishingNacosServiceFactory.class); if (configurer != null) {
} configurer.setIgnoreResourceNotFound(ignoreResourceNotFound);
configurer.setIgnoreUnresolvablePlaceholders(
ignoreUnresolvablePlaceholders);
}
}
}
public static void registerNacosConfigPropertiesBindingPostProcessor(BeanDefinitionRegistry registry) { /**
registerInfrastructureBeanIfAbsent(registry, NacosConfigurationPropertiesBindingPostProcessor.BEAN_NAME, * Register Global Nacos Properties Bean with specified name
NacosConfigurationPropertiesBindingPostProcessor.class); *
} * @param attributes the attributes of Global Nacos Properties may contain
* placeholders
* @param registry {@link BeanDefinitionRegistry}
* @param propertyResolver {@link PropertyResolver}
* @param beanName Bean name
*/
public static void registerGlobalNacosProperties(AnnotationAttributes attributes,
BeanDefinitionRegistry registry, PropertyResolver propertyResolver,
String beanName) {
if (attributes == null) {
return; // Compatible with null
}
AnnotationAttributes globalPropertiesAttributes = attributes
.getAnnotation("globalProperties");
registerGlobalNacosProperties((Map<?, ?>) globalPropertiesAttributes, registry,
propertyResolver, beanName);
}
public static void registerNacosConfigListenerMethodProcessor(BeanDefinitionRegistry registry) { /**
registerInfrastructureBeanIfAbsent(registry, NacosConfigListenerMethodProcessor.BEAN_NAME, * Register Global Nacos Properties Bean with specified name
NacosConfigListenerMethodProcessor.class); *
} * @param globalPropertiesAttributes the attributes of Global Nacos Properties may
* contain placeholders
* @param registry {@link BeanDefinitionRegistry}
* @param propertyResolver {@link PropertyResolver}
* @param beanName Bean name
*/
public static void registerGlobalNacosProperties(Map<?, ?> globalPropertiesAttributes,
BeanDefinitionRegistry registry, PropertyResolver propertyResolver,
String beanName) {
Properties globalProperties = resolveProperties(globalPropertiesAttributes,
propertyResolver);
registerSingleton(registry, beanName, globalProperties);
}
public static void registerNacosPropertySourcePostProcessor(BeanDefinitionRegistry registry) { public static void registerNacosApplicationContextHolder(
registerInfrastructureBeanIfAbsent(registry, NacosPropertySourcePostProcessor.BEAN_NAME, BeanDefinitionRegistry registry) {
NacosPropertySourcePostProcessor.class); registerInfrastructureBeanIfAbsent(registry, ApplicationContextHolder.BEAN_NAME,
} ApplicationContextHolder.class);
}
public static void registerAnnotationNacosPropertySourceBuilder(BeanDefinitionRegistry registry) { public static void registerNacosConfigPropertiesBindingPostProcessor(
registerInfrastructureBeanIfAbsent(registry, AnnotationNacosPropertySourceBuilder.BEAN_NAME, BeanDefinitionRegistry registry) {
AnnotationNacosPropertySourceBuilder.class); registerInfrastructureBeanIfAbsent(registry,
} NacosConfigurationPropertiesBindingPostProcessor.BEAN_NAME,
NacosConfigurationPropertiesBindingPostProcessor.class);
}
public static void registerXmlNacosPropertySourceBuilder(BeanDefinitionRegistry registry) { public static void registerNacosConfigListenerMethodProcessor(
registerInfrastructureBeanIfAbsent(registry, XmlNacosPropertySourceBuilder.BEAN_NAME, BeanDefinitionRegistry registry) {
XmlNacosPropertySourceBuilder.class); registerInfrastructureBeanIfAbsent(registry,
} NacosConfigListenerMethodProcessor.BEAN_NAME,
NacosConfigListenerMethodProcessor.class);
}
public static void registerNacosConfigListenerExecutor(BeanDefinitionRegistry registry, Environment environment) { public static void registerNacosPropertySourcePostProcessor(
final String beanName = NACOS_CONFIG_LISTENER_EXECUTOR_BEAN_NAME; BeanDefinitionRegistry registry) {
if (registry instanceof BeanFactory && ((BeanFactory) registry).containsBean(beanName)) { registerInfrastructureBeanIfAbsent(registry,
return; NacosPropertySourcePostProcessor.BEAN_NAME,
} NacosPropertySourcePostProcessor.class);
ExecutorService nacosConfigListenerExecutor = buildNacosConfigListenerExecutor(environment); }
registerSingleton(registry, beanName, nacosConfigListenerExecutor);
}
private static ExecutorService buildNacosConfigListenerExecutor(Environment environment) { public static void registerAnnotationNacosPropertySourceBuilder(
int parallelism = getParallelism(environment); BeanDefinitionRegistry registry) {
return Executors.newFixedThreadPool(parallelism, new ThreadFactory() { registerInfrastructureBeanIfAbsent(registry,
private final AtomicInteger threadNumber = new AtomicInteger(1); AnnotationNacosPropertySourceBuilder.BEAN_NAME,
AnnotationNacosPropertySourceBuilder.class);
}
@Override public static void registerXmlNacosPropertySourceBuilder(
public Thread newThread(Runnable r) { BeanDefinitionRegistry registry) {
Thread thread = new Thread(r); registerInfrastructureBeanIfAbsent(registry,
thread.setName("NacosConfigListener-ThreadPool-" + threadNumber.getAndIncrement()); XmlNacosPropertySourceBuilder.BEAN_NAME,
return thread; XmlNacosPropertySourceBuilder.class);
} }
});
}
private static int getParallelism(Environment environment) { public static void registerNacosConfigListenerExecutor(
int parallelism = environment.getProperty(NACOS_CONFIG_LISTENER_PARALLELISM, int.class, BeanDefinitionRegistry registry, Environment environment) {
DEFAULT_NACOS_CONFIG_LISTENER_PARALLELISM); final String beanName = NACOS_CONFIG_LISTENER_EXECUTOR_BEAN_NAME;
return parallelism < 1 ? DEFAULT_NACOS_CONFIG_LISTENER_PARALLELISM : parallelism; if (registry instanceof BeanFactory
} && ((BeanFactory) registry).containsBean(beanName)) {
return;
}
ExecutorService nacosConfigListenerExecutor = buildNacosConfigListenerExecutor(
environment);
registerSingleton(registry, beanName, nacosConfigListenerExecutor);
}
public static void registerNacosValueAnnotationBeanPostProcessor(BeanDefinitionRegistry registry) { private static ExecutorService buildNacosConfigListenerExecutor(
registerInfrastructureBeanIfAbsent(registry, NacosValueAnnotationBeanPostProcessor.BEAN_NAME, Environment environment) {
NacosValueAnnotationBeanPostProcessor.class); int parallelism = getParallelism(environment);
} return Executors.newFixedThreadPool(parallelism, new ThreadFactory() {
private final AtomicInteger threadNumber = new AtomicInteger(1);
/** @Override
* Register Nacos Common Beans public Thread newThread(Runnable r) {
* Thread thread = new Thread(r);
* @param registry {@link BeanDefinitionRegistry} thread.setName("NacosConfigListener-ThreadPool-"
*/ + threadNumber.getAndIncrement());
public static void registerNacosCommonBeans(BeanDefinitionRegistry registry) { return thread;
// Register NacosServiceFactory Bean }
registerNacosServiceFactory(registry); });
// Register AnnotationNacosInjectedBeanPostProcessor Bean }
registerAnnotationNacosInjectedBeanPostProcessor(registry);
}
/** private static int getParallelism(Environment environment) {
* Register Nacos Config Beans int parallelism = environment.getProperty(NACOS_CONFIG_LISTENER_PARALLELISM,
* int.class, DEFAULT_NACOS_CONFIG_LISTENER_PARALLELISM);
* @param registry {@link BeanDefinitionRegistry} return parallelism < 1 ? DEFAULT_NACOS_CONFIG_LISTENER_PARALLELISM : parallelism;
* @param environment {@link Environment} }
*/
public static void registerNacosConfigBeans(BeanDefinitionRegistry registry, Environment environment) {
// Register PropertySourcesPlaceholderConfigurer Bean
registerPropertySourcesPlaceholderConfigurer(registry);
registerNacosConfigPropertiesBindingPostProcessor(registry); public static void registerNacosValueAnnotationBeanPostProcessor(
BeanDefinitionRegistry registry) {
registerInfrastructureBeanIfAbsent(registry,
NacosValueAnnotationBeanPostProcessor.BEAN_NAME,
NacosValueAnnotationBeanPostProcessor.class);
}
registerNacosConfigListenerMethodProcessor(registry); public static void registerStringValueAnnotationBeanPostProcessor(
BeanDefinitionRegistry registry) {
registerInfrastructureBeanIfAbsent(registry,
SpringValueAnnotationBeanPostProcessor.BEAN_NAME,
SpringValueAnnotationBeanPostProcessor.class);
}
registerNacosPropertySourcePostProcessor(registry); /**
* Register Nacos Common Beans
*
* @param registry {@link BeanDefinitionRegistry}
*/
public static void registerNacosCommonBeans(BeanDefinitionRegistry registry) {
// Register NacosApplicationContextHolder Bean
registerNacosApplicationContextHolder(registry);
// Register AnnotationNacosInjectedBeanPostProcessor Bean
registerAnnotationNacosInjectedBeanPostProcessor(registry);
}
registerAnnotationNacosPropertySourceBuilder(registry); /**
* Register Nacos Config Beans
*
* @param registry {@link BeanDefinitionRegistry}
* @param environment {@link Environment}
* @param beanFactory {@link BeanFactory}
*/
public static void registerNacosConfigBeans(BeanDefinitionRegistry registry,
Environment environment, BeanFactory beanFactory) {
// Register PropertySourcesPlaceholderConfigurer Bean
registerPropertySourcesPlaceholderConfigurer(registry, beanFactory);
registerNacosConfigListenerExecutor(registry, environment); registerNacosConfigPropertiesBindingPostProcessor(registry);
registerNacosValueAnnotationBeanPostProcessor(registry); registerNacosConfigListenerMethodProcessor(registry);
registerConfigServiceBeanBuilder(registry); registerNacosPropertySourcePostProcessor(registry);
registerLoggingNacosConfigMetadataEventListener(registry); registerAnnotationNacosPropertySourceBuilder(registry);
}
/** registerNacosConfigListenerExecutor(registry, environment);
* Invokes {@link NacosPropertySourcePostProcessor}
*
* @param beanFactory {@link BeanFactory}
*/
public static void invokeNacosPropertySourcePostProcessor(BeanFactory beanFactory) {
NacosPropertySourcePostProcessor postProcessor =
beanFactory.getBean(NacosPropertySourcePostProcessor.BEAN_NAME, NacosPropertySourcePostProcessor.class);
postProcessor.postProcessBeanFactory((ConfigurableListableBeanFactory) beanFactory);
}
/** registerNacosValueAnnotationBeanPostProcessor(registry);
* Register {@link LoggingNacosConfigMetadataEventListener} Bean
*
* @param registry {@link BeanDefinitionRegistry}
*/
private static void registerLoggingNacosConfigMetadataEventListener(BeanDefinitionRegistry registry) {
registerInfrastructureBeanIfAbsent(registry, LoggingNacosConfigMetadataEventListener.BEAN_NAME,
LoggingNacosConfigMetadataEventListener.class);
}
/** registerStringValueAnnotationBeanPostProcessor(registry);
* Register Nacos Discovery Beans
*
* @param registry {@link BeanDefinitionRegistry}
*/
public static void registerNacosDiscoveryBeans(BeanDefinitionRegistry registry) {
registerNamingServiceBeanBuilder(registry);
}
/** registerConfigServiceBeanBuilder(registry);
* Register {@link AnnotationNacosInjectedBeanPostProcessor} with
* {@link AnnotationNacosInjectedBeanPostProcessor#BEAN_NAME name}
*
* @param registry {@link BeanDefinitionRegistry}
*/
private static void registerAnnotationNacosInjectedBeanPostProcessor(BeanDefinitionRegistry registry) {
registerInfrastructureBeanIfAbsent(registry, AnnotationNacosInjectedBeanPostProcessor.BEAN_NAME,
AnnotationNacosInjectedBeanPostProcessor.class);
}
private static void registerConfigServiceBeanBuilder(BeanDefinitionRegistry registry) { registerLoggingNacosConfigMetadataEventListener(registry);
registerInfrastructureBeanIfAbsent(registry, ConfigServiceBeanBuilder.BEAN_NAME, ConfigServiceBeanBuilder.class); }
}
private static void registerNamingServiceBeanBuilder(BeanDefinitionRegistry registry) { /**
registerInfrastructureBeanIfAbsent(registry, NamingServiceBeanBuilder.BEAN_NAME, NamingServiceBeanBuilder.class); * Invokes {@link NacosPropertySourcePostProcessor}
} *
* @param beanFactory {@link BeanFactory}
*/
public static void invokeNacosPropertySourcePostProcessor(BeanFactory beanFactory) {
NacosPropertySourcePostProcessor postProcessor = beanFactory.getBean(
NacosPropertySourcePostProcessor.BEAN_NAME,
NacosPropertySourcePostProcessor.class);
postProcessor
.postProcessBeanFactory((ConfigurableListableBeanFactory) beanFactory);
}
/** /**
* Get Global Properties Bean * Register {@link LoggingNacosConfigMetadataEventListener} Bean
* *
* @param beanFactory {@link BeanFactory} * @param registry {@link BeanDefinitionRegistry}
* @return Global Properties Bean */
* @throws NoSuchBeanDefinitionException if there is no such bean definition private static void registerLoggingNacosConfigMetadataEventListener(
*/ BeanDefinitionRegistry registry) {
public static Properties getGlobalPropertiesBean(BeanFactory beanFactory) throws NoSuchBeanDefinitionException { registerInfrastructureBeanIfAbsent(registry,
return beanFactory.getBean(GLOBAL_NACOS_PROPERTIES_BEAN_NAME, Properties.class); LoggingNacosConfigMetadataEventListener.BEAN_NAME,
} LoggingNacosConfigMetadataEventListener.class);
}
/** /**
* Get {@link NacosServiceFactory} Bean * Register Nacos Discovery Beans
* *
* @param beanFactory {@link BeanFactory} * @param registry {@link BeanDefinitionRegistry}
* @return {@link NacosServiceFactory} Bean */
* @throws NoSuchBeanDefinitionException if there is no such bean definition public static void registerNacosDiscoveryBeans(BeanDefinitionRegistry registry) {
*/ registerNamingServiceBeanBuilder(registry);
public static NacosServiceFactory getNacosServiceFactoryBean(BeanFactory beanFactory) throws NoSuchBeanDefinitionException { registerNamingMaintainServiceBeanBuilder(registry);
return beanFactory.getBean(CacheableEventPublishingNacosServiceFactory.BEAN_NAME, NacosServiceFactory.class); }
}
/** /**
* Get {@link Executor} Bean for Nacos Config Listener If Present * Register {@link AnnotationNacosInjectedBeanPostProcessor} with
* * {@link AnnotationNacosInjectedBeanPostProcessor#BEAN_NAME name}
* @param beanFactory {@link BeanFactory} *
* @return {@link Executor} Bean If Present, or <code>null</code> * @param registry {@link BeanDefinitionRegistry}
*/ */
public static ExecutorService getNacosConfigListenerExecutorIfPresent(BeanFactory beanFactory) { private static void registerAnnotationNacosInjectedBeanPostProcessor(
if (!beanFactory.containsBean(NACOS_CONFIG_LISTENER_EXECUTOR_BEAN_NAME)) { BeanDefinitionRegistry registry) {
return null; registerInfrastructureBeanIfAbsent(registry,
} AnnotationNacosInjectedBeanPostProcessor.BEAN_NAME,
return beanFactory.getBean(NACOS_CONFIG_LISTENER_EXECUTOR_BEAN_NAME, ExecutorService.class); AnnotationNacosInjectedBeanPostProcessor.class);
} }
/** private static void registerConfigServiceBeanBuilder(
* Get {@link ConfigServiceBeanBuilder} Bean BeanDefinitionRegistry registry) {
* registerInfrastructureBeanIfAbsent(registry, ConfigServiceBeanBuilder.BEAN_NAME,
* @param beanFactory {@link BeanFactory} ConfigServiceBeanBuilder.class);
* @return {@link ConfigServiceBeanBuilder} Bean }
* @throws NoSuchBeanDefinitionException if there is no such bean definition
*/
public static ConfigServiceBeanBuilder getConfigServiceBeanBuilder(BeanFactory beanFactory) throws NoSuchBeanDefinitionException {
return beanFactory.getBean(ConfigServiceBeanBuilder.BEAN_NAME, ConfigServiceBeanBuilder.class);
}
/** private static void registerNamingServiceBeanBuilder(
* Get {@link NamingServiceBeanBuilder} Bean BeanDefinitionRegistry registry) {
* registerInfrastructureBeanIfAbsent(registry, NamingServiceBeanBuilder.BEAN_NAME,
* @param beanFactory {@link BeanFactory} NamingServiceBeanBuilder.class);
* @return {@link ConfigServiceBeanBuilder} Bean }
* @throws NoSuchBeanDefinitionException if there is no such bean definition
*/ private static void registerNamingMaintainServiceBeanBuilder(
public static NamingServiceBeanBuilder getNamingServiceBeanBuilder(BeanFactory beanFactory) throws NoSuchBeanDefinitionException { BeanDefinitionRegistry registry) {
return beanFactory.getBean(NamingServiceBeanBuilder.BEAN_NAME, NamingServiceBeanBuilder.class); registerInfrastructureBeanIfAbsent(registry,
} NamingMaintainServiceBeanBuilder.BEAN_NAME,
NamingMaintainServiceBeanBuilder.class);
}
/**
* Get Global Properties Bean
*
* @param beanFactory {@link BeanFactory}
* @return Global Properties Bean
* @throws NoSuchBeanDefinitionException if there is no such bean definition
*/
public static Properties getGlobalPropertiesBean(BeanFactory beanFactory)
throws NoSuchBeanDefinitionException {
return beanFactory.getBean(GLOBAL_NACOS_PROPERTIES_BEAN_NAME, Properties.class);
}
/**
* Get {@link NacosServiceFactory} Bean
*
* @param beanFactory {@link BeanFactory}
* @return {@link NacosServiceFactory} Bean
* @throws NoSuchBeanDefinitionException if there is no such bean definition
*/
public static NacosServiceFactory getNacosServiceFactoryBean(BeanFactory beanFactory)
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);
}
/**
* Get {@link Executor} Bean for Nacos Config Listener If Present
*
* @param beanFactory {@link BeanFactory}
* @return {@link Executor} Bean If Present, or <code>null</code>
*/
public static ExecutorService getNacosConfigListenerExecutorIfPresent(
BeanFactory beanFactory) {
if (!beanFactory.containsBean(NACOS_CONFIG_LISTENER_EXECUTOR_BEAN_NAME)) {
return null;
}
return beanFactory.getBean(NACOS_CONFIG_LISTENER_EXECUTOR_BEAN_NAME,
ExecutorService.class);
}
/**
* Get {@link ConfigServiceBeanBuilder} Bean
*
* @param beanFactory {@link BeanFactory}
* @return {@link ConfigServiceBeanBuilder} Bean
* @throws NoSuchBeanDefinitionException if there is no such bean definition
*/
public static ConfigServiceBeanBuilder getConfigServiceBeanBuilder(
BeanFactory beanFactory) throws NoSuchBeanDefinitionException {
return beanFactory.getBean(ConfigServiceBeanBuilder.BEAN_NAME,
ConfigServiceBeanBuilder.class);
}
/**
* Get {@link NamingServiceBeanBuilder} Bean
*
* @param beanFactory {@link BeanFactory}
* @return {@link NamingServiceBeanBuilder} Bean
* @throws NoSuchBeanDefinitionException if there is no such bean definition
*/
public static NamingServiceBeanBuilder getNamingServiceBeanBuilder(
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
@ -51,231 +62,485 @@ import static org.springframework.core.annotation.AnnotationUtils.getAnnotationA
*/ */
public abstract class NacosUtils { public abstract class NacosUtils {
/** /**
* Default value of {@link String} attribute for {@link Annotation} * Default value of {@link String} attribute for {@link Annotation}
*/ */
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}
*/ */
public static final boolean DEFAULT_BOOLEAN_ATTRIBUTE_VALUE = false; public static final boolean DEFAULT_BOOLEAN_ATTRIBUTE_VALUE = false;
/** /**
* The separator * The separator
*/ */
public static final String SEPARATOR = "|"; public static final String SEPARATOR = "|";
/** /**
* 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 Logger logger = LoggerFactory.getLogger(NacosUtils.class); 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();
* Build The default name of {@link NacosConfigurationProperties @NacosPropertySource}
*
* @param dataId data Id
* @param groupId group Id
* @param properties Nacos Properties
* @return non-null
*/
public static String buildDefaultPropertySourceName(String dataId, String groupId, Map<?, ?> properties) {
return build(dataId, groupId, identify(properties));
}
/** private static BeanExpressionResolver resolver = new StandardBeanExpressionResolver();
* Generate Id of {@link NacosProperties Nacos Properties annotation}
*
* @param nacosProperties {@link NacosProperties Nacos Properties annotation}
* @return Id
*/
public static String identify(NacosProperties nacosProperties) {
return identify(getAnnotationAttributes(nacosProperties));
}
/** private static ConcurrentHashMap<String, Expression> expressionCache
* Generate Id of {@link NacosProperties Nacos Properties} = new ConcurrentHashMap();
*
* @param properties {@link Properties Nacos Properties}
* @return Id
*/
public static String identify(Map<?, ?> properties) { private static ConcurrentHashMap<Environment, StandardEvaluationContext> environmentContextCache
= new ConcurrentHashMap();
String namespace = (String) properties.get(NAMESPACE); private static final Logger logger = LoggerFactory.getLogger(NacosUtils.class);
String serverAddress = (String) properties.get(SERVER_ADDR);
String contextPath = (String) properties.get(CONTEXT_PATH);
String clusterName = (String) properties.get(CLUSTER_NAME);
String endpoint = (String) properties.get(ENDPOINT);
String accessKey = (String) properties.get(ACCESS_KEY);
String secretKey = (String) properties.get(SECRET_KEY);
String encode = (String) properties.get(ENCODE);
return build(namespace, clusterName, serverAddress, contextPath, endpoint, accessKey, secretKey, encode); /**
* Build The default name of {@link NacosConfigurationProperties @NacosPropertySource}
*
* @param dataId data Id
* @param groupId group Id
* @param properties Nacos Properties
* @return non-null
*/
public static String buildDefaultPropertySourceName(String dataId, String groupId,
Map<?, ?> properties) {
return build(dataId, groupId, identify(properties));
}
} /**
* Generate Id of {@link NacosProperties Nacos Properties annotation}
*
* @param nacosProperties {@link NacosProperties Nacos Properties annotation}
* @return Id
*/
public static String identify(NacosProperties nacosProperties) {
return identify(getAnnotationAttributes(nacosProperties));
}
private static String build(Object... values) { /**
StringBuilder stringBuilder = new StringBuilder(); * Generate Id of {@link NacosProperties Nacos Properties}
*
* @param properties {@link Properties Nacos Properties}
* @return Id
*/
for (Object value : values) { public static String identify(Map<?, ?> properties) {
String stringValue = value == null ? null : String.valueOf(value); String namespace = (String) properties.get(NAMESPACE);
if (StringUtils.hasText(stringValue)) { String serverAddress = (String) properties.get(SERVER_ADDR);
stringBuilder.append(stringValue); String contextPath = (String) properties.get(CONTEXT_PATH);
} String clusterName = (String) properties.get(CLUSTER_NAME);
stringBuilder.append(SEPARATOR); String endpoint = (String) properties.get(ENDPOINT);
} String accessKey = (String) properties.get(ACCESS_KEY);
String secretKey = (String) properties.get(SECRET_KEY);
String encode = (String) properties.get(ENCODE);
return stringBuilder.toString(); return build(namespace, clusterName, serverAddress, contextPath, endpoint,
} accessKey, secretKey, encode);
/** }
* Is {@link NacosProperties @NacosProperties} with default attribute values.
*
* @param nacosProperties {@link NacosProperties @NacosProperties}
* @return If default values , return <code>true</code>,or <code>false</code>
*/
public static boolean isDefault(final NacosProperties nacosProperties) {
final List<Object> records = new LinkedList<Object>(); private static String build(Object... values) {
StringBuilder stringBuilder = new StringBuilder();
ReflectionUtils.doWithMethods(nacosProperties.annotationType(), new ReflectionUtils.MethodCallback() { for (Object value : values) {
@Override
public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
if (Modifier.isPublic(method.getModifiers()) && method.getParameterTypes().length == 0) {
Object defaultValue = method.getDefaultValue();
if (defaultValue != null) {
try {
Object returnValue = method.invoke(nacosProperties);
if (!defaultValue.equals(returnValue)) {
records.add(returnValue);
}
} catch (Exception e) {
}
}
}
}
});
return records.isEmpty(); String stringValue = value == null ? null : String.valueOf(value);
} if (StringUtils.hasText(stringValue)) {
stringBuilder.append(stringValue);
}
stringBuilder.append(SEPARATOR);
}
public static Properties resolveProperties(NacosProperties nacosProperties, PropertyResolver propertyResolver) { return stringBuilder.toString();
return resolveProperties(nacosProperties, propertyResolver, null); }
}
public static Properties resolveProperties(NacosProperties nacosProperties, PropertyResolver propertyResolver, /**
Properties defaultProperties) { * Is {@link NacosProperties @NacosProperties} with default attribute values.
*
* @param nacosProperties {@link NacosProperties @NacosProperties}
* @return If default values , return <code>true</code>,or <code>false</code>
*/
public static boolean isDefault(final NacosProperties nacosProperties) {
Map<String, Object> attributes = getAnnotationAttributes(nacosProperties); final List<Object> records = new LinkedList<Object>();
return resolveProperties(attributes, propertyResolver, defaultProperties); ReflectionUtils.doWithMethods(nacosProperties.annotationType(),
new ReflectionUtils.MethodCallback() {
@Override
public void doWith(Method method)
throws IllegalArgumentException, IllegalAccessException {
if (Modifier.isPublic(method.getModifiers())
&& method.getParameterTypes().length == 0) {
Object defaultValue = method.getDefaultValue();
if (defaultValue != null) {
try {
Object returnValue = method.invoke(nacosProperties);
if (!defaultValue.equals(returnValue)) {
records.add(returnValue);
}
}
catch (Exception e) {
}
}
}
}
});
} return records.isEmpty();
}
/** public static String readFromEnvironment(String label, Environment environment) {
* {@link #resolveProperties(Map, PropertyResolver) Resolve} placeholders of {@link NacosProperties @NacosProperties}'s attributes via specified String value = resolvePlaceholders(label, environment);
* {@link PropertyResolver} if present, or try to {@link #merge(Properties, Properties) merge} from return StringUtils.hasText(value)
* default properties ? evaluate(value, environment)
* : value;
* @param attributes {@link NacosProperties @NacosProperties}'s attributes }
* @param propertyResolver the resolver of properties' placeholder
* @param defaultProperties default properties
* @return a new resolved {@link Properties} properties
* @see #resolveProperties(Map, PropertyResolver)
*/
public static Properties resolveProperties(Map<String, Object> attributes, PropertyResolver propertyResolver,
Properties defaultProperties) {
if (CollectionUtils.isEmpty(attributes)) { public static Object readFromBeanFactory(String label, ConfigurableBeanFactory beanFactory) {
return defaultProperties; if (beanFactory == null) {
} return label;
}
String value = beanFactory.resolveEmbeddedValue(label);
return StringUtils.hasText(value) ? evaluate(value, beanFactory) : value;
}
Properties resolveProperties = resolveProperties(attributes, propertyResolver); public static String resolvePlaceholders(String label, Environment environment) {
merge(resolveProperties, defaultProperties); return environment == null ? label : environment.resolvePlaceholders(label);
}
return resolveProperties; 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);
* Resolve placeholders of properties via specified {@link PropertyResolver} if present }
*
* @param properties The properties
* @param propertyResolver {@link PropertyResolver} instance, for instance, {@link Environment}
* @return a new instance of {@link Properties} after resolving.
*/
public static Properties resolveProperties(Map<?, ?> properties, PropertyResolver propertyResolver) {
PropertiesPlaceholderResolver propertiesPlaceholderResolver = new PropertiesPlaceholderResolver(propertyResolver);
return propertiesPlaceholderResolver.resolve(properties);
}
/** public static Object evaluate(String value, ConfigurableBeanFactory beanFactory) {
* Merge Nacos Properties If any property from target properties is absent return resolver.evaluate(value, new BeanExpressionContext(beanFactory, null));
* }
* @param targetProperties {@link Properties target Properties}
* @param sourceProperties {@link Properties source Properties}
*/
protected static void merge(Properties targetProperties, Properties sourceProperties) {
if (CollectionUtils.isEmpty(sourceProperties)) { public static String readFileExtension(String dataId) {
return; int lastIndex = dataId.lastIndexOf(".");
} final String extName = dataId.substring(lastIndex + 1);
FileTypeEnum fileTypeEnum = FileTypeEnum.getFileTypeEnumByFileExtensionOrFileType(extName);
return fileTypeEnum.getFileType();
}
for (Map.Entry entry : sourceProperties.entrySet()) { public static PropertyValues resolvePropertyValues(Object bean, String content,
String propertyName = (String) entry.getKey(); String type) {
if (!targetProperties.containsKey(propertyName)) { return resolvePropertyValues(bean, "", "", "", content, type);
String propertyValue = (String) entry.getValue(); }
targetProperties.setProperty(propertyName, propertyValue);
}
}
} 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)) {
* Get content from {@link ConfigService} via dataId and groupId String propertyValue = String
* .valueOf(configProperties.get(propertyName));
* @param configService {@link ConfigService} propertyValues.add(field.getName(), propertyValue);
* @param dataId dataId }
* @param groupId groupId }
* @return If available , return content , or <code>null</code> }
*/ });
public static String getContent(ConfigService configService, String dataId, String groupId) { return propertyValues;
String content = null; }
try {
content = configService.getConfig(dataId, groupId, DEFAULT_TIMEOUT);
} catch (NacosException e) {
if (logger.isErrorEnabled()) {
logger.error("Can't get content from dataId : " + dataId + " , groupId : " + groupId, e);
}
}
return content;
}
public static <T> Class<T> resolveGenericType(Class<?> declaredClass) { public static Properties resolveProperties(NacosProperties nacosProperties,
ParameterizedType parameterizedType = (ParameterizedType) declaredClass.getGenericSuperclass(); PropertyResolver propertyResolver) {
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments(); return resolveProperties(nacosProperties, propertyResolver, null);
return (Class<T>) actualTypeArguments[0]; }
}
public static Properties toProperties(String text) { public static Properties resolveProperties(NacosProperties nacosProperties,
Properties properties = new Properties(); PropertyResolver propertyResolver, Properties defaultProperties) {
try {
if (StringUtils.hasText(text)) {
properties.load(new StringReader(text));
}
} catch (IOException e) {
if (logger.isErrorEnabled()) {
logger.error(e.getMessage(), e);
}
}
return properties;
}
Map<String, Object> attributes = getAnnotationAttributes(nacosProperties);
return resolveProperties(attributes, propertyResolver, defaultProperties);
}
/**
* {@link #resolveProperties(Map, PropertyResolver) Resolve} placeholders of
* {@link NacosProperties @NacosProperties}'s attributes via specified
* {@link PropertyResolver} if present, or try to
* {@link #merge(Properties, Properties) merge} from default properties
*
* @param attributes {@link NacosProperties @NacosProperties}'s attributes
* @param propertyResolver the resolver of properties' placeholder
* @param defaultProperties default properties
* @return a new resolved {@link Properties} properties
* @see #resolveProperties(Map, PropertyResolver)
*/
public static Properties resolveProperties(Map<String, Object> attributes,
PropertyResolver propertyResolver, Properties defaultProperties) {
if (CollectionUtils.isEmpty(attributes)) {
return defaultProperties;
}
Properties resolveProperties = resolveProperties(attributes, propertyResolver);
merge(resolveProperties, defaultProperties);
return resolveProperties;
}
/**
* Resolve placeholders of properties via specified {@link PropertyResolver} if
* present
*
* @param properties The properties
* @param propertyResolver {@link PropertyResolver} instance, for instance,
* {@link Environment}
* @return a new instance of {@link Properties} after resolving.
*/
public static Properties resolveProperties(Map<?, ?> properties,
PropertyResolver propertyResolver) {
PropertiesPlaceholderResolver propertiesPlaceholderResolver = new PropertiesPlaceholderResolver(
propertyResolver);
return propertiesPlaceholderResolver.resolve(properties);
}
/**
* Merge Nacos Properties If any property from target properties is absent
*
* @param targetProperties {@link Properties target Properties}
* @param sourceProperties {@link Properties source Properties}
*/
protected static void merge(Properties targetProperties,
Properties sourceProperties) {
if (CollectionUtils.isEmpty(sourceProperties)) {
return;
}
for (Map.Entry entry : sourceProperties.entrySet()) {
String propertyName = (String) entry.getKey();
if (!targetProperties.containsKey(propertyName)) {
String propertyValue = (String) entry.getValue();
targetProperties.setProperty(propertyName, propertyValue);
}
}
}
/**
* Get content from {@link ConfigService} via dataId and groupId
*
* @param configService {@link ConfigService}
* @param dataId dataId
* @param groupId groupId
* @return If available , return content , or <code>null</code>
*/
public static String getContent(ConfigService configService, String dataId,
String groupId) {
String content = null;
try {
content = configService.getConfig(dataId, groupId, DEFAULT_TIMEOUT);
}
catch (NacosException e) {
if (logger.isErrorEnabled()) {
logger.error("Can't get content from dataId : " + dataId + " , groupId : "
+ groupId, e);
}
}
return content;
}
/**
* bind properties to bean
*
* @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;
}
Field[] fields = target.getDeclaredFields();
for (Field field : fields) {
String mergePropertyName = propertyName + "."
+ NacosUtils.resolvePropertyName(field);
bindBean(mergePropertyName, field.getType(), configProperties,
propertyValues);
}
}
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;
}
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}
* *
@ -32,42 +32,43 @@ import java.util.Properties;
*/ */
public class PropertiesPlaceholderResolver { public class PropertiesPlaceholderResolver {
private final PropertyResolver propertyResolver; private final PropertyResolver propertyResolver;
public PropertiesPlaceholderResolver(PropertyResolver propertyResolver) { public PropertiesPlaceholderResolver(PropertyResolver propertyResolver) {
this.propertyResolver = propertyResolver; this.propertyResolver = propertyResolver;
} }
/** /**
* Resolve placeholders in specified {@link Annotation annotation} * Resolve placeholders in specified {@link Annotation annotation}
* *
* @param annotation {@link Annotation annotation} * @param annotation {@link Annotation annotation}
* @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
return resolve(attributes); .getAnnotationAttributes(annotation);
} return resolve(attributes);
}
/** /**
* Resolve placeholders in specified {@link Map properties} * Resolve placeholders in specified {@link Map properties}
* *
* @param properties {@link Map source properties} * @param properties {@link Map source properties}
* @return Resolved {@link Properties source properties} * @return Resolved {@link Properties source properties}
*/ */
public Properties resolve(Map<?, ?> properties) { public Properties resolve(Map<?, ?> properties) {
Properties resolvedProperties = new Properties(); Properties resolvedProperties = new Properties();
for (Map.Entry<?, ?> entry : properties.entrySet()) { for (Map.Entry<?, ?> entry : properties.entrySet()) {
if (entry.getValue() instanceof CharSequence) { if (entry.getValue() instanceof CharSequence) {
String key = String.valueOf(entry.getKey()); String key = String.valueOf(entry.getKey());
String value = String.valueOf(entry.getValue()); String value = String.valueOf(entry.getValue());
String resolvedValue = propertyResolver.resolvePlaceholders(value); String resolvedValue = propertyResolver.resolvePlaceholders(value);
if (StringUtils.hasText(resolvedValue)) { // set properties if has test if (StringUtils.hasText(resolvedValue)) { // set properties if has test
resolvedProperties.setProperty(key, resolvedValue); resolvedProperties.setProperty(key, resolvedValue);
} }
} }
} }
return resolvedProperties; return resolvedProperties;
} }
} }

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
@ -36,80 +37,84 @@ import java.util.Properties;
*/ */
public class NacosConfigLoader { public class NacosConfigLoader {
private final ConfigurableEnvironment environment; private final ConfigurableEnvironment environment;
private final ConversionService conversionService; private final ConversionService conversionService;
private final PropertiesPlaceholderResolver resolver; private final PropertiesPlaceholderResolver resolver;
private NacosServiceFactory nacosServiceFactory; private NacosServiceFactory nacosServiceFactory;
private ConfigService configService; private ConfigService configService;
public NacosConfigLoader(ConfigurableEnvironment environment) { public NacosConfigLoader(ConfigurableEnvironment environment) {
this.environment = environment; this.environment = environment;
this.conversionService = environment.getConversionService(); this.conversionService = environment.getConversionService();
this.resolver = new PropertiesPlaceholderResolver(environment); this.resolver = new PropertiesPlaceholderResolver(environment);
} }
/** /**
* Load Nacos config vid dataId, groupId and {@link NacosProperties} * Load Nacos config vid dataId, groupId and {@link NacosProperties}
* *
* @param dataId dataId * @param dataId dataId
* @param groupId groupId * @param groupId groupId
* @param nacosProperties {@link NacosProperties} * @param nacosProperties {@link NacosProperties}
* @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)
Properties properties = resolver.resolve(nacosProperties); throws RuntimeException {
return load(dataId, groupId, properties); Properties properties = resolver.resolve(nacosProperties);
} return load(dataId, groupId, properties);
}
/** /**
* Load Nacos config vid dataId, groupId and {@link Properties acos Properties} * Load Nacos config vid dataId, groupId and {@link Properties acos Properties}
* *
* @param dataId dataId * @param dataId dataId
* @param groupId groupId * @param groupId groupId
* @param nacosProperties {@link Properties acos Properties} * @param nacosProperties {@link Properties acos Properties}
* @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)
try { throws RuntimeException {
configService = nacosServiceFactory != null ? try {
nacosServiceFactory.createConfigService(nacosProperties) : configService = nacosServiceFactory != null
NacosFactory.createConfigService(nacosProperties); ? nacosServiceFactory.createConfigService(nacosProperties)
} catch (NacosException e) { : NacosFactory.createConfigService(nacosProperties);
throw new RuntimeException("ConfigService can't be created with dataId :" }
+ dataId + " , groupId : " + groupId + " , properties : " + nacosProperties catch (NacosException e) {
, e); throw new RuntimeException("ConfigService can't be created with dataId :"
} + dataId + " , groupId : " + groupId + " , properties : "
return NacosUtils.getContent(configService, dataId, groupId); + nacosProperties, e);
} }
return NacosUtils.getContent(configService, dataId, groupId);
}
/** /**
* Load target class object from Nacos config * Load target class object from Nacos config
* *
* @param dataId dataId * @param dataId dataId
* @param groupId groupId * @param groupId groupId
* @param nacosProperties {@link NacosProperties} * @param nacosProperties {@link NacosProperties}
* @param targetClass target class * @param targetClass target class
* @param <T> target class * @param <T> target class
* @return target class object * @return target class object
* @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,
String config = load(dataId, groupId, nacosProperties); Class<T> targetClass) throws RuntimeException {
return conversionService.convert(config, targetClass); String config = load(dataId, groupId, nacosProperties);
} return conversionService.convert(config, targetClass);
}
public void setNacosServiceFactory(NacosServiceFactory nacosServiceFactory) { public void setNacosServiceFactory(NacosServiceFactory nacosServiceFactory) {
this.nacosServiceFactory = nacosServiceFactory; this.nacosServiceFactory = nacosServiceFactory;
} }
public ConfigService getConfigService() { public ConfigService getConfigService() {
return configService; return configService;
} }
} }

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,46 +51,55 @@ 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"))
private ConfigService configService2;
@NacosInjected(properties = @NacosProperties(encode = "GBK"))
private ConfigService configService3;
@NacosInjected
private NamingService namingService;
@NacosInjected(properties = @NacosProperties(encode = "UTF-8"))
private NamingService namingService2;
@NacosInjected(properties = @NacosProperties(encode = "GBK"))
private NamingService namingService3;
@NacosInjected(properties = @NacosProperties(encode = "UTF-8")) @Bean(name = ApplicationContextHolder.BEAN_NAME)
private ConfigService configService2; public ApplicationContextHolder applicationContextHolder(
ApplicationContext applicationContext) {
ApplicationContextHolder applicationContextHolder = new ApplicationContextHolder();
applicationContextHolder.setApplicationContext(applicationContext);
return applicationContextHolder;
}
@NacosInjected(properties = @NacosProperties(encode = "GBK")) @Override
private ConfigService configService3; protected String getServerAddressPropertyName() {
return "server.addr";
}
@NacosInjected @Test
private NamingService namingService; public void testInjection() {
@NacosInjected(properties = @NacosProperties(encode = "UTF-8")) Assert.assertEquals(configService, configService2);
private NamingService namingService2; Assert.assertNotEquals(configService2, configService3);
@NacosInjected(properties = @NacosProperties(encode = "GBK")) Assert.assertEquals(namingService, namingService2);
private NamingService namingService3; Assert.assertNotEquals(namingService2, namingService3);
}
@Test @Test
public void testInjection() { public void test() throws NacosException {
configService.publishConfig(DATA_ID, GROUP_ID, CONTENT);
Assert.assertEquals(configService, configService2); Assert.assertEquals(CONTENT, configService.getConfig(DATA_ID, GROUP_ID, 5000));
Assert.assertNotEquals(configService2, configService3); }
Assert.assertEquals(namingService, namingService2);
Assert.assertNotEquals(namingService2, namingService3);
}
@Test
public void test() throws NacosException {
configService.publishConfig(DATA_ID, GROUP_ID, CONTENT);
Assert.assertEquals(CONTENT, configService.getConfig(DATA_ID, GROUP_ID, 5000));
}
} }

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,45 +56,44 @@ 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
private User user;
@NacosInjected
private ConfigService configService;
@Autowired @Override
private User user; protected String getServerAddressPropertyName() {
return "nacos.server-addr";
}
@Override @Override
protected String getServerAddressPropertyName() { protected void init(EmbeddedNacosHttpServer server) {
return "nacos.server-addr"; Map<String, String> config = new HashMap<String, String>(1);
} config.put(DATA_ID_PARAM_NAME, "user");
config.put(GROUP_ID_PARAM_NAME, DEFAULT_GROUP);
config.put(CONTENT_PARAM_NAME, "id=" + 1 + "\nname=mercyblitz");
server.initConfig(config);
}
@Override @Test
protected void init(EmbeddedNacosHttpServer server) { public void testGetConfig() throws Exception {
Map<String, String> config = new HashMap<String, String>(1); configService.publishConfig(DATA_ID, DEFAULT_GROUP, "9527");
config.put(DATA_ID_PARAM_NAME, "user"); Assert.assertEquals("9527",
config.put(GROUP_ID_PARAM_NAME, DEFAULT_GROUP); configService.getConfig(DATA_ID, DEFAULT_GROUP, 5000));
config.put(CONTENT_PARAM_NAME, "id=" + 1 + "\nname=mercyblitz"); }
server.initConfig(config);
}
@NacosInjected @Test
private ConfigService configService; public void testUser() {
Assert.assertEquals(Long.valueOf(1L), user.getId());
@Test Assert.assertEquals("mercyblitz", user.getName());
public void testGetConfig() throws Exception { }
configService.publishConfig(DATA_ID, DEFAULT_GROUP, "9527");
Assert.assertEquals("9527", configService.getConfig(DATA_ID, DEFAULT_GROUP, 5000));
}
@Test
public void testUser() {
Assert.assertEquals(Long.valueOf(1L), user.getId());
Assert.assertEquals("mercyblitz", user.getName());
}
} }

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,101 +65,81 @@ 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,
}) DirtiesContextTestExecutionListener.class,
@TestExecutionListeners({DependencyInjectionTestExecutionListener.class, NacosBeanDefinitionRegistrarTest.class })
DirtiesContextTestExecutionListener.class, NacosBeanDefinitionRegistrarTest.class}) @EnableNacos(globalProperties = @NacosProperties(serverAddr = "${server.addr}"))
@EnableNacos(globalProperties = @NacosProperties(serverAddr = "${serverAddr}"))
@EnableNacosConfig @EnableNacosConfig
@EnableNacosDiscovery @EnableNacosDiscovery
public class NacosBeanDefinitionRegistrarTest extends AbstractNacosHttpServerTestExecutionListener { public class NacosBeanDefinitionRegistrarTest
extends AbstractNacosHttpServerTestExecutionListener {
@Override @Autowired
protected String getServerAddressPropertyName() { @Qualifier(NacosBeanUtils.GLOBAL_NACOS_PROPERTIES_BEAN_NAME)
return "serverAddr"; 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;
@Bean @Override
public Config config() { protected String getServerAddressPropertyName() {
return new Config(); return "server.addr";
} }
@Autowired @Bean
@Qualifier(NacosBeanUtils.GLOBAL_NACOS_PROPERTIES_BEAN_NAME) public Config config() {
private Properties globalProperties; return new Config();
}
@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
public void testGetConfig() throws Exception {
configService.publishConfig(DATA_ID, DEFAULT_GROUP, "9527");
Assert.assertEquals("9527", configService.getConfig(DATA_ID, DEFAULT_GROUP, 5000));
}
@Test
public void testGetConfig() throws Exception {
configService.publishConfig(DATA_ID, DEFAULT_GROUP, "9527");
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
* *
@ -30,57 +37,82 @@ import static com.alibaba.nacos.spring.context.annotation.config.EnableNacosConf
*/ */
public class EnableNacosConfigTest { 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, "", "test-value", ""); testResolvePlaceholder(ENDPOINT_PLACEHOLDER, "nacos.endpoint", "test-value",
"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, "", "test-value", ""); testResolvePlaceholder(NAMESPACE_PLACEHOLDER, "nacos.namespace", "test-value",
"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, "", "test-value", ""); testResolvePlaceholder(ACCESS_KEY_PLACEHOLDER, "nacos.access-key", "test-value",
"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, "", "test-value", ""); testResolvePlaceholder(SECRET_KEY_PLACEHOLDER, "nacos.secret-key", "test-value",
"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, "", "test-value", ""); testResolvePlaceholder(SERVER_ADDR_PLACEHOLDER, "nacos.server-addr", "test-value",
"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, "", "test-value", ""); testResolvePlaceholder(CONTEXT_PATH_PLACEHOLDER, "nacos.context-path",
"test-value", "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, "", "test-value", ""); testResolvePlaceholder(CLUSTER_NAME_PLACEHOLDER, "nacos.cluster-name",
"test-value", "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, "", "test-value", "UTF-8"); testResolvePlaceholder(ENCODE_PLACEHOLDER, "nacos.encode", "test-value",
} "test-value");
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,
MockEnvironment environment = new MockEnvironment(); String propertyValue, String expectValue) {
environment.setProperty(propertyName, propertyValue); MockEnvironment environment = new MockEnvironment();
String resolvedValue = environment.resolvePlaceholders(placeholder); environment.setProperty(propertyName, propertyValue);
Assert.assertEquals(expectValue, resolvedValue); String resolvedValue = environment.resolvePlaceholders(placeholder);
} Assert.assertEquals(expectValue, resolvedValue);
}
} }

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,20 +42,19 @@ 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
@Qualifier(CONFIG_GLOBAL_NACOS_PROPERTIES_BEAN_NAME)
private Properties properties;
@Autowired @Test
@Qualifier(CONFIG_GLOBAL_NACOS_PROPERTIES_BEAN_NAME) public void testRegisterBeanDefinitions() {
private Properties properties;
@Test }
public void testRegisterBeanDefinitions() {
}
} }

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,65 +59,87 @@ 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, NacosConfigListenerMethodProcessor.class,
ConfigServiceBeanBuilder.class, NacosConfigListenerMethodProcessorTest.class })
AnnotationNacosInjectedBeanPostProcessor.class, @TestExecutionListeners({ DependencyInjectionTestExecutionListener.class,
NacosConfigListenerMethodProcessor.class, DirtiesContextTestExecutionListener.class,
NacosConfigListenerMethodProcessorTest.class, NacosConfigListenerMethodProcessorTest.class })
@EnableNacosConfig(globalProperties = @NacosProperties(serverAddr = "${server.addr}"))
public class NacosConfigListenerMethodProcessorTest
extends AbstractNacosHttpServerTestExecutionListener {
}) @Autowired
public class NacosConfigListenerMethodProcessorTest { private Listeners listeners;
@NacosInjected
private ConfigService configService;
private volatile boolean received = false;
@Autowired @Bean(name = ApplicationContextHolder.BEAN_NAME)
private Listeners listeners; public ApplicationContextHolder applicationContextHolder(
ApplicationContext applicationContext) {
ApplicationContextHolder applicationContextHolder = new ApplicationContextHolder();
applicationContextHolder.setApplicationContext(applicationContext);
return applicationContextHolder;
}
@NacosInjected @Override
private ConfigService configService; protected String getServerAddressPropertyName() {
return "server.addr";
}
@PostConstruct @PostConstruct
public void initListener() throws NacosException { public void initListener() throws NacosException {
configService.addListener(DATA_ID, DEFAULT_GROUP, new AbstractListener() { configService.addListener(DATA_ID, DEFAULT_GROUP, new AbstractListener() {
@Override @Override
public void receiveConfigInfo(String config) { public void receiveConfigInfo(String config) {
assertEquals("9527", config); // asserts true assertEquals("9527", config); // asserts true
} }
}); });
} }
@NacosConfigListener(dataId = DATA_ID) @NacosConfigListener(dataId = DATA_ID)
public void onMessage(String config) { public void onMessage(String config) {
assertEquals("9527", config); // asserts true assertEquals("9527", config); // asserts true
} }
@NacosConfigListener(dataId = DATA_ID) @NacosConfigListener(dataId = DATA_ID)
public void onInteger(Integer value) { public void onInteger(Integer value) {
assertEquals(Integer.valueOf(9527), value); // asserts true assertEquals(Integer.valueOf(9527), value); // asserts true
} }
@NacosConfigListener(dataId = DATA_ID) @NacosConfigListener(dataId = DATA_ID)
public void onInt(int value) { public void onInt(int value) {
assertEquals(9527, value); // asserts true assertEquals(9527, value); // asserts true
} }
@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");
assertNull(listeners.getIntegerValue()); // asserts true
assertEquals(Double.valueOf(9527), listeners.getDoubleValue()); // asserts true
}
Thread.sleep(3000);
@Test assertNull(listeners.getIntegerValue()); // asserts true
public void testPublishUser() throws NacosException { assertEquals(Double.valueOf(9527), listeners.getDoubleValue()); // asserts true
configService.publishConfig("user", DEFAULT_GROUP, "{\"id\":1,\"name\":\"mercyblitz\"}"); }
}
@NacosConfigListener(dataId = "user", converter = UserNacosConfigConverter.class) @Test
public void onUser(User user) { public void testPublishUser() throws NacosException, InterruptedException {
assertEquals(Long.valueOf(1L), user.getId()); configService.publishConfig("user", DEFAULT_GROUP,
assertEquals("mercyblitz", user.getName()); "{\"id\":1,\"name\":\"mercyblitz\"}");
} int cnt = 3;
while (cnt >= 0 && !received) {
Thread.sleep(1000);
cnt--;
}
}
@NacosConfigListener(dataId = "user", converter = UserNacosConfigConverter.class)
public void onUser(User user) {
assertEquals(Long.valueOf(1L), user.getId());
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,107 +35,113 @@ import org.springframework.mock.env.MockEnvironment;
*/ */
public class NacosPropertiesTest { public class NacosPropertiesTest {
@EnableNacos(globalProperties = @NacosProperties) @Test
private static class NacosPropertiesDefaultValues { public void testConstants() {
} Assert.assertEquals("nacos.", NacosProperties.PREFIX);
Assert.assertEquals("endpoint", NacosProperties.ENDPOINT);
Assert.assertEquals("namespace", NacosProperties.NAMESPACE);
Assert.assertEquals("access-key", NacosProperties.ACCESS_KEY);
Assert.assertEquals("secret-key", NacosProperties.SECRET_KEY);
Assert.assertEquals("server-addr", NacosProperties.SERVER_ADDR);
Assert.assertEquals("context-path", NacosProperties.CONTEXT_PATH);
Assert.assertEquals("cluster-name", NacosProperties.CLUSTER_NAME);
Assert.assertEquals("encode", NacosProperties.ENCODE);
}
@EnableNacos( @Test
globalProperties = public void testAttributeDefaultValues() {
@NacosProperties( NacosProperties nacosProperties = getDefaultNacosProperties();
endpoint = "e", Assert.assertEquals("${nacos.endpoint:}", nacosProperties.endpoint());
namespace = "n", Assert.assertEquals("${nacos.namespace:}", nacosProperties.namespace());
accessKey = "a", Assert.assertEquals("${nacos.access-key:}", nacosProperties.accessKey());
secretKey = "s", Assert.assertEquals("${nacos.secret-key:}", nacosProperties.secretKey());
serverAddr = "127.0.0.1", Assert.assertEquals("${nacos.server-addr:}", nacosProperties.serverAddr());
contextPath = "/", Assert.assertEquals("${nacos.context-path:}", nacosProperties.contextPath());
clusterName = "c", Assert.assertEquals("${nacos.cluster-name:}", nacosProperties.clusterName());
encode = "GBK" Assert.assertEquals("${nacos.encode:UTF-8}", nacosProperties.encode());
) }
)
private static class NacosPropertiesValues {
}
@Test @Test
public void testConstants() { public void testAttributeValues() {
Assert.assertEquals("nacos.", NacosProperties.PREFIX); EnableNacos enableNacos = NacosPropertiesValues.class
Assert.assertEquals("endpoint", NacosProperties.ENDPOINT); .getAnnotation(EnableNacos.class);
Assert.assertEquals("namespace", NacosProperties.NAMESPACE); NacosProperties nacosProperties = enableNacos.globalProperties();
Assert.assertEquals("access-key", NacosProperties.ACCESS_KEY); Assert.assertEquals("e", nacosProperties.endpoint());
Assert.assertEquals("secret-key", NacosProperties.SECRET_KEY); Assert.assertEquals("n", nacosProperties.namespace());
Assert.assertEquals("server-addr", NacosProperties.SERVER_ADDR); Assert.assertEquals("a", nacosProperties.accessKey());
Assert.assertEquals("context-path", NacosProperties.CONTEXT_PATH); Assert.assertEquals("s", nacosProperties.secretKey());
Assert.assertEquals("cluster-name", NacosProperties.CLUSTER_NAME); Assert.assertEquals("127.0.0.1", nacosProperties.serverAddr());
Assert.assertEquals("encode", NacosProperties.ENCODE); Assert.assertEquals("/", nacosProperties.contextPath());
} Assert.assertEquals("c", nacosProperties.clusterName());
Assert.assertEquals("GBK", nacosProperties.encode());
}
@Test @Test
public void testAttributeDefaultValues() { public void testAttributeResolvedDefaultValues() {
NacosProperties nacosProperties = getDefaultNacosProperties(); NacosProperties nacosProperties = getDefaultNacosProperties();
Assert.assertEquals("${nacos.endpoint:}", nacosProperties.endpoint()); MockEnvironment environment = new MockEnvironment();
Assert.assertEquals("${nacos.namespace:}", nacosProperties.namespace()); Assert.assertEquals("",
Assert.assertEquals("${nacos.access-key:}", nacosProperties.accessKey()); environment.resolvePlaceholders(nacosProperties.endpoint()));
Assert.assertEquals("${nacos.secret-key:}", nacosProperties.secretKey()); Assert.assertEquals("",
Assert.assertEquals("${nacos.server-addr:}", nacosProperties.serverAddr()); environment.resolvePlaceholders(nacosProperties.namespace()));
Assert.assertEquals("${nacos.context-path:}", nacosProperties.contextPath()); Assert.assertEquals("",
Assert.assertEquals("${nacos.cluster-name:}", nacosProperties.clusterName()); environment.resolvePlaceholders(nacosProperties.accessKey()));
Assert.assertEquals("${nacos.encode:UTF-8}", nacosProperties.encode()); Assert.assertEquals("",
} 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
public void testAttributeValues() { public void testAttributeResolvedPropertyValues() {
EnableNacos enableNacos = NacosPropertiesValues.class.getAnnotation(EnableNacos.class); NacosProperties nacosProperties = getDefaultNacosProperties();
NacosProperties nacosProperties = enableNacos.globalProperties(); MockEnvironment environment = new MockEnvironment();
Assert.assertEquals("e", nacosProperties.endpoint()); environment.setProperty("nacos.endpoint", "e");
Assert.assertEquals("n", nacosProperties.namespace()); environment.setProperty("nacos.namespace", "n");
Assert.assertEquals("a", nacosProperties.accessKey()); environment.setProperty("nacos.access-key", "a");
Assert.assertEquals("s", nacosProperties.secretKey()); environment.setProperty("nacos.secret-key", "s");
Assert.assertEquals("127.0.0.1", nacosProperties.serverAddr()); environment.setProperty("nacos.server-addr", "127.0.0.1");
Assert.assertEquals("/", nacosProperties.contextPath()); environment.setProperty("nacos.context-path", "/");
Assert.assertEquals("c", nacosProperties.clusterName()); environment.setProperty("nacos.cluster-name", "c");
Assert.assertEquals("GBK", nacosProperties.encode()); environment.setProperty("nacos.encode", "GBK");
}
@Test Assert.assertEquals("e",
public void testAttributeResolvedDefaultValues() { environment.resolvePlaceholders(nacosProperties.endpoint()));
NacosProperties nacosProperties = getDefaultNacosProperties(); Assert.assertEquals("n",
MockEnvironment environment = new MockEnvironment(); environment.resolvePlaceholders(nacosProperties.namespace()));
Assert.assertEquals("", environment.resolvePlaceholders(nacosProperties.endpoint())); Assert.assertEquals("a",
Assert.assertEquals("", environment.resolvePlaceholders(nacosProperties.namespace())); environment.resolvePlaceholders(nacosProperties.accessKey()));
Assert.assertEquals("", environment.resolvePlaceholders(nacosProperties.accessKey())); Assert.assertEquals("s",
Assert.assertEquals("", environment.resolvePlaceholders(nacosProperties.secretKey())); environment.resolvePlaceholders(nacosProperties.secretKey()));
Assert.assertEquals("", environment.resolvePlaceholders(nacosProperties.serverAddr())); Assert.assertEquals("127.0.0.1",
Assert.assertEquals("", environment.resolvePlaceholders(nacosProperties.contextPath())); environment.resolvePlaceholders(nacosProperties.serverAddr()));
Assert.assertEquals("", environment.resolvePlaceholders(nacosProperties.clusterName())); Assert.assertEquals("/",
Assert.assertEquals("UTF-8", environment.resolvePlaceholders(nacosProperties.encode())); environment.resolvePlaceholders(nacosProperties.contextPath()));
} Assert.assertEquals("c",
environment.resolvePlaceholders(nacosProperties.clusterName()));
Assert.assertEquals("GBK",
environment.resolvePlaceholders(nacosProperties.encode()));
}
@Test private NacosProperties getDefaultNacosProperties() {
public void testAttributeResolvedPropertyValues() { EnableNacos enableNacos = NacosPropertiesDefaultValues.class
NacosProperties nacosProperties = getDefaultNacosProperties(); .getAnnotation(EnableNacos.class);
MockEnvironment environment = new MockEnvironment(); NacosProperties nacosProperties = enableNacos.globalProperties();
environment.setProperty("nacos.endpoint", "e"); return nacosProperties;
environment.setProperty("nacos.namespace", "n"); }
environment.setProperty("nacos.access-key", "a");
environment.setProperty("nacos.secret-key", "s");
environment.setProperty("nacos.server-addr", "127.0.0.1");
environment.setProperty("nacos.context-path", "/");
environment.setProperty("nacos.cluster-name", "c");
environment.setProperty("nacos.encode", "GBK");
Assert.assertEquals("e", environment.resolvePlaceholders(nacosProperties.endpoint())); @EnableNacos(globalProperties = @NacosProperties)
Assert.assertEquals("n", environment.resolvePlaceholders(nacosProperties.namespace())); private static class NacosPropertiesDefaultValues {
Assert.assertEquals("a", environment.resolvePlaceholders(nacosProperties.accessKey())); }
Assert.assertEquals("s", 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() { @EnableNacos(globalProperties = @NacosProperties(endpoint = "e", namespace = "n", accessKey = "a", secretKey = "s", serverAddr = "127.0.0.1", contextPath = "/", clusterName = "c", encode = "GBK"))
EnableNacos enableNacos = NacosPropertiesDefaultValues.class.getAnnotation(EnableNacos.class); private static class NacosPropertiesValues {
NacosProperties nacosProperties = enableNacos.globalProperties(); }
return nacosProperties;
}
} }

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,120 +67,136 @@ 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@"
+ System.currentTimeMillis();
private static final String TEST_CONTENT = TEST_PROPERTY_NAME + "="
+ TEST_PROPERTY_VALUE + System.getProperty("line.separator")
+ "PATH = /My/Path";
@NacosInjected
private ConfigService configService;
private static final String TEST_PROPERTY_VALUE = "mercyblitz@" + System.currentTimeMillis(); @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, TEST_CONTENT);
httpServer.initConfig(config);
}
private static final String TEST_CONTENT = TEST_PROPERTY_NAME + "=" + TEST_PROPERTY_VALUE @Override
+ System.getProperty("line.separator") protected String getServerAddressPropertyName() {
+ "PATH = /My/Path"; return "server.addr";
}
@NacosPropertySources({ @Bean(name = ApplicationContextHolder.BEAN_NAME)
@NacosPropertySource( public ApplicationContextHolder applicationContextHolder(
name = "second", ApplicationContext applicationContext) {
dataId = DATA_ID, ApplicationContextHolder applicationContextHolder = new ApplicationContextHolder();
first = true, applicationContextHolder.setApplicationContext(applicationContext);
before = SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME, return applicationContextHolder;
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 {
} @Test
public void testFirstOrder() throws NacosException {
@NacosPropertySource( AnnotationConfigApplicationContext context = createContext(DATA_ID, DEFAULT_GROUP,
dataId = DATA_ID, TEST_CONTENT);
before = SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME,
after = SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME)
private static class RelativeOrderNacosPropertySource {
} context.register(FirstOrderNacosPropertySource.class);
context.refresh();
@Test ConfigurableEnvironment environment = context.getEnvironment();
public void testFirstOrder() throws NacosException {
AnnotationConfigApplicationContext context = createContext(DATA_ID, DEFAULT_GROUP, TEST_CONTENT); PropertySource propertySource = environment.getPropertySources().get("first");
context.register(FirstOrderNacosPropertySource.class); PropertySource firstPropertySource = environment.getPropertySources().iterator()
.next();
context.refresh(); Assert.assertNotNull(propertySource);
ConfigurableEnvironment environment = context.getEnvironment(); Assert.assertEquals(propertySource, firstPropertySource);
PropertySource propertySource = environment.getPropertySources().get("first"); String systemProperty = System.getProperty(TEST_PROPERTY_NAME);
PropertySource firstPropertySource = environment.getPropertySources().iterator().next(); String propertyValue = environment.getProperty(TEST_PROPERTY_NAME);
Assert.assertNotNull(propertySource); Assert.assertNotEquals(systemProperty, propertyValue);
Assert.assertEquals(propertySource, firstPropertySource); Assert.assertEquals(TEST_PROPERTY_VALUE, propertyValue);
String systemProperty = System.getProperty(TEST_PROPERTY_NAME); Assert.assertEquals(TEST_PROPERTY_VALUE,
propertySource.getProperty(TEST_PROPERTY_NAME));
String propertyValue = environment.getProperty(TEST_PROPERTY_NAME); }
Assert.assertNotEquals(systemProperty, propertyValue); @Test
public void testRelativeOrder() throws NacosException {
Assert.assertEquals(TEST_PROPERTY_VALUE, propertyValue); AnnotationConfigApplicationContext context = createContext(DATA_ID, DEFAULT_GROUP,
TEST_CONTENT);
Assert.assertEquals(TEST_PROPERTY_VALUE, propertySource.getProperty(TEST_PROPERTY_NAME)); context.register(RelativeOrderNacosPropertySource.class);
} context.refresh();
@Test ConfigurableEnvironment environment = context.getEnvironment();
public void testRelativeOrder() throws NacosException {
AnnotationConfigApplicationContext context = createContext(DATA_ID, DEFAULT_GROUP, TEST_CONTENT); PropertySource propertySource = environment.getPropertySources().get("before");
context.register(RelativeOrderNacosPropertySource.class); // Java System Properties before Nacos Properties
String systemProperty = System.getProperty(TEST_PROPERTY_NAME);
String propertyValue = environment.getProperty(TEST_PROPERTY_NAME);
context.refresh(); Assert.assertEquals(systemProperty, propertyValue);
Assert.assertNotNull(TEST_PROPERTY_VALUE, propertyValue);
ConfigurableEnvironment environment = context.getEnvironment(); // Environment Variables after Nacos Properties
String path = System.getenv().get("PATH");
propertyValue = environment.getProperty("PATH");
PropertySource propertySource = environment.getPropertySources().get("before"); Assert.assertNotNull(path, propertyValue);
Assert.assertEquals("/My/Path", propertyValue);
}
// Java System Properties before Nacos Properties private AnnotationConfigApplicationContext createContext(String dataId,
String systemProperty = System.getProperty(TEST_PROPERTY_NAME); String groupId, String content) throws NacosException {
String propertyValue = environment.getProperty(TEST_PROPERTY_NAME); AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
Assert.assertEquals(systemProperty, propertyValue); ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
Assert.assertNotNull(TEST_PROPERTY_VALUE, propertyValue);
// Environment Variables after Nacos Properties configService.publishConfig(dataId, groupId, content);
String path = System.getenv().get("PATH");
propertyValue = environment.getProperty("PATH");
Assert.assertNotNull(path, propertyValue); beanFactory.registerSingleton(CONFIG_SERVICE_BEAN_NAME, configService);
Assert.assertEquals("/My/Path", propertyValue);
}
private AnnotationConfigApplicationContext createContext(String dataId, String groupId, String content) throws NacosException { context.register(AnnotationNacosInjectedBeanPostProcessor.class,
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); NacosPropertySourcePostProcessor.class, ConfigServiceBeanBuilder.class,
AnnotationNacosPropertySourceBuilder.class, TestConfiguration.class,
TestApplicationHolder.class);
return context;
}
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory(); @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 {
ConfigService configService = new MockConfigService(); }
configService.publishConfig(dataId, groupId, content); @NacosPropertySource(dataId = DATA_ID, before = SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, after = SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME)
private static class RelativeOrderNacosPropertySource {
beanFactory.registerSingleton(CONFIG_SERVICE_BEAN_NAME, configService); }
context.register(TestConfiguration.class, AnnotationNacosInjectedBeanPostProcessor.class,
NacosPropertySourcePostProcessor.class, ConfigServiceBeanBuilder.class,
AnnotationNacosPropertySourceBuilder.class);
return context;
}
} }

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