A little bit new with spring. When I instantiate a bean via interface, it doesn't seem to get events, if however, I use actual class implementing the interface, then the event is received. Why is this? Code below.
package javabeans.di;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextStartedEvent;
public class HelloWorldImpl implements HelloWorld, ApplicationListener<ContextStartedEvent> {
private String msg;
public HelloWorldImpl(String s){
msg = s;
}
@Override
public void printHelloWorld() {
System.out.println("Hello : " + msg);
}
public void onApplicationEvent(ContextStartedEvent event) {
System.out.println("ContextStartedEvent Received");
}
}
Here is the calling code:
public static void main(String[] args) {
ConfigurableApplicationContext ctx = new AnnotationConfigApplicationContext(HelloWorldConfig.class);
// Let us raise a start event.
ctx.start();
HelloWorld obj = (HelloWorld) ctx.getBean("helloWorld");
obj.printHelloWorld();
ctx.stop();
}
Config class:
@Configuration
public class HelloWorldConfig {
@Bean
@Scope("prototype")
public HelloWorld helloWorld(){
return new HelloWorldImpl("Hello java beans");
}
}
The interface:
package javabeans.di;
public interface HelloWorld {
void printHelloWorld();
}
"ContextStartedEvent Received" never gets shown if the bean has a prototype scope.
NOTE: If I change return type of bean method to HelloWorldImpl
in the config class, and also change HelloWorld
to HelloWorldImpl
inside main (two occurrences - basically on the line where I call getBean
), then this works also with prototype beans.
Why would that be? Additionally if I create two instances of HelloWorldImpl
in main, in a manner described in this paragraph, still the event is received only once (but that might be separate issue).
NoUniqueBeanDefinitionException. Another similar cause for the bean creation exception is Spring trying to inject a bean by type, namely by its interface, and finding two or more beans implementing that interface in the context.
It's because that as long as the prototype bean does not hold a reference to another resource itself, such as a database connection or a session object, it will get garbage collected as soon as all references to the object have been removed or the object goes out of scope.
Spring provides an ApplicationContextAware interface that allows beans access to the ApplicationContext . This interface provides a single setApplicationContext method. The following code shows the use of ApplicationContextAware . The preceding code is of a bean that implements ApplicationContextAware .
When using java based configuration what happens is very early in the process the @Configuration
classes are read with ASM (they aren't loaded through a class loader yet). Based on that read bytecode Spring creates the bean definitions and proxy based classes.
A @Bean
method (regardless where it is) is basically the same as a FactoryBean
. It acts more or less in the same way. When the meta data is created it does so by inspecting the method signature and using the return type to create a factory. This return type is basically used for the getObjectType
method of a FactoryBean
. And this the result of that method is used to determine what the bean supports.
Now when return HelloWorld
as a type you get a factory creating beans of that type. When using HelloWorldImpl
you will get a factory creating beans of that type. The first doesn't contain the ApplicationListener
interface and as such is ignored by spring, the second however does (it is detected at that point of generating the (auto) configuration meta data).
So when using @Configuration
with @Bean
it is important to be as specific as possible about the return type.
Isn't this because the interface itself doesn't have the listening method?
Shouldn't you
package javabeans.di;
public interface HelloWorld extends ApplicationListener<ContextStartedEvent>{
void printHelloWorld();
public void onApplicationEvent(ContextStartedEvent event);
}
And then @Override
in the implementing class?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With