Spring AOP pointcut expression for Subclass only method - spring

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).

Related

What's the meaning of the method use #Pointcut in Spring AOP,just a pointcut signature?

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.

Get a message converter bean in Spring boot

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());
}

Struts2 and Spring integration thread safe

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.

Design principle behind Transaction framework with Spring 3

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...
}

Using Aspect to annotate methods with #InsightOperation for Spring Insight

I wanted to instrument a large number of classes to use with Spring Insight and instead of adding the #InsightOperation manually to the methods, I wrote an aspect to annotate the methods using point cuts.
However, this is not working. While the manual annotation affects the Spring Insight trace logging, the AspectJ method does not work.
Is there anything I am doing wrong here? (I decompiled the classes after aspectizing and do find the annotation in the class methods)
This is the aspect code snippet:
declare #method :public * com.example.IExample.execute(..) : #InsightOperation;
Spring documentation says this:
Use of the #Insight* annotations are
optional. They make it easy for end
users to define custom operation
frames and end points without needing
to create a plug-in. Because end user
code modification is required to use
the annotations, they are an option
for users who cannot or do not wish to
write aspects.
http://static.springsource.com/projects/tc-server/2.5/devedition/htmlsingle/devedition.html
So looks like the only way is to write a custom plugin
http://static.springsource.com/projects/tc-server/2.5/devedition/htmlsingle/devedition.html#tutorial-plugin
It is possible that the Insight LTW does not pick up your introduced annotations. I'll have to dig deeper on that.
In the meantime, you can try a more low-level annotation:
com.springsource.insight.collection.method.MethodOperationsCollected
If you look at the spring-core plugin, you will see that it does something similar:
public aspect RepositoryMethodOperationCollectionAspect {
declare #type: #Repository * : #MethodOperationsCollected;
}
An easy work around is to call another method from within your aspect method to continue executing the join point. I only tried calling a static method in a static class. See below my code for adding the #InsightOperation to all my JSON serialization.
My aspect:
#Aspect
public class JSONSerializerAspect {
#Around("call(* *.JSONSerializer.serialize(..)) && args(target)")
public Object serialize(ProceedingJoinPoint joinPoint, Object target) throws Throwable {
return JSONSerializationWrapper.serialize(joinPoint, target);
}
}
The static class it is calling:
public class JSONSerializationWrapper {
#InsightOperation(label = "JSON_SERIALIZATION")
public static Object serialize(ProceedingJoinPoint joinPoint, Object target) throws Throwable {
return joinPoint.proceed(new Object[]{target});
}
}
I'm using this myself and tested that it works.

Resources