Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .github/workflows/maven-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ jobs:
matrix:
java: [ '17' , '21' , '25' ]
maven-profile-spring-boot: [ 'spring-boot-3.0' , 'spring-boot-3.1' , 'spring-boot-3.2' ,
'spring-boot-3.3' , 'spring-boot-3.4' ]
'spring-boot-3.3' , 'spring-boot-3.4'
]
steps:
- name: Checkout Source
uses: actions/checkout@v4
Expand Down
7 changes: 3 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@
[![Codecov](https://codecov.io/gh/microsphere-projects/microsphere-spring-boot/branch/main/graph/badge.svg)](https://app.codecov.io/gh/microsphere-projects/microsphere-spring-boot)
![Maven](https://img.shields.io/maven-central/v/io.github.microsphere-projects/microsphere-spring-boot.svg)
![License](https://img.shields.io/github/license/microsphere-projects/microsphere-spring-boot.svg)
[![Average time to resolve an issue](http://isitmaintained.com/badge/resolution/microsphere-projects/microsphere-spring-boot.svg)](http://isitmaintained.com/project/microsphere-projects/microsphere-spring-boot "Average time to resolve an issue")
[![Percentage of issues still open](http://isitmaintained.com/badge/open/microsphere-projects/microsphere-spring-boot.svg)](http://isitmaintained.com/project/microsphere-projects/microsphere-spring-boot "Percentage of issues still open")


Microsphere Spring Boot is a collection of libraries that extends Spring Boot's capabilities with additional features
focused on configuration management, application diagnostics, and enhanced monitoring. The project is structured as a
Expand Down Expand Up @@ -62,8 +61,8 @@ pom.xml:

| **Branches** | **Purpose** | **Latest Version** |
|--------------|-------------------------------------------|--------------------|
| **0.2.x** | Compatible with Spring Boot 3.0.x - 3.5.x | 0.2.4 |
| **0.1.x** | Compatible with Spring Boot 2.0.x - 2.7.x | 0.1.4 |
| **0.2.x** | Compatible with Spring Boot 3.0.x - 3.5.x | 0.2.5 |
| **0.1.x** | Compatible with Spring Boot 2.0.x - 2.7.x | 0.1.5 |

Then add the specific modules you need:

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import io.microsphere.annotation.ConfigurationProperty;
import org.springframework.boot.autoconfigure.AutoConfigurationImportFilter;
import org.springframework.boot.autoconfigure.AutoConfigurationMetadata;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.context.EnvironmentAware;
import org.springframework.core.Ordered;
import org.springframework.core.env.ConfigurableEnvironment;
Expand All @@ -12,13 +13,15 @@

import java.util.LinkedHashSet;
import java.util.Set;
import java.util.TreeSet;

import static io.microsphere.annotation.ConfigurationProperty.APPLICATION_SOURCE;
import static io.microsphere.spring.core.env.EnvironmentUtils.asConfigurableEnvironment;
import static io.microsphere.util.ArrayUtils.EMPTY_STRING_ARRAY;
import static io.microsphere.util.ArrayUtils.combine;
import static java.util.Arrays.asList;
import static java.util.Collections.emptySet;
import static java.util.Collections.unmodifiableSet;
import static org.springframework.boot.context.properties.bind.Binder.get;
import static org.springframework.util.Assert.isInstanceOf;
import static org.springframework.util.StringUtils.collectionToCommaDelimitedString;
import static org.springframework.util.StringUtils.commaDelimitedListToSet;
Expand All @@ -32,6 +35,11 @@
* <pre>{@code
* microsphere.autoconfigure.exclude=com.example.FooAutoConfiguration,com.example.BarAutoConfiguration
* }</pre>
* or
* <pre>{@code
* microsphere.autoconfigure.exclude[0]=com.example.FooAutoConfiguration
* microsphere.autoconfigure.exclude[1]=com.example.BarAutoConfiguration
* }</pre>
*
* <h4>Programmatically exclude classes</h4>
* <pre>{@code
Expand Down Expand Up @@ -70,18 +78,39 @@ public void setEnvironment(Environment environment) {
}

public static Set<String> getExcludedAutoConfigurationClasses(Environment environment) {
MutablePropertySources propertySources = getPropertySources(environment);
Set<String> allExcludedClasses = new TreeSet<>();
ConfigurableEnvironment configurableEnvironment = asConfigurableEnvironment(environment);
Set<String> allExcludedClasses = new LinkedHashSet<>();
addExcludedAutoConfigurationClasses(environment, getExcludedAutoConfigurationClasses(configurableEnvironment), allExcludedClasses);
addExcludedAutoConfigurationClasses(environment, getExcludedAutoConfigurationClassesFromBinder(configurableEnvironment), allExcludedClasses);
return allExcludedClasses.isEmpty() ? emptySet() : unmodifiableSet(allExcludedClasses);
}

private static void addExcludedAutoConfigurationClasses(Environment environment, String[] excludedClasses,
Set<String> allExcludedClasses) {
for (String excludedClass : excludedClasses) {
String resolvedExcludeClass = environment.resolvePlaceholders(excludedClass);
allExcludedClasses.addAll(commaDelimitedListToSet(resolvedExcludeClass));
}
}

private static String[] getExcludedAutoConfigurationClasses(ConfigurableEnvironment environment) {
Set<String> excludedClasses = new LinkedHashSet<>();
MutablePropertySources propertySources = environment.getPropertySources();
for (PropertySource propertySource : propertySources) {
Object property = propertySource.getProperty(AUTO_CONFIGURE_EXCLUDE_PROPERTY_NAME);
if (property instanceof String) {
String exclude = (String) property;
String resolvedExclude = environment.resolvePlaceholders(exclude);
Set<String> excludedClasses = commaDelimitedListToSet(resolvedExclude);
allExcludedClasses.addAll(excludedClasses);
Set<String> classes = commaDelimitedListToSet(resolvedExclude);
excludedClasses.addAll(classes);
}
}
return allExcludedClasses.isEmpty() ? emptySet() : unmodifiableSet(allExcludedClasses);
return excludedClasses.isEmpty() ? EMPTY_STRING_ARRAY : excludedClasses.toArray(EMPTY_STRING_ARRAY);
}

private static String[] getExcludedAutoConfigurationClassesFromBinder(ConfigurableEnvironment environment) {
Binder binder = get(environment);
return binder.bind(AUTO_CONFIGURE_EXCLUDE_PROPERTY_NAME, String[].class).orElse(EMPTY_STRING_ARRAY);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@

import static io.microsphere.collection.Lists.ofList;
import static io.microsphere.spring.boot.context.properties.bind.util.BindHandlerUtils.createBindHandler;
import static java.util.Arrays.asList;
import static io.microsphere.util.StringUtils.EMPTY_STRING;
import static org.springframework.boot.context.properties.bind.Bindable.ofInstance;
import static org.springframework.boot.context.properties.source.ConfigurationPropertySources.from;

Expand Down Expand Up @@ -81,6 +81,6 @@ public void bind(Map<String, Object> configurationProperties, boolean ignoreUnkn
BindHandler bindHandler = createBindHandler(ignoreUnknownFields, ignoreInvalidFields);

// Bind
binder.bind("", bindable, bindHandler);
binder.bind(EMPTY_STRING, bindable, bindHandler);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,14 @@

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.mock.env.MockEnvironment;

import java.util.Set;
import java.util.TreeSet;

import static io.microsphere.collection.Maps.ofMap;
import static io.microsphere.spring.boot.autoconfigure.ConfigurableAutoConfigurationImportFilter.AUTO_CONFIGURE_EXCLUDE_PROPERTY_NAME;
import static io.microsphere.spring.boot.autoconfigure.ConfigurableAutoConfigurationImportFilter.addExcludedAutoConfigurationClass;
import static io.microsphere.spring.boot.autoconfigure.ConfigurableAutoConfigurationImportFilter.getExcludedAutoConfigurationClasses;
Expand Down Expand Up @@ -50,9 +53,15 @@ class ConfigurableAutoConfigurationImportFilterTest {

private MockEnvironment environment;

private String[] autoConfigurationClasses;

private ConfigurableAutoConfigurationImportFilter filter;

@BeforeEach
void setUp() {
environment = new MockEnvironment();
this.environment = new MockEnvironment();
this.autoConfigurationClasses = ofArray(TEST_CLASS_NAME_1, TEST_CLASS_NAME_2, TEST_CLASS_NAME_3);
this.filter = new ConfigurableAutoConfigurationImportFilter();
}

@Test
Expand All @@ -62,97 +71,123 @@ void testConstants() {

@Test
void testMatch() {
ConfigurableAutoConfigurationImportFilter filter = new ConfigurableAutoConfigurationImportFilter();
filter.setEnvironment(this.environment);

String[] autoConfigurationClasses = ofArray(TEST_CLASS_NAME_1, TEST_CLASS_NAME_2, TEST_CLASS_NAME_3);

boolean[] result = filter.match(autoConfigurationClasses, null);
this.filter.setEnvironment(this.environment);
boolean[] result = this.filter.match(this.autoConfigurationClasses, null);
assertTrue(result[0]);
assertTrue(result[1]);
assertTrue(result[2]);

this.environment.setProperty(AUTO_CONFIGURE_EXCLUDE_PROPERTY_NAME, TEST_CLASS_NAME_1);
filter.setEnvironment(this.environment);
result = filter.match(autoConfigurationClasses, null);
this.filter.setEnvironment(this.environment);
result = this.filter.match(this.autoConfigurationClasses, null);
assertFalse(result[0]);
assertTrue(result[1]);
assertTrue(result[2]);

MutablePropertySources propertySources = this.environment.getPropertySources();
MapPropertySource mapPropertySource1 = new MapPropertySource("map-property-source-1",
ofMap(AUTO_CONFIGURE_EXCLUDE_PROPERTY_NAME, TEST_CLASS_NAME_2));
propertySources.addLast(mapPropertySource1);
this.filter.setEnvironment(this.environment);
result = this.filter.match(this.autoConfigurationClasses, null);
assertFalse(result[0]);
assertFalse(result[1]);
assertTrue(result[2]);

MapPropertySource mapPropertySource2 = new MapPropertySource("map-property-source-2",
ofMap(AUTO_CONFIGURE_EXCLUDE_PROPERTY_NAME, TEST_CLASS_NAME_3));
propertySources.addLast(mapPropertySource2);
this.filter.setEnvironment(this.environment);
result = this.filter.match(this.autoConfigurationClasses, null);
assertFalse(result[0]);
assertFalse(result[1]);
assertFalse(result[2]);
}

@Test
void testMatchFromBinder() {
this.environment.setProperty(AUTO_CONFIGURE_EXCLUDE_PROPERTY_NAME + "[0]", TEST_CLASS_NAME_1);
this.environment.setProperty(AUTO_CONFIGURE_EXCLUDE_PROPERTY_NAME + "[1]", TEST_CLASS_NAME_2);
this.environment.setProperty(AUTO_CONFIGURE_EXCLUDE_PROPERTY_NAME + "[2]", TEST_CLASS_NAME_3);
this.filter.setEnvironment(this.environment);
boolean[] result = this.filter.match(autoConfigurationClasses, null);
assertFalse(result[0]);
assertFalse(result[1]);
assertFalse(result[2]);
}

@Test
void testGetExcludedAutoConfigurationClasses() {
Set<String> classNames = getExcludedAutoConfigurationClasses(environment);
Set<String> classNames = getExcludedAutoConfigurationClasses(this.environment);
assertTrue(classNames.isEmpty());

environment.setProperty(AUTO_CONFIGURE_EXCLUDE_PROPERTY_NAME, TEST_CLASS_NAME_1);
classNames = getExcludedAutoConfigurationClasses(environment);
this.environment.setProperty(AUTO_CONFIGURE_EXCLUDE_PROPERTY_NAME, TEST_CLASS_NAME_1);
classNames = getExcludedAutoConfigurationClasses(this.environment);
assertEquals(singleton(TEST_CLASS_NAME_1), classNames);

environment.setProperty(AUTO_CONFIGURE_EXCLUDE_PROPERTY_NAME, TEST_CLASS_NAME_1 + "," + TEST_CLASS_NAME_2);
classNames = getExcludedAutoConfigurationClasses(environment);
this.environment.setProperty(AUTO_CONFIGURE_EXCLUDE_PROPERTY_NAME, TEST_CLASS_NAME_1 + "," + TEST_CLASS_NAME_2);
classNames = getExcludedAutoConfigurationClasses(this.environment);
assertEquals(new TreeSet(asList(TEST_CLASS_NAME_1, TEST_CLASS_NAME_2)), classNames);

environment.setProperty(AUTO_CONFIGURE_EXCLUDE_PROPERTY_NAME, TEST_CLASS_NAME_1 + "," + TEST_CLASS_NAME_2 + "," + TEST_CLASS_NAME_3);
classNames = getExcludedAutoConfigurationClasses(environment);
this.environment.setProperty(AUTO_CONFIGURE_EXCLUDE_PROPERTY_NAME, TEST_CLASS_NAME_1 + "," + TEST_CLASS_NAME_2 + "," + TEST_CLASS_NAME_3);
classNames = getExcludedAutoConfigurationClasses(this.environment);
assertEquals(new TreeSet(asList(TEST_CLASS_NAME_1, TEST_CLASS_NAME_2, TEST_CLASS_NAME_3)), classNames);

// Test the placeholders
environment.setProperty("exclude", TEST_CLASS_NAME_1 + "," + TEST_CLASS_NAME_3);
environment.setProperty(AUTO_CONFIGURE_EXCLUDE_PROPERTY_NAME, "${exclude}");
classNames = getExcludedAutoConfigurationClasses(environment);
this.environment.setProperty("exclude", TEST_CLASS_NAME_1 + "," + TEST_CLASS_NAME_3);
this.environment.setProperty(AUTO_CONFIGURE_EXCLUDE_PROPERTY_NAME, "${exclude}");
classNames = getExcludedAutoConfigurationClasses(this.environment);
assertEquals(new TreeSet(asList(TEST_CLASS_NAME_1, TEST_CLASS_NAME_3)), classNames);

environment.setProperty("exclude1", TEST_CLASS_NAME_1);
environment.setProperty(AUTO_CONFIGURE_EXCLUDE_PROPERTY_NAME, TEST_CLASS_NAME_2 + ",${exclude1}");
classNames = getExcludedAutoConfigurationClasses(environment);
this.environment.setProperty("exclude1", TEST_CLASS_NAME_1);
this.environment.setProperty(AUTO_CONFIGURE_EXCLUDE_PROPERTY_NAME, TEST_CLASS_NAME_2 + ",${exclude1}");
classNames = getExcludedAutoConfigurationClasses(this.environment);
assertEquals(new TreeSet(asList(TEST_CLASS_NAME_2, TEST_CLASS_NAME_1)), classNames);

environment.setProperty("exclude1", TEST_CLASS_NAME_1);
environment.setProperty("exclude2", TEST_CLASS_NAME_2);
environment.setProperty(AUTO_CONFIGURE_EXCLUDE_PROPERTY_NAME, "${exclude1},${exclude2}");
classNames = getExcludedAutoConfigurationClasses(environment);
this.environment.setProperty("exclude1", TEST_CLASS_NAME_1);
this.environment.setProperty("exclude2", TEST_CLASS_NAME_2);
this.environment.setProperty(AUTO_CONFIGURE_EXCLUDE_PROPERTY_NAME, "${exclude1},${exclude2}");
classNames = getExcludedAutoConfigurationClasses(this.environment);
assertEquals(new TreeSet(asList(TEST_CLASS_NAME_1, TEST_CLASS_NAME_2)), classNames);
}

@Test
void testAddExcludedAutoConfigurationClass() {
Set<String> classNames = getExcludedAutoConfigurationClasses(environment);
Set<String> classNames = getExcludedAutoConfigurationClasses(this.environment);
assertTrue(classNames.isEmpty());

addExcludedAutoConfigurationClass(environment, TEST_CLASS_NAME_1);
classNames = getExcludedAutoConfigurationClasses(environment);
addExcludedAutoConfigurationClass(this.environment, TEST_CLASS_NAME_1);
classNames = getExcludedAutoConfigurationClasses(this.environment);
assertEquals(singleton(TEST_CLASS_NAME_1), classNames);

addExcludedAutoConfigurationClass(environment, TEST_CLASS_NAME_2);
classNames = getExcludedAutoConfigurationClasses(environment);
addExcludedAutoConfigurationClass(this.environment, TEST_CLASS_NAME_2);
classNames = getExcludedAutoConfigurationClasses(this.environment);
assertEquals(new TreeSet(asList(TEST_CLASS_NAME_1, TEST_CLASS_NAME_2)), classNames);

// Test the placeholders
environment.setProperty("exclude3", TEST_CLASS_NAME_3);
addExcludedAutoConfigurationClass(environment, "${exclude3}");
classNames = getExcludedAutoConfigurationClasses(environment);
this.environment.setProperty("exclude3", TEST_CLASS_NAME_3);
addExcludedAutoConfigurationClass(this.environment, "${exclude3}");
classNames = getExcludedAutoConfigurationClasses(this.environment);
assertEquals(new TreeSet(asList(TEST_CLASS_NAME_1, TEST_CLASS_NAME_2, TEST_CLASS_NAME_3)), classNames);

// Test the duplicated elements
addExcludedAutoConfigurationClass(environment, TEST_CLASS_NAME_3);
classNames = getExcludedAutoConfigurationClasses(environment);
addExcludedAutoConfigurationClass(this.environment, TEST_CLASS_NAME_3);
classNames = getExcludedAutoConfigurationClasses(this.environment);
assertEquals(new TreeSet(asList(TEST_CLASS_NAME_1, TEST_CLASS_NAME_2, TEST_CLASS_NAME_3)), classNames);
}

@Test
void testIsExcluded() {
ConfigurableAutoConfigurationImportFilter filter = new ConfigurableAutoConfigurationImportFilter();
filter.setEnvironment(this.environment);
this.filter.setEnvironment(this.environment);

assertFalse(filter.isExcluded(null));
assertFalse(filter.isExcluded(""));
assertFalse(filter.isExcluded(" "));
assertFalse(this.filter.isExcluded(null));
assertFalse(this.filter.isExcluded(""));
assertFalse(this.filter.isExcluded(" "));

assertFalse(filter.isExcluded(TEST_CLASS_NAME_1));
assertFalse(this.filter.isExcluded(TEST_CLASS_NAME_1));

addExcludedAutoConfigurationClass(environment, TEST_CLASS_NAME_1);
filter.setEnvironment(this.environment);
assertTrue(filter.isExcluded(TEST_CLASS_NAME_1));
addExcludedAutoConfigurationClass(this.environment, TEST_CLASS_NAME_1);
this.filter.setEnvironment(this.environment);
assertTrue(this.filter.isExcluded(TEST_CLASS_NAME_1));
}
}
Original file line number Diff line number Diff line change
@@ -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 io.microsphere.spring.boot.constants;


import org.junit.jupiter.api.Test;
import org.springframework.boot.context.properties.source.ConfigurationPropertySources;

import static io.microsphere.reflect.FieldUtils.getStaticFieldValue;
import static io.microsphere.spring.boot.constants.SpringBootPropertyConstants.ATTACHED_PROPERTY_SOURCE_NAME;
import static io.microsphere.spring.boot.constants.SpringBootPropertyConstants.SPRING_AUTO_CONFIGURE_EXCLUDE_PROPERTY_NAME;
import static org.junit.jupiter.api.Assertions.assertEquals;

/**
* {@link SpringBootPropertyConstants} Test
*
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
* @see SpringBootPropertyConstants
* @since 1.0.0
*/
class SpringBootPropertyConstantsTest {

@Test
void testConstants() {
assertEquals("spring.autoconfigure.exclude", SPRING_AUTO_CONFIGURE_EXCLUDE_PROPERTY_NAME);

assertEquals("configurationProperties", ATTACHED_PROPERTY_SOURCE_NAME);
assertEquals(getStaticFieldValue(ConfigurationPropertySources.class, "ATTACHED_PROPERTY_SOURCE_NAME"), ATTACHED_PROPERTY_SOURCE_NAME);
}

}
Loading