Spring Framework 5.2.4.RELEASE 核心技术1.2翻译
原文连接spring framework
1.2 容器简介
本章节中org.springframework.context.ApplicationContext接口做为Spring IoC的容器,它的责任是实例化,配置和组装bean。容器是通过读取配置元数据,决定对哪些对象的进行实例化,配置和组合。这些配置元数据,有XML文件,注解,和JAVA代码三种形式。配置元数据可以用来展示你的应用程序的组成对象,以及这些对象之间复杂的关系。
Spring提供了几个ApplicationContext接口的实现类。在单个应用中,通常会创建一个ClassPathXmlApplicationContext或者FileSystemXmlApplicationContext的实例。XML是定义配置元数据的传统格式,你可以指定容器使用JAVA注解或者代码作为元数据格式,仅需要提供少量的XML配置,用来声明支持这些额外的元数据格式。
在大多数应用场景中,用户代码不需要显示的实例化一个或者多个Spring IoC容器。举个例子,在web应用场景中,一个应用通常只需要在web.xml模板文件中,写8行左右的配置。(参考 Convenient ApplicationContext Instantiation for Web Applications),如果你用了Spring Tool Suite(一个Eclipse提供的开发环境)你只用通过点击几下鼠标或者键盘就可以轻松的创建模板配置。
下面的示意图是Spring如何工作的一个高级展示。你应用中的类和配置元数据组合在一起,因此在ApplicationContext被创建和实例化后,你就拥有了一个完整配置过的,可以执行的系统或者应用。
图片1: spring container
1.2.1 配置元数据
正如上面图片所示,Spring IoC 容器消费了配置元数据表。配置元数据是应用开发者告诉Spring容器,该如何实例化,配置和组装应用内的对象。
配置元数据传统上是一种简单和直观的XML格式,这章中我们主要用XML格式来阐述Spring IoC 容器的主要概念和特性。
配置元数据不是只有XML这一种格式。Spring IoC容器本身写配置文件的时候,已经不再使用XML这种形式了。现在,很多开发者在开发Spring应用的时候,会选择基于Java代码的元数据配置方式。
如果想了解其他Spring容器的元数据配置格式,可以参考:
- 基于注解的配置:Spring 2.5引入了基于注解配置的元数据格式。
- 基于Java代码的配置:从Spring3.0开始,Spring JavaConfig工程提供了很多功能,逐步变成了Spring Framework核心的一部分。因此,你可以使用JAVA代码而不是XML文件,在应你的用程序的外部定义bean。为了使用这些新的特性,可以看 @Configuration, @Bean, @Import, and @DependsOn 注解。
Spring配置由容器管理的beans组成,这些beans至少一个,通常会是多个。基于XML的配置元数据,是通过<bean/>标签来配置bean元素的,<bean/>标签嵌套在顶级标签为<beans/>的内部。而基于JAVA的元数据配置格式,通常在@Configuration类中用@Bean-注解来进行配置。
生成与这些Bean定义一致的对象,这些对象是你应用的组成部分。通常,你定义服务层的对象,数据访问层对象(DAOs),表现层对象例如Structs Action实例,底层对象例如 Hibernate SessionFactories, JMS Queues等等。但是,容器一般不会配置细粒度的域对象,因为通常是由DAOs和业务逻辑去创建和加载域对象的。不过,你可以使用Spring集成AspectJ去配置,在IOC容器管理之外被创建的对象。参考Using AspectJ to dependency-inject domain objects with Spring
下面的例子展示了一个基于XML配置的元数据的基本样式
<?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">
<bean id="..." class="..."> ① ②
<!-- collaborators and configuration for this bean go here -->
</bean>
<bean id="..." class="...">
<!-- collaborators and configuration for this bean go here -->
</bean>
<!-- more bean definitions go here -->
</beans>
- ① id属性是每个bean定义的标识字符串。
- ② class属性定义了bean的类型,而且要使用全路径名。
id可以被协作对象所引用。上面XML中没有id被引用的内容。可以参考Dependencies获取更多信息。
1.2.2 实例化一个容器
ApplicationContext构造函数所用的配置文件地址是一些资源字符串,容器可以从各种各样的外部资源中加载配置元数据,例如当前文件系统,JAVA CLASSPATH等等。
ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");
当你了解了Spring IoC容器,你可能想知道Spring的资源提取机制,文件地址是按URI语法定义的,Spring提供了一个简单机制去读取该地址的输入流。特别是,Application Contexts and Resource Paths 中介绍了,Resource路径被用于去构造应用的上下文。
下面的例子展示了服务层对象(services.xml)的配置文件:
<?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">
<!-- services -->
<bean id="petStore" class="org.springframework.samples.jpetstore.services.PetStoreServiceImpl">
<property name="accountDao" ref="accountDao"/>
<property name="itemDao" ref="itemDao"/>
<!-- additional collaborators and configuration for this bean go here -->
</bean>
<!-- more bean definitions for services go here -->
</beans>
下面的例子展示了接入层配置文件daos.xml
<?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">
<bean id="accountDao"
class="org.springframework.samples.jpetstore.dao.jpa.JpaAccountDao">
<!-- additional collaborators and configuration for this bean go here -->
</bean>
<bean id="itemDao" class="org.springframework.samples.jpetstore.dao.jpa.JpaItemDao">
<!-- additional collaborators and configuration for this bean go here -->
</bean>
<!-- more bean definitions for data access objects go here -->
</beans>
在前面的例子中,服务层对象是由PetStoreServiceImpl类和两个数据接入对象组成的,这两个数据接入对象对应的类分别是JpaAccountDao和JpaItemDao。(基于JPA 对象关系映射标准)。property name标签指的是JavaBean属性的名字,ref标签指的是其他bean定义的名字。id和ref关键字之间的关联,是协作对象之间依赖的表示。想了解更多对象依赖,参考Dependencies
基于XML的组合型配置元数据
组合配置对于跨多个XML文件的bean定义很有作用。通常,每个独立的XML配置文件,代表你架构中的一个逻辑层或者一个模块。
你可以使用应用上下文构造器读取所有的xml文件,加载其中的bean定义。上个章节中提到的如何读取多个资源地址。另外,你还可以通过用一个或者多个< import/>标签去引入其他文件,从而加载bean定义。下面的例子展示了怎么去做:
<beans>
<import resource="services.xml"/>
<import resource="resources/messageSource.xml"/>
<import resource="/resources/themeSource.xml"/>
<bean id="bean1" class="..."/>
<bean id="bean2" class="..."/>
</beans>
在上面的例子中,可以从这三个文件 (services.xml, messageSource.xml, themeSource.xml)中加载他们的bean定义。import文件的路径是以bean定义文件的路径为基准路径,所以services.xml一定和该文件在同一个路径下或者在同一个classpath中,而messageSource.xml 和 themeSource.xml 一定在基准路径的resources文件夹下。正如你所见的,反斜杠会被忽略了。由于给定的路径是相对路径,最好不要使用反斜杠。这些能被引入的文件,顶级标签为<beans/>,必须是一个遵守遵守Spring约束的,有效的XML的bean定义。
有可能引入文件在当前路径的上一级,使用"…/"符号读取,但是不推荐这么做。这样做会导致依赖文件位于当前应用的外部。尤其要注意,classpath URLs(例如classpath:…/services.xml)不推荐使用这种引用, 运行的程序会选择当前的路径作为root路径,然后找它的上一级路径。Classpath配置的改变可能导致选择一个不同的,不正确的文件夹。
你可以使用绝对路径来代替相对路径,例如file:C:/config/services.xml或者classpath:/config/services.xml。不过,你需要知道你将应用的配置和这个特定的绝对路径耦合在一起。更推荐的是用间接手段使用绝对路径,例如使用“${…}”占位符,他可以在系统运行中解析JVM的系统属性。
命名空间本身提供的引入文件的特性。Spring提供了一些XML命名空间,它们相对于普通bean定义进一步的配置,例如context和util命名空间。
The Groovy Bean Definition DSL
Spring’s Groovy Bean Definition DSL(领域特征语言)来自于Grails框架,它可以在外部配置元数据,bean定义。通常,这些配置存在以".groovy"命名的文件中,如下所示:
beans {
dataSource(BasicDataSource) {
driverClassName = "org.hsqldb.jdbcDriver"
url = "jdbc:hsqldb:mem:grailsDB"
username = "sa"
password = ""
settings = [mynew:"setting"]
}
sessionFactory(SessionFactory) {
dataSource = dataSource
}
myService(MyService) {
nestedBean = { AnotherBean bean ->
dataSource = dataSource
}
}
}
这种配置文件的格式基本等于基于XML的Bean定义文件格式,甚至可以支持XML配置的命名空间。它也支持通过importBeans引入基于XML的Bean定义文件。
1.2.3使用容器
实现ApplicationContext接口的高级工程类,需要支持不同类型beans的注册和他们依赖的beans注册。通过调用方法 T getBean(String name, Class requiredType),你可以获取到bean的实例。
下面的例子展示了,ApplicationContext读取bean定义,获取bean对象。
// create and configure beans
ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");
// retrieve configured instance
PetStoreService service = context.getBean("petStore", PetStoreService.class);
// use configured instance
List<String> userList = service.getUsernameList();
使用Groovy进行配置,脚手架看起来很类似。它有一个不同的上下文实现类,就是 Groovy-aware(它也理解XML bean 定义格式)。下面例子是Groovy的配置
ApplicationContext context = new GenericGroovyApplicationContext("services.groovy", "daos.groovy");
GenericApplicationContext是最灵活的方式,可以和不同的配置读取代理进行结合。例如,使用XmlBeanDefinitionReader读取XML文件,如下所示:
GenericApplicationContext context = new GenericApplicationContext();
new XmlBeanDefinitionReader(context).loadBeanDefinitions("services.xml", "daos.xml");
context.refresh();
你也可以绑定GroovyBeanDefinitionReader,去读取Groovy文件,如下所示:
GenericApplicationContext context = new GenericApplicationContext();
new GroovyBeanDefinitionReader(context).loadBeanDefinitions("services.groovy", "daos.groovy");
context.refresh();
你可以在同一个ApplicationContext中混合和匹配不同的读取代理,从不同类型的配置源中读取bean的定义。
你还可以使用getBean去获取你的beans实例。ApplicationContext有少量的其他方法获取beans,但是理想情况下,你的应用不应该使用他们。事实上,你的应用程序代码不应该调用getBean方法, 也不应该依赖于Spring的 APIS。举个例子,Spring集成web框架,会提供许多web框架组件的依赖注入,例如controllers,JSF-managed beans, 你可以通过元数据(例如@autowiring)去声明一个特定对象的依赖。