Spring AOP Method Interceptor vs Method Advice - spring

I am new to AOP and I am trying to understand the difference between Method Interceptor and MethodAdvice(i.e. MethodBeforeAdvice or MethodAfterAdvice). To me looks like both are doing the same thing i.e. are called on method invocation. When should we use MethodInterceptor vs MethodAdvice.

Take a look at the definition of the org.aopalliance.interceptInterceptor interface (implemented by MethodInterceptor):
public interface Interceptor extends Advice {
}
It's easy to see that a MethodInterceptor actually IS an Advice.
The only difference between an Advice being defined in an #Aspect class and such an Interceptor is that Interceptor implementations can be added to and removed from Spring AOP Proxies at runtime (casting them to 'Advised'), whereas the Advice you're talking about is a more static construct. But their still essential to Spring AOP since their presence tells Spring which beans to wrap in a proxy object during application context startup.

Related

Spring AOP pointcut execution not working

I'm working on a Spring Boot project that uses Spring Cloud (io.awspring.cloud:spring-cloud-aws-dependencies:2.4.2) to produce and consume AWS SQS messages. I have several message producers and several message consumers, and all is working fine from that perspective.
I now have a cross cutting concern where I need to set a header on all messages being produced/sent; and to read that header on all messages being consumed (correlationId), and AOP seems like a good fit.
My aspect for handling (receiving) a message works fine:
#Before("execution(* org.springframework.messaging.handler.invocation.AbstractMethodMessageHandler.handleMessage(..))")
fun beforeHandleMessage(joinPoint: JoinPoint) {
The class and method that it is targeting is:
package org.springframework.messaging.handler.invocation;
...
public abstract class AbstractMethodMessageHandler<T>
implements MessageHandler, ApplicationContextAware, InitializingBean {
...
#Override
public void handleMessage(Message<?> message) throws MessagingException {
As mentioned, this works great.
However, I can't get my pointcut for sending a message working. This is my aspect:
#Before("execution(* org.springframework.messaging.support.AbstractMessageChannel.send(..))")
// #Before("execution(* io.awspring.cloud.messaging.core.QueueMessageChannel.send(..))")
fun beforeSendMessage(joinPoint: JoinPoint) {
And the class and method that I'm trying to target is this:
package org.springframework.messaging.support;
...
public abstract class AbstractMessageChannel implements MessageChannel, InterceptableChannel, BeanNameAware {
...
#Override
public final boolean send(Message<?> message) {
But it doesn't seem to work. I've also tried writing the pointcut to target the concrete implementation class (as commented out above), but that also does nothing.
I can't see what the difference is between my working pointcut for beforeHandleMessage and beforeSendMethod, other than the pointcut for beforeSendMethod is targeting a final method. Is that relevant?
Any pointers to get this working would be very much appreciated;
Thanks
Spring AOP uses dynamic proxies, i.e. it works by subclassing (CGLIB proxy) or by implementing interfaces (JDK proxies). In your case, you are targeting a class method rather than an interface method. The class method is final, which explains why it cannot work that way, because you cannot override a final method in a CGLIB proxy. What you should do instead is to
target the interface method MessageChannel.send(Message) and
make sure to use JDK proxies, i.e. not the "proxy target class" (CGLIB) mode. In Spring core, JDK proxy mode is the default, in Spring Boot CGLIB mode. So in Boot, you need to manually reconfigure the framework to permit for JDK proxies, which is only possible there via config file, not via annotations (they come too late in the bootstrapping process for Boot).
More specifically, you need this in src/main/resources/application.properties for Spring Boot:
# This works, now we can create JDK interface proxies. The seemingly equivalent alternative
# #EnableAspectJAutoProxy(proxyTargetClass = false)
# where 'false' is even the default, does *not* work in Spring Boot.
spring.aop.proxy-target-class=false
I found the answer from this other SO answer: Spring AOP ignores some methods of Hessian Service
I know that Spring AOP won't intercept local method calls. I.e. the proxy which is applied doesn't intercept the calls if the same object calls its own method, even if it matches the pointcut expression.
The problem was that the send method I was targeting was called by a number of other methods in the class.
Looking at the call stack I found a different method that was the first method called in the class. Changing the pointcut to target that method has worked.

Spring MVC #Configuration class constructor

As part of the Spring MVC initialization, I need to run an action (just calling a method on a 3rd party library) once as a setup operation. I'm working in Spring MVC environment where I don't really have control over the web.xml or anything, so I can't add a servlet context listener or anything. I tried making an implementation of a WebApplicationInitializer but it never seems to get called (no idea why though, or how to try and debug that any further).
If I annotate a class with #Configuration it does get created, so I'm wondering if I can use the class's constructor to perform that setup operation (calling a 3rd party setup method). Is this appropriate/safe to do? Are there any other alternatives for this kind of thing? I'm new to Spring, so I might just be missing something that's meant for this kind of thing.
Thanks
Configuration class would be an appropriate place to contain some initialization logic. You can place it in a constructor, method annotated with #PostConstruct or afterPropertiesSet() method if you implement the InitializingBean interface for example. The difference is that the constructor code will be called before the beans in your configuration class are instantiated, so if your initialization code depends on some Spring beans, go with the #PostConstruct / InitializingBean approach.
Example:
#Configuration
public class Config {
#PostConstruct
public void initialize() {
// Run some action
}
}

Invoking custom annotation using Spring AOP

I searched the web for a clear example on how to invoke my custom method annotation using Spring AOP but couldn't find a clear example.
I am building a framework to inject a user profile in the context when certain methods on any POJO is called.
The framework API should be invoked via a custom method annotation, say #RunAsAdmin. I can build the annotation part and parser, my question is what is the best way to invoke my parser when the annotated method is called.
We are using Spring 3.0 and would like to know what is the best practice to configure Spring framework to understand those methods annotated with specific annotation and invoke my annotation handler (parser).
Any example or guidance will be highly appreciated.
Intercepting a call on any annotated Spring bean method is straightforward, see the example below.
Intercepting a call on a POJO is not possible by definition - you have to return a proxy instead.
That is, you should implement a factory for these POJOs that will return proxies instead of real POJOs. You might use ProxyFactoryBean http://docs.spring.io/autorepo/docs/spring-framework/3.2.0.BUILD-SNAPSHOT/api/org/springframework/aop/framework/ProxyFactoryBean.html for this.
//intercepting a call to any method annotated with #com.yours.RunAsAdmin of any Spring-managed bean
#Component #Aspect class RunAsAdminAspect {
#Autowired
private YourRunAsAdminHandler handler;
#Before("#annotation(com.yours.RunAsAdmin)")
public void doRunAsAdmin() {
handler.grantAdminRightsToCurrentUser(); //your real stuff
}
}

Does this annotation work for Spring declarative transaction

As far as I know, Spring uses JDK to generate dynamic proxy for the classes that implement any inferface while use Cglib to generate dynamic proxy for the classes that do not implement any inferface. For decarative transcation, Spring uses proxy to add transaction aspect. Please take a look at the code below:
interface Demo {
void methodA();
}
public class DemoImpl implements Demo{
#Transactional
public void updateA() {}
#Transactional
public void updateB() {}
}
I think updateA can work well with transaction. But how about updateB method? Does the #Transactional work for it?
Maybe my understanding is not correct. It's great if the related Spring source code is provided to explain how Spring use JDK/cglib to proxy the class and interface. Thanks
I have the config in the xml:
<tx:annotation-driven transaction-manager="transactionManager" />
JDK dynamic proxy
In this case your bean is wrapped with a proxy implementing Demo interface. From that moment you can only use that interface. Trying to inject or fetch bean of DemoImpl type will result in dreadful Abstract DAO pattern and Spring's "Proxy cannot be cast to ..." problem!
This kind of answers your question - you can only access updateA() and this is the only transactional method. Annotation around updateB() is ignored.
However if you call updateB() from updateA() it will be transactional because it will bind to a transaction started by updateA() (with default transaction propagation).
CGLIB proxy
In this case the interface is ignored. cglib will create a subclass of DemoImpl (obviously also implementing Demo interface) and apply transaction behaviour on both update*() methods. Now if you inject bean of type DemoImpl (interface is not needed in this case at all and Impl suffix is ugly) you can safely and transactionally call both methods.
See my article: Spring pitfalls: proxying and Spring AOP riddle for greater details.

How to add a custom annotation to Spring MVC?

Can anyone explain what I need to do to implement my own annotation that would add functionality to my web requests?
For example:
#Controller
public class MyController {
#RequestMapping("/abc")
#RequiresSomeSpecialHandling
public void handleSecureRequest() {
}
}
Here #RequiresSomeSpecialHandling would be my own annotation that causes some special work to be done before or after the given web request /abc.
I know that on a very high level I would need to write a bean post processor, scan classes for my annotations, and inject custom mvc interceptors when needed. But are there any shortcuts to simplify this task? Especially for the two examples above.
Thanks in advance,
This kind of Annotations, (that add additional functionality when invoking a method) looks like annotations that trigger an AOP Advice.
#see Spring Reference Chapter 7. Aspect Oriented Programming with Spring
The idea is to use the Annotation to trigger the AOP Advice.
like:
#Pointcut("#target(com.example.RequiresAuth)")
Depends on what you want to do as a result of #RequiresSomeSpecialHandling. E.g. do you want it to influence request mappings or the invocation of the method (i.e. resolving method arguments, processing the return value)?
The support for annotated classes in Spring 3.1 became much more customizable. You can browse some examples in this repo.
Also keep in mind that a HandlerInterceptor in Spring 3.1 can cast the handler Object to HandlerMethod, which gives you access to the exact method including its annotations. That may be enough for what you need to do.
If caching is one of your goals, take a look at the #Cacheable annotation (and its siblings #CachePut, #CacheEvict and #Caching), available as of Spring 3.1.

Resources