Specifying pointcut in Spring AOP - java

I am familiar with Spring AOP, although not having much hands on experience on that.
My question is, if I want to have some AOP functionality for some methods of a class, not all, then can it be possible with single pointcut. Say, I have four methods save1,save2,get1 and get2 in my class and I want to apply AOP on save1 and save2 only, then in that case how can I create a single pointcut for that? How will my pointcut expression looks like? OR Is it even possible?

There are many ways to do it(with wildcard expression, with aspectJ annotation, ..)
i will give an example with aspectJ
class MyClass{
#MyPoint
public void save1(){
}
#MyPoint
public void save2(){
}
public void save3(){
}
public void save4(){
}
}
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public #interface MyPoint {
}
#Aspect
#Component
public class MyAspect {
#Before("#annotation(com.xyz.MyPoint)")
public void before(JoinPoint joinPoint) throws Throwable {
//do here what u want
}
}
So you are all set, as long as you marked #Mypoint annotation, spring will call before aspect for this method, make sure spring is managing this method and object, not you. include aspectJ in your classpath

You need to specify a pointcut expression to select the methods with to apply your advice.
See 7.2.3 Declaring a pointcut in the Spring Documentation and use the execution joinpoint designator to select the methods.

Having a pointcut expression like so should do the trick
**execution(* save*(..))**
See here for more information

You can use or and and with pointcut expressions:
execution(* my.Class.myMethod(..)) or execution(* my.Class.myOtherMethod(..))

Related

AspectJ on children objects

I'm starting to work with AspectJ and I'm trying to do something that I don't know if it's possible. This is my code:
public abstract class MyAbstractObject<T> {
private T myOtherObject;
public T getMyOtherObject() {
return myOtherObject;
}
}
#Component
public class MyObject extends MyAbstractObject<WhateverObject> {
}
#Aspect
#Component
public class MyAspects {
#Before("execution(* mypackage.MyAbstractObject.getMyOtherObject().set*(*))")
public void beforeExample(JoinPoint joinPoint) {
// DO THINGS
}
}
This code fails, with the error:
Caused by: java.lang.IllegalArgumentException: Pointcut is not well-formed: expecting ')' at character position 58 execution(* mypackage.MyAbstractObject.getMyOtherObject().set*(*))
However, I can intercept MyOtherObject like this, but not it's setters:
#Aspect
#Component
public class MyAspects {
#Before("execution(* mypackage.MyAbstractObject.getMyOtherObject())")
public void beforeExample(JoinPoint joinPoint) {
// DO THINGS
}
}
I don't want to intercept the setters of the object MyOtherObject everywhere, because this object is used in more places in the program where I don't need aspects. However I want to intercept them only when used in a class that extends MyAbstractObject.
I'm using Spring with AspectJ.
Thanks.
The syntax you just invented is illegal, unfortunately. You cannot describe chained method calls the ways you dreamed up.
What you really want is to intercept method executions of type WhateverObject, not of MyAbstractObject or MyObject. I.e., your pointcut should rather bet something like
execution(* mypackage.WhateverObject.set*(*))
I am just guessing, but if you want to limit matching to control flows where the setter method is called (directly or indirectly) from getMyOtherObject(), in AspectJ your would add something like
&& cflow(execution(* mypackage.MyAbstractObject.getMyOtherObject()))
to the first pointcut. But cflow pointcuts are unavailable in Spring AOP, which is what you seem to be using. So
either you switch to native AspectJ, which is easy to integrate into Spring applications, but can also be used outside of the Spring context because it is an idependent product,
or you check if Spring AOP's "lite" version of control flow pointcuts does what you need. I posted a few answers and links mentioning this almost undocumented feature here and there.
As a native AspectJ fan who does not normally use Spring, you can imagine which option I would recommend regarding control flow pointcuts, but I think you can make your own decision.

How to set a property value using Java custom annotation and Spring AOP?

