Fixing "The web application [ROOT] created a ThreadLocal with key of type [com.netflix.hystrix.Hystrix$1]" - spring-boot

I'm using Netflix cloud in a spring-boot API Gateway and I building the spring-boot app as a WAR that can be run standalone or deployed to a Tomcat container. When the spring-boot app is redeployed in Tomcat, for instance, using the Cargo Maven plugin, Tomcat MemoryLeakDetection complains about "The web application [ROOT] created a ThreadLocal with key of type [com.netflix.hystrix.Hystrix$1]".
After redeploying my spring-boot app 9 times Tomcat runs out of memory. How do I remove the Hystrix ThreadLocal so that it doesn't cause the WebappClassLoader instance to stick around every time I redeploy my spring-boot app. The result is that each redeploy leaves an instance of WebappClassLoader that can't be Garbage Collected because of the Hystrix ThreadLocal?
Here's the out-of-memory stacktrace:
29-Apr-2016 12:21:50.721 SEVERE [http-apr-8080-exec-38] org.apache.catalina.loader.WebappClassLoaderBase.checkThreadLocalMapForLeaks The web application [my-spring-boot-app] created a ThreadLocal with key of type [com.netflix.hystrix.Hystrix$1] (value [com.netflix.hystrix.Hystrix$1#8302924]) and a value of type [java.util.LinkedL
ist] (value [[]]) but failed to remove it when the web application was stopped. Threads are going to be renewed over time to try and avoid a probable memory leak.
29-Apr-2016 12:22:00.484 INFO [http-apr-8080-exec-38] org.apache.catalina.startup.HostConfig.undeploy Undeploying context [/my-spring-boot-app]
29-Apr-2016 12:22:09.353 INFO [http-apr-8080-exec-33] org.apache.catalina.startup.HostConfig.deployWAR Deploying web application archive D:\apache-tomcat-8.0.28\webapps\my-spring-boot-app.war
12:23:08,056 |-INFO in ch.qos.logback.classic.joran.action.ConfigurationAction - debug attribute not set
12:23:08,089 |-INFO in ch.qos.logback.classic.joran.action.ConfigurationAction - Setting ReconfigureOnChangeFilter scanning period to 30 seconds
12:23:08,089 |-INFO in ReconfigureOnChangeFilter{invocationCounter=0} - Will scan for changes in [[D:\apache-tomcat-8.0.28\webapps\my-spring-boot-app\WEB-INF\classes\logba
ck.xml]] every 30 seconds.
12:23:08,089 |-INFO in ch.qos.logback.classic.joran.action.ConfigurationAction - Adding ReconfigureOnChangeFilter as a turbo filter
12:23:08,106 |-INFO in ch.qos.logback.core.joran.action.StatusListenerAction - Added status listener of type [ch.qos.logback.core.status.OnConsoleStatusListener]
12:23:08,118 |-INFO in ch.qos.logback.core.joran.action.AppenderAction - About to instantiate appender of type [ch.qos.logback.core.ConsoleAppender]
12:23:08,136 |-INFO in ch.qos.logback.core.joran.action.AppenderAction - Naming appender as [CONSOLE]
12:23:08,176 |-INFO in ch.qos.logback.core.joran.action.NestedComplexPropertyIA - Assuming default type [ch.qos.logback.classic.encoder.PatternLayoutEncoder] for [encoder] property
java.lang.OutOfMemoryError: Metaspace
Dumping heap to java_pid15972.hprof ...
Heap dump file created [206407579 bytes in 1.201 secs]
29-Apr-2016 12:23:10.870 SEVERE [http-apr-8080-exec-33] org.apache.tomcat.util.modeler.BaseModelMBean.invoke Exception invoking method check
java.lang.OutOfMemoryError: Metaspace
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:763)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
at org.apache.catalina.loader.WebappClassLoaderBase.findClassInternal(WebappClassLoaderBase.java:2496)
at org.apache.catalina.loader.WebappClassLoaderBase.findClass(WebappClassLoaderBase.java:860)
at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1302)
at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1167)
at org.slf4j.impl.StaticLoggerBinder.init(StaticLoggerBinder.java:97)
at org.slf4j.impl.StaticLoggerBinder.<clinit>(StaticLoggerBinder.java:55)
at org.slf4j.LoggerFactory.bind(LoggerFactory.java:141)
at org.slf4j.LoggerFactory.performInitialization(LoggerFactory.java:120)
at org.slf4j.LoggerFactory.getILoggerFactory(LoggerFactory.java:331)
at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:283)
at org.apache.commons.logging.impl.SLF4JLogFactory.getInstance(SLF4JLogFactory.java:155)
at org.apache.commons.logging.impl.SLF4JLogFactory.getInstance(SLF4JLogFactory.java:132)
at org.apache.commons.logging.LogFactory.getLog(LogFactory.java:655)
at org.springframework.boot.context.web.SpringBootServletInitializer.onStartup(SpringBootServletInitializer.java:84)
at org.springframework.web.SpringServletContainerInitializer.onStartup(SpringServletContainerInitializer.java:175)

