Skip to content

Allow creation of Beans that cannot be autowired by type unless qualified #26528

Closed
@hjohn

Description

I'm seeing more and more problems with complex Spring / Spring Boot applications where beans created in some dependency interfere with the operation of either another dependency or our own code.

Dependencies like to declare Beans because it is convenient to inject them where needed in the dependency's own code. However, some of these beans really shouldn't be public and available for general use. By declaring a Bean, it becomes publicly available, even if given its own name or if it is declared with a Qualifier:

 @Bean("myName") @MyQualifer
 public MyBean myBean() { ... }

This bean can still be injected anywhere (when it is the only option) because Spring will match it by type:

 @Autowired private MyBean bean1;

This is highly undesirable for types that are used commonly by multiple dependencies. Some of the biggest offenders are ObjectMapper, ThreadPoolTaskScheduler, etc. Beans like this often get configured in a specific way for a specific dependency and making them public (by simple declaring them) means that these beans can end up in completely unrelated parts of an application.

Spring's injection capabilities are very useful, even in libraries, but just like a library should be able to limit what API is publicly available, it should also be able to decide which of its beans are safe to use in external code (published) and which are not (kept private).

Qualifiers and Bean names are however insufficient due to Spring's matching by type -- a Bean intended for internal use only can still leak out and be used in external code. I therefore suggest allowing Beans to be declared with restrictions on how it can be matched:

 @Bean(value = "myName", name-must-match = true) public MyBean myBean() { ... }

Or:

@Bean(must-be-qualified = true) @MyQualifier public MyBean myBean() { ... }

The first declaration would require the wiring site to specify the bean name:

@Autowired @Qualifer("myName") private MyBean bean1;

The second would require:

@Autowired @MyQualfier private MyBean bean1;

This would NOT match:

@Autowired private MyBean myBean;

In this fashion, library authors can keep certain beans private to the library by keeping the Qualifier private or by using an obscure bean name (use at your own risk in external code).

The suggested names and even the entire mechanism are just for illustration. I could imagine there being different annotations for this purpose: @NamedBean -- bean that must match by name to be considered for injection, and @QualifiedBean -- bean that must match all qualifiers to be considered.

Metadata

Assignees

Labels

in: coreIssues in core modules (aop, beans, core, context, expression)type: enhancementA general enhancement

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions