You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
In my code, I wanted to replace a hikari DataSource, which is a @Context bean; this is by definition a singleton auto-initialized with the context start. My factory replaced it as
Note the missing @Contextqualifier in this replacement; I would expect that the created bean definition has @Singleton (default) scope. This kind of replacement usually works - as the BeanDefinition is replaced incl. its construction procedure.
The expected outcome was that my replacement Bean will be seen as DataSource; subject to BeanCreation listeners etc. and that the original DataSource implementation will not be instantiated at all.
Actual Behaviour
The observed behaviour with @Context scoped beans is that:
both replacement, but also the original bean instances are created. Any unwanted side effect of the replaced bean's init code will happen.
sometimes, the original (not replacement) bean is injected
whether one or two instanceof of the bean are created depends on bean initialization order.
The example application demonstrates, that @Replaces changes scope, under regular circumstances. Not documented explcitly, but is implied the concept of "replacing the bean definition" (that includes the scope spec). This can be seen in ConsumerBean that injects Prototype beans that replace Singleton original definition. If it is not indended to work that way, it should be prominently documented and checked during the replacement process with at least warning log.
The example application demonstrates, in the default provided configuration, that both the replacement (ReplacementMultiBean) AND original (MultiBean) instances are created during startup. Only the proper (ReplacementMultiBean) is however injectable. The MultiBean should have not been created at all.
Next, if the example app is modified so that ReplacementConsumer is @Order(100) (instead of -1000), the original bean is injected and startup fails on assertion. The ReplacementMultiBean is never created:
beanCandidateCache is populated with ReplacementBeanFactory definition by findBeanCandidatesInternal (OK)
DefaultBeanContext.BeanKey equals for both ReplacementBeanFactory and MultiBeanFactory methods
the MultiBean (earlier initialized singleton) is already in the singletonByArgumentAndQualifier map
Therefore, even though SingletonScope.findBeanRegistration is called with ReplacementBeanFactory bean definition, the OTHER factory's bean instance is actually returned.
Note that the @Order is provided to demonstrate the outcome depends on eager initialization order. If @Order is absent (in most cases it is), the initialization order is random/unspecified and in my case even depended on FQN of the bean/factory: mere refactoring of example app classes into different package changed the behaviour from non-working to working.
Finally, if the code is changed so that ReplacementBeanFactory produces @Context-scoped bean, the original MultiBean definition is properly replaced even during eager singleton initialization at the context startup, and the MultiBean instance is never created at all.
Expected Behavior
In my code, I wanted to replace a hikari DataSource, which is a
@Context
bean; this is by definition a singleton auto-initialized with the context start. My factory replaced it asNote the missing
@Context
qualifier in this replacement; I would expect that the created bean definition has@Singleton
(default) scope. This kind of replacement usually works - as the BeanDefinition is replaced incl. its construction procedure.The expected outcome was that my replacement Bean will be seen as DataSource; subject to BeanCreation listeners etc. and that the original DataSource implementation will not be instantiated at all.
Actual Behaviour
The observed behaviour with
@Context
scoped beans is that:The example application demonstrates, that
@Replaces
changes scope, under regular circumstances. Not documented explcitly, but is implied the concept of "replacing the bean definition" (that includes the scope spec). This can be seen inConsumerBean
that injectsPrototype
beans that replaceSingleton
original definition. If it is not indended to work that way, it should be prominently documented and checked during the replacement process with at least warning log.The example application demonstrates, in the default provided configuration, that both the replacement (
ReplacementMultiBean
) AND original (MultiBean
) instances are created during startup. Only the proper (ReplacementMultiBean
) is however injectable. TheMultiBean
should have not been created at all.Next, if the example app is modified so that
ReplacementConsumer
is@Order(100)
(instead of -1000), the original bean is injected and startup fails on assertion. TheReplacementMultiBean
is never created:beanCandidateCache
is populated withReplacementBeanFactory
definition byfindBeanCandidatesInternal
(OK)DefaultBeanContext.BeanKey
equals for bothReplacementBeanFactory
andMultiBeanFactory
methodssingletonByArgumentAndQualifier
mapTherefore, even though
SingletonScope.findBeanRegistration
is called withReplacementBeanFactory
bean definition, the OTHER factory's bean instance is actually returned.Note that the
@Order
is provided to demonstrate the outcome depends on eager initialization order. If@Order
is absent (in most cases it is), the initialization order is random/unspecified and in my case even depended on FQN of the bean/factory: mere refactoring of example app classes into different package changed the behaviour from non-working to working.Finally, if the code is changed so that
ReplacementBeanFactory
produces@Context
-scoped bean, the originalMultiBean
definition is properly replaced even during eager singleton initialization at the context startup, and the MultiBean instance is never created at all.Steps To Reproduce
contextbean-errors
.@Order
of ReplacementConsumer as described above, and re-run. Wrong bean is injected, startup fails@Order
back,uncomment@Context
scope inReplacementBeanFactory
. Now only the proper instance of the bean is created.Environment Information
Example Application
https://github.com/sdedic/micronaut-dbbugs2
Version
4.7.6
The text was updated successfully, but these errors were encountered: