Logging with spring-aop - spring

I am trying to add some kind of tracing to my app. It would work like that: I set package name in my config and all calls to public methods of classes in this package are logged.
I can't use weaving here (due to some technical reasons), so I tried to use spring-proxy.
My pointcut
execution(public * com.my.package.*.*(..))
and it works fine. But what Spring uses Proxy or CGLIB to proxy class, so each class should at least
Have parameterless constructor
All methods should be implementations of some interface
Other classes could not be proxied. That is ok for me to do not log them. But spring creates proxies and ruins my app.
How can I tell spring: "do not proxy this class if it has no parameterless constructor and some of its methods are not implementations of interface"?

Not sure about the answer to your question, however, another way to do the tracing, is to use an annotation:
public #interface Monitor {
}
aspect:
public aspect MonitoringAspect {
pointcut methodToMonitor() : execution(#Monitor * *(..));
}
Usage:
#Monitor
public void methodToBeMonitored() {
}
This way you only affect the methods you want to.
I suppose for a big project, this might not work as you want to monitor many methods.

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.

What are the drawbacks of CGLIB proxy over dynamic proxy in Spring AOP?

As I understand it, Spring AOP generally involves:
dynamic proxy for interfaces
CGLIB proxy for those without (except for final methods and classes)
Why not just use CGLIB proxy all the time? I would expect the following gains:
Since its done during compilation, there should be performance gains over dynamic proxying
doesn't have the limiting factor of requiring interfaces
it can be to bypass the proxy if you return impl classes in some service factory
at the cost of configurability without compilation.
I'm not sure I understood the gains of CGLIB as you've presented them in the question.
Both dynamic proxy and CGLIB are created in runtime, it's not relevant to compile-time at all.
Basically, the major drawback of CGLIB is performance.
There are two aspects of performance that can be more or less important depending on the domain:
The Cost of creation of a proxy object
The cost of the Method call on a proxy.
Now, In both cases, the dynamic proxy mechanism is way more lightweight than a CGLIB proxy. That's why spring up to version 5 (mentioned in the question tag) has attempted to create Dynamic proxy if there was an interface and only if it wasn't possible it wrapped the real object with CGLIB.
This has changed in Spring 5 in favor of using CGLIB in any case but there is still a flag that can bring back the old behavior.
Interesting that CGLIB has a kind of advantage that you haven't mentioned that turned to be important to Spring (well, maybe that was the reason of the behavior change in Spring 5, I can't say for sure):
Many companies don't bother to create interfaces for the services and work directly by the implementation, or even if they do - they do not use injection by interface:
public interface MyService {
void foo();
}
#Component
public class MyServiceImpl implements MyService {
public void foo() {... whatever...}
}
#Component
public class AnotherService {
#Autowired // note, this is not an injection by inteface
private MyServiceImpl service;
public void bar() {
// do something
service.foo();
// do something else
}
}
Now, if you'll use a dynamic proxy (which in general could be used if the application code was using the injection by interface) - you'll generate something that implements the interface MyService but can't be injected into AnotherService because the generated proxy doesn't extend MyServiceImpl class. In this case, the CGLIB is the only viable solution.

How should I test a method with an aspect around?

I'm trying to do an integration test. These are my components:
UsersService
#ManageSession
public List<T> get() {
//...
return something;
}
ManageSessionAspect
#Autowired
AuthService authService;
#Before("manageSessionMethod()") //methods annotated with #ManageSession
public void doSomething() {
authService.doSomething();
}
I need to test UsersService.get() method. But I want to disable the aspect OR I want to be able to mock the AuthService inside it.
I have tried using an is() pointcut, but I get:
if() pointcut designator isn't supported by Spring.
Can you help me? Thanks.
This is a perfect use case for spring profiles. You can define profiles and tie your configuration classes to these profiles. A configuration tied to a profile will only get activated if the profile is active. See my answer on a related question for further details: A: How to mock bean and avoiding NoUniqueBeanDefinitionException. You will need to define a profile (eg.: test or integration-test) and use that profile in a configuration class to provide a mock implementation for your AuthService.
As a side note, I would strongly suggest you go with AspectJ (preferably compile-time weaving) instead of Spring AOP as it's much more powerful.

#Transactional with static method

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.

Dynamic AOP configuration in Spring

I'm new to Spring AOP, and I've to know if it's possible to implement my project with Spring AOP. Specifically, I want to know if in Spring AOP it's possible to configure, at runtime, which aspects will be executed and in which order. NB: I want to control only mine application aspects', without interfering with Spring-managed aspects like transactions or security.
You can control the ordering of aspesct (using declare precedence), but its hard to do this at run time, as it would need to reapply the weaving for already weaved classes.
The same goes for specifying which aspects to execute.
You could have an if(!enabled){return;} check at the start of each aspect method, and the enabled flag could be set on or off just like any normal bean. This way, the aspects are always weaved in, but they will do nothing if they are disabled.
UPDATE
Here is example of how to use an aspect as a bean.
Lets say you have an aspect like this:
#Component // IMPORTANT
public aspect MyAspect {
Object responder;
public void setResponder(Object object) {
this.responder=object;
}
}
Then in your spring service class, you can wiring the aspect like this:
#Service
public class MyServiceImpl implements MyService {
#Autowired
MyAspect aspect;
void action() {
aspect.setResponder(null);
}
}
This works because aspects are actually java classes. The component annotation causes the aspect to be recognised as a bean by the spring component scan.
I have compiled this code successfully, but not actually tested it runtime, so would be good to know if it works.

Resources