If I use both #PostConstruct and #Scheduled on a bean method what will be the consequences - job-scheduling

#Scheduled(fixedDelay=10000)
#PostConstruct
public void someMethod(){
//my refresh cache code here
}
If I use both #PostConstruct and #Scheduled on a bean method what will be the consequences. Will this method will be executed twice? one after the other of may be at same time ?

The consequence will be that as soon as the class containing this method is created, the #PostConstruct will run. And the #Scheduled will trigger this method after 10_000ms, but only if #EnabledScheduling is added to the context.
The #Scheduled annotation can do both hence they can be merged like that
#Scheduled(fixedDelay=10000, initialDelay=0)
public void someMethod(){
//my refresh cache code here
}

Related

Spring Boot - A bean referencing itself to trigger AOP #Async within the same class, not working

I want to within my own Bean call a method within itself which has its own #Async and #Transactional proxies but it isnt working.
public class MyClass {
private MyClass _selfWithProxy;
#PostConstruct
public void postContruct() {
_selfWithProxy = applicationContext.getBean(MyClass.class);
}
void myMethodA() {
_selfWithProxy.myMethodB()
}
#Async
#Transactinal
void myMethodB() {
//do stuff
}
However when I call myMethodA from another Bean the call to myMethodB does not intercept with an Async interceptor. I can see _selfWithProxy is a proxy bean, and the proxy activates but there are is no Async interceptor in the chain.
When I call myMethodB from another bean the #Async works, so I know it is setup correctly
Self invocation won't work for #Async. I believe that is because the proxy (your code + AOP advice) object calls your methodA on the target object (just your code) which then calls it's own methodB which isn't advised by AOP. In general I would not advise having spring bean methods call other methods of the same bean.
"#Async has two limitations:
It must be applied to public methods only.
Self-invocation — calling the async method from within the same class — won't work.
The reasons are simple: The method needs to be public so that it can be proxied. And self-invocation doesn't work because it bypasses the proxy and calls the underlying method directly."
https://www.baeldung.com/spring-async

How to call #Scheduled method in only one instance using #PostConstruct

There is job that needs to be done on cron schedule
The same logic as in the job must be performed at the start of the spring boot application, therefore #PostConstruct method is used
Shedlock is used, since it is planned to run the application in multiple instances
The question is: how to make the logic from the #PostConstruct method be called in only one instance and not called in others?
An example of my code:
#Component
#AllArgsConstructor
public class TestJob {
private TestService testService;
#PostConstruct
public void init() {
testService.upload();
}
#Scheduled(cron = "${cron}")
#SchedulerLock(name = "uploadJob", lockAtMostFor = "${lockAtMostFor}")
public void execute() {
testService.upload();
}
}
It should work if you put the #PostConstruct method to a different service and call the execute() method.
The reason is that ShedLock by default uses Spring AOP which wraps each method marked by #SchedulerLock in an aspect that does the locking. And Spring AOP usually does not get applied if you call another method in the same class.

Spring transaction when calling private method

I have two questions.
If I have a method:
#Transactional
public method1(){
method2()
}
public method2(){
dao.save()
}
If there is an exception in method2(), will there be a rollback?
Another question:
If I have a method:
#Transactional
public method1(){
method2()
}
private void method2(){
dao.save()
}
If there is an exception in method2(), will there be a rollback?
Yes, there will be a rollback.
The private methods will run within the same transaction. You should be aware that you can't have a #Transactional private method. It will not work without raising any error. This behavior is explained in Spring Docs:
Due to the proxy-based nature of Spring’s AOP framework, calls within
the target object are by definition not intercepted. For JDK proxies,
only public interface method calls on the proxy can be intercepted.
Yes to both. Transactional method means there must be no error during the entire runtime of the method.
If there is an error on one of the methods you are calling from within, these errors will be propagated and make the transaction fail and rollback.

Scheduled annotated method on a prototyped bean

I have a bean with scope "prototype" (not singleton) with a #Scheduled annotated method.
#Component
#Scope("prototype")
public class TestManager {
#Scheduled(fixedDelay = 5000)
public void updateStatuses(){
log.info("Scheduled update");
}
}
I call an instance of the bean when I need it and I expect each instance to launch the scheduled timer.
The scheduler annotation doesn't seem to work unless I remove the scope and I make the bean a singleton again.
Is there a good workaround? Why isn't this possible?

What is the proper way to save a resource in an #Async task?

I am trying to update a resource inside an asynchronous thread that repeats its task until cancelled. I am using Future to store the thread in a hashmap so it can be cancelled at a later time. The thread forks as expected, and the object instance within the Async method changes its values fine, but when I try to commit them, the changes are not reflected in the DB, and I cannot see any error messages on the console. I've tried many different combinations of #Async and #Transactional but still haven't gotten it. What am I doing wrong? Thanks in advance for any help!
RoomService.java
#Service
#Transactional
public class RoomService {
#Inject private FooService fooService;
...
public Future<String> startRoom(Room room) {
Future<String> future = fooService.startFoo(room.getId());
map.put(room.getId(), future);
return future;
}
FooService.java
#Service
#Transactional
public class FooService {
...
public void save(Foo foo) {
getSession().saveOrUpdate(foo);
}
#Async
public Future<String> startFoo(int id) {
Foo foo = getFooById(id);
try {
while (true) {
foo.setName("Peter");
save(foo);
Thread.sleep(10000);
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
return new AsyncResult<String>("done");
}
Having the #Async method be part of a #Transactional bean means Spring intercepts your method twice: once for #Transactional to wrap the method in a Transaction and once for #Async to execute the method in a separate Thread.
Because of the way proxying works, once you are inside a method of FooService, invoking
another method is done on the actual object, not on the proxy which has all the #Transactional behavior. As such, no new transaction is created/committed/rolled back. The actual Transaction boundary is the #Async method itself. But since your method executes an infinite loop, that commit will never happen.
I suggest you make your #Async method in a different class for which you create a bean and inject the FooService. This way, the #Transactional behavior is wrapping the actual call to
fooService.save(foo); // fooService is actually a proxy
and is therefore committed on each invocation.

Resources