Branch:
release· Version line:0.2.x· Artifacts:microsphere-spring-boot-*Spring Boot:3.0.13–4.1.1(profile-selected, default3.5.16) · Java: 17
Contents: 1 What This Branch Ships · 2 Repository Shape · 3 Module Dependency Graph · 4 Extension-Point Inventory · 5 Startup Sequence and Ordering · 6 The Binding Instrumentation Path · 7 Module Documents · 8 How to Read This Set · 9 Contribution Checklist · 10 Documentation Conventions
release maintains the 0.2.x line: the same source tree compiled and published against Spring Boot
3.0 through 4.1. Five artifacts reach Maven Central, one does not.
| Module | Artifact | Published | In BOM | Main sources | Tests |
|---|---|---|---|---|---|
microsphere-spring-boot-parent |
pom | yes | no | — | — |
microsphere-spring-boot-dependencies |
pom (BOM) | yes | — | — | — |
microsphere-spring-boot-compatible |
jar | no | no | 10 files | 0 |
microsphere-spring-boot-test |
jar | yes | yes | 4 | 5 |
microsphere-spring-boot-core |
jar | yes | yes | 47 | 48 |
microsphere-spring-boot-webmvc |
jar | yes | yes | 3 | 5 |
microsphere-spring-boot-webflux |
jar | yes | yes | 3 | 4 |
microsphere-spring-boot-actuator |
jar | yes | yes | 10 | 5 |
The libraries add no lifecycle of their own. Every class either implements a Spring Boot extension point or supports one that is already registered.
microsphere-spring-boot/ root aggregator, holds <revision> and <java.version>
├── pom.xml 8 <modules>, in build order
├── microsphere-spring-boot-parent/ spring-boot.version per profile, third-party BOM imports
├── microsphere-spring-boot-dependencies/ BOM: the five published artifacts
├── microsphere-spring-boot-compatible/ org.springframework.boot.* shims, build-time only
├── microsphere-spring-boot-test/ AbstractAutoConfigurationTest + three runner subclasses
├── microsphere-spring-boot-core/ listeners, initializers, filters, bind advisors, diagnostics
├── microsphere-spring-boot-webmvc/ servlet-stack auto-configuration
├── microsphere-spring-boot-webflux/ reactive-stack auto-configuration
├── microsphere-spring-boot-actuator/ endpoints, scheduler metrics, default endpoint policy
├── .github/workflows/ maven-build, maven-publish, merge-main-to-branches,
│ sync-branches-from-upstream, wiki-publish
└── docs/ user-guide/ + developer-guide/, each split by branch and language
compatible and test sit before core in <modules> on purpose: core's test scope depends on test, and
the Boot 4 profiles attach compatible to core.
Solid edges are compile dependencies; dotted edges are inheritance, test scope, or a profile-conditional attachment.
graph TD
PARENT["microsphere-spring-boot-parent"]
BOM["microsphere-spring-boot-dependencies (BOM)"]
COMPAT["microsphere-spring-boot-compatible<br/>(never published)"]
TEST["microsphere-spring-boot-test"]
CORE["microsphere-spring-boot-core"]
MVC["microsphere-spring-boot-webmvc"]
FLUX["microsphere-spring-boot-webflux"]
ACT["microsphere-spring-boot-actuator"]
APP["Application"]
PARENT -. inheritance .-> BOM
PARENT -. inheritance .-> COMPAT
PARENT -. inheritance .-> TEST
PARENT -. inheritance .-> CORE
PARENT -. inheritance .-> MVC
PARENT -. inheritance .-> FLUX
PARENT -. inheritance .-> ACT
BOM -. version management .-> CORE
BOM -. version management .-> MVC
BOM -. version management .-> FLUX
BOM -. version management .-> ACT
CORE -. test scope .-> TEST
MVC --> CORE
FLUX --> CORE
ACT --> CORE
CORE -. profiles spring-boot-4.0 and 4.1 .-> COMPAT
ACT --> APP
MVC --> APP
FLUX --> APP
CORE --> APP
TEST -. test scope .-> APP
Consequences worth remembering:
coreis the only module every other jar module depends on, and it depends on none of them.webmvcandwebfluxare siblings, never a chain: each is gated by its own availability condition.actuatorreaches Micrometer and Jolokia through its own POM, so acore-only application never pulls them.compatibleis invisible outside profilesspring-boot-4.0andspring-boot-4.1, and unreachable from Maven Central.
core/src/main/resources/META-INF/spring.factories is the whole wiring for the core module — there is no
@ComponentScan and no spring-boot-autoconfigure processor magic behind it:
Key in spring.factories |
Registered class | Fires during |
|---|---|---|
ApplicationContextInitializer |
report.ConditionEvaluationReportInitializer |
context init |
ApplicationContextInitializer |
env.config.OriginTrackedConfigurationPropertyInitializer |
context init |
SpringApplicationRunListener |
classloading.BannedArtifactClassLoadingListener |
earliest, starting() |
SpringApplicationRunListener |
listener.FailureReportSpringApplicationRunListener |
failed() |
ApplicationListener |
diagnostics.ArtifactsCollisionDiagnosisListener |
ApplicationContextInitializedEvent |
ApplicationListener |
report.ConditionEvaluationReportListener |
ApplicationReadyEvent |
ApplicationListener |
env.DefaultPropertiesApplicationListener |
ApplicationEnvironmentPreparedEvent |
SpringBootExceptionReporter |
report.ConditionEvaluationSpringBootExceptionReporter |
startup failure |
FailureAnalyzer |
diagnostics.ArtifactsCollisionFailureAnalyzer |
startup failure |
AutoConfigurationImportFilter |
autoconfigure.ConfigurableAutoConfigurationImportFilter |
auto-config import |
io.microsphere.spring.boot.env.DefaultPropertiesPostProcessor |
env.SpringApplicationDefaultPropertiesPostProcessor |
project-specific key, loaded by the listener above |
Auto-configuration classes are registered through META-INF/spring/AutoConfiguration.imports, one file per module:
| Module | Registered auto-configuration |
|---|---|
core |
io.microsphere.spring.boot.context.autoconfigure.ConfigurationPropertiesAutoConfiguration |
actuator |
io.microsphere.spring.boot.actuate.autoconfigure.ActuatorAutoConfiguration, ...ActuatorEndpointsAutoConfiguration |
webmvc |
io.microsphere.spring.boot.webmvc.autoconfigure.WebMvcAutoConfiguration |
webflux |
io.microsphere.spring.boot.webflux.autoconfigure.WebFluxAutoConfiguration |
core's auto-configuration is the interesting one because it is conditional on a Microsphere class and is
ordered before Boot's own counterpart:
@ConditionalOnClass(name = {
"io.microsphere.spring.context.annotation.BeanCapableImportCandidate"
})
@AutoConfigureBefore(name = {
"org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration"
})
@EnableConfigurationPropertiesExtension
public class ConfigurationPropertiesAutoConfiguration {
}@AutoConfigureBefore uses the by-name form so the same source compiles across Boot lines where the target
class moved packages — the recurring cross-version technique in this repository.
actuator additionally ships META-INF/services/io.microsphere.metadata.ConfigurationPropertyLoader
(pointing at io.microsphere.metadata.MetadataResourceConfigurationPropertyLoader), which is how the module's
META-INF/config/default/endpoints.properties is discovered as a property source.
The ordering values below are read from the branch sources, not inferred from convention:
| Class | Ordering | Source |
|---|---|---|
BannedArtifactClassLoadingListener |
setOrder(HIGHEST_PRECEDENCE) |
core/src/main/java/io/microsphere/spring/boot/classloading/BannedArtifactClassLoadingListener.java:79 |
ConfigurableAutoConfigurationImportFilter |
HIGHEST_PRECEDENCE + 99 |
.../autoconfigure/ConfigurableAutoConfigurationImportFilter.java:276 |
DefaultPropertiesApplicationListener |
DEFAULT_ORDER = LOWEST_PRECEDENCE - 1 |
.../env/DefaultPropertiesApplicationListener.java:76 |
DefaultPropertiesPostProcessor (interface default) |
LOWEST_PRECEDENCE |
.../env/DefaultPropertiesPostProcessor.java:67 |
OnceApplicationPreparedEventListener (and its logging subclasses) |
LOWEST_PRECEDENCE |
.../context/OnceApplicationPreparedEventListener.java:54, LoggingOnceApplicationPreparedEventListener.java:47 |
ArtifactsCollisionDiagnosisListener, ConditionEvaluationReportListener, ConditionEvaluationReportInitializer |
not Ordered — registration order applies |
their class declarations |
sequenceDiagram
participant Boot as SpringApplication
participant BANNED as BannedArtifactClassLoadingListener
participant DEFLT as DefaultPropertiesApplicationListener
participant COLLIDE as ArtifactsCollisionDiagnosisListener
participant INIT as ApplicationContextInitializer pair
participant FILTER as ConfigurableAutoConfigurationImportFilter
participant ADVISOR as ListenableConfigurationPropertiesBindHandlerAdvisor
participant AC as AutoConfiguration beans
Boot->>BANNED: starting() — HIGHEST_PRECEDENCE
Boot->>DEFLT: ApplicationEnvironmentPreparedEvent — LOWEST_PRECEDENCE - 1
Note over DEFLT: loads META-INF/config/default/*.properties<br/>through DefaultPropertiesPostProcessor
Boot->>COLLIDE: ApplicationContextInitializedEvent
Boot->>INIT: initialize(context)
Boot->>Boot: refresh()
FILTER->>FILTER: match(candidates, metadata) — HIGHEST_PRECEDENCE + 99
Note over FILTER: honours microsphere.autoconfigure.exclude<br/>plus Boot's own exclusions
FILTER->>AC: filtered auto-configuration set
ADVISOR->>ADVISOR: apply(BindHandler) during @ConfigurationProperties binding
Note over ADVISOR: wraps in ListenableBindHandlerAdapter<br/>with every ordered BindListener bean
ConfigurableAutoConfigurationImportFilter being HIGHEST_PRECEDENCE + 99 is deliberate: Boot's own filter
ordering leaves room below it, so the exclusion logic runs before the standard metadata/pattern filters while
still allowing a user filter to preempt it.
This is the design that distinguishes core: it turns Spring Boot's one-way binding operation into an
observable one, without touching Boot's code.
flowchart LR
A["Binder.bind(...)"] --> B["ConfigurationPropertiesBindHandlerAdvisor.apply(BindHandler)"]
B --> C["ListenableBindHandlerAdapter (decorator)"]
C --> D["BindListener beans, sorted by Order"]
D --> E["BindListener callbacks: pre / post / onSuccess / onError / onFinish"]
E --> F["EventPublishingConfigurationPropertiesBeanPropertyChangedListener"]
F --> G["ConfigurationPropertiesBeanPropertyChangedEvent"]
G --> H["Application @EventListener methods"]
Contributing a listener therefore means declaring a BindListener bean — no registration step, no
spring.factories entry — and the advisor discovers it through the BeanFactory it is given by
BeanFactoryAware.
| Document | Scope |
|---|---|
| core.md | Package map, spring.factories wiring, bind-advisor chain, diagnostics pipelines, patterns, recipes |
| actuator.md | Endpoint model, aggregation operations, scheduler metrics wiring, endpoints.properties |
| webmvc.md | Servlet-stack beans, the availability condition, by-name ordering across Boot lines |
| webflux.md | Reactive-stack auto-configuration and its condition |
| test.md | Test base-class hierarchy, generic runner bounds, inherited assertions |
| compatible.md | Same-FQCN shims, why the module is unpublished, profile-driven attachment |
| parent.md | Inheritance chain, managed properties, Boot profile selection |
| dependencies.md | BOM assembly and what a new module must do to join it |
| build-and-release.md | Local build, CI matrix, release pipeline, branch automation |
Three useful paths through the material:
| If you are... | Read in this order |
|---|---|
Adding a diagnostic or listener to core |
this file, then core.md, then test.md and build-and-release.md |
| Adding or changing an actuator endpoint | actuator.md, then core.md for the default-properties chain |
| Supporting a new Spring Boot minor version | build-and-release.md, then compatible.md, then parent.md |
Each module document ends with a See also table; cross-document links never rely on heading anchors, because the anchor text differs between the English and Chinese files.
For a change to be complete on this branch, all of these must hold. Steps 4–7 are the ones reviewers most often find missing.
- Code compiles under the default profile:
./mvnw -pl <module> -am clean verify. - Regression coverage exists in that module's
src/test/java; auto-configuration changes are tested with themicrosphere-spring-boot-testbase classes rather than a full@SpringBootTest. - Other Boot lines are smoke-tested locally:
./mvnw -pl <module> -am -Pspring-boot-3.0 test, and for a Boot 4 profile the reactor must includecompatible. - Cross-version API drift is handled the right way: a relocated class goes into a by-name annotation list;
a genuinely absent compile-time type goes into
compatibleand gets attached by the profiles that need it. - Wiring is updated where it lives —
spring.factoriesfor listeners/initializers/filters/analyzers,AutoConfiguration.importsfor auto-configuration classes,META-INF/config/default/*.propertiesfor defaults. - CI matrix picks the new line up: add the profile to
maven-profile-spring-bootin.github/workflows/maven-build.yml. - Docs are updated in both languages, in the same file and with the same section numbering:
docs/developer-guide/current/<module>.mdanddocs/developer-guide/current/zh/<module>.md, plusdocs/user-guide/current/<module>.mdand itszh/twin when the change is observable to a consumer. - No version literals are introduced into module POMs; versions come from
${revision}, the parent POM, or the imported BOMs. compatibleis never added to the BOM or to a published module's compile scope.
Releases are cut from release only, through the publish workflow — see
build-and-release.md.
| Convention | Detail |
|---|---|
| Branch scope | only release and release-1.x are documented; main and dev are integration surfaces |
| Evidence | class names, signatures, ordering constants and property keys are read from the branch sources, cited by path |
| Diagrams | Mermaid graph TD, flowchart, sequenceDiagram, classDiagram; every node is a class that exists on this branch |
| Language | English at this path, Chinese mirrored in zh/ with identical filenames and section numbers |
| Secrets | workflow secret names may appear; values never do |