IoC容器:容器概述(二)

概述

  • ApplicationContext接口代表Spring IoC容器,负责实例化配置组装Bean
  • 容器通过读取配置元数据来获取关于要实例化、配置和组装哪些对象的指示
  • 配置元数据XMLJava注解Java代码表示,它可以表达构成应用程序的对象以及这些对象之间丰富的相互依赖关系。

ApplicationContext 接口的常见实现类:ClassPathXmlApplicationContextFileSystemXmlApplicationContext

虽然XML一直是定义配置元数据的传统格式,但是可以通过提供少量的XML配置来指示容器使用Java注解或代码作为元数据格式,以声明性地启用对这些额外元数据格式的支持。

在大多数应用场景下,不需要明确的用户代码来实例化Spring IoC容器的一个或多个实例。例如:在Web应用场景中,通常只需要在应用程序的web.xml文件中编写8行(或更多)模板式的Web描述符就足够了。

下图显示了Spring工作方式的高层视图。应用程序类配置元数据相结合,在ApplicationContext被创建和初始化后,就会产生一个完全配置好的可执行系统或应用程序。

Spring工作方式的高层视图

配置元数据

配置元数据用于告诉Spring容器在应用中如何实例化、配置和组装对象。配置元数据在传统上是以简单直观的XML格式提供的。

除了基于XML来设置配置元数据之外,还可以基于Java代码基于注解来设置。Spring IoC容器本身与这种配置元数据的实际编写格式是完全解耦的。

Spring的配置至少要有一个,通常是一个以上的Bean定义,容器必须管理这些定义。

基于XML

基于XML的配置元数据将这些Bean配置为顶层<beans/>元素内的<bean/>元素。通常情况下,每个单独的XML配置文件代表了架构中的要给逻辑层或模块,因此让Bean的定义跨越多个XML文件可能很有用。可以使用<import/>标签从一个或多个文件中加载Bean定义。

XML的命名空间

命名空间本身提供了导入指令的功能。除了普通的Bean定义之外,更多的配置功能可以在Spring 提供的一些XML命名空间中获得,例如,contextutil 命名空间。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">

<!-- 加载其他的xml文件 -->
<import resource="services.xml"/>
<import resource="resources/messageSource.xml"/>
<import resource="/resources/themeSource.xml"/>


<bean id="..." class="...">
<!-- 这个bean的合作者和配置在这里 -->
</bean>
<!-- 更多bean 定义在这里 -->

<!-- 例如: -->
<bean id="student" class="org.example.domain.Student"/>
<!-- id 属性是一个字符串,用于识别单个Bean定义 -->
<!-- class 属性定义了 Bean 的类型,并使用类的全路径名 -->
</beans>

基于Java代码

基于Java的配置通常使用被@Configuration注解修饰的类(即配置类)中的被@Bean注解修饰的方法。

1
2
3
4
5
6
7
8
@Configuration  // 定义该类为配置类
public class AppConfig {
// Bean 定义,该方法返回的对象作为Spring容器中的一个bean,由Spring容器管理
@Bean
public MyBean myBean() {
return new MyBean();
}
}

基于注解

基于注解的配置通常使用例如@Component@Repository@Service@Controller这样的注解。使用基于注解的配置时,需要在配置类上使用@ComponentScan注解启动组件扫描,指定扫描的包路径。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 通用注解
@Component
public class MyComponent {
// ...
}

// dao层的注解
@Repository
public class MyRepository {
// ...
}

// service层的注解
@Service
public class MyService {
// ...
}

// controller层的注解
@Controller
public class MyController {
// ...
}
1
2
3
4
@Configuration  // 定义该类为配置类
@ComponentScan("com.example") // 用于启用组件扫描,指定扫描的包路径。
public class AppConfig {
}

实例化一个容器

实例化一个容器(ApplicationContext)时,需要传入一个或多个资源的路径(字符串),它让容器从各种外部资源(如本地文件系统Java CLASSPATH等)中加载配置元数据。

1
2
3
ApplicationContext context = new ClassPathXmlApplicationContext("services.xml",
"daos.xml");
// services.xml和daos.xml文件的格式参考上面基于XML的配置

使用容器

ApplicationContext 是一个高级工厂的接口,是能够维护不同Bean及其依赖关系的注册表。通过使用方法 T getBean(String name, Class<T> requiredType),可以检索到Bean的实例。

ApplicationContext 可以读取Bean定义(definition)并访问它们。

1
2
3
4
5
6
// 创建和配置bean
ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");
// 检索配置的实例
PetStoreService petStoreService = context.getBean("petStoreService", PetStoreService.class);
// 使用配置的实例
List<String> userList = petStoreService.getUsernameList();

最灵活的变体是 GenericApplicationContext 与 reader delegate 的结合。例如,与 XmlBeanDefinitionReader 一起用于XML文件,如下例所示。

1
2
3
4
GenericApplicationContext context = new GenericApplicationContext();
new XmlBeanDefinitionReader(context).loadBeanDefinitions("services.xml",
"daos.xml");
context.refresh();

除了使用getBean()来检索Bean实例之外,ApplicationContext接口还有其他一些检索Bean的方法。但理想情况下,应用代码不应该使用这些方法,也包括getBean()方法,因为这样就不会对Spring的API产生依赖性。

在通常情况下,想要获取Bean实例可以使用依赖注入的方式。例如,Spring与Web框架的集成为各种Web框架(如controller和JSF管理的Bean)提供了依赖注入,让你通过元数据(如autowiring注解)来声明对特定Bean的依赖。

作者

悟道心得

发布于

2025-02-26

更新于

2025-03-03

许可协议