I came across the following Spring AOP pointcut in a tutorial:
execution(public * * (..))
it was said that it would cause the execution of all public methods. Is that correct? AFAIK we can only intercept public methods, and that public keyword there is even illegal.
In addition to #Mario's answer, the spring docs on AOP say the following (emphasis mine):
Note Due to the proxy-based nature of Spring's AOP framework,
protected methods are by definition not intercepted, neither for JDK
proxies (where this isn't applicable) nor for CGLIB proxies (where
this is technically possible but not recommendable for AOP purposes).
As a consequence, any given pointcut will be matched against public
methods only!
If your interception needs include protected/private methods or even
constructors, consider the use of Spring-driven native AspectJ weaving
instead of Spring's proxy-based AOP framework. This constitutes a
different mode of AOP usage with different characteristics, so be sure
to make yourself familiar with weaving first before making a decision.
In addition, the pointcut grammer is as follows:
execution(modifiers-pattern? ret-type-pattern declaring-type-pattern?
name-pattern(param-pattern) throws-pattern?)
Wherby the modifier-pattern would be public,protected etc but is optional...
Yes, it seems to be a valid pointcut, and it does exactly what he says.
In addition, it is worth to note that replacing the "public" keyword with "protected" is perfectly legal and it still works! Strangely it works also with "private" methods...
(Tested with Spring 3.1.2 + AspectJ 1.6.9)
As far as I know, CGLib proxies can be used to proxy protected methods, however they are effective only if they are invoked from a different object instance. So technically, it should be possible to advice protected methods exactly in the same way as public ones.
(As reported by #beny23 advicing protected/private methods does not work with Spring AOP proxy implementation, but only with Spring driven AspectJ weaving)
pointcut: designator(modifier returnType package.type.method(params))
in your case
execution(public * * (..))
would execute for all public methods with ANY return type in the project dir with 0 to many parameters
Related
I am using Spring AOP to log the DB execution time, but it is applying to the entire method execution time.
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
public #interface TrackExecutionTime {
}
Is there any possibility that we can use this #TrackExecutionTime not in the method level but inside a method just above some statement like below -
#TrackExecutionTime
List<Release> releaseList = releaseRepo.findByProductName(productName.toUpperCase());
that way I can able to get only the DB execution time not only the entire method execution time, as my method contains other business logic too which also including if we use the AOP annotation at the method level.
Your question is not AOP-specific, because annotations are a Java language feature. The answer is: Annotations on arbitrary lines of code are not part of the Java language concept, which for you means you also cannot use them for AOP purposes. This is simply a Java limitation. Neither Spring AOP nor native AspectJ can support a feature which does not exist in Java to begin with.
Friendly suggestion: Please learn more about Java first, then get acquainted with some basic software design and clean code principles. Finally, you shall be able to achieve what you want, albeit in a different way from what you just dreamed up here.
Spring AOP default configuration uses proxies to execute the aspect hence only methods can be annotated.
A bit of a detour on the proxies. A proxy wraps a target method so when you call a method elsewhere Spring makes sure to invoke the method on the proxy and that invocation then contains the aspect code which gets executed before, after, around the call itself (depending on the aspect). There can be several proxies wrapping a single class.
Then an option is to add your aspect annotation to the repository method.
If we need to track the execution time only for subset of calls to the method (which sounds a bit strange a requirement) then we can add a wrapper method - say make a Spring-managed Metrics class with a said time tracking method that accepts a lambda and is annotated with the #TrackExecutionTime. The original call would then be something like
metrics.executeTimed(() -> releaseRepo.findByProductName(productName.toUpperCase()));
I am using a set of Spring AOP Aspects (mostly from my library here). I am finding that the ordering I specify for the aspects is no longer being respected (I am certain that, at some point in the past, say, 1 year ago on Boot 1.3.x, it was respected) when the scope of the aspect bean is "prototype". If I remove the 'scope="prototype"' in XML, or the #Scope("prototype") in JavaConfig, the ordering is correct, but when the scope is prototype the ordering does not work - the aspects fire in apparently random order. The aspects implement the Ordered interface.
Bean definitions follow the pattern (JavaConfig):
#Bean
#Scope("prototype")
public CircuitBreakerAspect circuitBreakerAspect()
{
CircuitBreakerAspect aspect = new CircuitBreakerAspect();
aspect.setGraphiteClient(graphiteClient);
aspect.setOrder(100);
return aspect;
}
I need the aspects to be prototype scope, because some of them (e.g., RetryInterceptor) are stateful (maintaining a count of failed operations, which is exported to JMX). If I remove the prototype scope, the ordering works correctly but the same singleton aspect instance is used for all advised bean instances!
I am on Spring Boot 1.4.1 and Java 8.
How can I get prototype aspects to order correctly?
I don't think that the prototype scope is supported for aspects or more likely it does not make sense. Documentation at 11.2.6 Aspect instantiation models specifically mentions this:
By default there will be a single instance of each aspect within the
application context.
To modify this behaviour, Spring AOP supports AspectJ perthis and pertarget instantiation models. Perhaps they will be useful to you.
This appears to be a bug in Spring. If I add the #Order annotation to the aspects, they order properly. I've submitted a bug with Spring. https://jira.spring.io/browse/SPR-14959
I need some information about Spring AOP jointpoint. I have read the below in Stackoverflow which explains the difference between jointpoint and pointcut.
As per that joint is
"A joinpoint is a candidate point in the execution of the application where an aspect can be plugged in. This point could be a method being called, an exception being thrown, or even a field being modified. These are the points where your aspect’s code can be inserted into the normal flow of your application to add new behavior."
After reading this to me it looks like every method and field in a class could be a jointpoint. Is there anything which couldn't be a jointput and hence advice couldn't be applied.
Spring AOP: What's the difference between JoinPoint and PointCut?
As for the difference between 'jointpoint' and 'pointcut' you're right so far. A jointpoint is every spot in your code where an aspect might be woven in, whereas a pointcut matches a concrete aspect definition.Acoording to the Spring Documentation, every method of a bean could be defined as a pointcut. Consider that using Spring AOP the definition of pointcuts is limited to method calls. If you're searching for something that supports more sophisticated AOP logic, you may take a look at AspectJ. With AspectJ you're able to choose for example instance beans as pointcuts.
Please consider following situation with spring 4.0.7
For Eclipselink, we use a load-time-weaver. So we wanted to experiment with Springs #Configurable annotation using #EnableSpringConfigured with #EnableLoadTimeWeaving at the same time.
This is fully functional, and Spring-Beans are injected perfectly into POJOs during construction. This functionality is helpful for us, because we want to keep some code regarding validation of these POJOs inside these and not somewhere else in a Bean.
SOme of our Spring Context contains Beans that do not implement any interface, because they are local to some package and used only there. Lets say, FooLogicBean is one of them. If this is to be injected into another Bean, and some Spring-AOP-Aspect (not-aspectj) like some performance measurement aspect is in the execution path, Spring will create a CGLIB autoproxy for the FooLogicBean and inject that. This is fully functional and works perfectly too.
Problems arise, when we want to actually use a POJO that is annotated with #Configurable as a parameter in a method of FooLogicBean (like fooLogicBean.doValidate(myPojo); ), respectively a CGLIB Proxy. In this case, some non-trivial magic stops that POJO from being woven thru aspectj (AnnotationBeanConfigurerAspect from spring-aspects). It is even never woven anywhere in the code regardless of calling the aforementioned doValidate() Method.
If we create that POJO inside FooLogicBean, but dont use it as a method Parameter, it gets woven again due to #Configurable.
Without knowing the Autoproxy creation code, we assume some fancy marking routine from hindering a class from being detected by aspectj, if that class was already used in spring-aop. use in this case means Access.
Did anyone experiment with such obscure constellation and knows a solution for that?
Thanks in advance!
Proxies are created by subclassing, i.e. when you create a proxy of an annotated class Foo:
class Foo {
#Bar
void bar() { }
}
the proxy is created by implementing a class
class Foo$Proxy extends Foo {
#Override
void bar() {
// Proxy logic
}
// Overridden methods of Object
}
This makes the Foo$Proxy class a valid Liskov substitute for Foo. However, normal override semantics apply, i.e. non-inherited annotations such as #Bar are not longer present for the overridden methods. Once another annotation-based API processes your beans, all annotations have disappeared which leads to your outcome. This is true for all kinds of annotations. Those on types, methods and method parameters.
But is it avoidable? It most certainly is by using a proxy generator that was written recently and is built with knowledge of what annotations are, something that is not true for cglib which was first shipped in the early days of the Java virtual machine. However, as long as Spring does not move away from cglib, you will have to live with today's limitations.
I'm currently trying to add a pointcut around calls to HttpServletResponse.sendRedirect (api doc http://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletResponse.html) using aspectj and spring aop. The code for the class and pointcut are as follows:
#Aspect
#Log4j
class ExampleAspect {
#Before("execution(* javax.servlet.http.HttpServletResponse.sendRedirect(..))")
void logRedirectBeforeSending() {
log.warn('holy cow batman, its a redirect!')
}
}
Currently although the above code compiles it doesn't actually ever execute (as evidenced by a lack of warn output in the log and debug breakpoints in the advice code never being hit).
Although I've omitted them here just for the sake of simplicity the aspect contains other pointcuts which do correctly fire so I have ruled out aspect configuration as a potential cause (which is why I am not including my spring bean configuration).
Further, I have double checked via debugging that a class which implements HttpServletResponse.sendRedirect() is being called when I'm testing my pointcut (if it helps, one of the implementing classes being called is org.apache.catalina.connector.Response https://tomcat.apache.org/tomcat-6.0-doc/api/org/apache/catalina/connector/Response.html).
Is there something I'm missing in my pointcut definition that's required when defining a pointcut around an interface? Best I could tell from the Spring AOP documentation it shouldn't require any special syntax.
I've been playing around with variations in the pointcut definition but haven't had any luck yet.
All in all I'm stumped, any ideas?
I expect that your response object is not coming from the Spring application context and as such it would not be subject to your aspect.
It doesn't matter that the call is being initiated from a Spring bean. It matters that the call is being invoked on a Spring bean. If you for example wrote a point cut to be applied to the append method in StringBuffer and then you did something like new StringBuffer().append('something'), your point cut would not be applied because the StringBuffer that you are interacting with is not a Spring bean. I don't know how your app is put together but unless your response is coming out of the Spring context, I don't expect your point cut to be applied.