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.
Related
I'm working on a Spring Boot API that's supposed to be deployed later this month. We created our own interface for a repository, and extended the CrudRepository. Spring boot autowires everything.
What I would like to do is add more logging capabilities, such as LOGGER.info("searched for solution ID").
Currently our code looks like this:
#Repository
public interface ProductSolutionRepository extends CrudRepository<ProductSolution, String> {
public List<ProductSolution> findBySolutionId(#Param("solutionId") int solutionId);
Since Spring configures everything don't really see a way of decorating these functions to add logging functionality. Can someone help me out by pointing me to the documentation, showing a nice example, or explaining the concept behind logging decorators?
First, I would like to point out some redundant codes for you.
You don't need to annotate the repository with #Repository, spring boot can autowire it automatically.
#Param is used when you write a sql with #Query, you just need to declare your parameters here.
The repository is the dao layer. A normal practice, you should create a service for each repository and autowire the repository into the service. Then you can implement transaction or write logs there.
You can use a single file AOP Logging Aspect using AspectJ cutting across your repository interfaces layer and logging method name, input args and output.
Assuming for this purpose a RepositoryLoggingAspect class, you'd have to annotate it first with #Aspect:
import org.aspectj.lang.annotation.Aspect;
#Aspect
public class RepositoryLoggingAspect {
//..
}
And then create a Pointcut aiming at your repository package you want to cut-accross:
#Pointcut("within(package.of.my.repositories..*)")
public void repositoriesPackagePointcut() {}
And finally define the logging logic in an #Around annotated method:
#Around("repositoriesPackagePointcut()")
public Object logMyRepos(ProceedingJoinPoint joinPoint) throws Throwable {
//log method name using: joinPoint.getSignature().getName()
//log method arguments using: Arrays.toString(joinPoint.getArgs())
//store and log method output using: Object myResult = joinPoint.proceed();
}
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.
I currently have a class called "AspectLogger" that logs Exceptions occurring in spring #Controllers. I am using native Spring AOP using AspectJ syntax.
#Before("(restController() || controller()) && publicMethod()")
public void logBefore(final JoinPoint joinPoint) throws IOException {
...
When a controller methods is requested from the frontend and there is no #RequestMapping that is able to handle it, I want to log this case too.
Using annotations, how can I achieve this? I guess I will need to create an aspect over one of the native Spring classes to handle this.
As far as I know, the most of Spring methods (which you need to intercept with AspectJ for this purpose) are protected or private, whereas AspectJ is for public methods only. Other work-around is using TRACE log-level on org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping class. Since you just want to log, I wanted let you know this option as well.
Why cant we use #Transactional for static methods to manage the transactions in my spring Project ?
#Transactional works well for non static method but not for static methods any specific reason ?
In order to understand why something like what you are proposing does not work you have to first understand at a high level how Spring handles beans that use #Transactional.
When you annotate a method or the class as #Transactional and make it a Spring Bean, Spring effectively creates a proxy for that class (using JDK Dynamic proxies or CGLIB proxies). That means that whenever your class is used (from Spring managed code that is), it's not your code that gets called immediately, but the proxy which first does whatever is needed, and then your code is called (in the case of caching support your code would perhaps not even be called at all).
A key thing to remember here is that the invoking code (the call site if you will) does not change at all, and the invocation of to the required target method (the proxy method) is performed by the JVM using the same bytecode (invokevirtual or invokeinterface).
With that in mind, the reason that static is not supported becomes clear.
You can't create a proxy for static method! Of course Java Dynamic Proxies cannot do this, and neither can CGLIB.
Supporting such a feature would require changing the bytecode of the invoking code, since calling a static method is implemented via invokestatic in bytecode, which hard-codes the target method.
This part of the Spring documentation explains Spring AOP in details
If you're using AspectJ, here's a simple, albeit ugly, workaround:
public static void doWhatever(final String param) {
new Runnable() {
#Transactional
public void run() {
// do whatever in transaction...
}
}.run();
}
This is feasible using:
#EnableTransactionManagement(mode = ASPECTJ) (or its XML equivalent)
all the configuration required to make AspectJ work
registering a custom aspect to handle #Transactional over static methods like this one I just stumbled upon (did not test it)
NB: in this post I asked about how to make package-private methods #Transactional.
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.