使用 @Autowired

在包含在本节的示例中,JSR 330 的 @Inject 注解可以用来代替 Infra @Autowired 注解。 有关更多详细信息,请参阅 此处

您可以将 @Autowired 注解应用于构造函数,如下例所示:

  • Java

public class MovieRecommender {

  private final CustomerPreferenceDao customerPreferenceDao;

  @Autowired
  public MovieRecommender(CustomerPreferenceDao customerPreferenceDao) {
    this.customerPreferenceDao = customerPreferenceDao;
  }

  // ...
}

如果目标 bean 最初只定义了一个构造函数,则不再需要在此类构造函数上添加 @Autowired 注解。 但是,如果有几个构造函数可用且没有主/默认构造函数,则必须至少有一个构造函数使用 @Autowired 进行注解,以指示容器使用哪一个。 有关详细信息,请参阅关于 构造函数解析 的讨论。

您还可以将 @Autowired 注解应用于 传统 的 setter 方法,如下例所示:

  • Java

public class SimpleMovieLister {

  private MovieFinder movieFinder;

  @Autowired
  public void setMovieFinder(MovieFinder movieFinder) {
    this.movieFinder = movieFinder;
  }

  // ...
}

您还可以将注解应用于具有任意名称和多个参数的方法,如下例所示:

  • Java

public class MovieRecommender {

  private MovieCatalog movieCatalog;

  private CustomerPreferenceDao customerPreferenceDao;

  @Autowired
  public void prepare(MovieCatalog movieCatalog,
      CustomerPreferenceDao customerPreferenceDao) {
    this.movieCatalog = movieCatalog;
    this.customerPreferenceDao = customerPreferenceDao;
  }

  // ...
}

您也可以将 @Autowired 应用于字段,甚至可以将其与构造函数混合使用,如下例所示:

  • Java

public class MovieRecommender {

  private final CustomerPreferenceDao customerPreferenceDao;

  @Autowired
  private MovieCatalog movieCatalog;

  @Autowired
  public MovieRecommender(CustomerPreferenceDao customerPreferenceDao) {
    this.customerPreferenceDao = customerPreferenceDao;
  }

  // ...
}

确保您的目标组件(例如,MovieCatalogCustomerPreferenceDao)的类型与您用于 @Autowired 注解注入点的类型一致声明。 否则,注入可能会由于运行时的“未找到类型匹配”错误而失败。

对于 XML 定义的 bean 或通过类路径扫描找到的组件类,容器通常预先知道具体类型。 但是,对于 @Bean 工厂方法,您需要确保声明的返回类型具有足够的表现力。 对于实现多个接口的组件或可能由其实现类型引用的组件,请考虑在工厂方法上声明最具体的返回类型(至少与引用 bean 的注入点所要求的具体程度相同)。

您还可以通过将 @Autowired 注解添加到期望该类型数组的字段或方法中,指示 Infra 提供 ApplicationContext 中所有特定类型的 bean,如下例所示:

  • Java

public class MovieRecommender {

  @Autowired
  private MovieCatalog[] movieCatalogs;

  // ...
}

这也适用于类型化集合,如下例所示:

  • Java

public class MovieRecommender {

  private Set<MovieCatalog> movieCatalogs;

  @Autowired
  public void setMovieCatalogs(Set<MovieCatalog> movieCatalogs) {
    this.movieCatalogs = movieCatalogs;
  }

  // ...
}

如果您希望数组或列表中的项按特定顺序排序,您的目标 bean 可以实现 infra.core.Ordered 接口或使用 @Order 或标准 @Priority 注解。 否则,它们的顺序遵循相应目标 bean 定义在容器中的注册顺序。

您可以在目标类级别和 @Bean 方法上声明 @Order 注解,可能用于单个 bean 定义(在使用相同 bean 类的多个定义的情况下)。 @Order 值可能会影响注入点的优先级,但请注意,它们不会影响单例启动顺序,这是由依赖关系和 @DependsOn 声明确定的正交关注点。

请注意,标准 jakarta.annotation.Priority 注解在 @Bean 级别不可用,因为它不能在方法上声明。 它的语义可以通过 @Order 值与每种类型的单个 bean 上的 @Primary 结合来建模。

只要预期的键类型为 String,即使是类型化的 Map 实例也可以自动装配。 映射值包含所有预期类型的 bean,键包含相应的 bean 名称,如下例所示:

  • Java

public class MovieRecommender {

  private Map<String, MovieCatalog> movieCatalogs;

  @Autowired
  public void setMovieCatalogs(Map<String, MovieCatalog> movieCatalogs) {
    this.movieCatalogs = movieCatalogs;
  }

  // ...
}

默认情况下,当没有匹配的候选 bean 可用于给定的注入点时,自动装配会失败。 在声明数组、集合或映射的情况下,至少需要一个匹配元素。

默认行为是将带注解的方法和字段视为指示所需的依赖项。 您可以像下面的示例演示的那样更改此行为,通过将其标记为非必需(即,通过将 @Autowired 中的 required 属性设置为 false),使框架能够跳过不可满足的注入点:

  • Java

public class SimpleMovieLister {

  private MovieFinder movieFinder;

  @Autowired(required = false)
  public void setMovieFinder(MovieFinder movieFinder) {
    this.movieFinder = movieFinder;
  }

  // ...
}

如果非必需方法的依赖项(或在多个参数的情况下的依赖项之一)不可用,则根本不会调用该方法。 在这种情况下,非必需字段根本不会被填充,从而保留其默认值。

换句话说,将 required 属性设置为 false 表示相应的属性对于自动装配目的是 可选的,如果无法自动装配,该属性将被忽略。 这允许为属性分配默认值,这些默认值可以通过依赖注入选择性地覆盖。

注入的构造函数和工厂方法参数是一个特例,因为 @Autowired 中的 required 属性由于 Infra 构造函数解析算法可能处理多个构造函数而具有稍微不同的含义。 构造函数和工厂方法参数实际上在默认情况下是必需的,但在单构造函数场景中有一些特殊规则,例如如果没有匹配的 bean 可用,多元素注入点(数组、集合、映射)解析为空实例。 这允许一种常见的实现模式,其中所有依赖项都可以在唯一的参数构造函数中声明——例如,声明为没有 @Autowired 注解的单个公共构造函数。

任何给定的 bean 类中只有一个构造函数可以将 @Autowiredrequired 属性设置为 true,指示在用作 Infra bean 时要自动装配 构造函数。 因此,如果 required 属性保留其默认值 true,则只能用 @Autowired 注解一个构造函数。 如果多个构造函数声明了该注解,它们都必须声明 required=false 才能被视为自动装配的候选者(类似于 XML 中的 autowire=constructor)。 将选择具有最多可以通过 Infra 容器中的匹配 bean 满足的依赖项的构造函数。 如果没有任何候选者可以满足,则将使用主/默认构造函数(如果存在)。 同样,如果一个类声明了多个构造函数,但没有一个用 @Autowired 注解,则将使用主/默认构造函数(如果存在)。 如果一个类最初只声明了一个构造函数,即使没有注解,也总是会使用它。 请注意,带注解的构造函数不必是公共的。

或者,您可以通过 Java 8 的 java.util.Optional 表达特定依赖项的非必需性质,如下例所示:

public class SimpleMovieLister {

  @Autowired
  public void setMovieFinder(Optional<MovieFinder> movieFinder) {
    ...
  }
}

您还可以使用 @Nullable 注解(任何包中的任何类型——例如,JSR-305 中的 javax.annotation.Nullable)或仅利用 Kotlin 内置的空安全支持:

  • Java

public class SimpleMovieLister {

  @Autowired
  public void setMovieFinder(@Nullable MovieFinder movieFinder) {
    ...
  }
}

您还可以将 @Autowired 用于众所周知的可解析依赖项接口:BeanFactoryApplicationContextEnvironmentResourceLoaderApplicationEventPublisherMessageSource。 这些接口及其扩展接口,如 ConfigurableApplicationContextPatternResourceLoader,会自动解析,无需特殊设置。 以下示例自动装配一个 ApplicationContext 对象:

  • Java

public class MovieRecommender {

  @Autowired
  private ApplicationContext context;

  public MovieRecommender() {
  }

  // ...
}

@Autowired@Inject@Value@Resource 注解由 Infra BeanPostProcessor 实现处理。 这意味着您不能在自己的 BeanPostProcessorBeanFactoryPostProcessor 类型(如果有)中应用这些注解。 这些类型必须通过使用 XML 或 Infra @Bean 方法显式地“连接”。