[ISSUE #12637] Add reference bean naming strategy to avoid @Resource by-name conflicts - #16438
zeng-bohan wants to merge 1 commit into
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## 3.3 #16438 +/- ##
============================================
+ Coverage 60.91% 60.92% +0.01%
- Complexity 11769 11783 +14
============================================
Files 1953 1953
Lines 89275 89287 +12
Branches 13474 13477 +3
============================================
+ Hits 54382 54402 +20
+ Misses 29312 29307 -5
+ Partials 5581 5578 -3
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
Friendly bump after two weeks: CI is green across the board (30/30 checks, patch coverage at 100%), and the change is non-breaking by construction — |
…ource by-name conflicts @dubboReference without an explicit id registers the ReferenceBean under the annotated field name. A same-named field of a different type then occupies that bean name, and JSR-250 @resource injections - which resolve by name later in the lifecycle, after @DubboReference has registered - fail with BeanNotOfRequiredTypeException (apache#12637). Add an opt-in strategy selected via the Spring environment property dubbo.application.reference-bean-naming-strategy: - field-name (default): historical behavior, bean name = annotated field/setter property name; byte-identical unless opted out - interface-name: bean name = simple name of the referenced service interface, so it no longer depends on the declaring field name An explicit id attribute always takes priority regardless of the strategy. Unknown or blank values fall back to field-name. Signed-off-by: zengbohan1 <310902929+zengbohan1@users.noreply.github.com>
fb7b459 to
0de30f1
Compare
|
Housekeeping, no functional change: I squashed the branch to a single commit and rebased it onto the current 3.3 tip ( |
|
@RainYuY @zrlw — could one of you take a first look at this one? It has been open three weeks with no review yet, and it is green across the board: 32/32 checks passing, patch coverage 100%, and no conflicts with the current The change adds a reference-bean naming strategy so Happy to adjust the switch shape, the default, or the naming if the team prefers something different. Thanks! |
Problem
When
@DubboReferenceis used on a field,ReferenceAnnotationBeanPostProcessorregisters aReferenceBeanwhose bean name defaults to the field name (when no explicitidattribute is set). If another bean in the same application context declares a field with the same name but a different type and injects it by name (JSR-250@Resource), the injection fails.Reproduction
Startup fails with:
Root cause
This is a cross-annotation conflict with a timing gap:
@DubboReferencevs@DubboReferencecollisions on the same bean name are already handled by a rename fallback (xxx#2) insideregisterReferenceBean.@Resourcenever registers a bean definition; it resolves by name at injection time, which happens after@DubboReferencehas already registered itsReferenceBeanunder the field name. So no rename/protection logic can kick in at that point.Proposal
Add an opt-in naming strategy for reference beans that do not declare an explicit
id, selected via a Spring environment property:field-name(default, current behavior): bean name = annotated field/setter property name.interface-name(new): bean name = simple name of the referenced service interface, so it no longer depends on the declaring field name.The default keeps full backward compatibility (non-breaking). An explicit
idattribute always takes priority regardless of the strategy.Verification
Reproduced and verified with a Spring Boot 2.7.13 + Dubbo 3.3.6 + JDK 17 consumer application (ZooKeeper registry) containing exactly the conflicting controllers above, with the patched class applied.
Scenario 1 - default strategy (
field-name, property not set): behavior unchanged, still failsScenario 2 -
-Ddubbo.application.reference-bean-naming-strategy=interface-name: application startsThe
Demo2Controllerreference bean is now registered asDemo2Service;Demo1Controller's@Resourcelookup by name finds nothing nameddemo1Service, falls back to by-type matching and successfully injects the localDemo1ServiceImplprovider bean.A new test
ReferenceBeanNamingStrategyTestcovers both strategies (default strategy derives names from the field name including the existing rename-to-#2fallback;interface-namestrategy derives them from the referenced interface simple names).Note
If desired, maintainers could consider flipping the default value to
interface-namein a future major/minor release (e.g. 3.4) after collecting feedback, since it removes a whole class of by-name conflicts.