Asynchronous executing #Aspect class or JPA event observer - java

Is that possible to execute methods annotated as #After (in class annotated as #Aspec) asynchronous? For example using annotation #Async or implements Runnable or Callable. And the same question for methods annotated as #PostPersist.
The real case is sending mail after registration. I don't want to execute method from some MailService in register method because this service will have too many dependencies and will be difficult to testing. But sending mail have to be executed asynchronous because this operation is very expensive.

Should not be a problem. Just start a new thread in the method "after" method.
AOP works as follows (by default):
When you register a bean that requires some aspects to be applied to, Spring creates a proxy around that bean and when you get the bean from the application context(by ctx.getBean(MyBean.class) or by Autowire is somewhere) you receive the proxy that has the real/target bean inside.
So, for example, when you tell Spring to execute a method after some target method this happens:
the application calls the method of the proxy
If something has to be executed before the target method(like configured #Before action) it's done.
call the real/target method
If something has to be executed after the target method(like configured #After action) it's done.
The next method in the call stack is executed
So basically with #After you just "insert" a method in the call stack. You can start a new thread from there, it will return the control immediately and the next thing after the target method will be executed.

Related

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?
Please go through the reference documentation
The following images shows a Conceptual view of calling a method on a
transactional proxy:
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

Where to place Spring #Async in a stack of methods calls

I am using Spring Boot 1.5.x, and in details, I am using the #Async annotation. My problem is that I have the following method in a repository.
#Repository
class Repository {
#Async
CompletableFuture<String> findSomething() {
/* Some code that returns something */
}
}
And then, I have the following method in a service, which calls the above repository.
#Service
class Service {
private Repository repository;
// ...
#Async
CompletableFuture<String> findSomething() {
return repository.findSomething()
}
}
My question is: should I place the #Async annotation also in the service.findSomething() method? Or should I place the annotation only in the service method?
I mean, Spring should schedule the execution of a method marked with #Async annotation in a dedicated thread. Is it correct?
Thanks in advance.
Annotating a method with #Async will cause the caller to return immediately and the actual execution will occur in a separate thread as part of a task submitted to the default SimpleAsyncTaskExecutor (if you haven't configured another one). Please see the relevant spring documentation.
That being said, for your goal there's no added benefit in nesting the #Async. If your goal is to make Repository.findSomething asynchronous and to be able to call it from different places, not only Service.findSomething, you should annotate only this method.
Also, Service.findSomething is asynchronous itself, even if not annotated with #Async, in the scenario you depicted. The method is not blocking by calling CompletableFuture.get() and it will return immediately, although it will not be executed in a separate thread.

Spring #Transactional multiple threads

I have a method A running in the transactional scope which:
Modifies an entity A to switch from state A to state B
Passes a task to a executor service that expects an Entity to be in state B when executed
The problem is when this task is run (that thing I have no control of) before the method A commits, it doesn't see the required state changed because it does not block until the method A level transaction ends.
Task is run using a spring bean and #Transactional-annotated method like this:
#Service
public class TransactionalProcessingAdapter implements ProcessingAdapter {
#Override
#Transactional
public void execute(ProcessingAdaptedMethod processingAdapter) {
processingAdapter.execute();
}
}
What am I doing wrong? Thanks!
The thing is that Spring transactions are thread bounded - eg a transaction is visible inside its initial threads only. ThreadLocal is used to implement that property.
You might want to implement your own TransactionSynchronizationManager in Spring and inject it. Use something like InheritableThreadLocal instead of ThreadLocal.

Spring #Scheduled annotation and Singleton class

I have created a bean of a class with default (Singleton) scope. Within the class I have a method which is scheduled to be run every hour.
public class TaskService implements InitializingBean {
#Scheduled(cron="0 0 */1 * * ?")
public void hourlyReportTask()
{
... code here ...
}
public void performAllTasks()
{
hourlyReportTask();
...
...
}
}
My application config looks something like this,
<bean id="reportService"
class="com.tasks.TaskService" />
I am assuming the Thread running the scheduled task will be using the same TaskService bean since its created in singleton scope. What shall happen if the application is currently running hourlyReportTask() and the Spring container kicks off a background scheduled thread to run hourlyReportTask() at the same time. Will it wait for the to get access of the TaskService instance?
The exact same instance is used by both your application and the scheduling service. There is no synchronization so the scheduling service may run that method while your application invokes it.
Pretty much the same way as you would have injected TaskService in something that can be accessed by multiple threads at the same time and those threads call that method concurrently.
There's no black magic behind #Scheduled: it invokes your method the same way as you would manually. If that method is not thread-safe you need to fallback on regular synchronization mechanism in Java (for instance by adding the synchronized keyword to your method declaration).
Spring Singleton, does not mean what you expect from Design Patterns Singleton. In Spring, Singleton means that a bean only has created only one instance (without meaning that another cannot be created) and that instance is used whenever Spring needs that type.
In your case your hourlyReportTask() method would execute twice.

correct way to pass service layer to threads

my service layer methods are transactional, when i use ExecutorService and submit task to threads, i cannot pass servicelayer as parameter to each threads, as i get error
Dec 14, 2009 10:40:18 AM com.companyx.applicationtest.applicationtestcompanyx.services.threadtestRunnable run
SEVERE: null
org.hibernate.HibernateException: No Hibernate Session bound to thread, and conf
iguration does not allow creation of non-transactional one here
at org.springframework.orm.hibernate3.SpringSessionContext.currentSessio
n(SpringSessionContext.java:63)
at org.hibernate.impl.SessionFactoryImpl.getCurrentSession(SessionFactor
yImpl.java:542)
my service layer
ExecutorService executor = Executors.newFixedThreadPool(10);
for (final Object item : CollectionsTest{
executor.submit(new threadtestRunnable((Long)item,collectionAfterfiltered,this)); //'this' is service layer
}
should i pass the service layer to each thread like this?
what is the proper way to do it, i need each thread to call method in service layer? (i'm using spring)
Generally, as said in the comments, transactions shouldn't be run in multiple threads. However, there are cases, where it is acceptable.
you need to make some asynchronous communication with a web-service (without making the user wait for the result), and store the result when it comes
you need read-only transactions in the multiple threads.
If you create your thread using new, it is not part of the spring context. Hence, when the method creating the thread finishes, your transaction interceptor will close the transaction (and session, eventually), and you will get the above exception.
(For more details - Spring docs, see "Lookup injection")
You need to create your threads within the spring context. And since you are probably creating them from a singleton bean, it is the rare case of creating prototype beans from a singleton bean. So in order to create a thread in the spring context, you can use:
<bean id="mainBean"
class="com.my.MyClass">
<lookup-method name="createThread" bean="myThreadBean"/>
</bean>
You should also map your ThreadtestRunnable class in the applicationContext.xml or annotate it as #Component("myThreadBean").
Then define an abstract method on your main bean named createThread and returning your thread class. Annotate your run method with #Transactional (or define the appropriate aop rules), and try it. Perhaps you will need to set propagation=Propagation.REQUIRES_NEW" in your #Transactional. If anything is wrong, get back here.

Categories

Resources