是在春季4中优雅处理的代理问题



我找不到任何文档回答此问题。

总结:

  • 我有一个实现接口的豆。
  • 我将代理 - 目标类设置为false。
  • i在Spring 3.2.17和4.3.3版本之间切换。
  • 当我使用Spring 3.2.17时,主类抛出此:

    java.lang.classcastException:com.sun.proxy。 com.package1.camera 在com.package1.app.main(app.java:8)

    这就是我所期望的。这是正确的行为,因为生成了JDK代理类。

  • 但是,当我使用弹簧4.3.3时,没有例外,主类也正确运行。

    生成了CGLIB代理类。但是,当我将代理目标级设置为false时,为什么会生成?

这是源文件:

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>

设置代理 - target-class = false时,CGLIB代理仍会使用相同的公式JDK代理创建。在春季文档中,他们说:

Spring AOP使用JDK Dynamic Proxies或CGLIB为给定目标对象创建代理。(每当您有选择时,JDK动态代理都是首选)。

如果要代理的目标对象至少一个接口,则将使用JDK动态代理。目标类型实现的所有接口将被代理。如果目标对象未实现任何接口,则将创建CGLIB代理。

请参阅更多:代理机制

通过反复试验和错误我提出了答案。

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

代理 - 目标级仍然默认为false。

但是现在,春季4足够聪明,它将生成什么代理(JDK或CGLIB)。

  • 如果您有一个空接口,它将生成一个CGLIB代理。

icamera.java

package com.package1;
public interface ICamera {}
  • 否则,将生成JDK代理。

icamera.java

package com.package1;
public interface ICamera {
    void snap();
}

hth。

最新更新