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:
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...
}
}
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:
![](https://cdn.codegym.cc/images/article/766255c1-68e6-48a5-8c32-2eff24488e98/1024.jpeg)
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();
}
}
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:
![](https://cdn.codegym.cc/images/article/bf53f886-eff2-400f-a965-821805e83846/800.jpeg)
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();
}
}
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:
public class SimplePojo implements Pojo {
public void foo() {
// it works, but... ugh!
((Pojo) AopContext.currentProxy()).bar();
} public void bar() {
// a little logic...
}
}
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:
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();
}
}
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:
// 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();
// 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>()