Spring: Side effects of #Async on Transactions handling? - spring

I have a Spring Boot REST API through which a web client can start the execution of a testsuite. The handling of the transactions was tricky, but i finally made it and everything work as expected. This is my setting:
the http request is handled by a controller (1)
when receiving the request, the controller publishes an event "start testsuite" (I use the Spring Event handling)
a method with #EventListener (2) listens to that event and calls the method in charge of the testsuite execution (3).
Now it turns out that the execution of the testsuite is sometime very long. As I don't want the http request to remain pending too long, I'd like to make the testsuite execution asynchron. To achieve that I added a #Async at the method of the service layer in charge of the testsuite execution(3).
As a result: I can tell that the process runs now indeed async but the testsuite execution behave in a weird way that make me think the transactions are not handled correctly anymore. So what I'm trying to understand, and that's the object of this question: in which way the #Async can, in this configuration, have side effects on the transaction handling?
I did some research. According to this article
If the #Async annotation is being used extra care should be taken with respect to transactions. In normal circumstances (without #Async) a transaction gets propagated through the call hierarchy from one Spring #Component to the other. However, when a #Transactional Spring #Component calls a method annotated with #Async this does not happen. The call to the asynchronous method is being scheduled and executed at a later time by a task executor and is thus handled as a 'fresh' call, i.e. without a transactional context. If the #Async method (or the #Component in which it is declared) is not #Transactional by itself Spring will not manage any needed transactions.
I get that point, but I don't think I'm in this situation since the calling method of the async method (= the event listener) has not been made transactional.
Does anyone have a clue?

Related

Understanding Spring AOP and Transaction Aspect

I was studying about the Proxy Object which spring gives when we autowire any interface. This is a very good link for understanding that https://www.youtube.com/watch?v=bEvGdWjeCy4&t=310s. Here he explains that If a POJO implements any interface then Spring proxy bean also implements that interface (using JDK Proxy mechanism) and adds additional logic such as transactional logic (if the method was annotated using jdbc code or delegating it to PlatformTransactionManager). Spring gives us a wrapper object which has the reference to the real object and it has additional code which it runs before and after the original method is invoked using MethodInvocationHandler. So My question is that how exactly spring is managing that transaction.Where that jdbc code to get connection and start transaction is written. Is it in the Spring Proxy object or any Aspect Class.
As in AOP there as Aspects which are basically the cross cutting concerns such as transaction common to the whole application. Is Spring inserting Transaction behavior code in the Proxy Object or is it Using PlatformTransactionManager to do that And Where does This AOP fits in this Flow. How the Aspect handling Transactional behavior getting invoked here if it is. How the call is getting transferred to it?
In term of JDK proxy , you have to supply a InvocationHandler implementation when creating a proxy object. When the proxy object is invoked , this InvocationHandler will be invoked around the actual object. (see this for a hello world example for how does JDK proxy works)
In term of the spring transaction , it already shipped with an InvocationHandler implementation (i.e. JdkDynamicAopProxy). It will then somehow invoke the transaction aspect (i.e. TransactionInterceptor). The transaction aspect is responsible for controlling the whole workflow such as when to create , commit or rollback the transaction and when to actually execute the actual method etc.
The transaction aspect also delegates to the PlatformTransactionManager to actually start , commit and rollback a transaction. Because different technologies has their own ways to start , commit and rollback a transaction , it is necessary to introduce a PlatformTransactionManager as an interface to abstract these operations such that we can switch different transaction technology by simply switching the PlatformTransactionManager implementation inside the transaction aspect .
So back to your questions :
Where that jdbc code to get connection and start transaction is
written. Is it in the Spring Proxy object or any Aspect Class.
None of them. It is actually the PlatformTransactionManager to get the connection and start the transaction which is invoked by the aspect.
Is Spring inserting Transaction behaviour code in the Proxy Object or
is it Using PlatformTransactionManager to do that And Where does This
AOP fits in this Flow.
Spring inserts the transaction behaviour in the aspect object (i.e. TransactionInterceptor). The aspects then delegate to the PlatformTransactionManager to actually start , commit and rollback the transaction.
How the Aspect handling Transactional behaviour getting invoked here
if it is. How the call is getting transferred to it?
Assuming the JDK proxy is used , the call flow is something like :
Someone invokes on the JDK proxy
InvocationHandler of this proxy will be invoked (i.e JdkDynamicAopProxy)
InvocationHandler somehow calls spring transaction aspect (i.e TransactionInterceptor)
Transaction aspect delegates to PlatformTransactionManager to actually start , commit and rollback the transaction if necessary.

Does Spring wait for each #PostConstruct to finish when loading ApplicationContext

I have some logic of loading data from the DB in #PostConstruct method in some of the service classes which takes a long time.
And there are some unrelated controllers which load quite quickly and could potentially start accepting HTTP requests.
So the question, does Spring just wait for each #PostConstruct method to return when loading the ApplicationContext, hence can't accept any requests, or are there any exceptions?
I know, I could load the data from DB asynchronously, but perhaps there're brighter solutions?
In Spring all the REST endpoint are actualized through RequestMappingHandlerMapping class.
And this kicks in after #PostContruct. So the way you are doing is perfectly fine.

What is difference between ContextRefreshedEvent, ContextStartedEvent, ContextStoppedEvent and ContextClosedEvent

