Autowired spring bean is not a proxy - spring

I'm working on a very small application connecting to a MySQL database.
I'm trying to create table record but getting 'no transaction in progress'.
I have all the right stuff in place:
a service interface MyService and its implementation MyServiceImpl
I have annotated the service impl with #Service
In the controller I used the interface name for the field #Autowired MyService
I have the correct transaction configuration as it was originally generated by roo
There is a public method MyService.create(...) which MyServiceImpl implements
But,
When I remote debug and inspect the controller's myService field what I see is something like
com.some.package.services.MyService#12345 (and NOT something like $Proxy73) which to me is not right, because what should be autowired is the proxy not he target bean (which is what I think this is). If I'm correct then it makes sense that there is no transaction as the annotation would only kick in when invoking a public method annotated with #Transactional on a proxy.
Please tell me why is spring injecting the target bean in this setup.
Thanks

If you have AspectJ-enabled transaction management (<tx:annotation-driven mode="aspectj" .../>) application of transactions happens in-place in the same class, either during build (compile-time weaving) or on startup (load-time weaving).
No new classes are created (like when using cglib) and no proxies (like with ordinary interface-based AOP in Spring). Instead bytecode of MyServiceImpl was modified directly without you even noticing. Unfortunately the only way to see AOP is to decompile your classes. If you use javap -c MyServiceImpl you'll find plenty of references to Spring transaction layer.

If you are using Spring MVC, make sure to scan specific controller classes alone in servlet context file. Otherwise it will scan 2 times and transaction is not available on the application context.

Related

What is the replacement of EJB SessionContext object in spring boot?

I am migrating an EJB project to Spring boot project. I have successfully replaced other annotations to the spring annotation, but havving problem with SessionContext object.
My legacy code is bellow
#Resource
SessionContext sessionContext;
.....
if (some condition) {
sessionContext.setRollbackOnly();
return false;
}
For this code i am getting the following error
A component required a bean of type 'javax.ejb.SessionContext' that could not be found.
Action:
Consider defining a bean of type 'javax.ejb.SessionContext' in your configuration.
I think you'll have to use a few different functionalities.
setRollbackOnly()
Most often I have seen Session Context used for Rollbacks. In Spring, you can replace this with:
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
or annotate class with
#Transactional(rollbackFor = MyException.class)
so you can throw your exception from class to cause rollback.
getBusinessObject()
The second most commonly used feature is method to load a business object so that I can, for example, create a new transaction within a same bean. In this case you can use Self-inject:
#Lazy private final AccountService self;
and annote method with #Transactional. This, of course, solves any other cases where you need to use the power of a proxy object.
Other functionality is provided by other classes in Spring, but I think that these two are the most commonly used in the Java EE world and when migrating, one will look to replace them in Spring.

#Controller, #Service, #Repository beans fails on #EnableTransactionManagement in mode = AdviceMode.PROXY or default fails

Why using #EnableTransactionManagement in default mode or PROXY mode attempts against beans creation like #Controller, #Service, and #Repositories. I don't discard another kind of beans targeting this bad behavior.
I have a project with:
SpringBoot 2.1.8.RELEASE + JPA + Rest Controller
PostgreSQL 9.6
#Transactional annotation on methods like save, update and delete (also, batch delete)
It creates proxy classes and nulls the remaining beans in the ApplicationContext.
The default mode is PROXY. When ASPECTJ advice mode is set, all the beans are injected in the right place. Check Spring current docs on the subject.
The mode() attribute controls how advice is applied: If the mode is AdviceMode.PROXY (the default), then the other attributes control the behavior of the proxying. Please note that proxy mode allows for interception of calls through the proxy only; local calls within the same class cannot get intercepted that way.
Note that if the mode() is set to AdviceMode.ASPECTJ, then the value of the proxyTargetClass() attribute will be ignored. Note also that in this case the spring-aspects module JAR must be present on the classpath, with compile-time weaving or load-time weaving applying the aspect to the affected classes. There is no proxy involved in such a scenario; local calls will be intercepted as well.
Like this:
Still, #Transactional methods fail. Due to "TransactionRequiredException", so ASPECTJ does not solve the problem in persistence layer, only grants beans injection (maybe no platform transaction manager is created). What to do next?
See the transaction exception:
!!! Solution:
When working with transactions, the scope has to be shared in the beans chain: #Service(also, caller method)<-#Repository(also, transactional method), #Service context (class, method) shall be marked as #Transactional. Applies to annotated methods or classes in the call stack that ends in transactional operation (bottom-up approach).
Annotation sequence:
#EnableTransactionManagement (in #Configuration alike classes or #SpringBootApplication -autoconfiguration-)
#Transactional annotated method/classes in beans injection chain (bottom-up: persistent method/class, then #Service/#Component layers)
#Autowired annotation on beans candidates (Service instance in #Controller class, Repository instance in #Service class)
Note: Spring AOP does not create proxy properties from functional interfaces based features, only object instances so recommended is using methods encapsulating persistence logic.
e.g
Function<T, R> function
BiFunction<T1,T2,R> function
Supplier<T> supplier
...

Why proxy is not used to autowire

I can not find any reason why every autowired bean are not autowired by proxy. I know that becasue #Transactional annotations do not work and I checked autowired component during debugging in eclipse. Of course every component implements some interface and I use #Autowired annotations in relation to the interface.
I have only one configuration of aop:
<tx:annotation-driven transaction-manager="transactionManager" />
I use JPA with hibernate, spring-mvc,spring-webflow, spring-security and spring-data. Interfaces which extends org.springframework.data.repository.CrudRepository are autowired by proxy. But my components are not. For example I have class MyClass which implement MyInterface:
#Service
public class MyClass implements MyInterface {
#Autowired
MyCrudReposiotry reposiotry;
....
}
If I autowire MyInterface somewhere:
#Autowired
MyInterface mi;
then mi is just reference to MyClass object, repository is refrence to proxy org.springframework.aop.framework.JdkDynamicAopProxy. Very interesting is that in testing mi is reference to proxy. My test's context does not contain web-flow and mvc configuration.
Maybe there is some indirect aop configuration which I should check. What can switch the autowiring by proxy off?
My guess is that you are scanning for the same components twice. You probably have a in your root context (for the ContextLoaderListener) and one for the DispatcherServlet. NO if the both scan for the same classes you end up with duplicated (and one proxied and one non proxied instance).
Proxying and auto wiring are independent of each other. When you use #AutoWired it finds another bean that implements the required interface and injects it. The bean instance it finds might be a normal object or a proxy - it doesn't matter to Autowired.
Proxies are created for certain beans automatically by spring. As you have noticed one scenario in which this happens is when you use #Transactional. When the spring container instantiates a bean which has the #Transactional annotation the object gets wrapped in a proxy. The actual object is replaced by the proxy in the context. This is done so that spring can intercept calls to those methods and add the begin / commit transaction calls before and after the method call. This is implemented by the spring-aop module. Any feature that relies on AOP (#Transactional, #Secured) will result in creation of a proxy.
The other case where proxies are used is to create an implementation on the fly. In case of the CRUDRepository you are required to only implement the interface. The implementation of that is created on the fly using the same proxy infrastructure.

Spring-data-mongo: MongoRepository not being wired unless I add #Component annotation

I am having a little weird behavior with my spring-data-mongo where my repository package is not being scanned by the <mongo:repositories/> tag. I am using spring 3.2.3.RELEASE with spring-data-mongo 1.2.1.RELEASE.
I have a project called edowmis and in it there are 2 maven modules, datalayer and web which a webapp.I am using the datalayer in isolation so the other module can be ignored. I have an application context for datalayer
So I wanted to test my setup by writing a small Unit/Integration test but I've noticed I can't autowire my UserRepository because It says there isn't such a bean
Since I am using IntelliJ I can see certain visuals when things are ok and not ok. I've addec <context:component-scan/> to my application context but no result.
But when I add the #Component annotation it has started identifying the Class.
all information you might need is on pastie.org
Is the #component or #Repository really necessary or something is wrong with my configuration?
Yes, the #Component or #Repository is necessary. The scan simply indicates that spring should look for classes identified via annotations (#Component, #Repository, #Service) and load them as beans. If you don't use repository or component scan, you would have to manually instantiate all spring-managed beans via XML configuration or Java configuration.
You have to tell spring which classes to turn into beans as it doesn't assume everything in the classpath is supposed to be a spring-managed bean, which is why you need to use the annotations.

Spring DefaultAdvisorAutoProxyCreator with #Transactional causing problems

I'm working on a Spring MVC project and trying to integrate Apache Shiro for the security. Everything was going just swimmingly until I realized Hibernate was prematurely closing the session/connection after a single query and causing a lazyinit exception. Not surprising, what I was doing should be done within a transaction so the session isn't closed.
Dilemmas…
I tried putting #Transactional on my controller method, but I get 404's then. Looking at my logs, I can see that when Spring is bootstrapping it ignores any mappings in my HomeController if that #Transactional annotation is on any method within the controller.
Without the #Transactional and it loads up just fine, and Ih can see the RequestMappingHandlerMapping bean sees all the #RequestMapping annotations in my controller.
With #Transactional but without DefaultAdvisorAutoProxyCreator, and it works except Shiro annotations are simply ignored.
tldr: Shiro requires DefaultAdvisorAutoProxyCreator, but if I create that bean, Spring blows up when using the #Transactional annotation.
I'm asking for help because I'm completely at a loss for how to proceed at this point.
This is typically because when you put #Transactional on a method, Spring creates a dynamic proxy for that bean - if the bean implements an interface then dynamic proxy is created based on that interface, otherwise CGLIB will be used for creating the proxy.
The problem in your case, I am guessing is because you probably have based your controller on some interface, or you are extending it based on a base class. This is ending up creating a proxy based on that interface, because of this when it comes time for mappings to be created for your request, Spring MVC is probably not finding your mappings from your bean.
The fix could be a few:
a. You can try and force proxies to be based on CGLIB for your transactions:
<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/>
b. You can use pure Aspectj,either load time weaving or compile time weaving
c. You can move the #Transactional into a Service (which has an interface) and delegate the call from the controller to the service, this way avoiding #Transaction on the controller

Resources