When I add ApplicationListener to a class, Spring instantiates the bean eagerly (probably to make sure that the bean gets all the events).
In my case, I have a bean which listens for "CacheFlush" events (i.e. I don't really care how many I might miss).
How do I implement a lazy ApplicationEvent listener in Spring 3.0?
I am not sure if what you want to do is possible directly, but one potential solution is to have a separate Observable bean listen for the cache flush events and notify its Observers when one comes in. Have your lazy bean register with the Observable when it is initialized.
Related
I have a CDI producer method which creates an UserBean. The producer fires an UserBeanEvent. Other beans rely on that user bean and those beans may be used in the observer methods.
CDI again tries to create the user bean, the producer is invoked, the event is fired and so on - endless loop.
Is there any neat way to fire the event AFTER the producer completed and the bean was fully added to the bean store? I looked through the sources but I was not able to find anything.
I'm using WELD 2.3.5.final on WildFly 10.1
You need to detail several things, and one of the most important one is scope, and at what point is the bean needed?
Obviously if there is an observer method that listens to this bean event, and also needs a reference to this bean in the observer parameter, then you are definitely creating a cyclic dependency, which you cannot resolve, as the events in CDI are synchronous by default (And even if you use the fireAsync, there is no guarantee that by the time the event arrive, CDI has put the bean into proper context)
I would solve this problem by doing a method injection on an eargerly loaded bean such as ejbs Singleton or #ApplicationScoped with some kind of earger loading, and then fire the event from there.
Assuming that the bean is eargerly loaded:
public class EargerBean {
#Inject
private Event<BeanEvent> event;
#Inject
public void onInjected(Bean bean){
BeanEvent beanEvent ...;
event.fire(beanEvent);
}
}
In my spring bean I want to use send spring event functionality. The problem is event can't be sent if spring context was not initialized and my bean by some reasons can send events before that happen.
I used the following:
implement ApplicationContextAware and use ConfigurableApplicationContext.isActive() - this becomes true in the beginning of the context initialization phase
use ConfigurableApplicationContext.isRunning() - this throws exception IllegalStateException("LifecycleProcessor not initialized...
listen for ContextRefreshedEvent - this doesn't work because this is inner bean and is used as a property for the bean that implements BeanFactoryPostProcessor
implementing SmartLifecycle also doesn't work because for inner beans
So what is the EASY and correct way to determine if context is running and event can be sent?
Hopefully this is already fixed SPR-13667 in spring 4.1.7.
I know that it is fired once when the ApplicationContext is fully loaded, but what about after that during runtime? The word "Refreshed" implies that it will be triggered on a refresh but I wonder what Spring qualifies as an ApplicationContext refresh?
Followup question:
Can this event be triggered by concurrent threads? Do I need to make the EventHandler for this event thread safe?
it is fired when properties, xml or any schema files are loaded/refreshed, http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/context/support/AbstractApplicationContext.html#refresh--
Load or refresh the persistent representation of the configuration,
which might an XML file, properties file, or relational database
schema.
It is fired implicitly by spring usually, but you should be able to fire that on certain instances, But here is java doc says when that happens
As this is a startup method, it should destroy already created
singletons if it fails, to avoid dangling resources. In other words,
after invocation of that method, either all or no singletons at all
should be instantiated.
I have a bean registered as singleton and init-method and destroy-method defined on it. I am accessing the bean and can see the calls being made to both the methods. However, on changing the scope to prototype the destroy-method is not invoked.
I am not getting the rationale behind this.
Read the documentation:
In contrast to the other scopes, Spring does not manage the complete lifecycle of a prototype bean: the container instantiates, configures, and otherwise assembles a prototype object, and hands it to the client, with no further record of that prototype instance. Thus, although initialization lifecycle callback methods are called on all objects regardless of scope, in the case of prototypes, configured destruction lifecycle callbacks are not called.
And that's quite logical: your application could ask for new instances of prototype beans every 10 milliseconds, do something with the bean, and then let it go out of scope. If Spring had to destroy() them when the application shuts down, it would have to keep a reference to every created prototype bean, preventing them to be garbage-collected, and thus causing a memory leak.
How does Spring know when to call 'destory' method on a session/request scoped bean (in other words, how does it detect that the concerned bean is going out of scope)?
I read somewhere that it uses request/session listeners to be notified of these events. But these listners need to be defined in web.xml, and there's no mention of defining such listeners in Spring literature. So how does this work?
The org.springframework.web.servlet.DispatcherServlet does it. It uses own code, e.g. the org.springframework.web.context.request.RequestAttributes#registerDestructionCallback callback list functionality to register all these scoped beans.
and there's no mention of defining such listeners in Spring literature
Oh, there is:
To support the scoping of beans at the request, session, and global session levels (web-scoped beans), some minor initial configuration is required before you define your beans.[...]
If you use a Servlet 2.4+ web container, [...] you need to add the following javax.servlet.ServletRequestListener to the declarations in your web applications web.xml file[...]
From: 4.5.4.1 Initial web configuration.
Also note that Spring does not call destroy on prototype-scoped beans.
You can implement the interface DisposableBean and InitializingBean for session scoped bean.
The org.springframework.beans.factory.InitializingBean interface allows a bean to perform initialization work after all necessary properties on the bean have been set by the container. The InitializingBean interface specifies a single method afterPropertiesSet().
Implementing the org.springframework.beans.factory.DisposableBean interface allows a bean to get a callback when the container containing it is destroyed. The DisposableBean interface specifies a single method destroy().
Read more about it here: http://docs.spring.io/spring/docs/current/spring-framework-reference/html/beans.html#beans-factory-nature