zengbohan1 opened a new pull request, #16438:
URL: https://github.com/apache/dubbo/pull/16438
## Problem
When `@DubboReference` is used on a field,
`ReferenceAnnotationBeanPostProcessor` registers a `ReferenceBean` whose bean
name defaults to the **field name** (when no explicit `id` attribute 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
```java
@RestController
public class Demo2Controller {
@DubboReference
private Demo2Service demo1Service; // registers ReferenceBean
'demo1Service' of type Demo2Service
}
@RestController
public class Demo1Controller {
@Resource
private Demo1Service demo1Service; // by-name lookup hits the
Demo2Service proxy -> failure
}
```
Startup fails with:
```
Caused by: org.springframework.beans.factory.BeanNotOfRequiredTypeException:
Bean named 'demo1Service' is expected to be of type
'com.example.dubbodemo.Demo1Service'
but was actually of type 'com.example.dubbodemo.Demo2ServiceDubboProxy0'
```
## Root cause
This is a cross-annotation conflict with a timing gap:
1. `@DubboReference` vs `@DubboReference` collisions on the same bean name
are already handled by a rename fallback (`xxx#2`) inside
`registerReferenceBean`.
2. However, `@Resource` never registers a bean definition; it resolves by
name at injection time, which happens *after* `@DubboReference` has already
registered its `ReferenceBean` under 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:
```
dubbo.application.reference-bean-naming-strategy=field-name | interface-name
```
- `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
`id` attribute 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 fails**
```
[INFO] Register dubbo reference bean: demo1Service =
ReferenceBean:com.example.dubbodemo.Demo2Service()
at private com.example.dubbodemo.Demo2Service
com.example.dubbodemo.Demo2Controller.demo1Service
...
Caused by: org.springframework.beans.factory.BeanNotOfRequiredTypeException:
Bean named 'demo1Service' is expected to be of type
'com.example.dubbodemo.Demo1Service'
but was actually of type 'com.example.dubbodemo.Demo2ServiceDubboProxy0'
[ERROR] Tests run: 1, Failures: 0, Errors: 1, Skipped: 0 (mvn test exit
code 1)
```
**Scenario 2 -
`-Ddubbo.application.reference-bean-naming-strategy=interface-name`:
application starts**
```
[INFO] Register dubbo reference bean: Demo2Service =
ReferenceBean:com.example.dubbodemo.Demo2Service()
at private com.example.dubbodemo.Demo2Service
com.example.dubbodemo.Demo2Controller.demo1Service
...
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0 (mvn test exit
code 0)
```
The `Demo2Controller` reference bean is now registered as `Demo2Service`;
`Demo1Controller`'s `@Resource` lookup by name finds nothing named
`demo1Service`, falls back to by-type matching and successfully injects the
local `Demo1ServiceImpl` provider bean.
A new test `ReferenceBeanNamingStrategyTest` covers both strategies (default
strategy derives names from the field name including the existing
rename-to-`#2` fallback; `interface-name` strategy derives them from the
referenced interface simple names).
## Note
If desired, maintainers could consider flipping the default value to
`interface-name` in a future major/minor release (e.g. 3.4) after collecting
feedback, since it removes a whole class of by-name conflicts.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]