24

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?

cb4
  • 6,689
  • 7
  • 45
  • 57
rapt
  • 11,810
  • 35
  • 103
  • 145

6 Answers6

28

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.

Biju Kunjummen
  • 49,138
  • 14
  • 112
  • 125
  • 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? – rapt Aug 12 '12 at 21:27
  • 2
    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. – Biju Kunjummen Aug 12 '12 at 21:34
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.

Akira
  • 4,001
  • 1
  • 16
  • 24
  • 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 ? – Olivier Boissé Jul 30 '22 at 19:56
11

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

hoodieman
  • 807
  • 10
  • 15
2

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

CBA110
  • 1,072
  • 2
  • 18
  • 37
1

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
Kms
  • 1,082
  • 2
  • 11
  • 27
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();
        }
    }
}
E.H.
  • 326
  • 1
  • 7