Search code examples
javahibernatespring-bootspring-transactions

Why in controllers or services, we can reach lazy loaded proxy object but not in a subclass of AbstractUserDetailsAuthenticationProvider?


I asked this question but it is closed and i haven't get my answer exactly; Spring @Transactional annotation is not working in the provider class which is a subclass of AbstractUserDetailsAuthenticationProvider

And I read this answer; Spring - @Transactional - What happens in background?

They said something about internal method call and external method call. But this works in any controller or service. Why not in provider class which annotated as @Component? Why can't Spring or Hibernate open a session in provider class even with @Transactional annotation? Is this something about spring security? What is the difference?


Solution

  • Please go through the reference documentation

    The following images shows a Conceptual view of calling a method on a transactional proxy:

    enter image description here

    Now with this information , a method annotated with @Transactional will start a transaction only when the call to the method comes in through the proxy object of the class that has this annotated method. This call is mentioned as the external call by the experts in your previous question.

    In case of your example ,

    The implementation of abstract method AbstractUserDetailsAuthenticationProvider.retrieveUser() is called from AbstractUserDetailsAuthenticationProvider.authenticate() , which is a self invocation. This is what the experts mentions as internal call . Also note that the method authenticate() is not @Transactional

    Go through the documentation under the section Using Transactional

    In proxy mode (which is the default), only external method calls coming in through the proxy are intercepted. This means that self-invocation (in effect, a method within the target object calling another method of the target object) does not lead to an actual transaction at runtime even if the invoked method is marked with @Transactional. Also, the proxy must be fully initialized to provide the expected behavior, so you should not rely on this feature in your initialization code (that is, @PostConstruct).

    In your provider class which is annotated with @Component the call to the proxy reaches a method which is not annotated with @Transactional and does a self-invocation or internal call to the method annotated with @Transactional , which does not work as explained earlier

    With the Controller or Service , the method annotated with @Transactional is getting called first (external call) , which initiates a transaction . The code flow within the context of that method is in a transaction and all the subsequent methods are participating in that transaction and you do not see the - no Session exception.

    Hope this helps