【问题标题】:Spring AOP proxy and interface implementationSpring AOP 代理和接口实现
【发布时间】:2024-07-01 16:55:01
【问题描述】:

我正在尝试了解 Spring 代理机制,但我有一件事有问题。 我有接口:

public interface MyInterface{
  void myMethod();
}

和实现类:

@Component
public class MyBean implements MyInterface{
  @Override
  public void myMethod(){
    //do something
  }
}

现在我创建Aspect,例如:

@Aspect
@Component
public class LogAspect {
    @Before("execution(public * *(..))")
    public void logBefore() {
        System.out.println("Before aspect");
    }
}

我有简单的入门课程:

@Configuration
@ComponentScan
@EnableAspectJAutoProxy
public class SpringAopApplication {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(
                SpringAopApplication.class);

        MyBean bean = ctx.getBean(MyBean.class);
//      MyInterface bean = ctx.getBean(MyInterface.class); //works
        bean.myMethod();

        ctx.close();
    }
}

根据我们可以阅读的 Spring 文档:

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

但我收到一个错误没有定义 [MyBean] 类型的合格 bean。它仅在我通过@EnableAspectJAutoProxy(proxyTargetClass = true) 启用 CGLib 代理时才有效。 有人可以解释我在这里缺少什么吗?为什么使用 AOP 时没有发现 MyBean? ctx.getBean(MyInterface.class) 有效,但我无法想象这种接口的许多实现情况。

【问题讨论】:

    标签: spring proxy spring-aop


    【解决方案1】:

    要代理的目标对象(MyBean)至少实现了一个接口(MyInterface),所以使用JDK代理。 此代理实现 MyInterface,但不是 MyBean 的实例。 这就是为什么

    MyInterface bean = ctx.getBean(MyInterface.class);
    

    工作和

    MyBean bean = ctx.getBean(MyBean.class);
    

    不是。

    CGLib 代理是通过子类化目标对象来创建的,所以创建的 bean 是 MyBean 的子类并实现了 MyInterface。 在这种情况下也是

    MyBean bean = ctx.getBean(MyBean.class);
    

    有效。

    ...但是我无法想象这种接口的许多实现的情况。

    MyInterface 的唯一原因可能是,允许 spring 创建一个 JDK 代理,所以不需要有很多实现。

    【讨论】:

      【解决方案2】:

      因为如果你检查你的 bean 类,你会发现 com.sun.proxy.$Proxy21 (或类似的东西),它包装了你的方法。即使它们具有相同的接口,它们也是不兼容的类型。 例如:

      public interface AnInterface {
         void func();
      }
      
      public class Bb implements AnInterface{
         @Override
         public void func() {
            System.out.println("bb");
         }
      }
      
      public class Cc implements AnInterface{
      @Override
         public void func() {
            System.out.println("cc");
         }
      }
      

      所以当你打电话时

      public static void main(String[] args) {
          Bb b = new Bb();
          Cc c=b; // Error
          AnInterface c=b; // Ok
      }
      

      【讨论】: