Does spring self injection lead to memory leakage? - java

In Spring, beans are encapsulated by a proxy object and when called from outer object the proxy object's method is also called. By using this trick transaction management is performed in proxy object's methods.
But when you are calling a method in the same bean and if you want the called method to be run in another transaction with the caller method it is not possible. Since the method calls in the same bean does not pass through the proxy object which performs transaction operations.
In order to solve this, self-injection of the bean inside itself is proposed.
like this
#Service
public class MyService{
#Autowired
public MyService myService;
#Transactional(propagation = Propagation.REQUIRES_NEW)
public void method1(){
method2();// runs in the same transaction with method1
myService.method2();// runs in separate transaction from method1
}
#Transactional(propagation = Propagation.REQUIRES_NEW)
public void method2(){
}
}
I want to ask whether self-injection leads to memory leakage.
Outer bean MyService includes injected myService and myService should include attribute of type MyService, which should include attribute of type MyService ....

The service is not copied, it is only a reference. But I'd be wary of such a design: it creates a circular reference and the object graph is impossible to create at once. You first need to create the incomplete service, then set its field. Furthermore, it is kind of confusing and surprising to find such a dependency to self
I'd propose a different solution:
#Component
public class WithTransaction {
#Transactional(propagation = Propagation.REQUIRES_NEW)
public void requiresNew(final Runnable runnable) {
runnable.run();
}
}
#Service
public class MyService{
private final WithTransaction withTransaction;
#Autowired
public MyService(final WithTransaction withTransaction) {
this.withTransaction = withTransaction;
}
#Transactional(propagation = Propagation.REQUIRES_NEW)
public void method1(){
method2();// runs in the same transaction with method1
withTransaction.requiresNew(this::method2); // runs in separate transaction from method1
}
#Transactional(propagation = Propagation.REQUIRES_NEW)
public void method2(){
}
}
And if you can avoid it: don't call any public methods from your service on the service itself. Split the service into smaller components so that each "public" call must go through the proxy.

Related

What happens when #Transactional(readonly=true) method calls #Transactional(readonly=false) method and vice versa?

I wonder, what happens when #Transactional(readonly=true) method calls #Transactional(readonly=false) method? Talking about the situation with propagation = Propagation.REQUIRED (within the outer transaction scope).
public class ServiceA {
ServiceB serviceB;
#Transactional(readonly = true)
public void readOnly() {
// some reading from repo
serviceB.write()
}
}
public class ServiceB {
#Transactional
public void write() {
// some write to repo
}
}
The same question for the opposite situation, what happens if #Transactional(readonly=false) method calls #Transactional(readonly=true) method? I suppose that for the last case it would just consider #Transactional(readonly=false) from the outer scope.
Calling readOnly=false from readOnly=true doesn't work since the previous transaction continues.
This is because the previous transactional is being continued.
If you want this to work, you must have it start a new transaction. Sample:
public class ServiceB {
#Transactional(propagation = Propagation.REQUIRES_NEW)
public void write() {
// some write to repo ..
}
}
In this case, it will work because a new transactional will be started.

Spring cacheable annotation doesn't work before deployment completes

I have the following classes and interfaces(simplified to make things clear).
#Serivce
class Service1 {
#Cacheable("cacheName")
public Metadata preLoadMetadata() {
// load data from database
}
}
#Service
class Service2 implements Loader {
#Autowired #Lazy
private Service1 service1;
#Overrride
public CacheWrapper getCacheWrapper() {
return new CacheWrapper(() -> service1.preLoadMetadata());
}
}
interface Loader {
CacheWrapper getCacheWrapper();
}
class CacheWrapper {
private Callable callable;
public CacheWrapper(Callable callable) {
this.callable = callable;
}
public getCallable() {
return callable;
}
}
The Spring bean responsible for loading the cache at the time of deployment.
#Component
class LoadCache {
#Autowired
private List<Loader> allLoaders;
#PostConstruct
public void load() {
allLoaders.getCacheWrapper().getCallable().call();
}
}
preLoadMetadata() doesn't save the data in the cache but it does execute. After deployment is complete and I call the same method preLoadMetadata() again, then it saves the data in the cache.
Why does #Cacheable doesn't work at the time of deployment?
If I manually use put method of Cache to populate cache inside method annotated with #PostConstruct, I am able to do it successfully while deployment.
I am using Tomcat as server.
I am using Couchbase cache behind Spring cache abstraction.
If you want to preload your cache I suggest you use an ApplicationListener that will execute once your application has started:
#Component
public class CacheInitializer implements ApplicationListener<ContextRefreshedEvent>{
#Autowired
private List<Loader> allLoaders;
#Override
public void onApplicationEvent(ContextRefreshedEvent event) {
allLoaders.getCacheWrapper().getCallable().call();
}
}
The root cause for not working of Cacheable annotation:
afterSingletonsInstantiated() method sets the initialized flag to true only when BeanFactory has instantiated all the beans. If the initialized flag is false, no caching operations are performed. Here, inside the post construct, when we start pre-loading caches, then it is highly probable that LoadCache is not the last bean to be instantiated. Hence, no caching operations are performed(while using caching annotations).
Hence, EventListener annotation responding to ContextRefreshEvent is the best thing to use in this case which ensures that the context has started and then only loading of caches take place.

