1919import io .microsphere .annotation .Nullable ;
2020import io .microsphere .logging .Logger ;
2121import org .springframework .beans .BeansException ;
22+ import org .springframework .beans .factory .InitializingBean ;
2223import org .springframework .beans .factory .SmartInitializingSingleton ;
23- import org .springframework .beans .factory .config .BeanFactoryPostProcessor ;
24- import org .springframework .beans .factory .config .ConfigurableListableBeanFactory ;
2524import org .springframework .boot .context .properties .ConfigurationProperties ;
2625import org .springframework .boot .context .properties .bind .BindContext ;
2726import org .springframework .boot .context .properties .bind .Bindable ;
3029import org .springframework .context .ApplicationContext ;
3130import org .springframework .context .ApplicationContextAware ;
3231import org .springframework .context .ConfigurableApplicationContext ;
33- import org .springframework .core .ResolvableType ;
34- import org .springframework .core .annotation .AnnotationAttributes ;
3532
3633import java .util .Map ;
3734import java .util .function .Supplier ;
3835
39- import static io .microsphere .collection .MapUtils .newHashMap ;
4036import static io .microsphere .logging .LoggerFactory .getLogger ;
37+ import static io .microsphere .spring .boot .context .properties .bind .ConfigurationPropertiesBeanContext .buildConfigurationPropertiesBeanContexts ;
4138import static io .microsphere .spring .boot .context .properties .bind .util .BindUtils .isBoundProperty ;
4239import static io .microsphere .spring .boot .context .properties .bind .util .BindUtils .isConfigurationPropertiesBean ;
4340import static io .microsphere .spring .boot .context .properties .source .util .ConfigurationPropertyUtils .getPrefix ;
44- import static io .microsphere .spring .boot .context .properties .util .ConfigurationPropertiesUtils .CONFIGURATION_PROPERTIES_CLASS ;
45- import static io .microsphere .spring .boot .context .properties .util .ConfigurationPropertiesUtils .findConfigurationProperties ;
46- import static io .microsphere .spring .core .annotation .AnnotationUtils .getAnnotationAttributes ;
47- import static org .springframework .util .Assert .isInstanceOf ;
41+ import static io .microsphere .spring .context .ApplicationContextUtils .asConfigurableApplicationContext ;
4842
4943/**
5044 * A {@link BindListener} implementation of {@link ConfigurationProperties @ConfigurationProperties} Bean to publish
5650 * @see ConfigurationPropertiesBeanPropertyChangedEvent
5751 * @since 1.0.0
5852 */
59- public class EventPublishingConfigurationPropertiesBeanPropertyChangedListener implements BindListener , BeanFactoryPostProcessor , ApplicationContextAware , SmartInitializingSingleton {
53+ public class EventPublishingConfigurationPropertiesBeanPropertyChangedListener implements BindListener , ApplicationContextAware , InitializingBean , SmartInitializingSingleton {
6054
6155 private static final Logger logger = getLogger (EventPublishingConfigurationPropertiesBeanPropertyChangedListener .class );
6256
63- private static final Class <ConfigurableApplicationContext > CONFIGURABLE_APPLICATION_CONTEXT_CLASS = ConfigurableApplicationContext .class ;
64-
6557 private Map <String , ConfigurationPropertiesBeanContext > beanContexts ;
6658
6759 private ConfigurableApplicationContext context ;
@@ -95,16 +87,14 @@ public <T> void onStart(ConfigurationPropertyName name, Bindable<T> target, Bind
9587 */
9688 @ Override
9789 public void onSuccess (ConfigurationPropertyName name , Bindable <?> target , BindContext context , Object result ) {
98- setConfigurationPropertiesBeanProperty (name , target , context , result );
90+ if (isBound ()) {
91+ setConfigurationPropertiesBeanProperty (name , target , context , result );
92+ }
9993 }
10094
10195 void initConfigurationPropertiesBeanContext (ConfigurationPropertyName name , Bindable <?> target , BindContext context ) {
10296 ConfigurationPropertiesBeanContext configurationPropertiesBeanContext = getConfigurationPropertiesBeanContext (name , target , context );
10397 if (configurationPropertiesBeanContext == null ) {
104- if (logger .isWarnEnabled ()) {
105- logger .warn ("No ConfigurationPropertiesBeanContext was found[name : '{}' , target : {} , depth : {}]" ,
106- name , target , context .getDepth ());
107- }
10898 return ;
10999 }
110100 if (isConfigurationPropertiesBean (context )) {
@@ -116,45 +106,27 @@ void initConfigurationPropertiesBeanContext(ConfigurationPropertyName name, Bind
116106 name , target , context .getDepth ());
117107 }
118108 } else {
119- configurationPropertiesBeanContext .initialize (bean );
109+ configurationPropertiesBeanContext .setBean (bean );
120110 if (logger .isTraceEnabled ()) {
121111 logger .trace ("The ConfigurationPropertiesBean binding is finished[name : '{}' , target : {} , depth : {} , bean : '{}']" ,
122112 name , target , context .getDepth (), bean );
123113 }
124114 }
125- } else {
126- configurationPropertiesBeanContext .initProperty (name , target );
127115 }
128116 }
129117
130118 @ Nullable
131119 private ConfigurationPropertiesBeanContext getConfigurationPropertiesBeanContext (ConfigurationPropertyName name ,
132120 Bindable <?> target , BindContext context ) {
133121 String prefix = getPrefix (name , context );
134- return beanContexts .computeIfAbsent (prefix , p -> newConfigurationPropertiesBeanContext (target , p ));
135- }
136-
137- ConfigurationPropertiesBeanContext newConfigurationPropertiesBeanContext (Bindable <?> target , String prefix ) {
138- ConfigurationProperties annotation = findConfigurationProperties (target );
139- if (annotation == null ) {
140- if (logger .isWarnEnabled ()) {
141- logger .warn ("The ConfigurationPropertiesBeanContext is not created caused by the missing @ConfigurationProperties annotation, target : {}" ,
142- target );
143- }
144- return null ;
145- }
146- AnnotationAttributes annotationAttributes = getAnnotationAttributes (annotation );
147- String actualPrefix = annotationAttributes .getString ("prefix" );
148- if (!prefix .equalsIgnoreCase (actualPrefix )) {
122+ ConfigurationPropertiesBeanContext configurationPropertiesBeanContext = this .beanContexts .get (prefix );
123+ if (configurationPropertiesBeanContext == null ) {
149124 if (logger .isWarnEnabled ()) {
150- logger .warn ("The ConfigurationPropertiesBeanContext is not created caused by the mismatched prefix[expected : '{}' , actual : '{}'], target : {}" ,
151- prefix , actualPrefix , target );
125+ logger .warn ("No ConfigurationPropertiesBeanContext was found[name : '{}' , target : {} , depth : {}] " ,
126+ name , target , context . getDepth () );
152127 }
153- return null ;
154128 }
155-
156- ResolvableType beanType = target .getType ();
157- return new ConfigurationPropertiesBeanContext (beanType , annotationAttributes , prefix , this .context );
129+ return configurationPropertiesBeanContext ;
158130 }
159131
160132 /**
@@ -170,88 +142,48 @@ void setConfigurationPropertiesBeanProperty(ConfigurationPropertyName name, Bind
170142 if (isBoundProperty (context )) {
171143 ConfigurationProperty property = context .getConfigurationProperty ();
172144 ConfigurationPropertiesBeanContext configurationPropertiesBeanContext = getConfigurationPropertiesBeanContext (name , target , context );
173- configurationPropertiesBeanContext .setProperty (property , result , isBound ());
145+ if (configurationPropertiesBeanContext == null ) {
146+ return ;
147+ }
148+ configurationPropertiesBeanContext .setProperty (property , result );
174149 if (logger .isTraceEnabled ()) {
175150 logger .trace ("binding Bean property is finished , configuration property : '{}' , type : '{}' , depth : {} , result : '{}'" , property , target .getType (), context .getDepth (), result );
176151 }
177152 }
178153 }
179154
180- /**
181- * Post-processes the bean factory to initialize the internal map of
182- * {@link ConfigurationPropertiesBeanContext} instances for all
183- * {@link ConfigurationProperties @ConfigurationProperties} beans.
184- *
185- * <h3>Example Usage</h3>
186- * <pre>{@code
187- * EventPublishingConfigurationPropertiesBeanPropertyChangedListener listener =
188- * new EventPublishingConfigurationPropertiesBeanPropertyChangedListener();
189- * listener.postProcessBeanFactory(beanFactory);
190- * }</pre>
191- *
192- * @param beanFactory the bean factory to post-process
193- * @throws BeansException if an error occurs
194- */
195- @ Override
196- public void postProcessBeanFactory (ConfigurableListableBeanFactory beanFactory ) throws BeansException {
197- initConfigurationPropertiesBeanContexts (beanFactory );
198- }
199-
200- private void initConfigurationPropertiesBeanContexts (ConfigurableListableBeanFactory beanFactory ) {
201- String [] beanNames = beanFactory .getBeanNamesForAnnotation (CONFIGURATION_PROPERTIES_CLASS );
202- int beanCount = beanNames .length ;
203- this .beanContexts = newHashMap (beanCount );
204- }
205-
206155 /**
207156 * Sets the {@link ApplicationContext}, which must be a {@link ConfigurableApplicationContext},
208157 * for publishing property change events.
209158 *
210- * <h3>Example Usage</h3>
211- * <pre>{@code
212- * EventPublishingConfigurationPropertiesBeanPropertyChangedListener listener =
213- * new EventPublishingConfigurationPropertiesBeanPropertyChangedListener();
214- * listener.setApplicationContext(applicationContext);
215- * }</pre>
216- *
217159 * @param context the application context, must be a {@link ConfigurableApplicationContext}
218160 * @throws BeansException if the context is not a {@link ConfigurableApplicationContext}
219161 */
220162 @ Override
221163 public void setApplicationContext (ApplicationContext context ) throws BeansException {
222- Class <ConfigurableApplicationContext > expectedType = CONFIGURABLE_APPLICATION_CONTEXT_CLASS ;
223- isInstanceOf (expectedType , context , "The 'context' argument is not an instance of " + expectedType .getName ());
224- this .context = expectedType .cast (context );
164+ this .context = asConfigurableApplicationContext (context );
165+ }
166+
167+ @ Override
168+ public void afterPropertiesSet () {
169+ this .beanContexts = buildConfigurationPropertiesBeanContexts (this .context );
225170 }
226171
227172 /**
228173 * Called after all singleton beans have been instantiated, marking that initial binding
229174 * is complete. Subsequent binding operations will detect and publish property changes.
230- *
231- * <h3>Example Usage</h3>
232- * <pre>{@code
233- * EventPublishingConfigurationPropertiesBeanPropertyChangedListener listener = ...;
234- * // Called automatically by the Spring container
235- * listener.afterSingletonsInstantiated();
236- * assertTrue(listener.isBound());
237- * }</pre>
238175 */
239176 @ Override
240177 public void afterSingletonsInstantiated () {
178+ for (ConfigurationPropertiesBeanContext beanContext : this .beanContexts .values ()) {
179+ beanContext .bindPropertyValues ();
180+ }
241181 bound = true ;
242182 }
243183
244184 /**
245185 * Returns whether the initial binding of all singleton beans has been completed.
246186 *
247- * <h3>Example Usage</h3>
248- * <pre>{@code
249- * EventPublishingConfigurationPropertiesBeanPropertyChangedListener listener = ...;
250- * if (listener.isBound()) {
251- * // Property changes will now be published as events
252- * }
253- * }</pre>
254- *
255187 * @return {@code true} if initial binding is complete, {@code false} otherwise
256188 */
257189 public boolean isBound () {
0 commit comments