diff --git a/microsphere-spring-boot-core/src/main/java/io/microsphere/spring/boot/context/OnceApplicationPreparedEventListener.java b/microsphere-spring-boot-core/src/main/java/io/microsphere/spring/boot/context/OnceApplicationPreparedEventListener.java index 7ec0a685..b5199a41 100644 --- a/microsphere-spring-boot-core/src/main/java/io/microsphere/spring/boot/context/OnceApplicationPreparedEventListener.java +++ b/microsphere-spring-boot-core/src/main/java/io/microsphere/spring/boot/context/OnceApplicationPreparedEventListener.java @@ -5,6 +5,7 @@ import org.springframework.boot.context.event.ApplicationPreparedEvent; import org.springframework.context.ApplicationListener; import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.event.ContextClosedEvent; import org.springframework.core.Ordered; import java.util.Map; @@ -113,6 +114,12 @@ public final void onApplicationEvent(ApplicationPreparedEvent event) { markProcessed(contextId); + context.addApplicationListener(event -> { + if (event instanceof ContextClosedEvent && context == ((ContextClosedEvent) event).getApplicationContext()) { + processedContextIds.remove(contextId); + } + }); + onApplicationEvent(springApplication, args, context); } diff --git a/microsphere-spring-boot-core/src/main/java/io/microsphere/spring/boot/context/properties/bind/ConfigurationPropertiesBeanContext.java b/microsphere-spring-boot-core/src/main/java/io/microsphere/spring/boot/context/properties/bind/ConfigurationPropertiesBeanContext.java index b2b63947..d9e96e9d 100644 --- a/microsphere-spring-boot-core/src/main/java/io/microsphere/spring/boot/context/properties/bind/ConfigurationPropertiesBeanContext.java +++ b/microsphere-spring-boot-core/src/main/java/io/microsphere/spring/boot/context/properties/bind/ConfigurationPropertiesBeanContext.java @@ -124,7 +124,7 @@ public void setProperty(ConfigurationProperty property, Object newValue) { Object oldValue = getPropertyValue(propertyName); if (!Objects.deepEquals(oldValue, convertedNewValue)) { initializedBeanWrapper.setPropertyValue(propertyName, convertedNewValue); - publishEvent(property, propertyName, oldValue, newValue); + publishEvent(property, propertyName, oldValue, convertedNewValue); } } @@ -250,9 +250,12 @@ private void initBinding(Class beanClass, String prefix, Map * @return the converted value, or the original value if conversion is not supported */ Object convertForProperty(String propertyName, Object value) { + if (value == null) { + return null; + } Class propertyType = this.initializedBeanWrapper.getPropertyType(propertyName); ConversionService conversionService = this.initializedBeanWrapper.getConversionService(); - if (conversionService.canConvert(value.getClass(), propertyType)) { + if (conversionService != null && conversionService.canConvert(value.getClass(), propertyType)) { return conversionService.convert(value, propertyType); } return value; diff --git a/microsphere-spring-boot-core/src/main/java/io/microsphere/spring/boot/context/properties/bind/ListenableBindHandlerAdapter.java b/microsphere-spring-boot-core/src/main/java/io/microsphere/spring/boot/context/properties/bind/ListenableBindHandlerAdapter.java index f489fbee..a5943dc4 100644 --- a/microsphere-spring-boot-core/src/main/java/io/microsphere/spring/boot/context/properties/bind/ListenableBindHandlerAdapter.java +++ b/microsphere-spring-boot-core/src/main/java/io/microsphere/spring/boot/context/properties/bind/ListenableBindHandlerAdapter.java @@ -164,7 +164,9 @@ public Object onCreate(ConfigurationPropertyName name, Bindable target, BindC @Override public Object onFailure(ConfigurationPropertyName name, Bindable target, BindContext context, Exception error) throws Exception { try { - return super.onFailure(name, target, context, error); + Object result = super.onFailure(name, target, context, error); + bindHandlers.onFailure(name, target, context, error); + return result; } catch (Exception e) { bindHandlers.onFailure(name, target, context, error); throw e; diff --git a/microsphere-spring-boot-core/src/main/java/io/microsphere/spring/boot/diagnostics/ArtifactsCollisionDiagnosisListener.java b/microsphere-spring-boot-core/src/main/java/io/microsphere/spring/boot/diagnostics/ArtifactsCollisionDiagnosisListener.java index 82dd2baf..02c813c6 100644 --- a/microsphere-spring-boot-core/src/main/java/io/microsphere/spring/boot/diagnostics/ArtifactsCollisionDiagnosisListener.java +++ b/microsphere-spring-boot-core/src/main/java/io/microsphere/spring/boot/diagnostics/ArtifactsCollisionDiagnosisListener.java @@ -12,6 +12,7 @@ import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.io.ResourceLoader; +import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Set; @@ -20,7 +21,6 @@ import static io.microsphere.annotation.ConfigurationProperty.APPLICATION_SOURCE; import static io.microsphere.collection.CollectionUtils.size; import static io.microsphere.collection.MapUtils.newLinkedHashMap; -import static io.microsphere.collection.SetUtils.newLinkedHashSet; import static io.microsphere.constants.SeparatorConstants.LINE_SEPARATOR; import static io.microsphere.logging.LoggerFactory.getLogger; import static io.microsphere.spring.boot.constants.PropertyConstants.MICROSPHERE_SPRING_BOOT_PROPERTY_NAME_PREFIX; @@ -130,12 +130,14 @@ protected Set diagnose(ClassLoader classLoader) { ArtifactDetector detector = new ArtifactDetector(classLoader); List artifacts = detector.detect(false); // Artifacts conflict Map - Map artifactsCollisionMap = getArtifactsCollisionMap(artifacts); + Map> artifactsCollisionMap = getArtifactsCollisionMap(artifacts); if (!artifactsCollisionMap.isEmpty()) { StringJoiner stringJoiner = new StringJoiner(LINE_SEPARATOR, "-\t", ""); logger.error("Artifacts collision detected:"); - for (Artifact artifact : artifactsCollisionMap.values()) { - stringJoiner.add(artifact.toString()); + for (List collidingArtifacts : artifactsCollisionMap.values()) { + for (Artifact artifact : collidingArtifacts) { + stringJoiner.add(artifact.toString()); + } } logger.error(stringJoiner.toString()); } @@ -145,27 +147,33 @@ protected Set diagnose(ClassLoader classLoader) { /** * Build a map of colliding artifacts from the given list. An artifact is considered colliding * if another artifact with the same identifier (groupId:artifactId) already exists in the list. + * All occurrences of a collision (both first and subsequent duplicates) are tracked. * *

Example Usage

*
{@code
      *   ArtifactDetector detector = new ArtifactDetector(classLoader);
      *   List artifacts = detector.detect(false);
-     *   Map collisionMap = listener.getArtifactsCollisionMap(artifacts);
-     *   collisionMap.forEach((id, artifact) -> System.err.println("Collision: " + id));
+     *   Map> collisionMap = listener.getArtifactsCollisionMap(artifacts);
+     *   collisionMap.forEach((id, artifacts) -> System.err.println("Collision: " + id + " -> " + artifacts));
      * }
* * @param artifacts the list of detected {@link Artifact} instances - * @return a map of colliding artifact identifiers to their {@link Artifact} instances + * @return a map of colliding artifact identifiers to all their colliding {@link Artifact} instances */ - Map getArtifactsCollisionMap(List artifacts) { + Map> getArtifactsCollisionMap(List artifacts) { int size = size(artifacts); - Map artifactsCollisionMap = newLinkedHashMap(size); - Set ids = newLinkedHashSet(size); + Map seenArtifacts = newLinkedHashMap(size); + Map> artifactsCollisionMap = newLinkedHashMap(size); for (int i = 0; i < size; i++) { Artifact artifact = artifacts.get(i); String id = buildId(artifact); - if (!ids.add(id)) { - artifactsCollisionMap.put(id, artifact); + Artifact firstSeen = seenArtifacts.putIfAbsent(id, artifact); + if (firstSeen != null) { + artifactsCollisionMap.computeIfAbsent(id, k -> { + List list = new ArrayList<>(); + list.add(firstSeen); + return list; + }).add(artifact); } } return artifactsCollisionMap; diff --git a/microsphere-spring-boot-core/src/main/java/io/microsphere/spring/boot/env/config/OriginTrackedConfigurationPropertyInitializer.java b/microsphere-spring-boot-core/src/main/java/io/microsphere/spring/boot/env/config/OriginTrackedConfigurationPropertyInitializer.java index abb52fb1..b42cb734 100644 --- a/microsphere-spring-boot-core/src/main/java/io/microsphere/spring/boot/env/config/OriginTrackedConfigurationPropertyInitializer.java +++ b/microsphere-spring-boot-core/src/main/java/io/microsphere/spring/boot/env/config/OriginTrackedConfigurationPropertyInitializer.java @@ -121,7 +121,9 @@ void initializePropertySources(MutablePropertySources propertySources) { String name = propertySource.getName(); try { PropertySource originTrackedPropertySource = createOriginTrackedPropertySource(propertySource); - propertySources.replace(name, originTrackedPropertySource); + if (originTrackedPropertySource != null) { + propertySources.replace(name, originTrackedPropertySource); + } } catch (IOException e) { logger.error("Failed to create the origin tracked PropertySource[name : '{}', class : '{}']", name, propertySource.getClass().getName()); diff --git a/microsphere-spring-boot-core/src/test/java/io/microsphere/spring/boot/diagnostics/ArtifactsCollisionDiagnosisListenerTest.java b/microsphere-spring-boot-core/src/test/java/io/microsphere/spring/boot/diagnostics/ArtifactsCollisionDiagnosisListenerTest.java index 3778302c..7d568506 100644 --- a/microsphere-spring-boot-core/src/test/java/io/microsphere/spring/boot/diagnostics/ArtifactsCollisionDiagnosisListenerTest.java +++ b/microsphere-spring-boot-core/src/test/java/io/microsphere/spring/boot/diagnostics/ArtifactsCollisionDiagnosisListenerTest.java @@ -98,9 +98,10 @@ void testDiagnose() { @Test void testGetArtifactsCollisionMap() { List artifacts = createArtifacts(); - Map artifactsCollisionMap = this.listener.getArtifactsCollisionMap(artifacts); + Map> artifactsCollisionMap = this.listener.getArtifactsCollisionMap(artifacts); assertEquals(1, artifactsCollisionMap.size()); assertTrue(artifactsCollisionMap.containsKey("test-artifact")); + assertEquals(2, artifactsCollisionMap.get("test-artifact").size()); } private List createArtifacts() {