Spring java 基于注释的配置不起作用,但基于 xml 的配置可以吗?

Spring java annotation-based config won't work, but xml-based config does?

我一直在关注第 4 版“Spring in Action”一书的第 1 章。 第一章有一个演示依赖注入和 bean 连接的简单示例。 (https://livebook.manning.com/book/spring-in-action-fourth-edition/chapter-1)

我已经将代码复制到 intelliJ 中,但必须制作我自己的项目结构。 我在应用程序上下文方面遇到了一些麻烦。如果我将 xml 文件与 ClassPathXmlApplicationContext 一起使用,它工作正常。但是,当我尝试使用 .java 文件来声明我的 bean 和 AnnotationConfigApplicationContext 时,它不起作用,给我以下错误消息:

org.springframework.context.annotation.AnnotationConfigApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@41a4555e: startup date [Mon Jan 17 20:22:09 GMT 2022]; root of context hierarchy
Exception in thread "main" org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.springinaction.knights.Knight] is defined
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:319)
    at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:987)
    at com.springinaction.knights.KnightMain.main(KnightMain.java:12)

2个相关的类如下所示:

src/main/java/com/springinaction/knights/config/KnightBeans.java :

package com.springinaction.knights.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.springinaction.knights.BraveKnight;
import com.springinaction.knights.Knight;
import com.springinaction.knights.Quest;
import com.springinaction.knights.SlayDragonQuest;

@Configuration
public class KnightBeans
{
   @Bean
   public Knight knight() {
      return new BraveKnight(quest());
   }

   @Bean
   public Quest quest() {
      return new SlayDragonQuest(System.out);
   }

}

src\main\java\com\springinaction\knights\KnightMain.java :

package com.springinaction.knights;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class KnightMain {

   public static void main(String[] args) throws Exception {
      AnnotationConfigApplicationContext context =
            new AnnotationConfigApplicationContext(
                  "com.springinaction.knights.config.KnightBeans.class");
      Knight knight = context.getBean(Knight.class);
      knight.embarkOnQuest();
      context.close();
   }

}

附加信息: 我已经为 Knight 和 Quest 创建了接口,它们由 BraveKnight 和 SlayDragonQuest 类 实现。所有这些以及 KnightMain.java 都位于“骑士”包中。 KnightBeans.java 位于名为 config 的子包中。

我试过将各种类路径放入 new AnnotationConfigApplicationContext() 中,但总是出现相同的错误。

谁能解释这是为什么?

根据 AnnotationConfigApplicationContextjavadoc,采用字符串参数的构造函数需要 包的名称 来扫描配置文件。您也可以传递一个或多个 class 对象或工厂。

在您的情况下,Spring 将期望找到一个名为 com.springinaction.knights.config.KnightBeans.class 的包。相反,您可能想传递 class 本身,不带双引号:

AnnotationConfigApplicationContext context =
    new AnnotationConfigApplicationContext(com.springinaction.knights.config.KnightBeans.class);

你也可以

AnnotationConfigApplicationContext context =
    new AnnotationConfigApplicationContext("com.springinaction.knights.config");

扫描 config 包中的所有配置。

当您使用 context.getBean() 获取 bean 时,您需要传递 bean 的方法名称,以便 spring 知道 bean 需要注入什么。

package com.springinaction.knights;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class KnightMain {

public static void main(String[] args) throws Exception {
  AnnotationConfigApplicationContext context =
        new AnnotationConfigApplicationContext(
              "full class path");
  Knight knight = context.getBean("knight",Knight.class);
  knight.embarkOnQuest();
  context.close();
}

}

并且在 AnnotationConfigApplicationContext