16
16
17
17
package com .alibaba .cloud .nacos .annotation ;
18
18
19
+ import java .beans .PropertyDescriptor ;
19
20
import java .lang .reflect .Field ;
20
21
import java .lang .reflect .Method ;
21
22
import java .lang .reflect .Type ;
37
38
import org .slf4j .Logger ;
38
39
import org .slf4j .LoggerFactory ;
39
40
41
+ import org .springframework .beans .BeanUtils ;
42
+ import org .springframework .beans .BeanWrapper ;
43
+ import org .springframework .beans .BeanWrapperImpl ;
40
44
import org .springframework .beans .BeansException ;
45
+ import org .springframework .beans .NotReadablePropertyException ;
46
+ import org .springframework .beans .factory .annotation .AnnotatedBeanDefinition ;
47
+ import org .springframework .beans .factory .config .BeanDefinition ;
41
48
import org .springframework .beans .factory .config .BeanPostProcessor ;
42
49
import org .springframework .context .ApplicationContext ;
43
50
import org .springframework .context .ApplicationContextAware ;
51
+ import org .springframework .context .support .GenericApplicationContext ;
44
52
import org .springframework .core .PriorityOrdered ;
45
53
import org .springframework .core .annotation .AnnotationUtils ;
54
+ import org .springframework .core .annotation .MergedAnnotation ;
55
+ import org .springframework .core .annotation .MergedAnnotations ;
56
+ import org .springframework .core .type .MethodMetadata ;
46
57
import org .springframework .util .ReflectionUtils ;
47
58
48
59
public class NacosAnnotationProcessor implements BeanPostProcessor , PriorityOrdered , ApplicationContextAware {
@@ -68,12 +79,12 @@ private String getGroupKeyContent(String dataId, String group) throws Exception
68
79
}
69
80
synchronized (this ) {
70
81
if (!groupKeyCache .containsKey (GroupKey .getKey (dataId , group ))) {
71
- String content = nacosConfigManager .getConfigService ().getConfig (dataId , group , 5000 );
82
+ String content = getNacosConfigManager () .getConfigService ().getConfig (dataId , group , 5000 );
72
83
groupKeyCache .put (GroupKey .getKey (dataId , group ), new AtomicReference <>(content ));
73
84
74
85
log .info ("[Nacos Config] Listening config for annotation: dataId={}, group={}" , dataId ,
75
86
group );
76
- nacosConfigManager .getConfigService ().addListener (dataId , group , new AbstractListener () {
87
+ getNacosConfigManager () .getConfigService ().addListener (dataId , group , new AbstractListener () {
77
88
@ Override
78
89
public void receiveConfigInfo (String s ) {
79
90
groupKeyCache .get (GroupKey .getKey (dataId , group )).set (s );
@@ -94,13 +105,20 @@ public String toString() {
94
105
95
106
@ Override
96
107
public Object postProcessBeforeInitialization (Object bean , String beanName ) throws BeansException {
97
- return BeanPostProcessor .super .postProcessBeforeInitialization (bean , beanName );
108
+ BeanPostProcessor .super .postProcessBeforeInitialization (bean , beanName );
109
+ return bean ;
98
110
}
99
111
100
112
@ Override
101
113
public Object postProcessAfterInitialization (Object bean , String beanName ) throws BeansException {
102
114
BeanPostProcessor .super .postProcessAfterInitialization (bean , beanName );
103
115
Class clazz = bean .getClass ();
116
+ NacosConfig annotationBean = AnnotationUtils .findAnnotation (clazz , NacosConfig .class );
117
+ if (annotationBean != null ) {
118
+ handleBeanNacosConfigAnnotation (annotationBean .dataId (), annotationBean .group (), annotationBean .key (), beanName , bean , annotationBean .defaultValue ());
119
+ return bean ;
120
+ }
121
+
104
122
for (Field field : getBeanFields (clazz )) {
105
123
handleFiledAnnotation (bean , beanName , field );
106
124
}
@@ -129,6 +147,86 @@ private void handleFiledAnnotation(Object bean, String beanName, Field field) {
129
147
}
130
148
}
131
149
150
+ private void handleBeanNacosConfigAnnotation (String dataId , String group , String key , String beanName , Object bean ,
151
+ String defaultValue ) {
152
+ try {
153
+ String config = getDestContent (getGroupKeyContent (dataId , group ), key );
154
+ if (!org .springframework .util .StringUtils .hasText (config )) {
155
+ config = defaultValue ;
156
+ }
157
+ //Init bean properties.
158
+ if (org .springframework .util .StringUtils .hasText (config )) {
159
+ Object targetObject = convertContentToTargetType (config , bean .getClass ());
160
+ //yaml and json to object
161
+ BeanUtils .copyProperties (targetObject , bean , getNullPropertyNames (targetObject ));
162
+ }
163
+ String refreshTargetKey = beanName + "#instance#" ;
164
+ TargetRefreshable currentTarget = targetListenerMap .get (refreshTargetKey );
165
+ if (currentTarget != null ) {
166
+ log .info ("[Nacos Config] reset {} listener from {} to {} " , refreshTargetKey ,
167
+ currentTarget .getTarget (), bean );
168
+ targetListenerMap .get (refreshTargetKey ).setTarget (bean );
169
+ return ;
170
+ }
171
+ log .info ("[Nacos Config] register {} listener on {} " , refreshTargetKey ,
172
+ bean );
173
+ TargetRefreshable listener = null ;
174
+ if (org .springframework .util .StringUtils .hasText (key )) {
175
+ listener = new NacosPropertiesKeyListener (bean , wrapArrayToSet (key )) {
176
+ @ Override
177
+ public void configChanged (ConfigChangeEvent event ) {
178
+ try {
179
+ ConfigChangeItem changeItem = event .getChangeItem (key );
180
+ String newConfig = changeItem == null ? null : changeItem .getNewValue ();
181
+ if (!org .springframework .util .StringUtils .hasText (newConfig )) {
182
+ newConfig = defaultValue ;
183
+ }
184
+ if (org .springframework .util .StringUtils .hasText (newConfig )) {
185
+ Object targetObject = convertContentToTargetType (newConfig , getTarget ().getClass ());
186
+ //yaml and json to object
187
+ BeanUtils .copyProperties (targetObject , getTarget (), getNullPropertyNames (targetObject ));
188
+ }
189
+ }
190
+ catch (Exception e ) {
191
+ throw new RuntimeException (e );
192
+ }
193
+ }
194
+
195
+ @ Override
196
+ public String toString () {
197
+ return String .format ("[spring cloud alibaba nacos config instance key listener , key %s , target %s ] " , key , bean );
198
+ }
199
+ };
200
+ }
201
+ else {
202
+ listener = new NacosConfigRefreshableListener (bean ) {
203
+ @ Override
204
+ public void receiveConfigInfo (String configInfo ) {
205
+ if (!org .springframework .util .StringUtils .hasText (configInfo )) {
206
+ configInfo = defaultValue ;
207
+ }
208
+ if (org .springframework .util .StringUtils .hasText (configInfo )) {
209
+ Object targetObject = convertContentToTargetType (configInfo , bean .getClass ());
210
+ //yaml and json to object
211
+ BeanUtils .copyProperties (targetObject , getTarget ());
212
+ }
213
+ }
214
+
215
+ @ Override
216
+ public String toString () {
217
+ return String .format ("[spring cloud alibaba nacos config instance listener , key %s , target %s ] " , key , bean );
218
+ }
219
+ };
220
+ }
221
+ getNacosConfigManager ().getConfigService ()
222
+ .addListener (dataId , group , listener );
223
+ targetListenerMap .put (refreshTargetKey , listener );
224
+ }
225
+ catch (Exception e ) {
226
+ throw new RuntimeException (e );
227
+ }
228
+ }
229
+
132
230
private void handleMethodNacosConfigKeysChangeListener (NacosConfigKeysListener annotation , String beanName , Object bean ,
133
231
Method method ) {
134
232
String dataId = annotation .dataId ();
@@ -166,7 +264,7 @@ public String toString() {
166
264
}
167
265
};
168
266
nacosPropertiesKeyListener .setLastContent (getGroupKeyContent (dataId , group ));
169
- nacosConfigManager .getConfigService ().addListener (dataId , group ,
267
+ getNacosConfigManager () .getConfigService ().addListener (dataId , group ,
170
268
nacosPropertiesKeyListener );
171
269
targetListenerMap .put (refreshTargetKey , nacosPropertiesKeyListener );
172
270
}
@@ -278,7 +376,7 @@ public String toString() {
278
376
};
279
377
}
280
378
281
- nacosConfigManager .getConfigService ().addListener (dataId , group , listener );
379
+ getNacosConfigManager () .getConfigService ().addListener (dataId , group , listener );
282
380
targetListenerMap .put (refreshTargetKey , listener );
283
381
if (annotation .initNotify () && org .springframework .util .StringUtils .hasText (configInfo )) {
284
382
try {
@@ -415,7 +513,7 @@ public String toString() {
415
513
};
416
514
}
417
515
418
- nacosConfigManager .getConfigService ()
516
+ getNacosConfigManager () .getConfigService ()
419
517
.addListener (dataId , group , listener );
420
518
targetListenerMap .put (refreshTargetKey , listener );
421
519
@@ -500,7 +598,7 @@ public String toString() {
500
598
};
501
599
}
502
600
503
- nacosConfigManager .getConfigService ()
601
+ getNacosConfigManager () .getConfigService ()
504
602
.addListener (dataId , group , listener );
505
603
targetListenerMap .put (refreshTargetKey , listener );
506
604
return true ;
@@ -606,12 +704,58 @@ private void handleMethodAnnotation(final Object bean, String beanName, final Me
606
704
handleMethodNacosConfigListener (configAnnotation , beanName , bean , method );
607
705
return ;
608
706
}
707
+ if (!applicationContext .containsBeanDefinition (beanName )) {
708
+ return ;
709
+ }
710
+ BeanDefinition beanDefinition = ((GenericApplicationContext ) applicationContext ).getBeanDefinition (beanName );
711
+ if (beanDefinition instanceof AnnotatedBeanDefinition ) {
712
+ MethodMetadata factoryMethodMetadata = (((AnnotatedBeanDefinition ) beanDefinition ).getFactoryMethodMetadata ());
713
+ if (factoryMethodMetadata != null ) {
714
+ MergedAnnotations annotations = factoryMethodMetadata .getAnnotations ();
715
+ if (annotations != null && annotations .isPresent (NacosConfig .class )) {
716
+ MergedAnnotation <NacosConfig > nacosConfigMergedAnnotation = annotations .get (NacosConfig .class );
717
+ Map <String , Object > stringObjectMap = nacosConfigMergedAnnotation .asMap ();
718
+ String dataId = (String ) stringObjectMap .get ("dataId" );
719
+ String group = (String ) stringObjectMap .get ("group" );
720
+ String key = (String ) stringObjectMap .get ("key" );
721
+ String defaultValue = (String ) stringObjectMap .get ("defaultValue" );
722
+ handleBeanNacosConfigAnnotation (dataId , group , key , beanName , bean , defaultValue );
723
+ }
724
+ }
725
+ }
609
726
610
727
}
611
728
612
729
@ Override
613
730
public void setApplicationContext (ApplicationContext applicationContext ) throws BeansException {
614
731
this .applicationContext = applicationContext ;
615
- nacosConfigManager = this .applicationContext .getBean (NacosConfigManager .class );
616
732
}
733
+
734
+ private NacosConfigManager getNacosConfigManager () {
735
+ if (nacosConfigManager == null ) {
736
+ nacosConfigManager = this .applicationContext .getBean (NacosConfigManager .class );
737
+ }
738
+ return nacosConfigManager ;
739
+ }
740
+
741
+ private static String [] getNullPropertyNames (Object source ) {
742
+ final BeanWrapper src = new BeanWrapperImpl (source );
743
+ PropertyDescriptor [] pds = src .getPropertyDescriptors ();
744
+ Set <String > nullPropertyNames = new HashSet <>();
745
+ for (PropertyDescriptor pd : pds ) {
746
+ String propertyName = pd .getName ();
747
+ try {
748
+ Object propertyValue = src .getPropertyValue (propertyName );
749
+ if (propertyValue == null ) {
750
+ nullPropertyNames .add (propertyName );
751
+ }
752
+ }
753
+ catch (NotReadablePropertyException e ) {
754
+ //ignore
755
+ nullPropertyNames .add (propertyName );
756
+ }
757
+ }
758
+ return nullPropertyNames .toArray (new String [0 ]);
759
+ }
760
+
617
761
}
0 commit comments