Spring ApplicationListener is not receiving events - java

I have the following ApplicationListener:
package org.mycompany.listeners;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextStartedEvent;
public class MyApplicationListener implements ApplicationListener<ContextStartedEvent> {
public MyApplicationListener() {
super();
System.out.println("Application context listener is created!");
}
/**
* {#inheritDoc}
*/
public void onApplicationEvent(final ContextStartedEvent event) {
System.out.println("Context '" + event.getApplicationContext().getDisplayName() + "' is started!");
}
}
And the following bean definition:
<bean name="myApplicationListener" class="org.mycompany.listeners.MyApplicationListener" />
I can see that bean is created as message from the constructor is printed, but context start event is never recieved. What am I missing?

ContextStartedEvent is published when you explicitly invoke ConfigurableApplicationContext.start() on the context. If you need an event that is published when context is initialized, use ContextRefreshedEvent.
See also:
3.13.2 Standard and Custom Events

Since you have no lazy loaded beans (according to you) then you are most likely using events for the wrong reason and probably should use something like InitializingBean interface instead:
public class MyBean implements InitializingBean {
#Override
public void afterPropertiesSet() throws Exception {
// ...
}
}
From Spring manual:
To interact with the container's management of the bean lifecycle, you
can implement the Spring InitializingBean and DisposableBean
interfaces. The container calls afterPropertiesSet() for the former
and destroy() for the latter to allow the bean to perform certain
actions upon initialization and destruction of your beans. You can
also achieve the same integration with the container without coupling
your classes to Spring interfaces through the use of init-method and
destroy method object definition metadata.
Source: Spring Framework - Lifecycle callbacks

Not sure if this helps, but I vaguely remember having a similar problem, which was solved by preloading and not lazy loading. Here's a quick overview of both

Related

Spring core. Default #Bean destroy method

