How do I properly restart a Spring boot application? - java

I'm using the code from here to restart my Spring Boot application:
Thread restartThread = new Thread(() -> restartEndpoint.restart());
restartThread.setDaemon(false);
restartThread.start();
However, the restarted application fails to create beans, ultimately due to a RejectedExecutionException thrown when trying to schedule #Scheduled-annotated methods:
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'myBean' defined in URL [insert-path-here]: Initializetion of bean failed; nested exception is org.springframework.core.TaskRejectedException: Executor [java.util.concurrent.ScheduledThreadPoolExecutor#284a4a89[Terminated, pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 21508]] did not accept task: my.package.MyBean.scheduledMethod
The logs immediately after the doRestart() invocation indicate that the ExecutorService taskScheduleris being shut down, which would explain why this is happening. What I'm not entirely sure of is why the ExecutorService isn't recreated. Embarrassingly enough, it turns out that taskScheduler was a bean defined by my application and was not annotated #RefreshScope. Now the error I'm getting is
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'anotherBean' definen in URL[...]: Unsatisfied dependency expressed through constructor parameter 0 ... nested exception is java.lang.IllegalStateException: org.springframework.boot.servlet.context.AnnotationConfigServletWebServerApplicationContext#2a95076c has been closed already
Scrolling up a bit in the logs reveals that there's an ApplicationContextException thrown with the stacktrace containing doRestart:
org.springframework.ApplicationContextException: Unable to start web server; nested exception is java.lang.IllegalStateException: Filters cannot be added to context [/myapp] as the context has been initialized
at org.springframework.context.ServletWebServerApplicationContext.onRefresh(ServletWebServerApplicationContext.java:157)
...
at org.springframework.boot.SpringApplication.run(SpringApplication.java:316)
at org.springframework.cloud.context.restart.RestartEndpoint(RestartEndpoint.java:160)
at my.package.MyBean.lambda$doThingAndRestart$2 (MyBean.java: 118)
Googling this error seems to result in a single page that isn't relevant, although I do note that this application is running on tomcat as well.
I suspect that this is related to the application creating a wrong sort of application context, which is a AnnotationConfigServletWebServerApplicationContext, which doesn't extend AbstractRefreshableAplicationContext.
What do I need to do to get rid of this error?
Please bear with me when I only copy single lines from the stack trace. I'm on a two-computer set-up, so I can't copy-and paste and am no allowed to otherwise move the logs to a computer connected to the Internet.

It turns out that RestartEndpoint only works with Spring's internal Tomcat, not an external one. So, another solution is required. The ones I discovered are
Using Tomcat's WatchedResource to re-deploy the server when a configuration file is overwritten. This has the downside of needing to maintain the Tomcat configuration when maintaining the doThingAndRestart functionality.
Using Tomcat's Manager App. I noticed that the reload request blocks until the app is done reloading, which overflowed the heap space.
Using Spring's RefreshEndpoint. For whatever reason, this didn't refresh the datasources.

Related

Spring, Interceptors, some ExtJs and a HibernateException on console vs IntelliJ

Weired world... let me try:
I have the follwing mavenized setup:
- Springboot (1.5.5.RELEASE)
- Hibernate (5.0.9.Final; I do know there is newer variants but I stick with what I have right now)
- ExtJs (6.0.0)
- IntelliJ (2017.3)
I do partly get running into an Hibernate Exception:
2018-11-20_15:04:58.007 [http-nio-8081-exec-7] [ERROR] o.a.c.c.C.[.[.[/].[dispatcherServlet]:181 - Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.hibernate.HibernateException:
Could not obtain transaction-synchronized Session for current thread] with root cause
org.hibernate.HibernateException: Could not obtain transaction-synchronized Session for current thread
at org.springframework.orm.hibernate5.SpringSessionContext.currentSession(SpringSessionContext.java:133)
at org.hibernate.internal.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:697)
...
This does not happen on all threads! Partly the requests from ExtJs go through, Partly they don't. But would they not open a transaction on the webserver side?
I do have an Interceptor; well a web Interceptor implementing org.springframework.web.servlet.HandlerInterceptor
Within the interceptor's preHandle method I do call a Service in order to check if a user is logged in and do some rights management handling.
The called #Autowired service fails. I thought the fact of accessing an #Autowired service method takes care of session/transaction handling.
Well, this was the scenario having my project manually created and run with a java-8 (java 8 sdk; not 9, not 10, not 11) command like from the console:
mvn clean package -DskipTests && java -jar target/MyBuild.jar application-local.properties
I just observed that the login consists of three request from browser to the backend. These three are all handled in separate threads by the backend.
When running the project within IntelliJ it all works fine. Ok, IntelliJ most likely does not jar the application and builds its own startup command.
But exactly that brings me out of rhythm due to the fact that we do process the code through a deployment / CI pipeline where we manually build the project.
And that is where it fails :-(
Amendment:
I changed everything to run with JPA instead of Hibernate (well it is still hibernate in the background). Just as 'M. Deinum' suggested.
Now, the problem still exists.
Two things I somewhat extracted.
In my Interceptor I do have some logging calls which ask the EntityManager for a hibernate-session (entityManager.unwrap( Session.class )).
This is the point where now.
So it seems that on the preHandle(...) of my interceptor there is sometimes no current session active. I am stating 'sometimes' since there are calls to the Interceptor when it works.
The exception comes as following now:
java.lang.IllegalStateException: No transactional EntityManager available
at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:272)
at com.sun.proxy.$Proxy117.unwrap(Unknown Source)
at com.mypackage.dataaccess.DataAccessImpl.getCurrentSession(DataAccessImpl.java:89)
at com.mypackage.dataaccess.DataAccessImpl.queryByHQL(DataAccessImpl.java:382)
Ok. I ended up noting all Spring web controllers to have an #Transactional (where DB usage is given.)
That works.
From my understanding it does not matter where to put the #Transactional annotation as long as the method/owning Object is invoked through spring's #Autowire mechanism.
If I want something to run under the transactional behaviour I would annotated with it on the closest scope possible.
That's how I would decide where to put the #Transactional
At the end it does work but I am not satisfied with the solution.
If anyone could clarify the behaviour and/or my understanding let me welcomely know :-)

