使用AnnotationConfigApplicationContext实例化Spring容器

以下部分记录了Spring的AnnotationConfigApplicationContext,引入自Spring 3.0。这个多才多艺的ApplicationContext实现能够接受不仅@Configuration类作为输入,还可以接受普通的@Component类和带有JSR-330元数据注解的类。

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

当提供@Component和JSR-330类时,它们将被注册为bean定义,并假定在这些类中必要时使用了DI元数据,如@Autowired@Inject

简单构造

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

  • 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注解的类都可以作为构造函数的输入,如下例所示:

  • 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

通过register(Class<?>…​)方法以编程方式构建容器

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

  • 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()
}

使用scan(String…​)启用组件扫描

要启用组件扫描,您可以如下注解您的@Configuration类:

  • Java

  • Kotlin

@Configuration
@ComponentScan(basePackages = "com.acme") (1)
public class AppConfig  {
	// ...
}
1 此注解启用组件扫描。
@Configuration
@ComponentScan(basePackages = ["com.acme"]) (1)
class AppConfig  {
	// ...
}
1 此注解启用组件扫描。

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

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

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

  • 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元注解元注解,因此它们是组件扫描的候选对象。在上面的示例中,假设AppConfigcom.acme包(或其任何子包)中声明,它将在调用scan()时被捕获。在refresh()之后,所有其@Bean方法都将被处理并注册为容器中的bean定义。

使用AnnotationConfigWebApplicationContext支持Web应用程序

有一个AnnotationConfigApplicationContextWebApplicationContext变体可用,名为AnnotationConfigWebApplicationContext。当配置Spring的ContextLoaderListener servlet监听器、Spring MVC的DispatcherServlet等时,您可以使用此实现。以下web.xml片段配置了一个典型的Spring MVC Web应用程序(请注意contextClass上下文参数和init-param的使用):

<web-app>
	<!-- 配置ContextLoaderListener以使用AnnotationConfigWebApplicationContext
		而不是默认的XmlWebApplicationContext -->
	<context-param>
		<param-name>contextClass</param-name>
		<param-value>
			org.springframework.web.context.support.AnnotationConfigWebApplicationContext
		</param-value>
	</context-param>

	<!-- 配置位置必须由一个或多个逗号或空格分隔的完全限定的@Configuration类组成。也可以指定完全限定的包以进行组件扫描 -->
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>com.acme.AppConfig</param-value>
	</context-param>

	<!-- 像往常一样使用ContextLoaderListener引导根应用程序上下文 -->
	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>

	<!-- 声明一个Spring MVC DispatcherServlet,像往常一样 -->
	<servlet>
		<servlet-name>dispatcher</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<!-- 配置DispatcherServlet以使用AnnotationConfigWebApplicationContext
			而不是默认的XmlWebApplicationContext -->
		<init-param>
			<param-name>contextClass</param-name>
			<param-value>
				org.springframework.web.context.support.AnnotationConfigWebApplicationContext
			</param-value>
		</init-param>
		<!-- 再次,配置位置必须由一个或多个逗号或空格分隔的完全限定的@Configuration类组成 -->
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>com.acme.web.MvcConfig</param-value>
		</init-param>
	</servlet>

	<!-- 将所有请求映射到/dispatcher servlet的/app/* -->
	<servlet-mapping>
		<servlet-name>dispatcher</servlet-name>
		<url-pattern>/app/*</url-pattern>
	</servlet-mapping>
</web-app>
对于编程用例,可以使用GenericWebApplicationContext作为AnnotationConfigWebApplicationContext的替代方案。有关详细信息,请参阅GenericWebApplicationContext的javadoc。