mirror of
https://github.com/spring-projects/spring-framework.git
synced 2026-09-17 16:39:29 +00:00
Clarify Bean Overrides and Spring AOP Proxies documentation
A user reported confusion between two distinct uses of "wraps" in the AOP proxy documentation for Bean Overrides: the sense in which a Mockito spy wraps the original bean instance it was created from, and the sense in which a Spring AOP proxy wraps the spy in the actual object graph. To address that, this commit adds two small diagrams to the general "Bean Overrides and Spring AOP Proxies" section, illustrating, from a caller's perspective, the shape of the bean for the REPLACE/REPLACE_OR_CREATE strategy (no proxy at all) versus the WRAP strategy (an AOP proxy still created, now wrapping the override instance instead of the original bean). Both diagrams use the same generic "override instance" label, since the section is not specific to Mockito; a Mockito spy created by @MockitoSpyBean is mentioned only as an example. The accompanying text is revised to reserve "wraps" for the AOP proxy relationship and to explicitly call out that a Mockito spy's relationship to its original bean instance is a separate concern from AOP proxy nesting. The @MockitoSpyBean-specific strategy paragraph in the @MockitoBean/@MockitoSpyBean documentation has also been revised similarly, and now points to the new diagram. See gh-37121
This commit is contained in:
+7
-6
@@ -76,13 +76,14 @@ xref:testing/testcontext-framework/bean-overriding.adoc#testcontext-bean-overrid
|
||||
Overrides and Spring AOP Proxies] for details.
|
||||
|
||||
The `@MockitoSpyBean` annotation uses the `WRAP`
|
||||
xref:testing/testcontext-framework/bean-overriding.adoc#testcontext-bean-overriding-strategy[strategy],
|
||||
and the original instance is wrapped in a Mockito spy. This strategy requires that
|
||||
exactly one candidate bean exists. In contrast to `@MockitoBean`, if the original bean
|
||||
would have been wrapped in a Spring AOP proxy, that proxy is still created around the spy.
|
||||
See
|
||||
xref:testing/testcontext-framework/bean-overriding.adoc#testcontext-bean-overriding-strategy[strategy]:
|
||||
an early instance of the original bean is captured and used to create a Mockito spy.
|
||||
This strategy requires that exactly one candidate bean exists. In contrast to
|
||||
`@MockitoBean`, if the original bean would have been wrapped in a Spring AOP proxy, that
|
||||
proxy is still created — but it now wraps the spy instead of the original bean. See
|
||||
<<spring-testing-annotation-beanoverriding-mockitospybean-aop-proxies,`@MockitoSpyBean` and Spring AOP Proxies>>
|
||||
for the consequences this has for stubbing and verification.
|
||||
for a diagram and further details on the consequences this has for stubbing and
|
||||
verification.
|
||||
|
||||
[TIP]
|
||||
====
|
||||
|
||||
+43
-7
@@ -106,13 +106,49 @@ the override.
|
||||
original bean (`@Transactional`, `@Cacheable`, `@Retryable`, method security, and so
|
||||
on) is present.
|
||||
* Overrides that use the `WRAP` strategy (such as `@MockitoSpyBean`) capture an early
|
||||
reference to the original bean and wrap it before the rest of the container's
|
||||
post-processors — including the one responsible for creating AOP proxies — have run.
|
||||
Consequently, if the original bean would have been proxied, that proxy is still
|
||||
created, but with the override instance as its target rather than the original bean.
|
||||
The bean that ends up in the `ApplicationContext`, and that is injected into
|
||||
collaborating beans and test classes, is therefore a proxy wrapping the override
|
||||
instance, not the bare override instance itself.
|
||||
reference to the original bean and use it to create the override instance, before the
|
||||
rest of the container's post-processors — including the one responsible for creating
|
||||
AOP proxies — have run. Consequently, if the original bean would have been proxied,
|
||||
that proxy is still created, but it now wraps the override instance instead of the
|
||||
original bean. The bean that ends up in the `ApplicationContext`, and that is injected
|
||||
into collaborating beans and test classes, is therefore the AOP proxy, with the
|
||||
override instance as its target — not the bare override instance itself.
|
||||
|
||||
The following diagrams illustrate the resulting shape of the bean for each strategy, from
|
||||
the perspective of a caller invoking a method on the injected bean.
|
||||
|
||||
With the `REPLACE` or `REPLACE_OR_CREATE` strategy, there is no AOP proxy at all: the
|
||||
caller invokes the override instance directly.
|
||||
|
||||
[source]
|
||||
----
|
||||
caller
|
||||
│
|
||||
▼
|
||||
[ override instance ]
|
||||
----
|
||||
|
||||
With the `WRAP` strategy, any AOP proxy that would normally have wrapped the original
|
||||
bean is still created, but now wraps the override instance instead:
|
||||
|
||||
[source]
|
||||
----
|
||||
caller
|
||||
│
|
||||
▼
|
||||
[ AOP proxy ] (for example, retry, caching, or transaction advice)
|
||||
│
|
||||
│ delegates to its target
|
||||
▼
|
||||
[ override instance ] (for example, a Mockito spy created by @MockitoSpyBean)
|
||||
----
|
||||
|
||||
For a `WRAP`-based override such as `@MockitoSpyBean`, the "wrapping" performed by the
|
||||
AOP proxy is unrelated to the manner in which the resulting Mockito spy itself "wraps"
|
||||
the original bean instance it was created from. The proxy shown above determines which
|
||||
object a caller actually invokes, whereas the spy's relationship to the original
|
||||
instance only determines what happens when an unstubbed method is invoked on the spy: it
|
||||
falls through to that instance's real behavior.
|
||||
|
||||
This distinction has practical consequences when combining bean overrides with Mockito's
|
||||
stubbing and verification APIs. See
|
||||
|
||||
Reference in New Issue
Block a user