I understand that #Transactional annotation in class affect all the method and #Transactional annotation in method only affect this method and override the class annotation.
But, this code makes sense?(no more methods in class)
#Service
#Transactional
public class Service extends AbstractCrudService<A,Repository> {
#Transactional(readOnly=true)
public Optional<A> getByApplicant(B b) {
return repository.findByB(b);
}
Is the same if put #Transactional annotation only in method?
#Service
public class Service extends AbstractCrudService<A,Repository> {
#Transactional(readOnly=true)
public Optional<A> getByApplicant(B b) {
return repository.findByB(b);
}
Both examples work the same way
#Transactional on the class set on all methodos with #Transactional, but if you put #Transactional o method, this replace the class annotation
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, getByApplicant(B b)) this will take precedence over the transactional settings defined at the class level.
More about it:
http://docs.spring.io/spring/docs/3.0.x/spring-framework-reference/html/transaction.html
Related
I have read this #Transactional method called from another method doesn't obtain a transaction and learned that we can't call a #Transactional method from another method in the same class. I'm wondering if the following code works. I know that we can't put #Transactional on doSomething and have doSomethingTransactionally to call it directly, so I created a utility method that has #Transactional annotation in another class which takes in a function and execute it. The goal is to keep all the logic in the same class. If the following code does not work, is there a way to achieve this goal?
#Component
class A {
#Autowired
B b;
public String doSomethingTransactionally() {
return b.transactionalHelper(this::doSomething);
}
public String doSomething() {
// a bunch of db operations
}
}
#Component
class B {
#Transactional
public T transactionalHelper(Supplier<T> supplier) {
return supplier.get();
}
}
I wanted to make a method writing to DB as async using #Async annotation.
I marked the class with the annotation #EnableAsync:
#EnableAsync
public class FacialRecognitionAsyncImpl {
#Async
public void populateDataInPushQueue(int mediaId, int studentId) {
//myCode
}
}
while calling the populateDataInPushQueue method, the write operation should be executed in another thread and the flow should continue from the class I am calling this method. But this is not happening and the program execution is waiting for this method to complete.
The #Async annotation has few limitations - check whether those are respected:
it must be applied to public methods only
it cannot be called from the same class as defined
the return type must be either void or Future
The following can be found at the documentation of #EnableAsync:
Please note that proxy mode allows for the interception of calls through the proxy only; local calls within the same class cannot get intercepted that way.
Another fact is that the class annotated with #EnableAsync must be a #Configuration as well. Therefore start with an empty class:
#EnableAsync
#Configuration
public class AsyncConfiguration { }
In my opinion, you are missing #Configuration annotation and your async service is not component scanned. Here is an example code fragment that should do the trick:
#Configuration
#EnableAsync //should be placed together.
public class FacialRecognitionAsyncService {
#Async
public void populateDataInPushQueue(int mediaId, int studentId) {
//myCode
}
}
#Configuration
#EnableAsync
public class FacialServiceConfig {
// this will make your service to be scanned.
#Bean
public FacialRecognitionAsyncService createFacialRecognitionService() {
return new FacialRecognitionAsyncService();
}
}
Now the service bean that is invoking the async method. Notice that it has been dependency injected. This way spring AOP proxies will be invoked on each invocation fo the facialService. Spring uses AOP in the back scenes in order to implement #Async.
#Service
public class MyBusinessService {
#Autowire
FacialRecognitionAsyncService facialService;
public myBusinessMethod() {
facialService.populateDataInPushQueue()
}
Notice that FacialService is injected in MyService through dependency injection.
I have #Tenantable annotation to decide for pointCut :
#Target({ElementType.TYPE, ElementType.METHOD})
#Retention(RetentionPolicy.RUNTIME)
#Inherited
public #interface Tenantable {
}
this my aspect :
#Slf4j
#Aspect
#Configuration
public class TenancyAspect {
#Pointcut("execution(public * *(..))")
public void publicMethod() {}
#Around("publicMethod() && #within(com.sam.example.aspect.aspectexample.model.Tenantable)")
public Object tenatable(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("my operations ...");
return joinPoint.proceed();
}
}
This is working without any problem for this service class :
#Tenantable
#Service
public class MyService(){
public void doSomething(){
...
}
}
my aspect is running when I call doSomething() method, It is ok but I want to implement aspect for CrudRepository interface that belongs spring data.
I have changed my Aspect to achieve this like below :
#Slf4j
#Aspect
#Configuration
public class TenancyAspect {
#Pointcut("execution(public * *(..))")
public void publicMethod() {}
#Pointcut("this(org.springframework.data.repository.Repository)")
public void repositoryExec(){}
#Around("publicMethod() && repositoryExec() && #within(com.sam.example.aspect.aspectexample.model.Tenantable)")
public Object tenatable(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("my operations ...");
return joinPoint.proceed();
}
}
this is repository :
#Tenantable
#Repository
public interface MyRepository extends CrudRepository{
}
But it doesn't work when I call any method inside of MyRepository.
Is there anyway to do this?
Edit :
It works for all repositories when I apply these :
#Pointcut("execution(public * org.springframework.data.repository.Repository+.*(..))")
and exclude this :
#within(com.sam.example.aspect.aspectexample.model.Tenantable)
But I need this anotation to apply it for specific repositories.
Having taken another look, I think I know what is going on here: You are assuming that just because you made your annotation #Inherited, it will be inherited by implementing classes if you annotate an interface. But this assumption is wrong. #Inherited only works in exactly one case: when extending an annotated base class. It does not work for annotated interfaces, methods etc. This is also documented here:
Note that this meta-annotation type has no effect if the annotated type is used to annotate anything other than a class. Note also that this meta-annotation only causes annotations to be inherited from superclasses; annotations on implemented interfaces have no effect.
As soon as you annotate your implementing class, it works.
Your repositoryExec pointcut should end with + to advice all subclass of Repository
#Pointcut("this(org.springframework.data.repository.Repository+)")
I am new to AOP and currently trying to implement an aspect for controller methods annotated with a custom annotation.
I allways get a NullPointerException on repository when myFunction is invoked. It seems that i have two instances of of the controller. One of them is instantiated without autowiring the repository. When i remove #MyAnnotation everything works as expected.
Can you give me any hint on how to force Spring/AspectJ to use my constructor?
My controller looks like:
#RestController
#RequestMapping(value = "/api")
public class MyController {
private Repository repository;
public MyController(Repository repository) {
this.repository = repository;
}
#RequestMapping(value = "/{variable1}", method = GET)
#MyAnnotation
public final FeatureCollection myFunction(
final #PathVariable(required = true) long variable1
) {
repository.findById(variable1);
(...)
}
}
The aspect:
#Aspect
public class MyAspect {
#Around("#annotation(MyAnnotation)")
public Object any(ProceedingJoinPoint pjp) throws Throwable {
return pjp.proceed();
}
}
The configuration:
#Configuration
#EnableAspectJAutoProxy
public class WebConfig {
#Bean
public MyAspect myAspect() {
return new MyAspect();
}
}
Try to Annotate Constructor with #Autowired
#Autowired
public MyController(Repository repository) {
this.repository = repository;
}
It comes from the fact that the annotated method is final.
If you can remove the final keyword, it'll work.
If you google something like "spring aop final methods", you'll find more info, but basically, when Spring creates the proxy, it generates a subclass from your original class, to wrap the call to super with your aspect. The problem is that a final method cannot be inherited by the subclass, so that makes it hard for the proxy to work. Therefore, a lot of limitations come from that, and AOP doesn't work that much with final stuff.
This limitation is mentioned in the docs, I don't think you'll get a workaround for it:
11.6 Proxying mechanisms
...
final methods cannot be advised, as they cannot be overridden.
Hoping this will help you!
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!