First Spring4 MVC Attempt not loading with Tomcat 7

Im fairly new to spring mvc and Im trying to launch a extremely simple project that will just display a greeting on a blank page but for some reason I cannot seem to get it to run on the tomcat server, I have gone over every little piece of code and I do not believe there are any mistakes as well as made sure that the tomcat server is configured correctly, any help anyone can give me would be appreciated (This isn't any kind of assignment for anything , this is purely for me trying to learn Spring MVC and learning the proper configuration, because after researching for hours I cannot find anything wrong with it)
I also did this purely in java, no xml. Did not use any dependency managers either ( No Maven or Gradle ) but I do have all necessary jars
I first start by configuring the dispatcher servlet and pass it the webConfig so that the application context can load beans via component scan, since this is a simple project I have no RootConfig class
In my WebConfig I enable Spring MVC ,I give ComponentScan the base package that will search for all Controller classes to create beans for the application context and I create a simple view resolver that will wrap view names with the specified prefix and suffix
My Controller again is really simple I annotate the class as the default handler for "/" requests and map the sayHello method to handle requests for "/home" where I attach a simple message to the model(map) and return the view name
And finally my view which displays the message, The tags in the header of the jsp I know are useless since I'm not using any tags in the form they are just something left over from a previous attempt
When I run this application on the tomcat server I get the following, Im running Tomcat 7 which does support spring mvc java configuration
The tomcat server is running properly
Project is in the webapps directory of tomcat server
And to the best of my knowledge the server configurations are correct
Console output
- Solution -
As mentioned below in the comments the warning I got was
SpringProjLibs is a user library I created and placed all my spring jars inside
This comment along with some research on this warning led me to realize I had failed to add the library to the deployment assembly like below (the entry highlighted in blue was not there , I added that) after adding the line in blue it solved that problem
IMPORTANT
Im adding a follow up to this post since this still pertains to my original question. After completing the above step it resolved THAT issue but another issue presented itself.
I got the following error and tomcat failed to launch
Jun 18, 2018 5:57:37 PM
org.springframework.web.servlet.DispatcherServlet initServletBean
SEVERE: Context initialization failed
org.springframework.beans.factory.BeanCreationException: Error
creating bean with name 'requestMappingHandlerAdapter' defined in
class
org.springframework.web.servlet.config.annotation.DelegatingWebMvcConfiguration:
Instantiation of bean failed; nested exception is
org.springframework.beans.factory.BeanDefinitionStoreException:
Factory method [public
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport.requestMappingHandlerAdapter()]
threw exception; nested exception is
org.springframework.beans.factory.BeanCreationException: Error
creating bean with name 'mvcValidator' defined in class
org.springframework.web.servlet.config.annotation.DelegatingWebMvcConfiguration:
Invocation of init method failed; nested exception is
java.lang.NoClassDefFoundError: com/fasterxml/classmate/Filter
After doing some research I discovered that contrary to what ive studied and seen in online material the annotations #EnableWebMvc and #ComponentScan together in the WebConfig class were causing this issue. I resolved this issue by moving the #EnableWebMvc annotation to the Initializer class , now my classes look like the following
This resolved all my issues and my project launched successfully

Memory leak in Spring Boot 1.5.8

I'm observing a Spring Boot application is going out of memory in production environment following is the exception logs generated by application.
stackTrace":"java.lang.OutOfMemoryError: GC overhead limit
exceeded\nWrapped by:
org.springframework.beans.factory.BeanCreationException: Error
creating bean with name
'org.springframework.context.annotation.internalConfigurationAnnotationProcessor':
Initialization of bean failed; nested exception is
java.lang.OutOfMemoryError: GC overhead limit exceeded\n\tat
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:564)\n\tat
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483)\n\tat
org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)\n\tat
org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)\n\tat
org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)\n\t...
48 frames truncated\n"}
I also took heap dump for application and analyzing it using MAT tool, This are the suspected leaks
We are not able to figure out how come multiple application context are being created. This should be a singleton ideally. This behavior is not producible in our local environment.We are also having dependency on Consul where we are storing configurations.I am also not understanding why object of AnnotationConfigApplicationContext is not getting garbage collected.There can be possible bug inside Spring Boot.
AbbstractApplicationContext$2 is the anonymous inner class registered by registerShutdownHook() method. You can decompile this class yourself if you want to confirm it.
It looks like somehow you have registered 1,807,588,080 shutdown hooks, place a breakpoint in registerShutdownHook() and debug what's going on. It could be that instead of a single Spring context you are creating multiple new Spring contexts and they each register a shutdown hook thread.
We found issues is with spring cloud dependencies which we are using to fetch application configs from Consul. It has watch configured by default which keeps on polling consul server in every 1000ms and refresh the application context if found any changes in the configurations.We disabled it by setting property : spring.cloud.consul.config.watch.enabled to false to solve this memory leak issue.