I have my own bean:
#Bean
public MyBean myBean(){...
following spring documentation to release its own resources I should specify destroyMethod. I've not found any default destroy methods called by spring in case if destroyMethod is not specified directly.
I used
#Bean(destroyMethod = "close")
public MyBean myBean(){...
but think about possibility to do not specify destroy method directly if it has value by default.
Does spring try something by default like destroy, close, release?
If spring tries some methods by default to release resources - which ones?
As documented in Bean.destroyMethod:
As a convenience to the user, the container will attempt to infer a
destroy method against an object returned from the #Bean method. For
example, given an #Bean method returning an Apache Commons DBCP
BasicDataSource, the container will notice the close() method
available on that object and automatically register it as the
destroyMethod. This 'destroy method inference' is currently limited
to detecting only public, no-arg methods named 'close' or 'shutdown'.
In other words, if you don't specify destroyMethod, but the bean has a public close() or shutdown() method, it will be automatically used as the destroy-method.
To disable this inference, use #Bean(destroyMethod = "").
You can implement a method which will be executed before destroying and annotate it with #PreDestroy
#PreDestroy
public void methodName() {
//Your code..
}
The org.springframework.beans.factory.DisposableBean interface specifies a single method −
void destroy() throws Exception;
Simply implement it −
public class ExampleBean implements DisposableBean {
public void destroy() {
// do some destruction work
}
}
for XML-based configuration
<bean id = "exampleBean" class = "examples.ExampleBean" destroy-method = "destroy"/>
and in the bean
public class ExampleBean {
public void destroy() {
// do some destruction work
}
}
or annotate with #PreDestroy
You can extend DisposableBeanAdapter class. One of the methods it provides is the destroy method being called by Spring. This way you don't have to provide any implementation while it is required when you're using DisposableBean interface.

How to advice flowscope bean in Spring webflow

My project is using Spring web flow 2.4, and I need to use Spring AOP to advice flow scope bean to handle aspect requirement like logging.
Here is the aspect class:
#Aspect
#Component
public class LogFlowEventExecutor {
#Pointcut("execution(public * com.xyz.app.flow.*FlowBean.*(..))")
private void flowFunction() {}
#Before("flowOperation()")
public void logFlowEvent(JoinPoint jp) throws Throwable {
//logic ignored
...
}
}
And defines autoproxy in the root WebApplicationContext:
<aop:aspectj-autoproxy />
And each individual -flow.xml file
<flow xmlns="http://www.springframework.org/schema/webflow"...>
<var name="abcFlowBean" class="com.xyz.app.flow.AbcFlowBean" />
...
</flow>
I used the same pattern to easily advice Service beans and Controllers, but it didn't work on flow scoped beans, the aspect is never executed.
I thought it might be something with the JDK dynamic interface proxy, however it failed with CGLIB as well (proxy-target-class="true" attribute was set). The pointcut never got intercepted. So I doubted the flow-scope bean was never properly proxied when it's instantiated.
I tried to switch to LTW, but it threw an NoSuchMethodError (the bean was woven from the weaveinfo log). Maybe it's better to open another thread for that alone.
My question is that will it be possible to use Spring AOP to advice a flow scope bean and how to do it?
I worked around this issue by writing a Flow Execution Listener, basically the FlowExecutionListener defines a lot of callback methods that will be invoked when certain things happen in the course of a flow execution life cycle. So I created a custom listener class extends from FlowExecutionListenerAdapter that implements all methods by using empty method bodies and override what I am interested about, and this almost has the same kind of effect like AOP if you want global callbacks on all flow scope beans. But if you only need to intercept a few of them, then that's another story.
public class MyFlowExecutionListener extends FlowExecutionListenerAdapter{
#Override
public void eventSignaled(RequestContext context, Event event) {...}
#Override
public void transitionExecuting(RequestContext context, TransitionDefinition transition) {...}
#Override
public void viewRendered(RequestContext context, View view, StateDefinition viewState) {...}
#Override
public void exceptionThrown(RequestContext context, FlowExecutionException exception) {...}
...
}

Spring's method injection

I'm reading the Spring current version's documentation and have problems with understanding of the chapter 5.4.6 Method Injection. As far as I got we can provide the ability of recreation a bean every time we call the method using the bean. Documentation provides the following code example:
public class CommandManager implements ApplicationContextAware {
//Imports and comments were omitted
private ApplicationContext applicationContext;
public Object process(Map commandState) {
Command command = createCommand();
command.setState(commandState);
return command.execute();
}
protected Command createCommand() {
return this.applicationContext.getBean("command", Command.class);
}
public void setApplicationContext(
ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
where ApplicationContextAware interface looks like:
public interface ApplicationContextAware {
//JavaDocs ommited
void setApplicationContext(ApplicationContext applicationContext) throws BeansException;
}
So, what is the method public Object process(Map commandState)? Is it a callback? If so, where is it going to be called and who performs that call? After all, it's not clear why the bean is goign to be recreated every time it needed.
The Command and CommandManager classes are just example classes, where process() is a part of that example. They have nothing to do with ApplicationContextAware.
Note the comment in the example for CommandManager:
// a class that uses a stateful Command-style class to perform some processing
process() is to be called by the application, somewhere else; it doesn't matter for the sake of the example. If you are not using exactly the same model in your code, you should ignore this method and just call applicationContext.getBean() where applicable.
Finally, yes CommandManager should be registered as a bean in order for spring to call setApplicationContext().
edit
why does spring know that it have to recreate the bean with the name command every time
Given the contents of the example, it doesn't. The example code calls getBean(), which, according to the javadocs:
Return an instance, which may be shared or independent, of the specified bean.
In order to ensure that you always get a new instance, you'll need to use the prototype scope.
<bean id="beanB class="Command" scope="prototype"/>
Injection is happening actually here:
protected Command createCommand() {
// notice the Spring API dependency!
return this.applicationContext.getBean("command", Command.class);
}
We are just getting bean with different lifecycle in this method.
According to Spring's suggestion
A solution is to forego some inversion of control. You can make bean A aware of the container by implementing the ApplicationContextAware interface, and by making a getBean("B") call to the container ask for (a typically new) bean B instance every time bean A needs it.
solution for method get() could look like this:
public class SingletonA implements ApplicationContextAware {
private ApplicationContext applicationContext;
public PrototypeB getPrototypeB() {
return applicationContext.getBean("prototypeB",PrototypeB.class);
}
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
with beans defenition
<bean id="singletonA" class="di.methodinjection.SingletonA" autowire="byName"/>
<bean id="prototypeB" class="di.methodinjection.PrototypeB" scope="prototype"/>

Run a method only at Spring Application Context startup?

I need to run a method after the Spring Application Context of my web app has started up. I looked at this question but it refers to Java Servlet startup, and none of the Spring stuff has run at that point.
Is there a "SpringContext.onStartup()" method I can hook into?
Use something like the following code:
#Component
public class StartupListener implements ApplicationListener<ContextRefreshedEvent> {
#Override
public void onApplicationEvent(final ContextRefreshedEvent event) {
// do your stuff here
}
}
Of course StartupListener will need to be within the component scan's reach
Take note however that if your application uses multiple contexts (for example a root context and a web context) this method will be run once for each context.
You can write listener like this:
#Component
public class SpringContextListener implements ApplicationListener<ApplicationEvent> {
public void onApplicationEvent(ApplicationEvent arg0) {
System.out.println("ApplicationListener");
};
}
Just add component scan path like this:
<context:component-scan base-package="com.controller" />
Have a look at Better application events in Spring Framework 4.2
#Component
public class MyListener {
#EventListener
public void handleContextRefresh(ContextRefreshedEvent event) {
...
}
}
Annotate a method of a managed-bean with #EventListener to automatically register an ApplicationListener matching the signature of the method. #EventListener is a core annotation that is handled transparently in a similar fashion as #Autowired and others: no extra configuration is necessary with java config and the existing < context:annotation-driven/> element enables full support for it.

Spring IoC - Ensuring all beans are created before #PostConstruct/afterProperiesSet

I've got a project using Spring IoC for dependency injection, and I'm trying to slightly simplify my model by having one central location for accessing most of my beans.
I'm running into a problem using the #PostConstruct mechanism, or alternatively when implementing the InitializingBean interface. While all the dependencies in that particular bean may have been resolved, the dependencies in injected beans may not have been. For example I have:
public class A {
public void doSomething() {};
}
public class B {
private A objectA;
#Required
public void setObjectA(A objectA) {
this.objectA = objectA;
}
public A getObjectA() {
return objectA;
}
}
public class C implements InitializingBean {
private B objectB;
#Required
public void setObjectB(B objectB) {
this.objectB = objectB;
}
public void afterPropertiesSet() throws Exception {
objectB.getObjectA().doSomething();
}
}
My context.xml file defines these three beans and injects the appropriate properties, but I get a NullPointerException when the object of class C gets instantiated and the afterPropertiesSet method is called, debugging shows me that the call to getObjectA() returns null. If I inject object A directly into class C I get no errors.
Is there a mechanism I can use to ensure that all beans have been completely instantiated before my afterPropertiesSet method / any method annotated with #PostConstruct is called?
Thanks,
Joseph.
The afterPropertiesSet() is little too early to call methods on injected dependencies. Indeed, the init-method (if you have that in XML) is called after afterPropertiesSet() and then postProcessAfterInitialization() of BeanPostProcessors are called. You have #Required annotation and so, ofcourse, RequiredAnnotationBeanPostProcessor is executed.
Lifecycle callback methods are what they are: they inform you about lifecycle events and their purpose is not to enable you to hijack the task that Spring is performing. (Though you can do it as you did when directly injecting object A in C- but it is not recommended).
If you want to use object A (or any other spring bean for that matter) in class C, then I would recommend to use ApplicationContextAware (or BeanFactoryAware as the case may be) and use getBean() method to get fully baked and ready to serve bean!
Implement ApplicationListener[ContextRefreshedEvent] and do your work in onApplicationEvent(). Word of caution - ContextRefreshedEvent is sometimes published multiple times, so you may want to set a flag after the first time you get it to ignore the additional events.
Use #DependsOn to ensure that A is instantiated before C.

Categories