A transaction, in particular, is applied using AOP; the default AOP mechanism in Spring is to use a proxy. When using Spring Boot in proxy mode, class-based proxy classes are installed.
You can fix this in one of 2 ways.
- Remove
final from your method - Disable class-based proxies by adding
spring.aop.proxy-target-class=false to your application.properties
Now that you have added @Transactional , this will lead to the creation of a proxy server for your UserServiceImpl , a class-based proxy, to be exact. It happens that a subclass is created for your UserServiceImpl , and all methods are overridden to apply a TransactionInterceptor . However, since your method is marked final , a dynamically created class cannot override this method. As a result, the method considers field instances in a dynamically created proxy class, which will always be null .
When removing final method can be overridden, the applicable behavior will be considered in the corresponding field instances (the actual UserServiceImpl instead of the proxy server).
When disabling class-based proxies, you get a dynamic JDK proxy, which is basically a thin shell that implements all the interfaces that your service has. It applies the added behavior (transactions) and calls the actual service. No extension of the actual class is required, and as such you can proxy the final methods (for now, this is part of your interface).
source share