#Cacheable and #Async not always working in the same class - spring

I stumbled into this problem somewhat surprisingly.
But the requirement is actually nothing special. Using Cache and Async from inside the same service.
I created a repository to demonstrate the problem: https://github.com/MBurchard/cachedemo
There are two versions:
v1: Without "self injection" only calling the service methods from controller
v2: with self injection to test all.. calling from internal and external.
As long as you don't need another proxy, because you don't want to use #Async in the same class, this also works with version v2, i.e. with the "self inject" via InitializingBean.
But even this requirement to have #Async and #Cacheable in the same service is not too much of a stretch now.
Of course I don't want to use both annotations on the same method, that's for sure.
But as you can see in version v2, only the #Async calls, but not the #Cacheable calls, work externally, for example from a controller.
But internally, using the self reference, only the #Cacheable calls work, but not the #Async calls.
It looks like Spring injects into the controller one proxy and into the service (itself) the other proxy.
As you can see in version v1, without the self injection both, #Cacheable and #Async, work from the controller...
Solutions:
Do not use #Cacheable but use Caffeine or Guava Cache directly...
Use Runables: Spring #Async method inside a Service ... But I don't think it's a pretty solution
Split the Service... Not always possible and can also lead to less maintainable code.
Suggestions?

Related

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

Why do we need #Component spring annotation for Jersey resource in spring-boot-starter-jersey project?

This question is regarding the sample:
https://github.com/spring-projects/spring-boot/blob/master/spring-boot-samples/spring-boot-sample-jersey/src/main/java/sample/jersey/Endpoint.java
Why do we need "#Component" annotation for Jersey resource when using spring-boot -starter-jersey project?
If I remove it, the Jersey servlet can still serve resources.
So what is the need for "#Component"?
You don't need it. Jersey uses HK2 as it's internal DI framework, and HK2 has a Spring bridge. This is what's used internally to bridge Spring components into the HK2 IoC container, so that they can be injected into Jersey components. And Jersey implements an AutowiredInjectionResolver1 that allows for injection of Spring components using #Autowired. You don't even need #Autowired though. All the Spring components can be injected with the normal #Inject.
The only drawback I've ran into, not making the Jersey components a Spring #Component is that it doesn't support #Value when you want to inject property values.
The one thing I don't like is that when you declare something a Spring #Component, it automatically makes it a singleton. But Jersey resources are by default request scoped. You can add a Spring #Scope("request"), and it should change the resource to a request scoped resource. Jersey has declared the Spring RequestScope, so we can use it. How exactly it ties in to Jersey's request scope, I am not a hundred percent sure. I ran into a problem a while back. I can't remember what it was, but that has kept me from ever using the Spring request scope again.
Assuming I want to keep all my resources request scoped, I would take sticking to the normal Jersey request scope, and not being able to inject #Values, over having to use Spring's request scope. Maybe I'm imagining things, and there was no issue using it, but personally I'll just stick to what I know works :-)
UPDATE
Another thing that does't work if you don't make the resource a Spring #Component is Spring's AOP. That's fine with me though as HK2 also has AOP.
1 - An InjectionResolver allows you to use custom annotations to create injection targets.
When you remove #Component jersey takes control of the scope of the instance. With #Component a singleton instance is created, removing it you can use the following jersey annotations:
• Request scope (Default):
By using the #RequestScope annotation or none, we can have a life-cycle till
the request lasts. This is the default scope of the root-resource classes. For
each new request, a new root-resource instance is being created and served
accordingly for the first time. However, when the same root-resource method
is being called, then the old instance will be used to serve the request.
• Per-lookup scope:
The #PerLookup annotation creates root-resource instances for every request.
• Singleton:
The #Singleton annotation allows us to create only a single instance
throughout the application.
Try different behaviors using a counter inside your class...
public class MyWebResource {
private int counter;
#GET
#Path("/counter")
#Produces(MediaType.APPLICATION_JSON)
public Response getCounter() {
counter++;
return Response.status(Status.OK).entity(counter).build();
}
}

What is Spring proxy

I know what is Proxy in network community (server intermediary), but what is proxy in Spring ? Why spring beans are wrapped proxy ? I don't understand the idea of proxy in Spring. Thanks for response.
A proxy is a Spring generated class, that wraps your class for a given purpose, ie: adding transactional behaviour
Take a deeper look at the documentation here
It's a class that wraps your class. It is a proxy because all calls to methods of your class pass through it before actually getting to your class. The goal is to enhance your class with additional functionality, for example as #CristianMeneses said, to add transactional behavior to it, or inject some resources.

How does #transactional works?

I want to know how spring change my method that has #transactional annotation on it?
for example I read here about how to run a transactional method without using #transactional.
What spring do exactly?
Spring effectively makes proxies for your objects. So if class "MyApplication" injects "DBService", and DBService has a #Transactional on it, spring will make a DBService Proxy. The Proxy will be injected into MyApplication, and all calls to methods of the DBService will instead call that Proxy. That Proxy would then be allowed to start transactions or do whatever it needs before calling the actual DBService method.
MyApplication -> DBService Proxy (intercepts calls) -> DBService
The details of how the proxy is made may change based on spring version and the way you've setup your code. You can use interfaces allowing spring to make a proxy of that, although, if you choose not to use interfaces, spring can extend the actual class too (using a library called CGLIB. Pre 4, this required a default constructor, although, in the latest Spring 4 the default constructor is not required and it does it via a slightly different mechanism)

omit transactions for specific methods in spring

I'm using the #Transactional annotation for my entire Dao class with spring and hibernate. Everything works great, it's just that I would like to omit the behaviour for a few non database related methods in my Dao.
http://static.springsource.org/spring/docs/2.5.4/reference/transaction.html#transaction-declarative-annotations
Every time I step into these methods during a debugging session, I always get to JdkDynamicAopProxy.class which is super annoying.
Is there any way to omit transactional for specific methods? Or at least fix this annoying debugging behavior?
In Spring you can put the #Transactional annotation on only the methods you want to make transactional, instead of putting it at the class level.
Otherwise perhaps consider extracting those specific non-transactional methods into a separate class?

Resources