Spring依赖其他Bean列表的Bean创建机制解析及规范问询
Great question! Let’s walk through exactly how Spring handles the scenario where a bean depends on a list of other beans, including the core mechanics and what the Spring specification defines.
Core Mechanism: Autowiring Collection Types
At its core, this is part of Spring’s Dependency Injection (DI) autowiring logic specifically tailored for collection types. Here’s the step-by-step breakdown for your code example:
1. Candidate Bean Discovery
First, Spring scans your application context for all beans that match the generic type of the collection parameter. In your case:
TestImpl1andTestImpl2are annotated with@Service, so Spring automatically registers them as beans in the context.- Both classes implement the
Testinterface, so they qualify as matching candidates for theList<Test>parameter in yourtestContainerbean factory method.
2. Spring Specification Definition
The behavior is clearly defined in the Spring Core Specification, which states:
When a bean constructor, factory method, or @Autowired method/parameter requires a collection type (such as
List,Set, orMap), Spring automatically collects all bean instances that match the collection's element type and injects them into the collection.For ordered collections like
List, the order of elements follows:
- The
@Orderannotation value (lower values first) or theOrderedinterface implementation of the beans.- If no ordering is specified, the order in which beans were registered in the application context.
Generic type parameters are used to narrow down candidates—Spring will only include beans that are compatible with the generic type of the collection.
3. Applying This to Your Code
When Spring creates the testContainer bean:
- It first resolves the
List<Test>parameter by gathering allTest-type beans (TestImpl1andTestImpl2) from the context. - This list is passed into your factory method, where you iterate over it to populate the
TestContainer's internal list.
A More Concise Alternative
You can simplify your code to align with Spring’s best practices. Instead of manually adding each test bean, use constructor injection directly in TestContainer:
public class TestContainer { private final List<Test> testList; // Constructor injection (preferred over field injection or manual addition) public TestContainer(List<Test> testList) { this.testList = new ArrayList<>(testList); } }
Then your bean factory method becomes much cleaner:
@Bean public TestContainer testContainer(List<Test> testList) { return new TestContainer(testList); }
Extra Details: Ordering and Filtering
- Controlling List Order: If you want
TestImpl1to appear beforeTestImpl2in the list, add the@Orderannotation to the service classes:@Service @Order(1) public class TestImpl1 implements Test { } @Service @Order(2) public class TestImpl2 implements Test { } - Filtering Beans: If you only want to include specific
Testbeans, use the@Qualifierannotation alongside the collection parameter. For example, to only inject beans with the qualifier "specialTest":
Don’t forget to add@Bean public TestContainer testContainer(@Qualifier("specialTest") List<Test> testList) { return new TestContainer(testList); }@Qualifier("specialTest")to the relevantTestimplementation classes.
内容的提问来源于stack exchange,提问作者Suttonese

