Instantiating the Spring Container by Using AnnotationConfigApplicationContext

以下部分记录了 Spring 3.0 中引入的 Spring AnnotationConfigApplicationContext。这个用途广泛的 ApplicationContext 实现不仅能够接受 @Configuration 类作为输入,还可以接受普通的 @Component 类以及用 JSR-330 元数据注释的类。

The following sections document Spring’s AnnotationConfigApplicationContext, introduced in Spring 3.0. This versatile ApplicationContext implementation is capable of accepting not only @Configuration classes as input but also plain @Component classes and classes annotated with JSR-330 metadata.

@Configuration 类作为输入提供时,@Configuration 类本身被注册为一个 Bean 定义,并且类中所有声明的 @Bean 方法也被注册为 Bean 定义。

When @Configuration classes are provided as input, the @Configuration class itself is registered as a bean definition and all declared @Bean methods within the class are also registered as bean definitions.

@Component 和 JSR-330 类提供时,它们被注册为 Bean 定义,并且假定在这些类中在必要的地方使用了诸如 @Autowired@Inject 之类的 DI 元数据。

When @Component and JSR-330 classes are provided, they are registered as bean definitions, and it is assumed that DI metadata such as @Autowired or @Inject are used within those classes where necessary.

Simple Construction

与将 Spring XML 文件用作实例化 ClassPathXmlApplicationContext 时作为输入的方式非常类似,您可以在实例化 AnnotationConfigApplicationContext 时将 @Configuration 类用作输入。这样可以完全无 XML 地使用 Spring 容器,如下面的示例所示:

In much the same way that Spring XML files are used as input when instantiating a ClassPathXmlApplicationContext, you can use @Configuration classes as input when instantiating an AnnotationConfigApplicationContext. This allows for completely XML-free usage of the Spring container, as the following example shows:

  • Java

  • Kotlin

public static void main(String[] args) {
	ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
	MyService myService = ctx.getBean(MyService.class);
	myService.doStuff();
}
import org.springframework.beans.factory.getBean

fun main() {
	val ctx = AnnotationConfigApplicationContext(AppConfig::class.java)
	val myService = ctx.getBean<MyService>()
	myService.doStuff()
}

如前所述,AnnotationConfigApplicationContext 不仅限于与 @Configuration 类一起使用。也可以将任何带有 @Component 或 JSR-330 注释的类作为输入提供给构造函数,如下面的示例所示:

As mentioned earlier, AnnotationConfigApplicationContext is not limited to working only with @Configuration classes. Any @Component or JSR-330 annotated class may be supplied as input to the constructor, as the following example shows:

  • Java

  • Kotlin

public static void main(String[] args) {
	ApplicationContext ctx = new AnnotationConfigApplicationContext(MyServiceImpl.class, Dependency1.class, Dependency2.class);
	MyService myService = ctx.getBean(MyService.class);
	myService.doStuff();
}
import org.springframework.beans.factory.getBean

fun main() {
	val ctx = AnnotationConfigApplicationContext(MyServiceImpl::class.java, Dependency1::class.java, Dependency2::class.java)
	val myService = ctx.getBean<MyService>()
	myService.doStuff()
}

前面的示例假定 MyServiceImplDependency1Dependency2 使用 Spring 依赖注入注释,如 @Autowired

The preceding example assumes that MyServiceImpl, Dependency1, and Dependency2 use Spring dependency injection annotations such as @Autowired.

Building the Container Programmatically by Using register(Class<?>…​)

您可以使用无参数构造函数实例化 AnnotationConfigApplicationContext,然后使用 register() 方法对其进行配置。这种方法在以编程方式构建 AnnotationConfigApplicationContext 时特别有用。以下示例演示了如何执行此操作:

You can instantiate an AnnotationConfigApplicationContext by using a no-arg constructor and then configure it by using the register() method. This approach is particularly useful when programmatically building an AnnotationConfigApplicationContext. The following example shows how to do so:

  • Java

  • Kotlin

public static void main(String[] args) {
	AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
	ctx.register(AppConfig.class, OtherConfig.class);
	ctx.register(AdditionalConfig.class);
	ctx.refresh();
	MyService myService = ctx.getBean(MyService.class);
	myService.doStuff();
}
import org.springframework.beans.factory.getBean

fun main() {
	val ctx = AnnotationConfigApplicationContext()
	ctx.register(AppConfig::class.java, OtherConfig::class.java)
	ctx.register(AdditionalConfig::class.java)
	ctx.refresh()
	val myService = ctx.getBean<MyService>()
	myService.doStuff()
}

Enabling Component Scanning with scan(String…​)

要启用组件扫描,您可以按如下方式注释 @Configuration 类:

To enable component scanning, you can annotate your @Configuration class as follows:

Java
@Configuration
@ComponentScan(basePackages = "com.acme") (1)
public class AppConfig  {
	// ...
}
1 This annotation enables component scanning.
Kotlin
@Configuration
@ComponentScan(basePackages = ["com.acme"]) (1)
class AppConfig  {
	// ...
}
2 This annotation enables component scanning.

经验丰富的 Spring 用户可能熟悉 Spring 的 context: 命名空间中与此等效的 XML 声明,如下面的示例所示:

Experienced Spring users may be familiar with the XML declaration equivalent from Spring’s context: namespace, shown in the following example:

<beans>
	<context:component-scan base-package="com.acme"/>
</beans>

在前面的示例中,会扫描 com.acme 包以查找任何带 @Component 注释的类,并且这些类作为 Spring Bean 定义注册在容器中。AnnotationConfigApplicationContext 公开 scan(String…​) 方法以允许进行相同的组件扫描功能,如下面的示例所示:

In the preceding example, the com.acme package is scanned to look for any @Component-annotated classes, and those classes are registered as Spring bean definitions within the container. AnnotationConfigApplicationContext exposes the scan(String…​) method to allow for the same component-scanning functionality, as the following example shows:

  • Java

  • Kotlin

public static void main(String[] args) {
	AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
	ctx.scan("com.acme");
	ctx.refresh();
	MyService myService = ctx.getBean(MyService.class);
}
fun main() {
	val ctx = AnnotationConfigApplicationContext()
	ctx.scan("com.acme")
	ctx.refresh()
	val myService = ctx.getBean<MyService>()
}

请记住,@Configuration 类是用 @Component 声明的 meta-annotated,因此它们是组件扫描的候选对象。在前面的示例中,假设 AppConfigcom.acme 包(或其下的任何包)中声明,它在调用 scan() 时被选取。在 refresh() 时,它的所有 @Bean 方法都将处理并作为容器中的 bean 定义注册。

Remember that @Configuration classes are meta-annotated with @Component, so they are candidates for component-scanning. In the preceding example, assuming that AppConfig is declared within the com.acme package (or any package underneath), it is picked up during the call to scan(). Upon refresh(), all its @Bean methods are processed and registered as bean definitions within the container.

Support for Web Applications with AnnotationConfigWebApplicationContext

可以使用 AnnotationConfigWebApplicationContext 获取 AnnotationConfigApplicationContextWebApplicationContext 变体。在配置 Spring ContextLoaderListener servlet 监听器、Spring MVC DispatcherServlet 等时可以使用此实现。以下 web.xml 代码片段配置一个典型的 Spring MVC Web 应用程序(注意,使用了 contextClass 上下文参数和初始化参数):

A WebApplicationContext variant of AnnotationConfigApplicationContext is available with AnnotationConfigWebApplicationContext. You can use this implementation when configuring the Spring ContextLoaderListener servlet listener, Spring MVC DispatcherServlet, and so forth. The following web.xml snippet configures a typical Spring MVC web application (note the use of the contextClass context-param and init-param):

<web-app>
	<!-- Configure ContextLoaderListener to use AnnotationConfigWebApplicationContext
		instead of the default XmlWebApplicationContext -->
	<context-param>
		<param-name>contextClass</param-name>
		<param-value>
			org.springframework.web.context.support.AnnotationConfigWebApplicationContext
		</param-value>
	</context-param>

	<!-- Configuration locations must consist of one or more comma- or space-delimited
		fully-qualified @Configuration classes. Fully-qualified packages may also be
		specified for component-scanning -->
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>com.acme.AppConfig</param-value>
	</context-param>

	<!-- Bootstrap the root application context as usual using ContextLoaderListener -->
	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>

	<!-- Declare a Spring MVC DispatcherServlet as usual -->
	<servlet>
		<servlet-name>dispatcher</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<!-- Configure DispatcherServlet to use AnnotationConfigWebApplicationContext
			instead of the default XmlWebApplicationContext -->
		<init-param>
			<param-name>contextClass</param-name>
			<param-value>
				org.springframework.web.context.support.AnnotationConfigWebApplicationContext
			</param-value>
		</init-param>
		<!-- Again, config locations must consist of one or more comma- or space-delimited
			and fully-qualified @Configuration classes -->
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>com.acme.web.MvcConfig</param-value>
		</init-param>
	</servlet>

	<!-- map all requests for /app/* to the dispatcher servlet -->
	<servlet-mapping>
		<servlet-name>dispatcher</servlet-name>
		<url-pattern>/app/*</url-pattern>
	</servlet-mapping>
</web-app>

对于以编程方式使用的情况,GenericWebApplicationContext 可作为 AnnotationConfigWebApplicationContext 的替代方案。有关详细信息,请参阅https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/context/support/GenericWebApplicationContext.html[GenericWebApplicationContext]javadoc。

For programmatic use cases, a GenericWebApplicationContext can be used as an alternative to AnnotationConfigWebApplicationContext. See the GenericWebApplicationContext javadoc for details.