Disclaimer: I've read follownig heelpful staff about JDK dynamic proxy and CGLIB: https://stackoverflow.com/a/21762454/2674303
I''ve read following interesting article:Injecting Spring Prototype bean into Singleton bean
First case:
Prototype:
@Service
@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
class MessageBuilder {
private static final AtomicInteger instanceCounter = new AtomicInteger(0);
MessageBuilder() {
instanceCounter.incrementAndGet();
}
static int getInstanceCounter() {
return instanceCounter.get();
}
....
}
Singleton:
@Service
class MessageService {
private final MessageBuilder messageBuilder;
MessageService(MessageBuilder messageBuilder) {
this.messageBuilder = messageBuilder;
}
Message createMessage(String content, String receiver) {
return messageBuilder
.withContent(content)
.withReceiver(receiver)
.build();
}
}
Test:
@RunWith(SpringRunner.class)
@SpringBootTest
public class MessageServiceTest {
@Autowired
private MessageService messageService;
@Test
public void shouldCreateTwoBuilders() throws Exception {
//when
messageService.createMessage("text", "alice");
messageService.createMessage("msg", "bob");
//then
int prototypeCounter = MessageBuilder.getInstanceCounter();
assertEquals("Wrong number of instances", 2, prototypeCounter);
}
}
Obviously test fails because injection happens only once and actual result will be 1 but we expected 2.
Second case:
Singleton and Test are the same but prototype now looks like this(proxyMode was changed):
@Service
@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE,
proxyMode = ScopedProxyMode.TARGET_CLASS)
class MessageBuilder {
// ...
}
When we start our test we see that actual result is 6 because of inside createMessage
method messageBuilder is accessed 3 times. and createMessage
method is invoked twice so 3*2=6.
To explain behaviour author provided following picture:
I can't understand which bean is dependant and why each access to proxy messageBuilder
genetares new bean instantiation. Why for first case the situation different ? Could you explain it ? As far I understand it - proxy are crated anyway - using CGLIB or using Dynamic proxy so anyway proxy is injected