In Spring 5.x, what is the difference between following events?
ContextRefreshedEvent
ContextStartedEvent
ContextStoppedEvent
ContextClosedEvent
Which event correlate with the servlet context events (as per https://docs.oracle.com/javaee/6/api/javax/servlet/ServletContextListener.html):
ServletContextListener.contextInitialized(ServletContextEvent); and
ServletContextListener.contextDestroyed(ServletContextEvent)?
I have the following situation:
In want to initialize a logging subsystem as soon as possible, should that be done in ContextRefreshedEvent or ContextStartedEvent?
I also want to destruct it as late as possible, should that be done in ContextClosedEvent or ContextStoppedEvent?
The documentation for these built-in events can be found here, specifically:
ContextRefreshedEvent
Published when the ApplicationContext is initialized or refreshed (for example, by using the refresh() method on the ConfigurableApplicationContext interface). Here, “initialized” means that all beans are loaded, post-processor beans are detected and activated, singletons are pre-instantiated, and the ApplicationContext object is ready for use. As long as the context has not been closed, a refresh can be triggered multiple times, provided that the chosen ApplicationContext actually supports such “hot” refreshes. For example, XmlWebApplicationContext supports hot refreshes, but GenericApplicationContext does not.
ContextStartedEvent
Published when the ApplicationContext is started by using the start() method on the ConfigurableApplicationContext interface. Here, “started” means that all Lifecycle beans receive an explicit start signal. Typically, this signal is used to restart beans after an explicit stop, but it may also be used to start components that have not been configured for autostart (for example, components that have not already started on initialization).
ContextStoppedEvent
Published when the ApplicationContext is stopped by using the stop() method on the ConfigurableApplicationContext interface. Here, “stopped” means that all Lifecycle beans receive an explicit stop signal. A stopped context may be restarted through a start() call.
ContextClosedEvent
Published when the ApplicationContext is closed by using the close() method on the ConfigurableApplicationContext interface. Here, “closed” means that all singleton beans are destroyed. A closed context reaches its end of life. It cannot be refreshed or restarted.
RequestHandledEvent
A web-specific event telling all beans that an HTTP request has been serviced. This event is published after the request is complete. This event is only applicable to web applications that use Spring’s DispatcherServlet.
Afaik, none of these correlate directly to the ServletContext. That's a different beast than Spring's application context, and there are separate events for that.
Setting up and tearing down a logging system can be complicated and will depend on which logging system you use. In short, you may want to try with ContextRefreshedEvent and ContextClosedEvent. The other two are only dispatched when you call start() or stop() on the application context, so you wouldn't want to use those.
If you're using Spring Boot, you may want to look at Spring Boot's
own abstraction of logging systems (org.springframework.boot.logging.LoggingSystem), which defines beforeInitialize, initalize, and cleanUp methods, and also a shutdownHandler that is called when the JVM exists.
And see org.springframework.boot.context.logging.LoggingApplicationListener for reference. Spring Boot comes with additional application events. The initialization of the logging system seems to be done on the ApplicationEnvironmentPreparedEvent. Cleanup is done on ContextClosedEvent and ApplicationFailedEvent.

Lazy loading works, but shouldn't

The context of this question is within spring-boot, using spring-data-jpa and hibernate.
A colleague wrote an #Service and annotated the service method with #Transactional. The service method loads an entity, and subsequently hits a one-to-many lazily loaded collection (fetch = FetchType.LAZY). The service method is invoked by some custom delegator, which i will come back to. This works fine when invoked from a #RestController endpoint.
When i invoked the service from a camel route (again via the custom delegator) it barfed with a lazy initialization exception.
On digging, found that the service implements an interface, the custom delegator looks up the service (it is injected so has proper proxy) and calls a method
on the interface which is actually a java-8 default method. This default-method then locally calls the #Transactional method.
So there's the problem :- this is a LOCAL method call so the aspecting/proxy-ing of the #Transactional annotation is not done (we use aspectJAutoProxy) so the method is NOT invoked within a transaction, so the lazy-loading SHOULD fail. And to double-check, also tried it via an #Scheduled annotation: same behaviour. Barfs like it should.
My Question: So why does it work when called from the #RestController? This is driving me nuts!
There is no transactional annotation on the rest controller endpoint.
I added some debug code to the service using TransactionSynchronizationManager.isActualTransactionActive() and it shows that in no case is there a transaction, even when being called via the controller endpoint.
So why does the lazy loading work when being called from the controller?
I dumped all SQL and at no points are the lazy-collection already loaded, so they are not in any hibernate cache.
I remember reading once that lazy loading was a hint, not a command, but still... why does it work in that one case?
after being perplexed by this on many occasions, have stumbled across the answer:
sprint-boot is doing an open-entity-manager-in-view behind our backs via the OpenEntityManagerInView interceptor. Had no idea this was going on.
See this excellent answer from Vlad Mihalcea https://stackoverflow.com/a/48222934/208687
When your method annotate to transactional hibernate session close after return method , if object that return from method have lazy , lazy property not load and you get exception that session close. You can use fetch in query or using OSIV

Rolling back a transaction in Spring ApplicationListener

Normal Spring ApplicationListners are running synchronously within the same thread of the event publisher.
Is there any way to rollback the main context transaction in the listener?
I have a method annotated #Transactional and it publishes an event, I want to make execute the listeners in the scope of the main method, and rollback the main transaction in case of exceptions.
I am using a LocalTransactionManager on Hibernate SessionFactory.
Is there any way to do this using Spring 3.3.x?

Resources