Continue to load webapp even if one spring bean initialization fails

So if spring initialization fails in a webapp then the webapp itself does not come up. To prevent this, I can probably not re-throw any exception from my code for that specific bean initialization and the webapp will continue to load, right?
Is there any other way to tell to spring not to fail the webapp itself on particular bean initialization failure?
Continue to load webapp even if one spring bean initialization fails
AFAIK, you can't do this.
I do multiple DNS lookups on start up. I do not want the webapp to fail if one of them fails.
In that case, you need to modify your bean(s) to handle the case where the DNS lookup fails, leaving the bean instance in a state where it is essentially inactive but harmless, or where it can retry the DNS lookup later on.
In short, you have to cope with this yourself.
Have attribute lazy-init="true" in that bean and every dependant bean. Link for more details.
why would you do this? If your spring context is not correct, something is seriously wrong and there will be issues. The correct way to deal with this is to fix the application context.

Disable Spring from Starting up after BeanInstantiationException (Tomcat)

for the project I'm currently working at there is the requirement to disable the webapp context to be started when spring fails to initialize some beans (that call webservices during initialization and therefore are likely to crash then).
However, when a bean throws any exception during initialization, it looks like this:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'latestAdsRepository' defined in file [...]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [...]: Constructor threw exception; nested exception is java.io.IOException: SHUT DOWN NOW!!
...
Caused by: org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [...]: Constructor threw exception; nested exception is java.io.IOException: SHUT DOWN NOW!!
however the context starts and all references to the bean that was not able to start are null. Needless to say, this causes various bad Nullpointer Exceptions all over the place. Especially because this bean is very important for the webapp.
So I need a way to explicitly tell Spring that this webapp has failed to start if a bean could not be initialized. System.exit(1) however is not an option, because there are also other webapps on this Tomcat server.
Any ideas?
As far as I know, by default, the context startup fails when Spring fails to instantiate a bean, if the exception is propagated through the startup listener to the servlet container.
You can use the #Required annotation to mark a certain injection point as mandatory.
How are you loading the Spring context?
Sounds like you might be doing it manually (i.e. you are calling new ApplicationContext() somewhere), instead you should use the ContextLoaderListener so that your context is loaded automatically upon application startup (and shutdown during application shutdown). Exceptions during the Spring context startup will propogate to failing the web application context startup.

Categories