Execute method after Spring context initialized but before requests are accepted - java

In a spring boot app (2.3), is it possible to have a method be executed after context is initialized, but before the app starts to take requests? I don't know if becoming ready to accept requests is part of the spring context initialization or if that is a separate step.
Note that ideally if this method throws an exception, the service fails to start, but that is not a requirement.
I tried ContextRefreshedEvent. However, the app is accepting requests at that point. (While my ContextRefreshedEvent event listener method is executing, requests can come in and execute at the same time.)
(I can't use #PostContruct, because my method depends on many different beans being initialized.)
The specific use case is that I have a spring cloud config server. I want it to pre-load authentication data into cache prior to accepting requests. The loading of this data depends on bootstrap/app config files being loaded, ApplicationEnvironmentPreparedEvent listener being called, beans being constructed, etc.

As Andy Wilkinson pointed out (thank you!), to do this, implement a bean's method with the desired behavior and add the #PostConstruct annotation. The method will be called after all beans are initialized (and environment prepared) but before the service starts taking requests.

Related

Clean up method for spring boot application after request process

How to implement a clean up method after request finish process in a spring boot application for clean data such as thread locals
I try with ServletRequestListener.requestDestroyed api, but it does not get hit after the request finish
One possible answer is that you have neglected to register the listener. The Servlet javadocs say:
In order to receive these notification events, the implementation class must be either declared in the deployment descriptor of the web application, annotated with WebListener, or registered via one of the addListener methods defined on ServletContext.
There may be other ways to implement this using Spring; e.g. using a handler intercepter; see Remove ThreadLocal object within a Spring MVC website?
If you were using plain servlets (without the Spring MVC infrastructure), another approach would be to do the cleanup in your servlet's service method or the doXxx methods. Or in a Filter in front of the servlet.

How to trigger an event when all the controllers are ready in Spring Context?

I am trying to execute a code in PostConstruct of one my controllers. But this action is such that it will also cause one other controller from this same module to be triggered by some other external module. I observed that the other controllers are not ready when our code in postConstruct gets executed.
I also tried out using ApplicationContext listener on ContextRefreshed and ContextStarted event, but still all the controllers don't seem to be ready by this time if some external modules try to contact them.
What am I missing? Is there any hook available to trigger a method execution when all the controllers are ready for current module?
Context refreshed event should work unless you are using LAZY initialization (which is not enabled by default).
Be sure to listen for correct context event. There are two (or more) refresh events - one for root context and one for each servlet context.

How to share data/objects between client service calls on the serverside with Spring?

I'm currently using Spring and Hibernate. At the moment, if I make a create object call (for example) from the client a request comes in on the service stub on the serverside. The service call has to create a new hibernate session factory, get the session, and then make the transaction. The problem is that this occurs every single time, so the session factory needs to be recreated to be used. This seems to be extremely wasteful and performance impacting since creating that factory takes a toll.
What I would like to do is reuse that one session factory, for example, across different service calls made by the client or multiple clients. The problem is I don't know how to do that since the entry point to the serverside functionality is the service call. I know that I would have to save state on the serverside somehow so that different calls could access the same session factory. I know of the scalability issues with keeping state and such, but there has to be a way to reuse previously created objects.
My question is how would I do this with Spring (am I supposed to use Session beans or HttpSession)? Is it possible for the container to set these things up on startup or does it have to wait for a service request to come in?
I'm for the most part a Spring newb, is it just that I don't understand the web service role?
Thanks in advance.
Yours is typical MVC scenario which is achieved by GWT+MVP. Based on your description seems you are creating the session-factory on every call which is obviously not a standard practice.
Session-factory is created only once and every request executes in a different session created by the session-factory.
With Spring, typical approach would be to configure the session-factory with spring wiring and hibernate. This config will be loaded only once when application starts up.
On every service request, get the reference of session-factory from the bean-container (instead of creating it every time) and create session from it for DB operation.
Check out this project which uses GWT+MVP+Spring+MyBatis. I understand that you use Hibernate instead of MyBatis but this would server as reference for this type of project.

Trigger an action to perform a persistance commit right before Tomcat shutdown

We recently changed our system to keep the latest data in the memory instead of writing to the database. (it will be written to the database when the I/O is relatively free)
However, now we are stuck if in the event of Shutdown is required, there might be some data that have not written to the Database yet.
Is there anyway in Tomcat to trigger a call either a servlet method or some sort to perform action when a "shutdown" is issue to tomcat? We are using the following setup:
OS: Windows Server 2008
Tomcat: 5.5.30
Any idea how to perform the above?
Note: at the moment, we shutdown the tomcat from the windows services.
Like everyone else has pointed out, looks like Servlet.destroy() may be what you want.
public void destroy()
Called by the servlet container to indicate to a servlet that the servlet
is being taken out of service. This
method is only called once all threads
within the servlet's service method
have exited or after a timeout period
has passed. After the servlet
container calls this method, it will
not call the service method again on
this servlet.
This method gives the servlet an opportunity to clean up any resources
that are being held (for example,
memory, file handles, threads) and
make sure that any persistent state is
synchronized with the servlet's
current state in memory.
Does this meet your requirements? You can also implement a context listener:
Handling Servlet Life-Cycle Events
You can monitor and react to events in
a servlet's life cycle by defining
listener objects whose methods get
invoked when life cycle events occur.
To use these listener objects, you
must define the listener class and
specify the listener class.
There's examples there too.
ServletContextListener is what should do the trick
http://download.oracle.com/javaee/1.3/api/javax/servlet/ServletContextListener.html
sample code from PetStore Demo
http://java.sun.com/j2ee/tutorial/1_3-fcs/examples/src/web/bookstore1/listeners/ContextListener.java

Threads in Spring

I have a Web application using spring and hibernate and struts (it runs on Tomcat)
The call sequence is something like this...
Struts action calls spring service bean which in turn calls Spring DAO bean. The DAO implementation is a Hibernate implementation.
The question is
Would all my spring beans be running in the same thread ?
Can I store something in the ThreadLocal and get it in another bean?
I am quite sure this would not work in Stateless Session Bean.
The EJB container can (or will) spawn a new thread for every call to the session bean
Will the spring container do the same? i.e. run all beans in the same thread ?
When I tried a JUnit test - I got the same id via Thread.currentThread().getId() in the Test Case and the two beans- which leads me to believe there was only one thread in action
Or is the behavior unpredictable?
Or will it change when running on Tomcat server ?
Clarification
I do not wish to exchange data between two threads. I want to put data in the ThreadLocal and be able to retrieve it from all beans in the call stack. This will work only if all beans are in the same thread
Spring doesn't spawn the threads. Tomcat does. Spring is just creating and wiring up the objects for you.
Each request from the browser is processed in one request. It is Tomcat that handles the request. It is Tomcat that creates the thread to process the request.
Assuming you have just created a singleton bean in Spring called "X". Then the same instance of X is used by all requests.
The Spring beans don't live in a thread. They are just allocated on the heap.
Would all my spring beans be running
in the same thread ? Can I store
something in the ThreadLocal and get
it in another bean?
AFAIK for the components you mentioned (service bean, DAO bean - i guess they are plain spring beans), Spring does not spawn a new thread. I do not understand your use case (ie, exchanging data between two threads).
For most webapps, a new thread is spawned for each new request, and if you want to share data between two requests you normally:
- use the get/post parameters to pass the data
- use the session to share data
To answer your question, I'm pretty sure the spring container does not spawn threads for most components.
Yes, you can do this. The same thread will be used to execute your action so the ThreadLocal will work. Typically, the same thread is used for the stateless session bean as well, assuming it is running in the same app server instance. I would not depend on this though, as it is probably vendor dependent.
We use this technique to access the callers identity anywhere in the code. We use session beans and jms as well, but explicitly pass the information between containers and set the ThreadLocal at each entry point. This way it doesn't matter if the bean (session or mdb) are local or not.
In addition to all the other answers, I will just add the following:
Normally the only reason to switch threads is because of some requirement for parallellity. Since this normally does not come for free in terms of complexity, you will usually be clearly informed when this happens.
Switching threads within what appears to be a single-threaded processing of a request is actually extremely complex. This will normally only happen at one place in a container, and this is usually handled by tcp/ip socket readers that receive the request from the external clients. These reader threads usually determine which thread(pool) should process the request and forward the request to that thread. After that the request stays with that thread.
So normally the only thing that will/can happen is that additional threads get created for parallelity or asynchronous processing (like JMS).

Categories

Resources