I would like to use custom Java annotation to insert a value in a private class property using Spring AOP (and/or AspectJ). Quick example:
MyAnnotation.java:
#Retention(RetentionPolicy.RUNTIME)
#Target({ ElementType.FIELD })
public #interface MyAnnotation {
}
MyController.java:
public class MyControllerImpl implements MyController {
...
#MyAnnotation
private String var1;
#Override
public String getVarExample() {
// imagine this is a REST API that gets called on #GET
// request and returns a string
System.out.println(this.var1); // <-- I'd like this to be "helloworld"
// this is just for illustration
// of course, I will want to do
// something more meaningful with
// the 'var1' variable
return "ok"; <- unimportant for this example
}
...
MyAspect.java:
#Aspect
#Component
public class MyAspect {
#Pointcut("#annotation(com.mypackage.annotation.MyAnnotation)")
public void fieldAnnotatedWithMyAnnotation() {
}
#Around("fieldAnnotatedWithMyAnnotation()")
public Object enrichVar1(ProceedingJoinPoint pjp) throws Throwable {
// problem #1 - the program never enters here
// problem #2 - I need to figure out how to set up the var1 here
// to "helloworld" , how?
return pjp.proceed();
}
...
}
What would I like to happen?
I will call and get into the getVarExample() and after it returns I would like to see "helloworld" in console or log. I would like to somehow set the var1 to a custom value using AOP. Any property variable that will be annotated with #MyAnnotation will be set to "helloworld". I hope the example above is clear.
What have I tried?
I made sure there is no typo in the package names, also fiddled with different AOP advice annotations like #Around and #Before. I also tried different targets in the MyAnnotation and ended up with ElementType.FIELD which should be correct.
Can you help me to get it working?
I know this can be done, but couldn't find any working example online. Again, I would like to see 2 answers:
1. How to get the pointcut to trigger on MyController entrance? I want to catch a breakpoint inside the enrichVar1(..) method of the MyAspect class.
2. How can I modify the annotated var1 value inenrichVar1(..) method of the MyAspect class?
I don't know what I am doing wrong. Any help will be greatly appreciated. Thank you!
The AOP is set up correctly in my project. I know that because I am already using AOP for different things (logging for example).
Update #1:
Please, note there are not getters or setters for the var1 private variable. The variable will be only used within the MyControllerImpl. To illustrate this better I changed the return value of the getVarExample.
Like I said in my comment:
The pointcut designator #annotation() intercepts annotated methods, not annotated fields. For that, native AspectJ has get() and set(). I.e., the pointcut would also need to be changed if migrating to AspectJ. But I agree that sticking to Spring AOP and annotating getter methods instead of fields is probably enough here.
But because you insist that you want to keep the controller class unchanged, here is the native AspectJ solution. Please read chapter Using AspectJ with Spring Applications for how to configure that with #EnableLoadTimeWeaving and JVM parameter -javaagent:/path/to/aspectjweaver.jar.
In order to demonstrate that this solution really does work independently of Spring, I am using no Spring classes or annotations at all, only POJOs and native AspectJ. You can simply do the same within your Spring application. Please note that native AspectJ aspects do not need #Component annotations, in contrast to Spring AOP aspects.
package de.scrum_master.app;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
#Retention(RetentionPolicy.RUNTIME)
#Target({ ElementType.FIELD })
public #interface MyAnnotation {}
package de.scrum_master.app;
public interface MyController {
String getVarExample();
}
package de.scrum_master.app;
public class MyControllerImpl implements MyController {
#MyAnnotation
private String var1;
#Override
public String getVarExample() {
System.out.println(this.var1);
return "ok";
}
}
package de.scrum_master.app;
public class Application {
public static void main(String[] args) {
MyController myController = new MyControllerImpl();
myController.getVarExample();
}
}
package de.scrum_master.aspect;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
#Aspect
public class MyAspect {
#Pointcut("get(#de.scrum_master.app.MyAnnotation * *)")
public void fieldAnnotatedWithMyAnnotation() {}
#Around("fieldAnnotatedWithMyAnnotation()")
public Object enrichVar1(ProceedingJoinPoint pjp) throws Throwable {
System.out.println(pjp);
return "helloworld";
}
}
When running Application, the console log is going to be:
get(String de.scrum_master.app.MyControllerImpl.var1)
helloworld
The AspectJ manual explains the syntax of field get and set join point signatures and field patterns.
Note: I think that your use case might be a hack rather than a valid application design. You ought to refactor rather than hack into an application like this.
As it goes from Spring docs Spring AOP does support Spring beans' method execution join points. To make field access join points work you need to use AspectJ's backend with load time weaving for AOP.
But for your case it's not required to use field join points, you can put your annotation on the getter and this should work.

Spring AOP - Point Cut not getting called

I have a SpringBoot Application.
I have defined an Annotation say "Track", and I have annotated few methods in different packages which I want aop to consider.
The annotation has been defined as below :
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public #interface Track {
}
I have not missed the #EnableAspectJAutoProxy in the #Configuration class of my package.
I have a Pointcut and an Advice defined in the Aspect like below :
#Aspect
#Component
public class MyAspect {
#Pointcut("execution(#Track * *.*(..))")
void annotatedMethod() {
// No Implementation required
}
#Around("annotatedMethod() && #annotation(methodLevelTrack)")
public void adviseAnnotatedMethods(ProceedingJoinPoint proceedingJoinPoint,
Track methodLevelTrack) throws Throwable {
// do some task
proceedingJoinPoint.proceed();
// do some task after the method is executed.
}
}
My intention is: for any method (annotated with #Track) in any package, with any access modifier, and any number of input arguments, and any return type, to follow the aspect's #Around advice.
Now, the interesting situation is as below :
I have a class say "Engine" which calls other classes and downstream systems to perform a long-running operation. Let's define the class as follows :
public class Engine {
// bunch of other autowired objects
public void processTask() {
<autowired_object_A>.someMethod() // this method has been annotated with #Track
<autowired_object_B>.someMethod() // this method has also been annotated with # Track
.... // bunch of other methods in other autowired objects that have been annotated with # Track
someMethodOfEngineClass(); // Now this has been defined in the Engine class as below, but pointcut doesn't recognize this method!
}
#Track
private void someMethodOfEngineClass() {
// do something
}
}
All the "other" autowired objects' methods are getting recognized by pointcut as expected but the method within this Engine class, that has been annotated with #Track, is not recognized. What's the mystery?
I have tried making "someMethodOfEngineClass" method public, return something instead of void and all those combinations and it doesn't work.
What am I missing?
Is it the pointcut definition expression?
I have defined the aspect in one of the sub packages, is aspect supposed to be defined at the top level in the package structure?
Can you folks please suggest something that can work? I am kinda stuck at this.
When you define aop spring creates proxy around the class,
so when the method is called, actually call is delegated to proxy, sth like
your.package.Engine$$FastClassBySpringCGLIB$$c82923b4.someMethodOfEngineClass()
But this works only when a method is called from outside it's class
If you call class method from the same class you are effectively calling it by this.someMethodOfEngineClass()
here -> http://www.nurkiewicz.com/2011/10/spring-pitfalls-proxying.html
you can find more info about proxying
so proxy is bypassed and aop is not working.

How to specify single pointcut for all classes that extend a specific class

I have multiple classes from different packages that extends a class Super.
And i want to create an AOP pointcut around that match all the methods in all classes that extends Super.
I have tried this:
#Around("within(com.mypackage.that.contains.super..*)")
public void aroundAllEndPoints(ProceedingJoinPoint joinPoint) throws Throwable {
LOGGER.info("before Proceed ");
joinPoint.proceed();
LOGGER.info("after Proceed");
}
But it doesn't work.
Any Suggestions?
The pointcut should be:
within(com.mypackage.Super+)
where com.mypackage.Super is the fully qualified base class name and + means "all subclasses". This works for Spring AOP. In AspectJ this would match too many joinpoints, not just method executions. Here is another pointcut that works for both Spring AOP and AspectJ:
execution(* com.mypackage.Super+.*(..))

What is the difference between Advisor and Aspect in AOP?

I am new to Spring AOP. Based on my understanding, I noticed that both Advisor (for example DefaultPointcutAdvisor) and Aspect (for example the class annotated with #Aspect) can both help to solve the cross-cutting problem by doing something more when a method is invoked.
What is the different between these two term please?
Most aspects are a combination of advice that defines the
aspect’s behavior and a pointcut defining where the aspect should be executed.
Spring recognizes this and offers advisors, which combine advice and pointcuts
into one object.
More specifically, the PointcutAdvisor does this.
public interface PointcutAdvisor {
Pointcut getPointcut();
Advice getAdvice();
}
Most of Spring’s built-in pointcuts also have a corresponding PointcutAdvisor.
This is convenient if you want to define a pointcut and the advice it is managing
in one place.
Read more in Spring in Action, 3rd Edition
Sanpshots
Advisors seem to be an old "AOP lite" type of defining cross-cutting concerns from Spring 1.2 when Java 5 usage was still somewhat uncommon and thus #AspectJ syntax (via Java annotations) not used in Spring. The concept has still survived for lovers of schema-based AOP rather than annotation-based AOP or pure AspectJ syntax, see Spring documentation on advisors.
The concept of "advisors" comes from the AOP support defined in Spring and does not have a direct equivalent in AspectJ. An advisor is like a small self-contained aspect that has a single piece of advice. The advice itself is represented by a bean and must implement one of the advice interfaces described in Advice Types in Spring. Advisors can take advantage of AspectJ pointcut expressions.
In my understanding, Aspect is just Aspect Oriented Programming jargon and Advisor is Spring Framework jargon.
Maybe this simple example will be helpful:
Foo.java
public interface Foo {
void foo();
void baz();
}
FooImpl.java
public class FooImpl implements Foo {
#Override
public void foo() {
System.out.println("Foo!");
}
#Override
public void baz() {
System.out.println("Baz!");
}
}
MethodBeforeAdviceBarImpl.java
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;
public class MethodBeforeAdviceBarImpl implements MethodBeforeAdvice {
#Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println("Bar!");
}
}
and finally App.java
import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.support.NameMatchMethodPointcutAdvisor;
public class App {
public static void main(String[] args) {
final MethodBeforeAdvice advice = new MethodBeforeAdviceBarImpl();
final NameMatchMethodPointcutAdvisor nameMatchMethodPointcutAdvisor = new NameMatchMethodPointcutAdvisor();
nameMatchMethodPointcutAdvisor.setMappedName("foo");
nameMatchMethodPointcutAdvisor.setAdvice(advice);
final ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.addAdvisor(nameMatchMethodPointcutAdvisor);
final Foo foo = new FooImpl();
proxyFactory.setTarget(foo);
final Foo fooProxy = (Foo) proxyFactory.getProxy();
fooProxy.foo();
fooProxy.baz();
}
}
Running the main method in App.java will output:
Bar!
Foo!
Baz!
So as you see here NameMatchMethodPointcutAdvisor is an Advisor and it consists of a mappedName, which is the pointcut and the Advice itself, which in this case is MethodBeforeAdvice.
And in Aspect Oriented Programming Jargon, an Aspect is Advice + Pointcut, so there you go.. An Advisor seems to be an Aspect after all..
Advice is the way you take an action on your Pointcut. You can use before, after or even around advice to apply any action you defined. Talking about Spring Aspect, it is only a class which is a high level and merge two concepts : joinpoint and advice. It can be done through XML based blueprint, or programmatically. Also you should specify your point where you want to plug in an aspect, it is done by using Joinpoint.
Also Spring Aspects and Advice aren't substitute for each other, because Aspects is only merger for joinpoint and advice.

Categories