Run a method only at Spring Application Context startup? - java

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.

Related

Understanding Spring Boot's App Lifecycle and Startup Listeners

In Sprint Boot 2.x we can initialize our application in one of 2 approaches:
#SpringBootApplication
public class MyApp {
public static void main(String[] args) {
SpringApplication.run(MyApp.class, args);
init();
}
private void init() {
// Init the app from in here...
}
}
Or we can use a startup listener that will execute on startup:
public class StartupListener implements ApplicationListener<ContextRefreshedEvent> {
#Override
public void onApplicationEvent(ContextRefreshedEvent event) {
// Init the app from in here...
}
}
I'm wondering what tradeoffs exist by taking either approach. Not knowing much about Spring Boot's "app lifecycle", I'm wondering if there are things I will/won't have access to in either setup. Thanks in advance!
The init method is only called after startup, and is only called when running your application as a command-line program.
The init method is e.g. not called when deploying your application as a .war file.
The onApplicationEvent method is called whenever a ContextRefreshedEvent is fired, which does happen during startup, but can be called again later. See e.g. "When is ContextRefreshedEvent fired in Spring?"
For a more comparable event to the init method, use ApplicationStartedEvent.

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) {...}
...
}

EJB injection into non managed objects

we are upgrading our web application to Oracle WebLogic 12c with EJB 3.x, and we got an issue.
This is the scenario...
We have a simple EJBs that we are going to call MyService, defined with its bean and local/remote interfaces defined by the EJB 3.x annotations.
Here is a pseudo code of the scenario:
class MyListener implements ServletContextListener {
#EJB private MyService myService;
public void contextInitialized(ServletContextEvent arg0) {
// Here myService is correctly instantiated, so we do something...
}
}
Now we have to move the contextInitialized method logic inside an utility class, so the new scenario will be:
class MyUtility {
#EJB private MyService myService;
public void doSomething() {
// Here myService is NULL!!!!!
}
}
class MyListener implements ServletContextListener {
public void contextInitialized(ServletContextEvent arg0) {
new MyUtility().doSomething();
}
}
I have read a lot of documentation about that problem, and I discovered that only some kind of classes are scanned by the Application Server to resolve the injected EJBs ( Java EE 6, 5, 7 | List of managed beans or classes: EJBs , JSF beans and ..? ).
Is there a workaround to force the scanning of a custom class like mine with WebLogic?
Thank you very much.
There is an option to wrap you Injection into a CDI-Component and to use this one in your code. CDI has the capability to work in standalone java, as soon as you configured it well.
Another helpful option can be the fact, that CDI supports EJB-injection too (in some usecases):
CDI.current().select(MyService.class).get();
BUT: EJBs has their own Transaction-Management. So I would prefer the wrapping into a cdi-component to get more controll in it.

Spring #Autowired not working for eagerly initialized beans

I am trying to write a service-oriented application.
I have a been called memory defined as such:
package com.example.assets;
//imports ignored
#Resource
public class Memory {
}
And I have a service been called memoryHandler defined as such:
package com.example.service;
//imports ignored
#Service
public class MemoryHandler {
#Autowired
private Memory memory;
public void execute() {
//do something with memory
}
}
There is also another class, which is a BeanFactoryPostProcessor:
package com.example.service;
//imports ignored
#Component
public class PostProcessor implements BeanFactoryPostProcessor {
#Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
beanFactory.getBeansOfType(MemoryHandler.class, false, true);
}
}
Which prematurely looks up the bean, memoryHandler, leaving it instantiated` but not autowired. However, I want the bean to be autowired before it is fetched by the factory.
In my Main class I have written:
package com.example.service;
//imports ignored
public class Main {
public static void main(String[] args) {
final ApplicationContext context = new ClassPathXmlApplicationContext("/context.xml");
context.getBean(MemoryHandler.class).execute();
}
}
I get a NullPointerException on the line I work with the memory. I replaced the above declaration with a setter injection, and upon tracing realized that the injection never occurs.
I have changed the annotations on both components to Service, Repository, and Component and also have tried replacing Autowired with Resource to no avail.
What am I missing here? I have read all the questions that have shown up in my search for an answer, and none of them helps me (I got the tip about using Resouce annotations there).
Needless to say, I have not missed annotation configuration for my beans:
<context:annotation-config/>
<context:component-scan base-package="com.example"/>
Moreover, autowiring works just fine when autowired beans are defined in the XML configuration file, and not via annotations.
I am using Spring 3.2.3.RELEASE.
Changing the implementation of the PostProcessor is the key:
Instead of:
public class PostProcessor implements BeanFactoryPostProcessor {
I will have to write:
public class PostProcessor implements ApplicationContextAware {
This ensures that the context will be fully populated before it is post-processed, which in my case works just fine. But I am wondering if there is another way to do this, using the usual BeanFactoryPostProcessor interface?

Spring ApplicationListener is not receiving events

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

Categories