spock spock - 9 days ago 5
Java Question

Is the proxy issue handled gracefully in Spring 4?

I can't find any documentation answering this question.

To summarize:


  • I have a bean that implements an interface.

  • I set proxy-target-class to false.

  • I toggle between Spring 3.2.17 and 4.3.3 versions.

  • When I use Spring 3.2.17, the main class throws this:

    java.lang.ClassCastException: com.sun.proxy.$Proxy7 cannot be cast to
    com.package1.Camera
    at com.package1.App.main(App.java:8)

    This is what I expected. This is the correct behaviour because the JDK proxy class was generated.

  • But when I use Spring 4.3.3, no exception is thrown and main class runs properly.

    The CGLIB proxy class was generated. But why was it generated when I set the proxy-target-class to false?



Here are the source files:

App.java

package com.package1;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
Camera camera = (Camera) context.getBean("camera");
camera.snap();
context.close();
}
}


ICamera.java

package com.package1;
public interface ICamera {}


Camera.java

package com.package1;

import org.springframework.stereotype.Component;

@Component("camera")
public class Camera implements ICamera {
public void snap() {
System.out.println("SNAP!");
}
}


Logger.java

package com.package1;

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 Logger {

@Pointcut("execution(void com.package1.Camera.snap())")
public void cameraSnap() {

}

@Before("cameraSnap()")
public void beforeAdvice() {
System.out.println("Before advice...");
}

}


beans.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">


<context:component-scan
base-package="com.package1">
</context:component-scan>

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

</beans>


pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.package1</groupId>
<artifactId>spring-test-app</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.3.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>4.3.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>4.3.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>4.3.3.RELEASE</version>
</dependency>
</dependencies>
</project>

Answer

Thru trial and error I had come up with the answer.

App.java

package com.package1;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        Object o = context.getBean("camera");
        System.out.println("class=" + o.getClass());
        Camera camera = (Camera) context.getBean("camera");
        camera.snap();
        context.close();
    }
}

proxy-target-class still defaults to false.

But now, Spring 4 is smart enough what proxy will it generate (JDK or CGLIB).

  • If you have an empty interface, it will generate a CGLIB proxy.

ICamera.java

package com.package1;
public interface ICamera {}
  • Otherwise, JDK proxy will be generated.

ICamera.java

package com.package1;

public interface ICamera {
    void snap();
}

HTH.