当我还有一个针对 Spring 中的 bean 的方面时,为什么不可能有一个通用 bean?

Why is it not possible to have a generic bean when i have also an Aspect targeting the bean in Spring?

您好,关于 Spring 方面,我有一个相当具体的问题让我感到困惑。我尝试了 Springs 和 Apsects,并尝试了一个非常简单的例子来了解它是如何工作的:

@Component
public class Comment {
    private String text;
    private String author;

    public String get() {
        return text;
    }
    public void setText(String text) {
        this.text = text;
    }

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }
}
@Aspect
public class LoggingAspect {
    @Around("execution(* aop.beans.*.*(..))")
    public void log(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("Start Aspect for method: " + joinPoint.getSignature());
        joinPoint.proceed();
    }
}

我的配置文件:

@Configuration
@ComponentScan("aop.beans")
@EnableAspectJAutoProxy
public class ProjectConfig {
    @Bean
    public LoggingAspect aspect() {
        return new LoggingAspect();
    }
}

然后我使用了一个简单的 Main 方法来稍微尝试一下这个概念:

public class Main {
    public static void main(String[] args) {
        @SuppressWarnings("resource")
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ProjectConfig.class);
        context.registerShutdownHook();

        CommentService service = context.getBean(CommentService.class);

        Comment comment = context.getBean(Comment.class);
        comment.setAuthor("Andreas");
        comment.setText("Hallo.");

        service.publishComment(comment);
        System.out.println(service.getClass());
    }
}

这工作正常,但当我更改评论的层次结构时会发生一些奇怪的事情 class。我想看看如果 class 实现通用接口会发生什么,所以我将其更改如下

public class Comment implements Supplier<String>

我立即收到以下堆栈跟踪错误:

Exception in thread "main" org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'aop.beans.Comment' available
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:351)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:342)
    at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1172)
    at aop.Main.main(Main.java:17)

这让我想知道这是为什么?如果我删除通用超级接口或方面 bean everthing 工作正常,但两者一起似乎不太好。有人可以提供解释吗?如果 class 有通用的 superclass,Spring 是否无法创建 Proxy 对象?

编辑:解决方案在评论中 :) 我在 Spring Proxy Mechanism Documentation

中找到了有关该机制的更多文档

发生这种情况是因为 Spring 实现 AOP 的方式。

当代理 class(在您的情况下为 Comment)未实现任何接口时,将使用 CGLib 代理。基本上,它生成一个 class,它是代理 class 的子 class。因此,您可以通过 parent 的 class.

getBean

当有实现的接口时,Spring使用JDK动态代理,它不扩展代理class,而是实现它的所有接口,因此你找不到bean 是 class.

这就是为什么通过接口而不是 class 自动装配 bean 始终是一个好习惯的原因。

解决方案

  • 您可以通过注释配置 class @EnableAspectJAutoProxy(proxyTargetClass = true).
  • 强制 Spring 使用 AspectJ 的 CGLib 代理
  • 如果您想使用 JDK 动态代理,请为 Comment 创建接口,然后使用 context.getBean(YourInterfaceName.class)