Spring AOP uses either JDK or CGLIB dynamic proxies to create a proxy for a given target. JDK dynamic proxies are built into the JDK, while CGLIB is a regular open source class definition library (repackaged into spring-core).

If the proxied target implements although one interface, a dynamic JDK proxy is used. All interfaces implemented by the target type are proxied. If the target object does not implement any interfaces, a CGLIB proxy is created.

If you want to force CGLIB proxying (for example, to proxy every method defined on the target object, not just those implemented by its interfaces), this is also doable. However, the following issues should be considered:

  • In the case of CGLIB, final methods cannot be provided with hints because they cannot be overridden in subclasses created at run time.

  • Starting with Spring 4.0, the proxied object's constructor is NOT called twice anymore because the CGLIB proxy is instantiated through Objenesis. If your JVM does not allow constructor bypass, you may notice double calls and corresponding debug log entries from Spring's AOP support.

To force the use of the CGLIB proxy, set the value the proxy-target-class attribute of the <aop:config> element to true, as shown below:


<aop:config proxy-target-class="true">
    <!-- other beans defined here... -->
</aop:config>

To force CGLIB proxying when using auto-proxy support in @AspectJ, set the proxy-target-class of the <aop:aspectj-autoproxy> element in true, as shown below:

<aop:aspectj-autoproxy proxy-target-class="true"/>;

Multiple sections <aop:config/> are collapsed into one single auto-proxy creator at runtime, which applies the most strict proxy settings specified in any of the <aop:config/> sections (usually from different XML bean definition files). This also applies to the <tx:annotation-driven/> and <aop:aspectj-autoproxy/> elements.

For more understanding, use of proxy-target-class="true" in <tx:annotation-driven/>, <aop:aspectj-autoproxy/> or <aop:config/> forces the CGLIB proxy for all three elements.

Understanding AOP Proxy

Spring AOP is based on a proxy. It is critical that you understand the semantics of what the last statement means before you write your own aspects or use any of the Spring AOP-based aspects that come with the Spring Framework.

Let's first consider a scenario in which You have an ordinary, typical, non-proxied, non-special, direct reference to an object, as shown in the following code fragment:

Java

public class SimplePojo implements Pojo {
    public void foo() {
        // the next method call is a direct call to the
        "this" reference this.bar();
    } public void bar() {
        // a little logic...
    }
}
Kotlin

class SimplePojo : Pojo {
    fun foo() {
        // the next method call is a direct call to the "this" reference
        this.bar()
    }
    fun bar() {
        // a little logic...
    }
}

If you call a method on an object reference, then the method is called directly on that object reference, as shown in the following image and listing:

Java

public class Main {
    public static void main(String[] args) {
        Pojo pojo = new SimplePojo();
        // this is a direct call to the method by reference "pojo"
        pojo.foo();
    }
}
Kotlin

fun main() {
    val pojo = SimplePojo()
    // this is a direct method call by reference "pojo"
    pojo.foo()
}

The situation changes a little if the reference contained in the client code is a proxy. Consider the following diagram and code fragment:

Java

public class Main {
    public static void main(String[] args) {
        ProxyFactory factory = new ProxyFactory(new SimplePojo());
        factory.addInterface(Pojo.class);
        factory.addAdvice(new RetryAdvice());
        Pojo pojo = (Pojo) factory.getProxy();
        // this is a method call for the proxy!
        pojo.foo();
    }
}
Kotlin

fun main() {
    val factory = ProxyFactory(SimplePojo())
    factory.addInterface (Pojo::class.java)
    factory.addAdvice(RetryAdvice())
    val pojo = factory.proxy as Pojo
    // this is a method call for the proxy!
    pojo.foo()
}

The most important thing to understand here is that the client code is inside the main(..) method of the Main contains a link to the proxy. This means that method calls on this object reference are proxy calls. As a result, the proxy can delegate all interceptors (advices) that are relevant to that particular method call. However, once the call reaches the target object (in this case the SimplePojo link), all the method calls it can make on itself, such as this.bar() or this.foo() will be called on the this reference, not the proxy. This has important consequences. This means that the call itself will not cause the advice associated with the method call to be executed.

Okay, but what can you do about it? The best approach (the term "best" is used loosely here) is to refactor your code so that the call itself does not occur. This requires some effort on your part, but it is the best, least invasive approach. This next approach is absolutely terrible, and we're not sure it's worth focusing on precisely because it's so terrible. You can (as painful as it may seem to us) completely bind the logic inside your class to Spring AOP, as shown in the following example:

Java

public class SimplePojo implements Pojo {
    public void foo() {
        // it works, but... ugh!
        ((Pojo) AopContext.currentProxy()).bar();
    } public void bar() {
        // a little logic...
    }
}
Kotlin

class SimplePojo : Pojo {
    fun foo() {
        // it works, but... ugh!
        (AopContext.currentProxy() as Pojo).bar()
    } fun bar() {
            // a little logic...
    }
}

This approach is completely will bind your code to Spring AOP, and the class itself will know that it is being used in an AOP context, which goes against AOP. It will also require some additional configuration when creating the proxy, as shown in the following example:

Java

public class Main {
    public static void main(String[] args) {
        ProxyFactory factory = new ProxyFactory(new SimplePojo());
        factory.addInterface(Pojo.class);
        factory.addAdvice(new RetryAdvice());
        factory.setExposeProxy(true);
        Pojo pojo = (Pojo) factory.getProxy();
        // this is a method call for the proxy!
        pojo.foo();
    }
}
Kotlin

fun main() {
    val factory = ProxyFactory(SimplePojo())
    factory.addInterface (Pojo::class.java)
    factory.addAdvice(RetryAdvice())
    factory.isExposeProxy = true
    val pojo = factory.proxy as Pojo
    // this is a method call for the proxy!
    pojo.foo()
}

Finally, it should be noted that AspectJ does not have this self-calling issue because it is not a proxy-based AOP framework.

Programmatically creating @AspectJ proxies

In addition to declaring aspects in the configuration using <aop:config> or <aop:aspectj-autoproxy>, you can also programmatically create proxies that provide advice to targets. In this part, we want to focus on the ability to automatically create proxies using @AspectJ aspects.

You can use the org.springframework.aop.aspectj.annotation.AspectJProxyFactory class to create proxies for target object that has been advised by one or more @AspectJ. The basic usage of this class is extremely simple, as shown in the following example:

Java

// create a factory that can generate a proxy for a given target
AspectJProxyFactory factory = new AspectJProxyFactory(targetObject);
// add an aspect, the class must be an aspect @AspectJ
// you can call it as many times as needed with different aspects
factory.addAspect(SecurityManager.class);
// existing aspect instances can also be added, the type of the provided object must be an aspect @AspectJ
factory.addAspect(usageTracker);
// now we get the proxy object...
MyInterfaceType proxy = factory.getProxy();
Kotlin

// create a factory that can generate proxies for given target object
val factory = AspectJProxyFactory(targetObject)
// add an aspect, the class must be an aspect @AspectJ
// you can call it as many times as needed with different aspects
factory.addAspect(SecurityManager::class.java)
// you can also add existing aspect instances, the type of the provided object must be an aspect @AspectJ
factory.addAspect(usageTracker)
// now get the proxy object...
val proxy = factory.getProxy<Any>()