I have gone through number of post regarding tx with spring and AspectJ. Below is the summary,
Say, I have a service class and its interface
interface TestService {
void methodA();
void methodB();
}
class TestServiceImpl implements TesService {
#Transactional
void methodA() {
methodB();
}
#Transactional(propagation=Propagation.NEVER)
void methodB(){}
}
And my configuration
<tx:annotation-driven transaction-manager="jpaTxManager"/>
<bean id="jpaTxManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory"><ref bean="entityManagerFactory"/></property>
<property name="dataSource"><ref bean="dataSource"/></property>
</bean>
<bean id="testService" class="com.motherframework.plugin.test.service.TestServiceImpl">
<property name="testDAO" ref="testDAO"/>
</bean>
I am calling testService.methodA() from some client class. As per spring's JDK dynamic proxy usage, it will only care about #Transactional on methodA(), but not #Transactional(propagation=Propagation.NEVER) on methodB(). So the code executes with proper transaction and commits. If we use AspectJ mode then it will also check for #Transactional(propagation=Propagation.NEVER) on methodB() and will throw an exception.
Now my question is, why this limitation is imposed by Spring? Now there are two possibilities for Spring design,
It is a technical limitaion with spring that they can not check annotation in methodB(), though it is public? But if AspectJ can check it, then why not Spring?
Intentionally they have limited this AOP checking for internal method calls. Is this kind of method call (where target method is annotated with different transactionPropagation) is against proper design methodology?
Yes, it's a technical limitation. When you don't use AspectJ, the transactional aspect is implemented by returning a proxy around the actual bean class instance and returning/injecting this proxy into other beans. So, when you call testService.methodA(), the following (basically) happens:
caller ---> transactionalProxy.methodA() ---> testServiceImpl.methodA()
The proxy applies the transactional aspect around the call to testServiceImpl.methodA(): it starts the transaction before, and commits/rollbacks it after.
If you call this.methodB() from methodA(), the following happens:
caller ---> transactionalProxy.methodA() ---> testServiceImpl.methodA() ---> testServiceImpl.methodB()
And since you bypass the proxy, no transactional aspect can be applied.
AspectJ is different because it transforms the byte-code of TestServiceImpl in order to apply aspects around various method invocations.
I wouldn't say that applying aspects around internal method calls is not proper design. You just need to be aware that it works only with byte-code instrumentation.
It is a technical limitation (as others have answered). If you want Spring to check this, you could modify your service like this:
class TestServiceImpl implements TesService {
TesService thiz; // setter left outside, assumed to be injected by Spring
#Transactional
void methodA() {
thiz.methodB();
}
#Transactional(propagation=Propagation.NEVER)
void methodB(){}
}
The idea here is that the outermost method knows what is best for the whole transaction. But, as you noticed, there are corner cases.
Workaround: Move the implementations of the methods to a second bean and inject that bean into your TestServiceImpl. Since you'll get a proxy injected, all method calls will heed the annotations.
You will need to split some methods. If you have this situation:
methodX() {
...code before...
methodB();
...code after...
}
you can use a callback:
methodX() {
Callable<Void> callback = new Callable<Void>() {
Void call() {
realImpl.methodB();
}
}
realImpl.methodX(callback);
}
and in your inner bean:
void methodX(Callable<Void> callback) {
...code before...
callback();
...code after...
}
Related
learning the Spring AOP, the code like this:
#Component
#Aspect
public class FanAnnotationImpl {
#Pointcut("#annotation(com.fan.spboot.core.aopdemo.FanAnnotation)")
private void entry(){
System.out.println("entry annotation");
}
#Around("entry()")
public void around(ProceedingJoinPoint joinPoint)throws Throwable{
System.out.println("around before");
try {
joinPoint.proceed();
}catch (Exception e){
e.printStackTrace();
}
System.out.println("around after");
}
#Before("entry()")
public void before(){
System.out.println("Before entry");
}
#After("entry()")
public void after(){
System.out.println("After entry");
}
}
the spring-aop-pointcut-tutorial has a introduction:
"The method declaration is called the pointcut signature. It provides a name that can be used by advice annotations to refer to that pointcut."
What make me feel puzzled is the method use #Pointcut ,it's just a pointcut signature?
Because I find the code in this method not executed, and change the type of this method is OK;
Then why is a method? Use a variable is also OK?
You already quoted the manual yourself. It is pretty clear, is it not? Spring AOP is based on annotations, not on variables. Annotations are a standard way in Java to add information to classes, methods or other language elements.
A #Pointcut method is only a way to define pointcuts which can be used in multiple places, e.g. if you want to combine multiple pointcuts like pointcut1 && (pointcut2 || pointcut3) or just use the same pointcut in multiple advice methods. It is a way for you as a developer not to have to repeat yourself and write the same pointcut many times. Another advantage is that you can modify the pointcut in one place and it gets updated everywhere it is used.
The method annotated by #Pointcut of course is never called by Spring AOP because the method is only a dummy you need to get decorated by the pointcut annotation. You need to put the annotation somewhere, after all.
If you use your pointcut in only a single place, there is no need to define it via #Pointcut, you can just write the pointcut directly into your #Before, #After or #Around annotation.
Actually this answer is pretty much superfluous because everything is explained well in the Spring AOP manual.
I have a scenario in which i need to intercept some subclass methods, but i couldn't find a proper pointcut expression to do so.
I have a client facing interface InfoService which has a method getClientDetails.
package sample;
public interface InfoService {
InfoVO getClientDetails(int id);
}
The implementation class has some nested methods like get*Info().
package sample;
public class InfoServiceImpl implements InfoService{
public InfoVO getClientDetails(int id) {
InfoVO clientInfo = new InfoVO();
clientInfo.setA(getAInfo(id));
clientInfo.setB(getBInfo(id));
clientInfo.setC(getCInfo(id));
return clientInfo;
}
public Object getAInfo(int id) {
return null;
}
public Object getBInfo(int id) {
return null;
}
public Object getCInfo(int id) {
return null;
}
}
When the user invoke the getClientDetails method i would like to intercept the get*Info() methods. I can easily intercept the getClientDetails but nothing seems to intercept the subclass method. I even tried annotating those info methods using custom annotation but with no luck. So far I came up with the following aspect
<aop:aspect ref="infoAspect">
<aop:pointcut expression="execution(* sample.InfoService+.*Info(..))"
id="infoMethods" />
<aop:around method="aroundAdviceForinfoMethods" pointcut-ref="infoMethods" />
</aop:aspect>
Setting the <aop:aspectj-autoproxy proxy-target-class="false"/> to true or false didn't help either.
I know AOP cannot intercept on private subclass methods but these are public ones. Is it even possible to do this? Any help is much appreciated.
PS: The example shown is for demo purpose. The actual implementations are huge, so moving those inner methods to a different bean and invoking won't be feasible.
This is a classic one, having been asked here dozens of times already. I guess you have not read the Spring manual's info about Spring AOP being proxy-based and that for this reason Spring aspects cannot intercept self-invocation. If you really need AOP to work for self-invoked methods (even private ones if necessary), say goodbye to Spring AOP and hello to full AspectJ and LTW (load-time weaving).
I am trying to instantiate a resolver from spring-cloud-aws-messaging, specifically the NotificationMessageArgumentResolver. The problem is that it takes a MessageConvertor as an argument. So, this is what I have so far:
private NotificationMessageArgumentResolver notificationMessageArgumentResolver() {
new NotificationMessageArgumentResolver(this.messageConvertor);
}
To get the messageConvertor, I have tried:
#Autowired
public MvcConfig(MessageConvertor messageConvertor) {}
#Autowired
public MvcConfig(MappingJackson2MessageConverter messageConvertor) {}
but I get the same error either ways no bean found. The documentation is simply asking to use the XML:
<mvc:annotation-driven>
<mvc:argument-resolvers>
<ref bean="notificationResolver" />
</mvc:argument-resolvers>
<aws-messaging:notification-argument-resolver id="notificationResolver" />
Which, according to the doc
registers three argument resolvers: NotificationStatusHandlerMethodArgumentResolver, NotificationMessageHandlerMethodArgumentResolver, and NotificationSubjectHandlerMethodArgumentResolver.
So, following the answer from How to use argument-resolvers using annotation in Spring boot?, I am able to get 2 of the 3 beans added, as they don't need any beans I cannot access, however I am not able to instantiate NotificationMessageArgumentResolver due to the lack of a MessageConvertor. I am expecting all my messages to come purely in JSON, so I do know exactly which MessageConvertor to use, which is the default one for JSON that ships with Spring Boot.
EDIT
The entire file, if anyone is interested: http://pastebin.com/tM471AEv
I wonder if you really need the NotificationMessageArgumentResolver as that is intended to be used when using messaging. As you can see it implements the HandlerMethodArgumentResolver from the org.springframework.messaging package.
I suspect that you want to use the NotificationMessageHandlerMethodArgumentResolver instead. Which is the HandlerMethodArgumentResolver for use with the web instead of messaging. Which is also registered when using <aws-messaging:notification-argument-resolver id="notificationResolver" />
I would also suggest to use the NotificationHandlerMethodArgumentResolverFactoryBean instead of 3 individual beans as that is also the class that is used internally by the namespace and annotation driven configuration.
Your configuration would look something like this.
#Bean
public NotificationHandlerMethodArgumentResolverFactoryBean notificationHandlerMethodArgumentResolverFactoryBean() {
return new NotificationHandlerMethodArgumentResolverFactoryBean();
}
#Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
argumentResolvers.add(notificationHandlerMethodArgumentResolverFactoryBean.getObject());
}
We are using Struts2-Spring integration and all my action classes implement SessionAware, sample code to action class and their spring definition is given below,
public class IRXxxxAction extends ActionSupport implements SessionAware {
private Map session;
public String execute()
{//}
public void setSession(Map<String, Object> session)
{
this.session = session;
}
}
Spring Configuration
<bean name="userAction" class="com.IRXxxxAction" >
<property name="adminDAO" ref="adminDAO" />
</bean>
If I understand correctly, each auto-wired property will be a singleton, so if the above is true, is there anyway that the session map get shared between two simultaneous requests?
Regards,
Ayush
You have asked same question on the user mailing list and as said if you are using Struts2-Spring plugin make sure to put bean scope as prototype.
Struts2 create new instance of action on each request, since action work as a model also and in order to make it thread safe a new object is being created on each request and placed on value stack.
Not proving scope will be treated by Spring as singleton and for ever request same action instance will be given back which can leads to a lot of issue from data corruption to weird behavior.
supose I have the following example:
#Transactional(propagation=Propagation.SUPPORTS, readOnly=true)
public class MyServiceImpl implements MyService {
...
#Transactional(propagation=Propagation.REQUIRED, readOnly=false)
public TransactionResponse addMyEntity(MyEntity e) throws SQLException{
...
}
...
}
And in my applicationContext:
<tx:annotation-driven transaction-manager="txManager" />
Ok, now I want to add an interceptor after the rollback of the transaction if an SQLException is thrown. How can I do this?
Thanks in advance
EDIT
I'll try to clarify what I'm trying to do:
I have a WS, that persists some information on a DB and returns a response (an isOk boolean and an errorMessage if something went wrong)
Whenever an exception is risen, I need to:
Rollback the transaction
Build the response with the error message and return it to the client.
It's like a try/catch around spring's transaction proxy
Use the order attribute of tx:annotation-driven, and of the interceptor you will be using. Thus you specify which one runs before the other. See the AOP AspectJ advice ordering section