Ok, I think I solved my own problem such that Tomcat MemoryLeakDetection no longer complains about the Hystrix ThreadLocal anymore. What I did was I added a custom ServletContextListener and in the "contextDestroyed()" method I found a way to forcibly remove the private static ThreadLocal from the com.netflix.hystrix.Hystrix class. This appears to solve the problem. Here's an excerpt from my custom servlet listener:
/**
* The listener interface for receiving ServletContext events.
* The class that is interested in processing a ServletContext
* event implements this interface, and the object created
* with that class is registered with a component using the
* component's <code>addServletContextListener<code> method. When
* the ServletContext event occurs, that object's appropriate
* method is invoked.
*
* #see ServletContextEvent
*/
#Component
public class GatewayServletContextListener implements ServletContextListener{
private static final Logger LOG = LoggerFactory.getLogger(GatewayServletContextListener.class);
#Override
public void contextInitialized(ServletContextEvent arg0) {
LOG.info("Servlet context listener observed context initialized");
}
#Override
public void contextDestroyed(ServletContextEvent arg0) {
LOG.info("Servlet context listener observed context destroyed");
cleanupThreadLocals();
}
/**
* Cleanup thread locals.
*/
private void cleanupThreadLocals() {
try {
LOG.info("Cleaning up ThreadLocals ...");
Field currentCommandField = ReflectionUtils.findField(Hystrix.class, "currentCommand");
Preconditions.checkNotNull(currentCommandField);
ReflectionUtils.makeAccessible(currentCommandField);
#SuppressWarnings("rawtypes")
ThreadLocal currentCommand = (ThreadLocal)currentCommandField.get(null);
Preconditions.checkNotNull(currentCommand);
currentCommand.remove();
LOG.info("Forcibly removed Hystrix 'currentCommand' ThreadLocal");
LOG.info("Done cleaning up ThreadLocals");
} catch(Exception e) {
LOG.warn(e.getMessage(), e);
}
}
}
And here's the Tomcat log on my spring-boot app redeploy:
2016-05-03/10:11:08.646/PDT [http-apr-8080-exec-3] INFO x.y.z.listeners.GatewayServletContextListener - Servlet context listener observed context destroyed
2016-05-03/10:11:08.648/PDT [http-apr-8080-exec-3] INFO x.y.z.listeners.GatewayServletContextListener - Cleaning up ThreadLocals ...
2016-05-03/10:11:08.652/PDT [http-apr-8080-exec-3] INFO x.y.z.listeners.GatewayServletContextListener - Forcibly removed Hystrix 'currentCommand' ThreadLocal
2016-05-03/10:11:08.654/PDT [http-apr-8080-exec-3] INFO x.y.z.listeners.GatewayServletContextListener - Done cleaning up ThreadLocals

Related

How can I confirm that Spring Transactions are working properly?

