Spring AOP target() vs this()
Asked Answered
M

6

26

From Spring Documentation:

  • any join point (method execution only in Spring AOP) where the proxy implements the AccountService interface:

    this(com.xyz.service.AccountService)
    
  • any join point (method execution only in Spring AOP) where the target object implements the AccountService interface:

    target(com.xyz.service.AccountService)
    

I don't understand what "target object" and the expression target(...) mean.

How is target different from this?

Marisolmarissa answered 12/8, 2012 at 18:28 Comment(0)
P
29

this(AType) means all join points where this instanceof AType is true. So this means that in your case once the call reaches any method of AccountService this instanceof AccountService will be true.

target(AType) means all join points where anObject instanceof AType . If you are calling a method on an object and that object is an instanceof AccountService, that will be a valid joinpoint.

To summarize a different way - this(AType) is from a receivers perspective, and target(AType) is from a callers perspective.

Painful answered 12/8, 2012 at 21:3 Comment(2)
If I get you right... both this and target do the same thing??? Once my code tries to execute some method of AccountService, then from the receiver point of view, this instanceof AccountService is true; and from the caller point of view calledObject instanceof AccountService is also true. So why is this redundancy?Marisolmarissa
It matters in AspectJ but you are right not that much in Spring AOP - because call(typically used with target) will weave the caller, whereas execution(along with this) will weave the class itself. This is important as with something like compile time weaving you may not have access to third party class to weave using execution, you can then weave the calls to the third party libraries.Painful
J
12

I know this is an old post but I just came across an important difference between this and target while not using AspectJ.

Consider the following introduction aspect:

@Aspect
public class IntroductionsAspect {

    @DeclareParents(value="a.b.c.D", defaultImpl=XImpl.class)
    public static X x;

    @After("execution(* a.b.c.D.*(..)) && this(traceable)")
    public void x(Traceable traceable) {
        traceable.increment();
    }

}

Simply put, this aspect is doing two things:

  1. Making the a.b.c.D class implement the X interface.
  2. Adding a call to traceable.increment() to be executed before each method of a.b.c.D.

The important part is "execution(* a.b.c.D.*(..)) && this(traceable)". Notice that I used this, not target.

If you use target instead, you are trying to match the original class a.b.c.D, not the introduced interface X. So Spring AOP will not find any join point in a.b.c.D.

In summary:

this - Checks the proxy type, or introduced type. target - Checks the declared type.

Justen answered 9/10, 2013 at 13:0 Comment(1)
still don't understand why this(traceable) would be true. Shouldn't it be public void x(X traceable) ? Where does come from the Traceable class in your example ?Akee
B
12

From official documentation:

Spring AOP is a proxy-based system and differentiates between the proxy object itself (bound to 'this') and the target object behind the proxy (bound to 'target').

http://docs.spring.io/spring/docs/current/spring-framework-reference/html/aop.html#aop-pointcuts-designators

Barye answered 21/9, 2014 at 17:44 Comment(1)
This should be accepted answer. short and exactly to the point.Kirkham
Q
3

This topic is often a source of confusion when it comes to AOP programming. I found a very good excerpt explanation on the web which summaries the differences:

this limits matching to join points where the bean reference is an instance of the given type, while target limits matching to join points where the target object is an instance of the given type. The former works when Spring AOP creates a CGLIB-based proxy, and the latter is used when a JDK-based proxy is created.

Suppose that the target class implements an interface:

public class FooDao implements BarDao {
    ...
}

In this case, Spring AOP will use the JDK-based proxy and you should use the target PCD because the proxied object will be an instance of Proxy class and implement the BarDao interface:

@Pointcut("target(com.baeldung.pointcutadvice.dao.BarDao)")

On the other hand if FooDao doesn't implement any interface or proxyTargetClass property is set to true then the proxied object will be a subclass of FooDao and the this PCD could be used:

@Pointcut("this(com.baeldung.pointcutadvice.dao.FooDao)")

You can find out more on the following link:

Introduction to Pointcut Expressions in Spring

Quartan answered 1/4, 2021 at 22:30 Comment(0)
C
2

I tried to give the layman code for target and this pointcut designator. It is already too late, but hoping, it would be helpful for someone.

Aspect Class

package com.opensource.kms;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class SecurityService {

    @Pointcut("target(com.opensource.kms.FooDao)")
    public void myPointCut1() {}

    @Pointcut("this(com.opensource.kms.SooDao)")
    public void myPointCut2() {}

    @Before("myPointCut1()")
    public void beforeMethodTarget() {
        System.out.println("beforeMethodTarget myPointCut1");
    }

    @Before("myPointCut2()")
    public void beforeMethodThis() {
        System.out.println("beforeMethodThis myPointCut2");
    }
}

FooDao Class : JDK dynamic proxy

package com.opensource.kms;
import org.springframework.stereotype.Component;

interface BarDao {
    String m();
}

@Component
public class FooDao implements BarDao {

    public String m() {
        System.out.println("implementation of m");
        return "This is return value";
    }
}

SooDao Class : CGLIB proxy

package com.opensource.kms;
import org.springframework.stereotype.Component;

@Component
public class SooDao {

    public String m() {
        System.out.println("implementation of m : SooDao");
        return "This is return value";
    }
}

Main App

    AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(JavaConfig.class);
    SooDao ob1 = ctx.getBean("sooDao", SooDao.class);
    System.out.println("Data using this ->"+ob1.m());
    System.out.println("********************");
    BarDao ob2 = ctx.getBean("fooDao", BarDao.class);
    System.out.println("Data using target -> "+ob2.m());

Output

beforeMethodThis myPointCut2
implementation of m : SooDao
Data using this ->This is return value
********************
beforeMethodTarget myPointCut1
implementation of m
Data using target -> This is return value
Compliancy answered 3/5, 2020 at 9:19 Comment(0)
C
1

Try next code. In this code.

  1. We have cached and non cached method.
  2. Advice added for non cached method.
  3. Cached method called inside advice.

Result:

With designator 'this' caching will work. Because, it will return proxy object which includes caching logic.

With designator 'target' caching will not work. Because, it will return object without proxy.

enter image description here

import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.concurrent.ConcurrentMapCacheManager;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

@EnableAspectJAutoProxy
@SpringBootTest(classes = {
        DifferenceThisAndTarget1Tests.MyService.class,
        DifferenceThisAndTarget1Tests.AspectConfig.class,
        ConcurrentMapCacheManager.class
})
class DifferenceThisAndTarget1Tests {
    @Autowired
    MyService myService;

    @Test
    void test() {
        myService.methodCached();
        myService.method("1");
    }

    @Service
    public static class MyService {
        public void method(String arg) {
            System.out.println("method called");
        }

        @Cacheable("test")
        public void methodCached() {
            System.out.println("methodCached called");
        }
    }

    @Component
    @Aspect
    @EnableCaching
    public static class AspectConfig {
        @Pointcut("execution(* com.example.demoaop.DifferenceThisAndTarget1Tests.MyService.method(*))")
        public void pointCut() {
        }

        /**
         * Just update target to this and compare result
         * 1. With designator 'target' caching will not work.
         *    Because, it will return object without proxy.
         * 2. With designator 'this' caching will work.
         *    Because, it will return proxy object which includes caching logic.
         */
        @After("pointCut() && target(service)")
        public void advice(MyService service) {
            System.out.println("Advice worked!");
            service.methodCached();
        }
    }
}
Contextual answered 9/9, 2022 at 20:7 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.