Crystal Paladin opened SPR-15767 and commented
Whenever a Prototype scoped Bean is marked with an @Autowired
Environment(Spring framework provided bean),
and that prototype scoped Bean is instantiated by JSR330 Provider,
and the Class which has the Provider implements a Runnable interface and a thread is created from the program execution point main method,
we run into an issue where the Environment bean is not injected at all and results in NoSuchBeanDefinitionException: No bean named 'environment' available
Spring Creates the Environment Object as well as the Environment Bean Defined in the Java Config Classes... But When Using a thread inside a try with resources block, Spring Destroys the Environment Object that it created but not the One It created from the Java Config Classes when the try with resource block reaches the end...
@Configuration
@ComponentScan
public class ClassConfig {
@Bean
public Environment environment(ApplicationContext context) {
return context.getEnvironment();
}
}
but if we Autowire the Environment in ClassC (which is the threaded bean), the injection works fine...
but if we try to Autowire the Environment in ClassB (which is at the third level injected at a prototype class ClassA), We get the injection error 'environment' bean not found
i'm not sure if this is a Spring Issue or a JSR 330 issue since the Provider\
Note: Please Refer the Attached Sample Java Source files for complete analysis
Affects: 4.3.9
Reference URL: https://stackoverflow.com/questions/45076679/threaded-beans-doesnt-get-environment-autowired-to-them-in-spring-when-using-j
Attachments: - ClassA.java (622 bytes) - ClassB.java (570 bytes) - ClassC.java (841 bytes) - ClassConfig.java (207 bytes) - DummyParent.java (186 bytes) - InterA.java (73 bytes) - InterB.java (75 bytes) - SpringIssueReplicator.java (489 bytes)
Comment From: spring-projects-issues
Crystal Paladin commented
simple java config file
Comment From: spring-projects-issues
Crystal Paladin commented
Although the Environment Bean is not injected Automatically, we can implement a workaround in the java config file and include the following to make it work...
@Bean
public Environment environment(ApplicationContext context) {
return context.getEnvironment();
}
Comment From: spring-projects-issues
Juergen Hoeller commented
The root of the problem is that you're closing your ApplicationContext
through the try-with-resources clause here: This is effectively the same as an explicit close()
call right after obtaining your bean reference. After closing, none of the context's resources are guaranteed to be available anymore since they've been cleaned up at that point; this includes the associated Environment
. For that reason, your test case not only fails with asynchronous execution in a different thread; it also fails with a straight obj.run()
call right after the try-with-resources.
Consider your ApplicationContext
as a stateful resource with lifecycle-managed components, not just as a factory. You'll have to keep the context open as long as you're using some of its resources, including instance providers.
I'm repurposing this issue towards better error reporting here. The exception should really indicate that the context has been closed at that point, like it does for other access operations already... but not for cached autowired references yet.
Comment From: spring-projects-issues
Crystal Paladin commented
Is there a specific reason that spring doesn't destroy(during ApplicationContext close()) the beans auto created on java config classes?
Comment From: spring-projects-issues
Crystal Paladin commented
Is it possible to empower the JSR330 Provider to inject Environment (lazily during runtime) even if ApplicationContext is closed?
Comment From: spring-projects-issues
Juergen Hoeller commented
An ApplicationContext
effectively destroys all beans on close: by calling destroy methods on them, and by letting go of their instances eventually. However, if your bean doesn't have a destroy method declared (e.g. through implementing DisposableBean
or (Auto)Closeable
), the instance won't notice that it is already inactive from the context perspective (and that the context is closed).
In any case, once the ApplicationContext
is closed, fresh resolution of dependencies is not going to work anymore - by definition. You may keep using injected references (in case of a regular non-lazy Environment
injection point) but you really shouldn't bend this so far. Instead, make sure that your ApplicationContext
remains active as long as you need it, i.e. don't prematurely close it.