What is the difference between defining #Transactional on class vs method

Case1
#Transactional
public class UserServiceImpl implements UserService {
...................
public void method1(){
try{
method2();
}catch(Exception e){
}
}
public void method2(){
}
}
Case2
public class UserServiceImpl implements UserService {
...................
public void method1(){
try{
method2();
}catch(Exception e){
}
}
#Transactional
public void method2(){
}
}
In case1 if any exception occurs it rollback is working, but in case 2 it's not working. Is there any performance issues if I follow the case1?
In case 1 #Transactional is applied to every public individual method. Private and Protected methods are Ignored by Spring.
Spring applies the class-level annotation to all public methods of
this class that we did not annotate with #Transactional. However, if
we put the annotation on a private or protected method, Spring will
ignore it without an error.
In case 2 #Transactional is only applied to method2(), not on method1()
Case 1:
- Invoking method1() -> a transaction is started. When method1() calls method2() no new transaction is started, because there is already one
Case 2:
- Invoking method1() -> no transaction is started. When method1() calls method2() NO new transaction is started. This is because #Transactional does not work when calling a method from within the same class. It would work if you would call method2() from another class.
From the spring reference manual:
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, will 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 behaviour so you should not rely on this feature in your initialization code, i.e. #PostConstruct.
#Transactionalon a class applies to each method on the service. It is a shortcut. Typically, you can set #Transactional(readOnly = true) on a service class, if you know that all methods will access the repository layer. You can then override the behavior with #Transactional on methods performing changes in your model. Performance issues between 1) and 2) are not known.
Suppose you have the following class:
#Transactional(readOnly = true)
public class DefaultFooService implements FooService {
public Foo getFoo(String fooName) {
// do something
}
// these settings have precedence for this method
#Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
public void updateFoo(Foo foo) {
// do something
}
}
The #Transactional annotation on the class level will be applied to every method in the class.
However, when a method is annotated with #Transactional (like, updateFoo(Foo foo)) this will take precedence over the transactional settings defined at the class level.
More info:
Transaction management in Spring
Quoting from here
The Spring team's recommendation is that you only annotate concrete classes with the #Transactional annotation, as opposed to annotating interfaces.
Since this mechanism is based on proxies, only 'external' method calls coming in through the proxy will be intercepted. This means that 'self-invocation', i.e. a method within the target object calling some other method of the target object, won't lead to an actual transaction at runtime even if the invoked method is marked with #Transactional!

Spring: Should I have #Transactional annotation in between?

I have 3 Spring Components calling first->second->third.
If I only have #Transactional annotation on first and third will transaction be propagated properly?
#Component public class C1 {
#Autowired C2 c2;
#Transactional public method1() {
...
c2.method2();
}
}
#Component public class C2 {
#Autowired C3 c3;
public method2() {
...
c3.method3();
}
}
#Component public class C3 {
#Transactional public method3() {
...
}
}
Yes, Transaction support is thread-bound. When method2() is executing, it does so in the same Thread and therefore has access to the current Transaction. The same goes for method3().
#Transactional works as below
if its marked on any method then we can specify an attribute called propagation whose value could be Required by default or RequiredNew.
sample is
#Transactional(readOnly = true,propagation=Propagation.REQUIRES_NEW)
public void somemethod(){
anotherMethod();
}
if the attribute is just "Required" which is there by default then it maintains a single transaction for whole propogation of all methods no matter whether you declare #transactional in each method or not.
so all methods execution comes under same transaction and if any rollback happens in last method it affects til the method called.
if the attribute is set to "RequiredNew" then each method runs in their own tranactions so rollback in one method does not rollback other methods tranactions.
hope you are clear now

Injecting multiple dao into one service

if I have several DAOs to be injected into a Service that need to work together in a single transaction, how can I do this ?
#Component
public class CallerClass{
#Autowired
private TransactionClass1 class1;
#Autowired
private TransactionClass2 class2;
public void saveOperation(){
try{
class1.save();
class2.save();
}catch(Exception ex){
}
}
}
Like above simple codes. However, this code is lack
You would just inject all the DAOs in the same manner as you do normally i.e. setter or constructor using #Inject or #Autowired.
You then annotate your service method as Transactional and invoke the required operations on the multiple DAOs. The transaction will encompass all of the dao calls within it.
#Transactional
public void doStuff() {
dao1.doStuff();
dao2.doStuff();
}
You must open the transaction before you use the first dao (For example with #Transactional).
public class MyService{
#Inject
Dao1 dao1;
#Inject
Dao2 dao2;
#Transactional
public doStuffInOneTransaction{
Object x = dao1.load();
Object y = doSomething(x);
dao2.save(y);
}
}
Do you use JTA? Do you implement your transactions on your own? Please provide more information about your architecture so we can respond accordingly.
EDIT:
Check this one out, for example:
http://community.jboss.org/wiki/OpenSessionInView

Categories