3
votes

I was reading some articles about Spring AOP and encountered this:

AOP proxy: the object created by AOP to implement the aspect contracts. In Spring, proxy objects can be JDK dynamic proxies or CGLIB proxies. By default, the proxy objects will be JDK dynamic proxies, and the object being proxied must implement an interface, that will also be implemented by the proxy object. But a library like CGLIB can be used to create proxies by subclassing too, so an interface is not needed.

Could you look at the following structure and imagine that we want to advise bar() method.

public interface Foo {
    void foo();
}

public class FooImpl implements Foo {

    @Override
    public void foo() {
        System.out.println("");
    }

    public void bar() {
        System.out.println("");
    }

}

Does it mean that in this case CGLIB proxy will be used? Since JDK dynamic proxy isn't able to implement any interface in order to override bar() method.

3
It depends--how are you injecting the bean?chrylis -cautiouslyoptimistic-

3 Answers

5
votes

Spring will only use CGLIB if you tell it to. This is enabled (for annotation based configurations) by setting the proxyTargetClass element of @EnableAspectJAutoProxy to true.

@EnableAspectJAutoProxy(proxyTargetClass = true)

Consider this minimal example (assuming your FooImpl is annotated with @Component)

@Aspect
@Component
class FooAspect {
    @Before("execution(public void bar())")
    public void method() {
        System.out.println("before");
    }
}

@Configuration
@EnableAspectJAutoProxy
@ComponentScan
public class Example {
    public static void main(String[] args) throws Exception {
        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(Example.class);
        FooImpl f = ctx.getBean(FooImpl.class); // throw exception here
        f.bar();
    }
}

By default, proxyTargetClass is false. In this case, Spring will not use CGLIB. Because of the @Before advice in the @Aspect class, Spring will decide that it needs to proxy the FooImpl with a JDK proxy. Unfortunately, because of this proxying behavior, the bean actually stored in the context will be of a dynamic JDK Proxy type (also a subtype of the Foo interface) and therefore trying to get the bean with FooImpl.class will fail.

Even if you tried to retrieve it as a Foo, you wouldn't be able to invoke a bar() method since the proxy object isn't a FooImpl.

If you enable the proxyTargetClass, the code above works as intended, a CGLIB proxy is created, and the @Before advice is invoked.

3
votes

See AOP Proxies in the Spring documentation:

Spring AOP defaults to using standard JDK dynamic proxies for AOP proxies. This enables any interface (or set of interfaces) to be proxied.

Spring AOP can also use CGLIB proxies. This is necessary to proxy classes rather than interfaces. By default, CGLIB is used if a business object does not implement an interface.

-2
votes

Spring AOP defaults to using standard JDK dynamic proxies for AOP proxies. This enables any interface (or set of interfaces) to be proxied.

Spring AOP can also use CGLIB proxies. This is necessary to proxy classes rather than interfaces. CGLIB is used by default if a business object does not implement an interface. As it is good practice to program to interfaces rather than classes; business classes normally will implement one or more business interfaces. It is possible to force the use of CGLIB, in those (hopefully rare) cases where you need to advise a method that is not declared on an interface, or where you need to pass a proxied object to a method as a concrete type.

It is important to grasp the fact that Spring AOP is proxy-based. See Understanding AOP proxies for a thorough examination of exactly what this implementation detail actually means.

https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#aop-introduction