Spring AOP target() vs this()

Viewed 15585

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?

6 Answers

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

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();
        }
    }
}

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
Related