Spring 5(Java 9环境)如何从Environment获取List<Flow>对象列表?
To convert your root-level YAML flow list into a List<Flow> type (without adding a prefix to the YAML) and retrieve it via Environment—especially within an EnvironmentPostProcessor—follow these practical steps:
1. Define the Flow POJO
First, create a simple class to represent each entry in your flow list:
public class Flow { private String name; private String url; // Add getters and setters (or use Lombok @Data for cleaner code) public String getName() { return name; } public void setName(String name) { this.name = name; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } }
2. Bind the YAML List to List Using Spring Binder
Directly calling env.getProperty("flow", List.class) won’t work due to Java type erasure—Spring can’t infer the Flow generic type from List.class. Instead, use Spring’s Binder (the engine behind @ConfigurationProperties) with ParameterizedTypeReference to capture the generic type information at runtime.
Here’s how to implement this in your EnvironmentPostProcessor:
import org.springframework.boot.SpringApplication; import org.springframework.boot.env.EnvironmentPostProcessor; import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.ParameterizedTypeReference; import org.springframework.boot.context.properties.bind.Binder; import java.util.List; import java.util.Collections; public class FlowEnvironmentPostProcessor implements EnvironmentPostProcessor { @Override public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) { // Bind the root-level "flow" property to List<Flow> List<Flow> flowList = Binder.get(environment) .bind( "flow", Bindable.of(new ParameterizedTypeReference<List<Flow>>() {}) ) .orElse(Collections.emptyList()); // Register a bean with a single flow configuration (e.g., the first entry) if (!flowList.isEmpty()) { application.addInitializers(context -> { context.getBeanFactory().registerSingleton("singleFlowBean", flowList.get(0)); }); } } }
3. Optional: Reusable ConfigurationProperties Class
If you want to reuse this binding elsewhere in your application, create a @ConfigurationProperties class with an empty prefix (to match the root-level flow key in YAML):
import org.springframework.boot.context.properties.ConfigurationProperties; import java.util.List; @ConfigurationProperties(prefix = "") // Empty prefix targets root-level properties public class FlowProperties { private List<Flow> flow; public List<Flow> getFlow() { return flow; } public void setFlow(List<Flow> flow) { this.flow = flow; } }
You can then bind to this class in your EnvironmentPostProcessor like so:
FlowProperties flowProps = Binder.get(environment) .bind("", Bindable.of(FlowProperties.class)) .orElse(new FlowProperties()); List<Flow> flowList = flowProps.getFlow();
Key Notes
- Type Erasure Workaround:
ParameterizedTypeReferencepreserves the generic typeList<Flow>at runtime, allowing Spring to correctly map the YAML entries to your POJO. - EnvironmentPostProcessor Context: Since this processor runs before the application context is fully initialized, using
Binderis the safe approach—avoid relying on@Autowiredor fully initialized beans here. - Bean Registration: Using
application.addInitializers()ensures your bean is registered early and available when the context starts up.
内容的提问来源于stack exchange,提问作者Matthew Campbell