I working on an Spring 3.2 application running in OC4j. I have a number of methods annotated with Spring's #Transactional annotation as follows:
// in MyServiceImpl
#Transactional()
public void insertPaymentData(PaymentParams paymentParams) {
// call to MyDaoImpl which in turn calls a
// Spring JDBC Stored Procedure implementation
}
// in the Stored Procedure implementation
#Transactional(propagation = Propagation.MANDATORY)
public void insertPaymentData(PaymentParams paymentParams) {
// execute procedure here
}
In the logs for my local OC4J instance I see entries such as the following which make me think that Transactions are configured correctly:
[1.2.3.4-user123] 2019-03-20 17:36:14,805 DEBUG AbstractFallbackTransactionAttributeSource::getTransactionAttribute - Adding transactional method 'MyServiceImpl.insertPaymentData' with attribute: PROPAGATION_REQUIRED,ISOLATION_DEFAULT,timeout_1800; ''
[1.2.3.4-user123] 2019-03-20 17:36:14,809 DEBUG AbstractBeanFactory::doGetBean - Returning cached instance of singleton bean 'transactionManager'
[1.2.3.4-user123] 2019-03-20 17:36:14,812 DEBUG AbstractPlatformTransactionManager::getTransaction - Creating new transaction with name [my.app.service.payments.MyServiceImpl.insertPaymentData]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT,timeout_1800; ''
[1.2.3.4-user123] 2019-03-20 17:36:14,821 DEBUG AbstractBeanFactory::doGetBean - Returning cached instance of singleton bean 'transactionManager'
[1.2.3.4-user123] 2019-03-20 17:36:14,822 DEBUG AbstractPlatformTransactionManager::handleExistingTransaction - Participating in existing transaction
[1.2.3.4-user123] 2019-03-20 17:36:14,822 DEBUG DataSourceUtils::doGetConnection - Fetching JDBC Connection from DataSource
[1.2.3.4-user123] 2019-03-20 17:36:14,823 DEBUG DataSourceUtils::doGetConnection - Registering transaction synchronization for JDBC Connection
[1.2.3.4-user123] 2019-03-20 17:38:42,550 DEBUG DataSourceUtils::doReleaseConnection - Returning JDBC Connection to DataSource
[1.2.3.4-user123] 2019-03-20 17:38:42,551 DEBUG AbstractPlatformTransactionManager::processCommit - Initiating transaction commit
Sometimes I see timeout and rollback messages there too.
However when I deploy to the development server provided by the ops department I do not see any messages like this in the logs, although the DEBUG level messages are displayed there too. I added in the following logging lines which I found somewhere on stack overflow:
logger.debug("Transaction name=" + TransactionSynchronizationManager.getCurrentTransactionName());
logger.debug("isActualTransactionActive=" + TransactionSynchronizationManager.isActualTransactionActive());
logger.debug("isSynchronizationActive=" + TransactionSynchronizationManager.isSynchronizationActive());
In the logs I now see things like this:
Transaction name=my.app.service.payments.MyServiceImpl.insertPaymentData
isActualTransactionActive=true
isSynchronizationActive=true
Are these values from TransactionSynchronizationManager telling me anything useful?
Is it telling me that transactions are working fine and to stop worrying?
I have the following in a Spring configuration file:
#Configuration
#EnableTransactionManagement
public class TransactionConfig {
#Bean
public JtaTransactionManager transactionManager() {
return new JtaTransactionManager();
}
}
And I have the following in a spring xml config file:
<tx:annotation-driven transaction-manager="transactionManager" />
Thanks!

Why doesn't Wildfly give my application access to org.Hornetq (HornetQ's API)?

I really need help.
I have a simple Java Client (run by Eclipse, outside a container).
I have Wildfly 9 running on localhost.
And I have a simple MDB deployed as an ear package on Wildfly.
The Client does a JNDI lookup for "jms/RemoteConnectionFactory "
It get's and uses a HornetQJMSConnectionFactory.
It sends an ObjectMessage to the Queue that my MDB listens to.
The MDB's onMessage(Message msg) shows it receives the message.
And that msg is an instance of HornetQObjectMessage.
But when I try to cast msg to a HornetQObjectMessage, so I can retrieve the Object, it fails.
The core error seems to be NoClassDefFoundError for HornetQObjectMessage, so my application has no access to the HornetQ API (org.hornetq module I think).
Note: The Cast is in a try catch block, but there is no output to the Wildfly log from the my catch block?
I've pasted the MDB code below.
My module.xml
And and extract of the relevant lines from the Wildfly log.
Clearly the message arrives. See lines with "XXXXXXXXXX" prefix.
Then failure!
The ear has no war module.
Note: I added #ApplicationScoped only because it was suggested to solve an earlier problem I posted. Is that my problem now?
Please help.
MDB CODE:
#MessageDriven(
activationConfig ={
#ActivationConfigProperty(propertyName="destinationType", propertyValue="javax.jms.Queue"),
#ActivationConfigProperty(propertyName="maxSession",propertyValue="1"),
#ActivationConfigProperty(propertyName="destination", propertyValue="jms/goSendToServerQueue")
})
public class GoMsgBean implements MessageListener {
#ApplicationScoped
#Inject
#JMSConnectionFactory ("java:jboss/DefaultJMSConnectionFactory")
private JMSContext jmsCtx;
#Resource(name = "java:jboss/exported/jms/goSendToClientQueue")
private Queue sendToClientQueue;
public GoMsgBean () {
}
#PostConstruct
public void myInit () {
System.out.println("XXXXXXXXXX Post Construct - GoMsgBean");
}
#PreDestroy
public void myDestroy () {
System.out.println("XXXXXXXXXX Post Destroy - GoMsgBean");
}
public void onMessage(Message msg) {
System.out.println("XXXXXXXXXX Greetings From GoMsgBean.onMessage()");
System.out.println("XXXXXXXXXX Message Type is " + msg.getClass().getSimpleName());
try {
HornetQObjectMessage oMsg = (HornetQObjectMessage) msg;
System.out.println("XXXXXXXXXX Successfully Cast msg to HornetQObjectMessage");
System.out.println("XXXXXXXXXX Object Type is " + oMsg.getObject().getClass().getSimpleName());
} catch (ClassCastException e) {
System.out.println("XXXXXXXXXX ClassCastException");
} catch (JMSException e) {
System.out.println("XXXXXXXXXX JMSException ");
} catch (Exception e) {
System.out.println("XXXXXXXXXX " + e.getClass().getSimpleName()");
}
}
}
MODULE.XML
<?xml version="1.0" encoding="UTF-8"?>
<module xmlns="urn:jboss:module:1.1" name="org.acmemq">
<dependencies>
<!-- we depend on org.hornetq module since we will send messages to -->
<!-- the HornetQ server embedded in the local WildFly instance -->
<module name="org.hornetq" />
</dependencies>
</module>
WILDFLY LOG (Extract of WARN and ERROR)
Calling "D:\Bulletproof\bpWildFly\bin\standalone.conf.bat"
Setting JAVA property to "C:\Program Files\Java\jdk1.8.0_05\bin\java"
===============================================================================
JBoss Bootstrap Environment
JBOSS_HOME: "D:\Bulletproof\bpWildFly"
JAVA: "C:\Program Files\Java\jdk1.8.0_05\bin\java"
JAVA_OPTS: "-Dprogram.name=standalone.bat -Xms64M -Xmx512M -XX:MaxPermSize=256M -Djava.net.preferIPv4Stack=true -Djboss.modules.system.pkgs=org.jbos
s.byteman"
===============================================================================
Java HotSpot(TM) 64-Bit Server VM warning: ignoring option MaxPermSize=256M; support was removed in 8.0
...
13:59:09,204 WARN [org.jboss.as.txn] (ServerService Thread Pool -- 60) WFLYTX0013: Node identifier property is set to the default value. Please make
sure it is unique.
13:59:09,880 INFO [org.jboss.as.connector.subsystems.datasources] (MSC service thread 1-6) WFLYJCA0001: Bound data source [java:jboss/datasources/ExampleDS]
13:59:09,994 WARN [org.jboss.as.messaging] (MSC service thread 1-6) WFLYMSG0001: AIO wasn't located on this platform, it will fall back to using pure
Java NIO.
13:59:10,010 INFO [org.jboss.as.server.deployment.scanner] (MSC service thread 1-1) WFLYDS0013: Started FileSystemDeploymentService for directory D:\
Bulletproof\bpWildFly\standalone\deployments
...
13:59:13,067 WARN [org.jboss.weld.Validator] (MSC service thread 1-8) WELD-001440: Scope type #javax.enterprise.context.ApplicationScoped() used on i
njection point [BackedAnnotatedField] #ApplicationScoped #Inject #JMSConnectionFactory private org.america3.gotest.server.messaging.GoMsgBean.jmsCtx
13:59:13,076 WARN [org.jboss.weld.Validator] (MSC service thread 1-8) WELD-001440: Scope type #javax.enterprise.context.ApplicationScoped() used on i
njection point [BackedAnnotatedField] #ApplicationScoped #Inject #JMSConnectionFactory private org.america3.gotest.server.messaging.GoMsgBean.jmsCtx
13:59:13,316 INFO [org.jboss.as] (Controller Boot Thread) WFLYSRV0025: WildFly Full 9.0.2.Final (WildFly Core 1.0.2.Final) started in 6207ms - Starte
d 480 of 676 services (264 services are lazy, passive or on-demand)
#START UP COMPLETED#
#MESSAGE RECEIVED#
14:01:04,983 INFO [stdout] (Thread-3 (HornetQ-client-global-threads-1527152166)) XXXXXXXXXX Post Construct - GoMsgBean
14:01:04,985 INFO [stdout] (Thread-3 (HornetQ-client-global-threads-1527152166)) XXXXXXXXXX Greetings From GoMsgBean.onMessage()
14:01:04,986 INFO [stdout] (Thread-3 (HornetQ-client-global-threads-1527152166)) XXXXXXXXXX Message Type is HornetQObjectMessage
14:01:04,987 INFO [stdout] (Thread-3 (HornetQ-client-global-threads-1527152166)) XXXXXXXXXX Post Destroy - GoMsgBean
14:01:04,989 ERROR [org.jboss.as.ejb3.invocation] (Thread-3 (HornetQ-client-global-threads-1527152166)) WFLYEJB0034: EJB Invocation failed on component GoMsgBean for method public void org.america3.gotest.server.messaging.GoMsgBean.onMessage(javax.jms.Message):javax.ejb.EJBTransactionRolledbackException: WFLYEJB0457: Unexpected Error
...
at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.NoClassDefFoundError: org/hornetq/jms/client/HornetQObjectMessage
...
... 52 more
Caused by: java.lang.ClassNotFoundException: org.hornetq.jms.client.HornetQObjectMessage from [Module "deployment.GoTest.ear.GoTest.jar:main" from Service Module Loader]
...
... 80 more
14:01:05,002 ERROR [org.hornetq.ra] (Thread-3 (HornetQ-client-global-threads-1527152166)) HQ154004: Failed to deliver message: javax.ejb.EJBTransactio
nRolledbackException: WFLYEJB0457: Unexpected Error
at org.jboss.as.ejb3.tx.CMTTxInterceptor.handleInCallerTx(CMTTxInterceptor.java:153)
...
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.NoClassDefFoundError: org/hornetq/jms/client/HornetQObjectMessage
...
... 52 more
Caused by: java.lang.ClassNotFoundException: org.hornetq.jms.client.HornetQObjectMessage from [Module "deployment.GoTest.ear.GoTest.jar:main" from Service Module Loader]
...
... 80 more

exceptionListener and errorHandler in apache camle jms component, not working for me

I am connecting to IBM MQ using apache camel Jms component using below code and configuration. When MQ manager goes down by any reason while message polling or is down at the time of camel route startup, my errorHandler or exceptionListener is not invoked.
jmsComponenet = JmsComponent.jmsComponentAutoAcknowledge((ConnectionFactory) obj);
camelContext.addComponent("ibm-mq", jmsComponenet);
camelContext.addRoutes(new RouteBuilder() {
#Override
public void configure() throws Exception {
from("ibm-mq:queue:PE_OUTBOUND?concurrentConsumers=5&exceptionListener=#exceptionListener&errorHandler=#errorHandler").to(
"mqprocessor");
}
});
Spring Application-Context :
<bean id="exceptionListener" class="com.*****.JMSExceptionListener" />
<bean id="errorHandler" class="com.*****.JMSConnectionErrorHandler" />
The classess implements required interface
javax.jms.ExceptionListener and org.springframework.util.ErrorHandler
Despite of specifying Handler and Listener still MQ Connection error is just logged as WARN message in log and controll do not reach these classes.
I am missing / doing anything incorrect here?
Here is DEBUG log -
11:18:20,783 DEBUG [org.springframework.beans.factory.support.DefaultListableBeanFactory] (http-localhost/127.0.0.1:8080-1) Returning cached instance of singleton bean 'errorHandler'
11:18:20,784 DEBUG [org.apache.camel.util.IntrospectionSupport] (http-localhost/127.0.0.1:8080-1) Configured property: errorHandler on bean: org.apache.camel.component.jms.JmsConfiguration#17b86db4 with value: com.manh.processors.JMSConnectionErrorHandler#4d2a5096
11:18:20,784 DEBUG [org.springframework.beans.factory.support.DefaultListableBeanFactory] (http-localhost/127.0.0.1:8080-1) Returning cached instance of singleton bean 'exceptionListener'
11:18:20,784 DEBUG [org.apache.camel.util.IntrospectionSupport] (http-localhost/127.0.0.1:8080-1) Configured property: exceptionListener on bean: org.apache.camel.component.jms.JmsConfiguration#17b86db4 with value: com.manh.processors.JMSExceptionListener#6c8b8e49
11:18:20,785 DEBUG [org.apache.camel.spring.SpringCamelContext] (http-localhost/127.0.0.1:8080-1) ibm-mq://queue:PE_OUTBOUND?concurrentConsumers=5&errorHandler=%23errorHandler&exceptionListener=%23exceptionListener converted to endpoint: Endpoint[ibm-mq://queue:PE_OUTBOUND?concurrentConsumers=5&errorHandler=%23errorHandler&exceptionListener=%23exceptionListener] by component: org.apache.camel.component.jms.JmsComponent#fb03c67
11:18:20,785 TRACE [org.apache.camel.management.DefaultManagementLifecycleStrategy] (http-localhost/127.0.0.1:8080-1) Checking whether to register Endpoint[ibm-mq://queue:PE_OUTBOUND?concurrentConsumers=5&errorHandler=%23errorHandler&exceptionListener=%23exceptionListener] from route: null
default testConnectionOnStartup = false. I set it to ture and got exception on startup of route.
ErrorHandler come into play only if exception occurs while processing of message.
Thank you for the help Daniel.
Logging with a warn message is default when an error handler cannot be found, so I suspect Camel is not able to find an instance of the provided bean. Try setting the camel log level to debug and see what it says when the route is started, I would expect some kind of message saying that the referenced beans cannot be found.

Spring Web Application: Post-DispatcherServlet initialization

I am using Spring 3.2 DispatcherServlet. I am looking for an initialization hook that takes place after the DispatcherServlet initialization completes; either a standard Spring solution or servlet solution. Any suggestions?
As a point of reference, the final logging statements after servlet startup follow. I want my initialization method to execute right after the configured successfully log statement.
DEBUG o.s.w.s.DispatcherServlet - Published WebApplicationContext of servlet 'mySpringDispatcherServlet' as ServletContext attribute with name [org.springframework.web.servlet.FrameworkServlet.CONTEXT.mySpringDispatcherServlet]
INFO o.s.w.s.DispatcherServlet - FrameworkServlet 'mySpringDispatcherServlet': initialization completed in 5000 ms
DEBUG o.s.w.s.DispatcherServlet - Servlet 'mySpringDispatcherServlet' configured successfully
From my research, so far the following have not had the desired effect:
Extending ContextLoaderListener/implementing ServletContextListener per this answer.
Implementing WebApplicationInitializer per the javaoc.
My beans use #PostConstruct successfully; I'm looking for a Servlet or container level hook that will be executed essentially after the container initializes and post-processes the beans.
The root issue was that I couldn't override the final method HttpsServlet.init(). I found a nearby #Override-able method in DispatcherServlet.initWebApplicationContext that ensured my beans and context were fully initialized:
#Override
protected WebApplicationContext initWebApplicationContext()
{
WebApplicationContext wac = super.initWebApplicationContext();
// do stuff with initialized Foo beans via:
// wac.getBean(Foo.class);
return result;
}
From Spring's Standard and Custom Events.
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;
#Component
public class ApplicationContextListener implements
ApplicationListener<ContextRefreshedEvent> {
#Override
public void onApplicationEvent(ContextRefreshedEvent event) {
System.out.println("ApplicationContext was initialized or refreshed: "
+ event.getApplicationContext().getDisplayName());
}
}
The event above will be fired when the DispatcherServlet is initialized, such as when it prints:
INFO org.springframework.web.servlet.DispatcherServlet - FrameworkServlet 'ServletName': initialization completed in 1234 ms
You can implement ApplicationListener<ContextStartedEvent> within your application context. This event listener will then be called once for your root context and once for each servlet context.
public class StartupListener implements ApplicationListener<ContextStartedEvent> {
public void onApplicationEvent(ContextStartedEvent event) {
ApplicationContext context = (ApplicationContext) event.getSource();
System.out.println("Context '" + context.getDisplayName() + "' started.");
}
}
If you define this listener within your servlet context, it should be called just once for the servlet context intself.
try this, change your port number.
In my case i changed from server.port=8001 to server.port=8002

How to prevent a Java EE app from starting when Spring DI fails

(I'm not sure if this question applies to Java EE apps in general or is Websphere-specific.)
When we get a Spring DI failure on apps we've deployed to WebSphere (a JNDI lookup failure, for example) the application still appears to have started successfully.
[15/02/11 17:21:22:495 GMT] 00000037 ContextLoader E org.springframework.web.context.ContextLoader initWebApplicationContext Context initialization failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'mybean' defined in
...big stack trace...
[15/02/11 17:21:22:526 GMT] 00000037 ApplicationMg A WSVR0221I: Application started: myapp
How can I make the application fail to start if exceptions are thrown during the spring initialisation?
Check if this helps. Based on that I'd guess it's application server-specific, but not sure.
Binding Spring context's lifecycle with an application's lifecycle should help.
Inside J2EE server Spring context is acquired mostly through the org.springframework.context.access.ContextSingletonBeanFactoryLocator (for example it is used by org.springframework.ejb.interceptor.SpringBeanAutowiringInterceptor). Invoking Spring context initialization eagerly on the application startup should do the job.
It could be done in the WebSphere specific way using Startup Beans:
#RemoteHome(AppStartUpHome.class)
#Stateless
public class SpringLifecycleBean {
private static Log logger = LogFactory.getLog(SpringLifecycleBean.class);
private static BeanFactoryReference bfr;
public boolean start() throws RemoteException {
logger.debug("Initializing spring context.");
try {
BeanFactoryLocator bfl = ContextSingletonBeanFactoryLocator.getInstance();
//hardcoded spring context's name (refactor for more complex use cases)
bfr = bfl.useBeanFactory("appContext");
} catch (Exception e) {
logger.error("Spring context startup failed", e);
return false;
}
return true;
}
public void stop() throws RemoteException {
if (bfr != null) {
logger.debug("Releasing spring context.");
bfr.release();
}
}
}
Adding a webapp module with javax.servlet.ServletContextListener containing similar code will also work.

Resources