
1.13. 环境抽象
环境界面 是集成在容器中的抽象,它对两个键进行建模 应用程序环境的各个方面:配置文件和属性。
概要文件是要注册到 Bean 定义的命名逻辑组 仅当给定配置文件处于活动状态时,容器。可以将 Bean 分配给配置文件 无论是在 XML 中定义还是使用批注定义。对象的作用与 与配置文件的关系在于确定哪些配置文件(如果有)当前处于活动状态, 以及默认情况下哪些配置文件(如果有)应处于活动状态。Environment
属性在几乎所有应用中都起着重要作用,可能源于 各种来源:属性文件、JVM 系统属性、系统环境 变量、JNDI、servlet 上下文参数、临时对象、对象等 上。对象与属性相关的角色是提供 用户具有方便的服务界面,用于配置属性源和解析 他们的属性。PropertiesMapEnvironment
1.13.1. Bean 定义配置文件
Bean 定义概要文件在核心容器中提供了一种机制,允许 在不同环境中注册不同的豆子。“环境”这个词, 对不同的用户可能意味着不同的事情,此功能可以帮助许多人 用例,包括:
- 在开发中处理内存中的数据源与查找相同的数据源 在 QA 或生产环境中来自 JNDI 的数据源。
- 仅在将应用程序部署到 性能环境。
- 为客户 A 与客户注册 Bean 的自定义实现 B 部署。
考虑实际应用中需要 a 的第一个用例。在测试环境中,配置可能类似于以下内容:DataSource
现在考虑如何将此应用程序部署到 QA 或生产环境中 环境,假设应用程序的数据源已注册 使用生产应用程序服务器的 JNDI 目录。乌尔豆 现在看起来像下面的列表:dataSource
问题是如何根据 当前环境。随着时间的推移,Spring用户已经设计了许多方法来 完成此操作,通常依赖于系统环境变量的组合 和包含解析令牌的 XML 语句 到正确的配置文件路径,具体取决于环境的值 变量。Bean 定义概要文件是一个核心容器功能,它提供 解决这个问题。<import/>${placeholder}
如果我们概括前面特定于环境的 Bean 示例中所示的用例 定义,我们最终需要在 某些上下文,但在其他上下文中则不然。你可以说你想注册一个 情况 A 中 Bean 定义的某些配置文件和情况 A 中的不同配置文件 情况B.我们首先更新我们的配置以反映这种需求。
用@Profile
@Profile注释允许您指示组件符合注册条件 当一个或多个指定的配置文件处于活动状态时。使用前面的示例,我们 可以按如下方式重写配置:dataSource
配置文件字符串可能包含简单的配置文件名称(例如)或 配置文件表达式。配置文件表达式允许更复杂的配置文件逻辑 表示(例如,)。以下运算符在 配置文件表达式:productionproduction & us-east
-
!:配置文件的逻辑“非” -
&:配置文件的逻辑“和” -
|:配置文件的逻辑“或”
您可以用作目的的元注释 创建自定义组合注释。以下示例定义了一个自定义批注,您可以将其用作直接替换:@Profile@Production@Profile("production")
@Profile也可以在方法级别声明为仅包含一个特定的 Bean 的配置类(例如,对于特定 Bean 的替代变体),作为 以下示例显示:
XML Bean 定义概要文件
XML 对应项是元素的属性。我们前面的示例 可以在两个 XML 文件中重写配置,如下所示:profile<beans>
也可以避免在同一文件中拆分和嵌套元素, 如以下示例所示:<beans/>
已约束为仅允许此类元素,例如 文件中的最后一个。这应该有助于提供灵活性而不会产生 XML 文件中杂乱无章。spring-bean.xsd
激活配置文件
现在我们已经更新了我们的配置,我们仍然需要指示 Spring 哪个 配置文件处于活动状态。如果我们现在开始我们的示例应用程序,我们将看到 抛出,因为容器找不到 春豆命名。NoSuchBeanDefinitionExceptiondataSource
激活配置文件可以通过多种方式完成,但最直接的是 它以编程方式针对可通过 a 获得的 API。以下示例演示如何执行此操作:EnvironmentApplicationContext
此外,您还可以通过属性以声明方式激活配置文件,该属性可以通过系统环境指定 变量、JVM 系统属性、servlet 上下文参数,甚至作为 JNDI 中的条目(参见属性源抽象)。在集成测试中,活动 可以通过在模块中使用注释来声明配置文件(请参阅使用环境配置文件进行上下文配置)。spring.profiles.activeweb.xml@ActiveProfilesspring-test
请注意,配置文件不是“非此即彼”的命题。您可以激活多个 一次配置文件。以编程方式,您可以向接受 varargs 的方法提供多个配置文件名称。以下示例 激活多个配置文件:setActiveProfiles()String…
声明性地,可以接受以逗号分隔的配置文件名称列表, 如以下示例所示:spring.profiles.active
默认配置文件
默认配置文件表示默认启用的配置文件。考虑 以下示例:
如果没有活动配置文件,则创建配置文件。你可以看到这个 作为为一个或多个 Bean 提供缺省定义的一种方法。如果有的话 配置文件已启用,则默认配置文件不适用。dataSource
您可以使用 理论,声明性地,通过使用属性。setDefaultProfiles()Environmentspring.profiles.default
1.13.2.抽象PropertySource
Spring 的抽象提供了对可配置的搜索操作 属性源的层次结构。请考虑以下列表:Environment
在前面的片段中,我们看到了一种高级方法,询问 Spring 的属性是否为 为当前环境定义。为了回答这个问题,对象执行 搜索一组属性源对象。A是对任何键值对源的简单抽象,并且 Spring 的标准环境配置了两个 PropertySource 对象——一个代表一组 JVM 系统属性。 () 和一个表示系统环境变量集 ().my-propertyEnvironmentPropertySourceSystem.getProperties()System.getenv()
具体来说,当你使用 时,如果系统属性或环境变量存在于 运行。StandardEnvironmentenv.containsProperty("my-property")my-propertymy-property
最重要的是,整个机制是可配置的。也许您有一个自定义来源 要集成到此搜索中的属性。为此,请实施 并实例化您自己的并将其添加到集合中对于 当前。以下示例演示如何执行此操作:PropertySourcePropertySourcesEnvironment
爪哇岛
科特林
在前面的代码中,已添加具有最高优先级的 搜索。如果它包含属性,则检测并返回该属性,以支持 任何其他财产。MutablePropertySourcesAPI 公开了许多方法,这些方法允许精确操作一组 属性源。MyPropertySourcemy-propertymy-propertyPropertySource
1.13.3. 使用@PropertySource
@PropertySource注释为添加 ato Spring 提供了一种方便的声明性机制。PropertySourceEnvironment
给定一个包含键值对的文件, 以下类以这样的方式使用 调用返回:app.properties=myTestBean@Configuration@PropertySourcetestBean.getName()myTestBean
资源位置中存在的任何占位符都是 针对已针对 环境,如以下示例所示:${…}@PropertySource
假设它已经存在于其中一个属性源中 已注册(例如,系统属性或环境变量),占位符为 解析为相应的值。如果没有,则使用 作为默认值。如果未指定默认值且无法解析属性,则引发 anis 。my.placeholderdefault/pathIllegalArgumentException
1.13.4. 语句中的占位符解析
从历史上看,元素中占位符的值只能针对 JVM 系统属性或环境变量。情况已不再如此。因为 抽象集成在整个容器中,很容易 通过它路由占位符解析。这意味着您可以配置 以您喜欢的任何方式解决过程。您可以更改搜索的优先级 系统属性和环境变量或完全删除它们。您还可以添加您的 酌情拥有组合的属性来源。Environment
具体来说,无论属性定义在哪里,以下语句都有效,只要它在:customerEnvironment
1.14. 注册LoadTimeWeaver
Theis 被 Spring 用来动态转换类,因为它们是 加载到 Java 虚拟机 (JVM) 中。LoadTimeWeaver
要启用加载时编织,您可以将 thep 添加到您的一个类,如以下示例所示:@EnableLoadTimeWeaving@Configuration
爪哇岛
科特林
或者,对于 XML 配置,您可以使用元素:context:load-time-weaver
一旦配置了,其中的任何 bean 都可以实现,从而接收对加载时间的引用 织工实例。这与Spring 的 JPA 支持结合使用时特别有用,其中加载时间编织可能是 JPA 类转换所必需的。 有关更多详细信息,请参阅LocalContainerEntityManagerFactoryBeanjavadoc。有关 AspectJ 加载时编织的更多信息,请参阅Spring 框架中的 Load-time Weaving with AspectJ。ApplicationContextApplicationContextLoadTimeWeaverAware
1.15. 的附加功能ApplicationContext
如本章引言中所讨论的,该包提供了管理和操作 bean 的基本功能,包括在 程序化方式。该包添加了ApplicationContext接口,该接口除了扩展其他接口外,还扩展了该接口 在更多应用程序中提供附加功能的接口 面向框架的风格。许多人使用他们的完全 声明式时尚,甚至不是以编程方式创建它,而是依赖于 支持类,例如自动实例化 Java EE Web 应用程序正常启动过程的一部分。org.springframework.beans.factoryorg.springframework.contextBeanFactoryApplicationContextContextLoaderApplicationContext
为了以更面向框架的风格增强功能,上下文 包还提供以下功能:BeanFactory
- 通过界面访问 i18n 风格的消息。
MessageSource - 通过界面访问资源,例如 URL 和文件。
ResourceLoader - 事件发布,即实现接口的 bean, 通过使用接口。
ApplicationListenerApplicationEventPublisher - 加载多个(分层)上下文,让每个上下文都集中在一个上下文上 特定层,例如应用程序的Web层,通过接口。
HierarchicalBeanFactory
1.15.1. 国际化使用MessageSource
该接口扩展了一个调用的接口, 因此,提供了国际化(“i18n”)功能。Spring 还提供了接口,可以分层解析消息。 这些接口共同为Spring 效果消息提供了基础。 分辨率。在这些接口上定义的方法包括:ApplicationContextMessageSourceHierarchicalMessageSource
-
String getMessage(String code, Object[] args, String default, Locale loc):基本 用于从中检索消息的方法。未找到消息时 对于指定的区域设置,将使用默认消息。传入的任何参数都将成为 替换值,使用标准提供的功能 图书馆。MessageSourceMessageFormat -
String getMessage(String code, Object[] args, Locale loc):本质上与 以前的方法,但有一个区别:无法指定默认消息。如果 找不到消息,AI 已抛出。NoSuchMessageException -
String getMessage(MessageSourceResolvable resolvable, Locale locale):所有属性 上述方法中使用的也包装在名为的类中,可以与此方法一起使用。MessageSourceResolvable
加载 anis 时,它会自动搜索上下文中定义的 abean。豆子必须有名字。如果这样的豆子 找到,则对上述方法的所有调用都将委托给消息源。如果没有 找到消息源,尝试查找包含 同名豆。如果是这样,它将使用该豆子作为。如果找不到任何消息源,则实例化 emptyis 以便能够接受对 上面定义的方法。ApplicationContextMessageSourcemessageSourceApplicationContextMessageSourceApplicationContextDelegatingMessageSource
Spring 提供了三种实现,和。所有这些都实现为了做嵌套 消息。Theis 很少使用,但提供了编程方式 将消息添加到源。以下示例显示:MessageSourceResourceBundleMessageSourceReloadableResourceBundleMessageSourceStaticMessageSourceHierarchicalMessageSourceStaticMessageSourceResourceBundleMessageSource
该示例假定您在类路径中调用和定义了三个资源包。任何解析消息的请求都是 以 JDK 标准方式处理,通过对象解析消息。对于 本示例的目的,假设上述两个资源包文件的内容 具体如下:formatexceptionswindowsResourceBundle
下一个示例显示用于运行该功能的程序。 请记住,所有实现也是实现,因此可以强制转换为接口。MessageSourceApplicationContextMessageSourceMessageSource
上述程序的结果输出如下:
总而言之,theis 在一个调用的文件中定义,其中 存在于类路径的根目录中。底比亚的定义是指 通过其属性的资源包数。这三个文件 在列表中传递给属性作为文件存在于您的根目录 类路径和分别被调用、和。MessageSourcebeans.xmlmessageSourcebasenamesbasenamesformat.propertiesexceptions.propertieswindows.properties
下一个示例显示传递给消息查找的参数。这些参数是 转换为对象并插入到查找消息的占位符中。String
调用该方法的结果输出如下所示:execute()
关于国际化(“i18n”),Spring 的各种实现遵循与标准 JDK 相同的语言环境解析和回退规则。简而言之,继续示例定义 以前,如果要解析针对英国 () 区域设置的邮件,则 将分别创建调用、和的文件。MessageSourceResourceBundlemessageSourceen-GBformat_en_GB.propertiesexceptions_en_GB.propertieswindows_en_GB.properties
通常,区域设置解析由 应用。在以下示例中,(英国)消息所针对的区域设置 已解决是手动指定的:
运行上述程序的结果输出如下:
您还可以使用接口获取对已定义的任何内容的引用。在实现接口的 an 中定义的任何 Bean 都注入了 创建并配置 Bean 时的应用程序上下文。MessageSourceAwareMessageSourceApplicationContextMessageSourceAwareMessageSource
1.15.2. 标准和自定义事件
事件处理是通过类和接口提供的。如果将实现接口的 Bean 部署到上下文中,则每次发布到 bean 时,都会通知该 Bean。 本质上,这是标准的观察者设计模式。ApplicationContextApplicationEventApplicationListenerApplicationListenerApplicationEventApplicationContext
下表描述了 Spring 提供的标准事件:
Table 7. Built-in Events
事件 | 解释 |
| 在初始化或刷新时发布(例如,由 在界面上使用方法)。 这里,“初始化”意味着加载了所有 bean,检测到后处理器 bean 并激活,单例被预先实例化,并且对象是 准备使用。只要上下文尚未关闭,就可以触发刷新 多次,前提是选择的人实际上支持这样的 “热”刷新。例如,支持热刷新,但不支持。 |
| 当使用接口上的方法启动时发布。在这里,“已启动”表示 allbean 接收到明确的启动信号。通常,此信号用于重新启动 bean 在显式停止后,但它也可用于启动尚未停止的组件 配置为自动启动(例如,尚未启动的组件 初始化)。 |
| 当使用接口上的方法停止时发布。在这里,“停止”意味着所有豆子接收到明确的停止信号。停止的上下文可以通过调用重新启动。 |
| 使用方法关闭时发布 在接口上或通过 JVM 关闭挂钩。这里 “关闭”意味着所有单例豆将被销毁。一旦上下文关闭, 它已达到其生命周期的终点,无法刷新或重新启动。 |
| 一个特定于 Web 的事件,告知所有 bean HTTP 请求已得到服务。这 事件在请求完成后发布。此活动仅适用于 使用 Spring 的 Web 应用程序。 |
| 的子类添加了特定于 Servlet 的上下文信息。 |
您还可以创建和发布自己的自定义事件。以下示例显示 扩展 Spring 基类的简单类:ApplicationEvent
若要发布自定义项,请在 上调用该方法。通常,这是通过创建一个实现的类并将其注册为 Spring Bean 来完成的。以下 示例显示了这样的类:ApplicationEventpublishEvent()ApplicationEventPublisherApplicationEventPublisherAware
在配置时,Spring 容器会检测到实现并自动调用。实际上,传入的参数是 Spring 容器本身。您正在通过其接口与应用程序上下文进行交互。EmailServiceApplicationEventPublisherAwaresetApplicationEventPublisher()ApplicationEventPublisher
要接收自定义,您可以创建一个实现的类并将其注册为 Spring Bean。以下示例 显示这样的类:ApplicationEventApplicationListener
请注意,它通常使用您的类型进行参数化 自定义事件(在前面的示例中)。这意味着该方法可以保持类型安全,避免任何向下转换的需要。 您可以根据需要注册任意数量的事件侦听器,但请注意,默认情况下,事件 侦听器同步接收事件。这意味着该方法 阻止,直到所有侦听器完成事件处理。这样做的一个优点 同步和单线程方法是,当侦听器收到事件时,它 如果事务上下文是 可用。如果需要另一种事件发布策略,请参阅 javadoc 对于 Spring 的应用程序事件多播器接口 和SimpleApplicationEventMulticaster实现,用于配置选项。ApplicationListenerBlockedListEventonApplicationEvent()publishEvent()
以下示例显示了用于注册和配置每个 上面的类:
把它们放在一起,当憨豆的方法 调用,如果有任何应阻止的电子邮件,则发布 typeis 的自定义事件。Thebean被注册为anand接收,此时它可以 通知相关方。sendEmail()emailServiceBlockedListEventblockedListNotifierApplicationListenerBlockedListEvent
基于注释的事件侦听器
您可以使用注释在受管 Bean 的任何方法上注册事件侦听器。可以重写如下:@EventListenerBlockedListNotifier
方法签名再次声明它侦听的事件类型, 但是,这一次,使用灵活的名称并且没有实现特定的侦听器接口。 只要实际事件类型,也可以通过泛型缩小事件类型的范围 解析其实现层次结构中的泛型参数。
如果您的方法应该侦听多个事件,或者如果您想定义它而不使用 参数,事件类型也可以在注释本身上指定。这 以下示例演示如何执行此操作:
还可以使用属性添加其他运行时筛选 定义SpEL表达式的注释,该注释应匹配 实际调用特定事件的方法。condition
以下示例显示了如何重写我们的通知程序,使其仅在事件的属性等于时调用:contentmy-event
每个表达式根据专用上下文进行评估。下表列出了 提供给上下文的项,以便您可以将它们用于条件事件处理:SpEL
Table 8. Event SpEL available metadata
名字 | 位置 | 描述 | 例 |
事件 | 根对象 | 实际的。 | |
参数数组 | 根对象 | 用于调用方法的参数(作为对象数组)。 | |
参数名称 | 评估背景 | 任何方法参数的名称。如果由于某种原因名称不可用 (例如,因为编译的字节码中没有调试信息),单个 参数也可以使用语法 其中代表 参数索引(从 0 开始)。 | |
请注意,这使您可以访问基础事件,即使您的方法 签名实际上是指已发布的任意对象。#root.event
如果需要发布一个事件作为处理另一个事件的结果,则可以更改 方法签名以返回应发布的事件,如以下示例所示:
该方法在它处理的每个方法上都会发布一个新内容。如果需要发布多个事件,可以返回 或事件数组。handleBlockedListEvent()ListUpdateEventBlockedListEventCollection
异步侦听器
如果希望特定侦听器异步处理事件,则可以重用常规@Async支持。 以下示例演示如何执行此操作:
使用异步事件时请注意以下限制:
- 如果异步事件侦听器引发 ,则不会传播到 访客。有关更多详细信息,请参阅AsyncUncaughtExceptionHandler。
Exception - 异步事件侦听器方法无法通过返回 价值。如果需要发布另一个事件作为处理的结果,请注入应用程序事件发布者以手动发布事件。
对侦听器进行排序
如果需要先调用一个侦听器,然后再调用另一个侦听器,则可以将注释添加到方法声明中,如以下示例所示:@Order
通用事件
您还可以使用泛型来进一步定义事件的结构。请考虑使用 anwhereis 创建的实际实体的类型。例如,您 可以创建以下侦听器定义以仅接收 a:EntityCreatedEvent<T>TEntityCreatedEventPerson
由于类型擦除,仅当触发的事件解析泛型时,这才有效 事件侦听器筛选的参数(即类似参数)。class PersonCreatedEvent extends EntityCreatedEvent<Person> { … }
在某些情况下,如果所有事件都遵循相同的内容,这可能会变得非常乏味 结构(如前面示例中的事件)。在这种情况下, 你可以实现引导框架超越运行时的内容 环境提供。以下事件演示如何执行此操作:ResolvableTypeProvider
1.15.3. 方便访问低级资源
为了以最佳方式使用和理解应用程序上下文,您应该熟悉 你自己与春天的抽象,如参考资料中所述。Resource
应用程序上下文是一个,可用于加载对象。 A本质上是JDKclass的一个功能更丰富的版本。 事实上,thewrap 的实现是一个实例,其中 适当。Acan 从几乎任何位置获取低级资源 透明时尚,包括从类路径、文件系统位置、任何位置 可以使用标准 URL 和其他一些变体进行描述。如果资源位置 字符串是一条没有任何特殊前缀的简单路径,这些资源来自哪里 特定于并适合实际的应用程序上下文类型。ResourceLoaderResourceResource.URLResource.URLResource
您可以配置部署到应用程序上下文中的 Bean 以实现特殊的 回调接口,,在 自动回调 初始化时间与应用程序上下文本身作为传入。 还可以公开用于访问静态资源的类型属性。 它们像任何其他属性一样注入其中。您可以将这些属性指定为简单路径,并依赖于这些文本的自动转换 字符串到实际对象,当部署 Bean 时。ResourceLoaderAwareResourceLoaderResourceResourceStringResource
提供给构造函数的一个或多个位置路径实际上是 资源字符串,并以简单形式根据特定 上下文实现。例如对待一个简单的 作为类路径位置的位置路径。您还可以使用位置路径(资源字符串) 使用特殊前缀强制从类路径或 URL 加载定义, 无论实际上下文类型如何。ApplicationContextClassPathXmlApplicationContext
1.15.4. 应用程序启动跟踪
管理Spring应用程序的生命周期,并提供丰富的 围绕组件的编程模型。因此,复杂的应用程序可以具有相同的功能 复杂的组件图和启动阶段。ApplicationContext
使用特定指标跟踪应用程序启动步骤有助于了解位置 在启动阶段花费了时间,但它也可以用作更好的方法 从整体上了解上下文生命周期。
(及其子类)与 an 一起检测,它收集有关各个启动阶段的数据:AbstractApplicationContextApplicationStartupStartupStep
- 应用程序上下文生命周期(基本包扫描、配置类管理)
- Bean 生命周期(实例化、智能初始化、后处理)
- 应用程序事件处理
下面是以下检测的示例:AnnotationConfigApplicationContext
应用程序上下文已通过多个步骤进行检测。 记录后,可以使用特定工具收集,显示和分析这些启动步骤。 有关现有启动步骤的完整列表,您可以查看专用附录部分。
默认实现是无操作变体,以实现最小的开销。 这意味着默认情况下,在应用程序启动期间不会收集任何指标。 Spring 框架附带了一个使用 Java Flight Recorder 跟踪启动步骤的实现:要使用此变体,您必须配置它的实例 一旦它被创建出来。ApplicationStartupFlightRecorderApplicationStartupApplicationContext
如果开发人员提供自己的子类,或者他们希望收集更精确的数据,他们也可以使用该基础结构。ApplicationStartupAbstractApplicationContext
要开始收集自定义,组件可以直接从应用程序上下文中获取实例,使其组件实现, 或要求在任何注射点上的类型。StartupStepApplicationStartupApplicationStartupAwareApplicationStartup
1.15.5. 方便的应用程序Web 应用程序的上下文实例化
例如,您可以使用 a.当然,您也可以创建实例 通过使用其中一个实现以编程方式。ApplicationContextContextLoaderApplicationContextApplicationContext
您可以使用 anby 注册,因为 以下示例显示:ApplicationContextContextLoaderListener
侦听器检查参数。如果参数没有 存在,侦听器用作默认值。当 参数确实存在,侦听器通过使用预定义的参数来分隔 分隔符(逗号、分号和空格),并将值用作位置 搜索应用程序上下文。还支持 Ant 样式路径模式。 示例是(对于名称以 和 结尾的所有文件,驻留在目录中)和(对于任何子目录中的所有此类文件)。contextConfigLocation/WEB-INF/applicationContext.xmlString/WEB-INF/*Context.xmlContext.xmlWEB-INF/WEB-INF/**/*Context.xmlWEB-INF
1.15.6. 部署 Springas a Java EE RAR 文件ApplicationContext
可以部署一个 Springas 一个 RAR 文件,封装 上下文及其在 Java EE RAR 部署中所有必需的 Bean 类和库 JAR 单位。这相当于引导独立(仅托管) 在 Java EE 环境中)能够访问 Java EE 服务器设施。RAR 部署 是部署无头 WAR 文件的场景的更自然的替代方法 — 实际上, 一个没有任何 HTTP 入口点的 WAR 文件,仅用于在 Java EE 环境中引导 Spring。ApplicationContextApplicationContextApplicationContext
RAR 部署非常适合不需要 HTTP 入口点但不需要 HTTP 入口点但 而是仅包含消息终结点和计划作业。在这种情况下,豆子可以 使用应用程序服务器资源,例如 JTA 事务管理器和 JNDI 绑定的 JDBC 实例和 JMS实例,还可以注册 该平台的JMX服务器 - 全部通过Spring的标准事务管理和JNDI。 和JMX支持设施。应用程序组件也可以与应用程序交互 服务器的JCA通过Spring的抽象。DataSourceConnectionFactoryWorkManagerTaskExecutor
请参阅SpringContextResourceAdapter类的 javadoc,了解 RAR 部署中涉及的配置详细信息。
对于将Spring ApplicationContext简单部署为Java EE RAR文件:
- 包 所有应用程序类都放入一个 RAR 文件(这是一个标准 JAR 文件,具有不同的 文件扩展名)。
- 将所有必需的库 JAR 添加到 RAR 存档的根目录中。
- 添加部署描述符(如SpringContextResourceAdapter 的 javadoc 所示) 以及相应的 Spring XML Bean 定义文件(通常)。
META-INF/ra.xmlMETA-INF/applicationContext.xml - 将生成的 RAR 文件拖放到您的 应用程序服务器的部署目录。
1.16. 接口BeanFactory
TheAPI 为 Spring 的 IoC 功能提供了底层基础。 它的具体合约主要用于与Spring的其他部分集成,并且 相关第三方框架及其实现 是更高级别的容器中的密钥委托。BeanFactoryDefaultListableBeanFactoryGenericApplicationContext
BeanFactory相关接口(如,,)是其他框架组件的重要集成点。 通过不需要任何注释甚至反射,它们允许非常有效的 容器与其组件之间的交互。应用程序级 bean 可以 使用相同的回调接口,但通常更喜欢声明性依赖项 而是通过注释或编程配置进行注入。BeanFactoryAwareInitializingBeanDisposableBean
请注意,coreAPI 级别及其实现不会对配置格式或任何 要使用的组件注释。所有这些口味都是通过扩展进入的 (如桑德)和 对共享对象进行操作作为核心元数据表示形式。 这就是Spring的容器如此灵活和可扩展的本质。BeanFactoryDefaultListableBeanFactoryXmlBeanDefinitionReaderAutowiredAnnotationBeanPostProcessorBeanDefinition
1.16.1.或?BeanFactoryApplicationContext
本节介绍容器级别之间的差异以及对引导的影响。BeanFactoryApplicationContext
除非你有充分的理由不这样做,否则你应该使用 an,它的子类作为自定义引导的常见实现。这些是主要条目 指向 Spring 的核心容器,用于所有常见目的:加载配置 文件, 触发类路径扫描, 以编程方式注册 Bean 定义 和带注释的类,以及(从 5.0 开始)注册函数式 Bean 定义。ApplicationContextGenericApplicationContextAnnotationConfigApplicationContext
因为 a 包含 a 的所有功能,所以它是 通常建议在平原上,除非已满 需要控制 Bean 加工。在一个(如实现)中,检测到几种 bean 按照约定(即按 Bean 名称或按 Bean 类型 — 特别是后处理器), 而普通人对任何特殊的豆子都不可知。ApplicationContextBeanFactoryBeanFactoryApplicationContextGenericApplicationContextDefaultListableBeanFactory
对于许多扩展容器功能,例如注释处理和 AOP 代理, BeanPostProcessor扩展点是必不可少的。 如果您仅使用普通处理器,则此类后处理器不会 默认情况下被检测并激活。这种情况可能会令人困惑,因为 您的 Bean 配置实际上没有任何问题。相反,在这种情况下, 容器需要通过其他设置完全引导。DefaultListableBeanFactory
下表列出了 and 接口和实现提供的功能。BeanFactoryApplicationContext
Table 9. Feature Matrix
特征 | | |
Bean 实例化/连接 | 是的 | 是的 |
集成的生命周期管理 | 不 | 是的 |
自动注册 | 不 | 是的 |
自动注册 | 不 | 是的 |
便捷的访问(用于国际化) | 不 | 是的 |
内置发布机制 | 不 | 是的 |
要显式注册 Bean 后处理器, 您需要以编程方式调用,如以下示例所示:DefaultListableBeanFactoryaddBeanPostProcessor
要应用于平原, 您需要调用 itsMethod,如以下示例所示:BeanFactoryPostProcessorDefaultListableBeanFactorypostProcessBeanFactory
在这两种情况下,显式注册步骤都不方便,即 为什么各种变体比普通的 Spring-Spring支持的应用程序更受欢迎,尤其是当 依靠实例进行扩展 典型企业设置中的容器功能。ApplicationContextDefaultListableBeanFactoryBeanFactoryPostProcessorBeanPostProcessor
2. 资源
本章介绍 Spring 如何处理资源以及如何在 春天。它包括以下主题:
- 介绍
- 资源接口
- 内置资源实现
- 资源加载器接口
- 资源模式解析器接口
- 资源加载器感知接口
- 作为依赖项的资源
- 应用程序上下文和资源路径
2.1. 简介
Java 的标准类和各种 URL 前缀的标准处理程序, 不幸的是,不足以满足所有获得低级资源的机会。为 例如,没有可用于访问 需要从类路径或相对于 a 获取的资源。虽然可以为专用前缀注册新的处理程序(类似于前缀的现有处理程序,例如),但这通常是 相当复杂,界面仍然缺乏一些理想的功能, 例如用于检查所指向的资源是否存在的方法。.URLURLServletContextURLhttp:URL
2.2. 界面Resource
位于包装中的弹簧接口是 旨在成为更强大的接口,用于抽象对低级资源的访问。这 以下列表提供了界面的概述。有关更多详细信息,请参阅资源javadoc。Resource.Resource
如接口的定义所示,它扩展了接口。以下清单显示了接口的定义:ResourceInputStreamSourceInputStreamSource
界面中一些最重要的方法是:Resource
-
getInputStream():查找并打开资源,返回 从资源读取。预计每次调用都会返回一个新的。调用方负责关闭流。InputStreamInputStream -
exists():返回指示此资源是否实际存在于 物理形式。boolean -
isOpen():返回指示此资源是否表示句柄 与开放的溪流。如果,无法多次读取并且 必须只读取一次,然后关闭以避免资源泄漏。返回 所有常用的资源实现,但 除外。booleantrueInputStreamfalseInputStreamResource -
getDescription():返回此资源的说明,用于错误 使用资源时的输出。这通常是完全限定的文件名或 资源的实际 URL。
其他方法允许您获取表示 资源(如果基础实现兼容并支持 功能)。URLFile
接口的某些实现还实现了扩展的WritableResource接口 支持写入的资源。Resource
Spring 本身广泛使用抽象,作为 需要资源时的许多方法签名。某些 Spring API 中的其他方法 (例如各种实现的构造函数)以朴素或简单的形式用于创建适合 该上下文实现或通过路径上的特殊前缀,让 调用方指定必须创建和使用特定实现。ResourceApplicationContextStringResourceStringResource
虽然接口在 Spring 和 Spring 中大量使用,但它实际上是 非常方便在您自己的代码中单独用作通用实用程序类,以便访问 资源,即使你的代码不知道或不关心 Spring 的任何其他部分。 虽然这会将您的代码与 Spring 耦合,但它实际上只将其耦合到这一小组 实用程序类,作为更有能力的替代和可以是 被认为等同于您用于此目的的任何其他库。ResourceURL
2.3. 内置实现Resource
Spring 包括几个内置的实现:Resource
- UrlResource
- ClassPathResource
- FileSystemResource
- PathResource
- ServletContextResource
- InputStreamResource
- ByteArrayResource
有关 Spring 中可用的实现的完整列表,请参阅 资源javadoc 的“所有已知的实现类”部分。Resource
2.3.1. UrlResource
UrlResource包装 aand 可用于访问任何对象 通常可通过 URL 访问,例如文件、HTTPS 目标、FTP 目标和 别人。所有 URL 都有一个标准化的表示形式,以便适当的 标准化前缀用于指示一种 URL 类型与另一种 URL 类型。这包括用于访问文件系统路径,用于通过 HTTPS协议,用于通过FTP访问资源等。.URLStringfile:https:ftp:
由 Java 代码显式使用构造函数创建的 Ais 但在调用采用用于表示路径的参数的 API 方法时,通常会隐式创建。对于后一种情况,JavaBeans最终决定创建哪种类型的of。如果路径字符串包含 众所周知(对属性编辑器,即)前缀(例如),它创建一个 适合该前缀。但是,如果它无法识别 前缀,它假定字符串是标准 URL 字符串并创建一个。UrlResourceUrlResourceStringPropertyEditorResourceclasspath:ResourceUrlResource
2.3.2. ClassPathResource
此类表示应从类路径获取的资源。它使用 线程上下文类装入器、给定类装入器或给定的类 加载资源。
此实现支持解析为 aif 类路径 资源驻留在文件系统中,但对于驻留在 jar 并且尚未扩展(通过 servlet 引擎或任何环境) 到文件系统。为了解决这个问题,各种实现始终支持 分辨率为 A。Resourcejava.io.FileResource.URL
AI 由 Java 代码显式使用构造函数创建,但在调用采用用于表示路径的参数的 API 方法时,通常是隐式创建的。对于后一种情况,JavaBeans识别字符串路径上的特殊前缀和 在这种情况下创建。ClassPathResourceClassPathResourceStringPropertyEditorclasspath:ClassPathResource
2.3.3. FileSystemResource
这是句柄的实现。它还支持句柄,应用Spring的标准基于字符串的路径。 转换,但通过 API 执行所有操作。对于纯基支持,请使用 arather.support resolution as aand as a。Resourcejava.io.Filejava.nio.file.Pathjava.nio.file.Filesjava.nio.path.PathPathResourceFileSystemResourceFileURL
2.3.4. PathResource
这是句柄的实现,执行所有 通过 API 进行操作和转换。它支持分辨率作为 aand 由于 AAAND 还有效地实现了 一个纯粹的替代方案 不同的行为。Resourcejava.nio.file.PathPathFileURLWritableResourcePathResourcejava.nio.path.PathFileSystemResourcecreateRelative
2.3.5. ServletContextResource
这是对解释 相关 Web 应用程序的根目录中的相对路径。ResourceServletContext
它始终支持流访问和 URL 访问,但仅允许访问 当 Web 应用程序存档展开并且资源在物理上位于 文件系统。它是否已扩展并在文件系统上或被访问 直接从JAR或其他地方(如数据库)实际上是 依赖于 Servlet 容器。java.io.File
2.3.6. InputStreamResource
Anis aimplementation为一个给定的。它 仅当没有适用的特定实现时,才应使用。在 特别是,在可能的情况下首选任何基于文件的实现。InputStreamResourceResourceInputStreamResourceByteArrayResourceResource
与其他实现相比,这是 已打开的资源。因此,它返回自。如果出现以下情况,请勿使用它 您需要将资源描述符保留在某个位置,或者如果您需要读取流 多次。ResourcetrueisOpen()
2.3.7. ByteArrayResource
这是给定字节数组的实现。它为给定的字节数组创建 a。ResourceByteArrayInputStream
它对于从任何给定的字节数组加载内容很有用,而不必求助于 一次性使用。InputStreamResource
2.4. 界面ResourceLoader
该接口旨在由可以返回的对象实现 (即加载)实例。以下清单显示了接口定义:ResourceLoaderResourceResourceLoader
所有应用程序上下文都实现接口。因此,所有 应用程序上下文可用于获取实例。ResourceLoaderResource
调用特定应用程序上下文和位置路径时 指定没有特定的前缀,你得到的 atype 是 适用于该特定应用程序上下文。例如,假设以下内容 针对实例运行的代码片段:getResource()ResourceClassPathXmlApplicationContext
针对 a,该代码返回 a。如果 对 ainstance 运行相同的方法,它会 返回 A。对于 a,它将返回 a。它同样会为每个上下文返回适当的对象。ClassPathXmlApplicationContextClassPathResourceFileSystemXmlApplicationContextFileSystemResourceWebApplicationContextServletContextResource
因此,您可以以适合特定应用程序的方式加载资源 上下文。
另一方面,您也可以强制使用,无论 应用程序上下文类型,通过指定特殊前缀,如下所示 示例显示:ClassPathResourceclasspath:
同样,您可以通过指定任何标准前缀来强制使用 ato。以下示例使用和前缀:UrlResource.URLfilehttps
下表总结了将对象转换为对象的策略:StringResource
Table 10. Resource strings
前缀 | 例 | 解释 |
类路径: | | 从类路径加载。 |
文件: | | 从文件系统加载为 a。另请参阅文件系统资源警告。 |
https: | | 加载为 a。 |
(无) | | 取决于标的物。 |
2.5. 界面ResourcePatternResolver
接口是接口的扩展 它定义了解析位置模式的策略(例如,Ant 样式路径) 模式)进入对象。ResourcePatternResolverResourceLoaderResource
如上所示,此接口还定义了特殊资源前缀 对于类路径中的所有匹配资源。请注意,资源位置为 在这种情况下,预期为没有占位符的路径 — 例如,。JAR 文件或类路径中的不同目录可以 包含具有相同路径和相同名称的多个文件。有关更多详细信息,请参阅应用程序上下文构造函数资源路径中的通配符及其小节 在通配符支持上,带有源前缀。classpath*:classpath*:/config/beans.xmlclasspath*:
可以检查传入的(例如,通过ResourceLoaderAware语义提供的传入)是否 它也实现了这个扩展接口。ResourceLoader
PathMatchingResourcePatternResolver是一个可用的独立实现 在阿南德之外也用于 填充豆 properties.is 能够 将指定的资源位置路径解析为一个或多个匹配对象。 源路径可以是与目标具有一对一映射的简单路径,也可以包含特殊前缀和/或内部 Ant 风格的正则表达式(使用 Spring 的实用程序匹配)。后者都是有效的 通配符。ApplicationContextResourceArrayPropertyEditorResource[]PathMatchingResourcePatternResolverResourceResourceclasspath*:org.springframework.util.AntPathMatcher
2.6. 界面ResourceLoaderAware
接口是一个特殊的回调接口,用于标识 希望提供参考的组件。以下列表 显示了接口的定义:ResourceLoaderAwareResourceLoaderResourceLoaderAware
当类实现和部署到应用程序上下文中时 (作为 Spring 管理的 bean),它被应用程序识别为 上下文。然后,应用程序上下文调用, 提供自身作为参数(请记住,Spring 中的所有应用程序上下文都实现了 界面)。ResourceLoaderAwareResourceLoaderAwaresetResourceLoader(ResourceLoader)ResourceLoader
由于 anis a,bean 还可以实现接口并使用提供的应用程序上下文直接到 加载资源。但是,一般来说,如果您只需要使用专用界面,最好使用专用界面。代码将仅与资源加载耦合 接口(可以被认为是一个实用程序接口),而不是整个 Springinterface。ApplicationContextResourceLoaderApplicationContextAwareResourceLoaderApplicationContext
在应用程序组件中,您还可以依赖自动布线 实现接口的替代方法。传统和自动配线模式(如自动配线协作者中所述) 能够为 构造函数参数或 分别是二传手方法参数。实现更大的灵活性(包括能够 自动连线字段和多参数方法),请考虑使用基于注释的 自动接线功能。在这种情况下,它们会自动连接到一个字段中, 构造函数参数,或期望类型尽可能长的方法参数 因为有问题的字段、构造函数或方法带有注释。 有关详细信息,请参阅使用@Autowired。ResourceLoaderResourceLoaderAwareconstructorbyTypeResourceLoaderResourceLoaderResourceLoader@Autowired
2.7. 资源作为依赖关系
如果 Bean 本身要通过某种排序确定并提供资源路径 在动态过程中,Bean 使用 theorInterface 加载资源可能是有意义的。例如,考虑加载 某种模板,其中所需的特定资源取决于 用户的角色。如果资源是静态的,则完全消除接口(或接口)的使用是有意义的,具有 Bean 公开了它需要的属性,并期望它们被注入其中。ResourceLoaderResourcePatternResolverResourceLoaderResourcePatternResolverResource
然后注入这些属性变得微不足道的是,所有应用程序上下文 注册并使用特殊的JavaBeans,它可以转换路径 到对象。例如,下面的类具有类型的属性。PropertyEditorStringResourceMyBeantemplateResource
在 XML 配置文件中,可以使用简单的 该资源的字符串,如以下示例所示:template
请注意,资源路径没有前缀。因此,由于应用程序上下文 本身将用作,资源通过 a、a 或 a 加载,具体取决于 应用程序上下文的确切类型。ResourceLoaderClassPathResourceFileSystemResourceServletContextResource
如果需要强制使用特定类型,可以使用前缀。这 以下两个示例演示如何强制 Aand A( 后者用于访问文件系统中的文件):ResourceClassPathResourceUrlResource
如果重构类以用于注释驱动的配置,则 路径可以存储在名为 — 例如, 在提供给 Spring 的属性文件中(参见环境抽象)。然后,可以使用属性占位符通过注释引用模板路径(请参阅使用@Value)。春天会 检索模板路径的值作为字符串,并特殊遗嘱 将字符串转换为要注入到构造函数中的对象。 下面的示例演示如何实现此目的。MyBeanmyTemplate.txttemplate.pathEnvironment@ValuePropertyEditorResourceMyBean
如果我们想支持在同一路径下发现多个模板 类路径中的位置(例如,在类路径中的多个 JAR 中)我们可以 使用 specialprefix 和通配符将 akey 定义为。如果我们按如下方式重新定义类, Spring 会将模板路径模式转换为对象数组 可以注入到构造函数中。classpath*:templates.pathclasspath*:/config/templates/*.txtMyBeanResourceMyBean
爪哇岛
科特林
2.8. 应用程序上下文和资源路径
本节介绍如何使用资源(包括快捷方式)创建应用程序上下文 适用于 XML、如何使用通配符以及其他详细信息。
2.8.1. 构建应用程序上下文
应用程序上下文构造函数(用于特定应用程序上下文类型)通常 将字符串或字符串数组作为资源的位置路径,例如 构成上下文定义的 XML 文件。
当这样的位置路径没有前缀时,从 该路径和用于加载 Bean 定义取决于并且适用于 特定的应用程序上下文。例如,请考虑以下示例,该示例将创建一个:ResourceClassPathXmlApplicationContext
Bean 定义是从类路径加载的,因为 ais 使用。但是,请考虑以下示例,该示例将创建一个:ClassPathResourceFileSystemXmlApplicationContext
现在,从文件系统位置加载 Bean 定义(在本例中,相对于 当前工作目录)。
请注意,在 位置路径覆盖默认类型“已创建”以装入 Bean 定义。请考虑以下示例:classpathResource
使用 从类路径加载 Bean 定义。 但是,它仍然是一个。如果随后将其用作 ,则任何不带前缀的路径仍被视为文件系统路径。FileSystemXmlApplicationContextFileSystemXmlApplicationContextResourceLoader
构造实例 — 快捷方式ClassPathXmlApplicationContext
公开许多构造函数以启用 方便的实例化。基本思想是,您只能提供一个字符串数组 仅包含 XML 文件本身的文件名(不带前导路径) 信息),并提供 a。然后派生 来自所提供类的路径信息。ClassPathXmlApplicationContextClassClassPathXmlApplicationContext
请考虑以下目录布局:
以下示例显示了 ainstance 如何由 在文件名和(位于 类路径)可以实例化:ClassPathXmlApplicationContextservices.xmlrepositories.xml
请参阅ClassPathXmlApplicationContextjavadoc 以获取有关各种构造函数的详细信息。
2.8.2. 应用程序上下文构造函数资源路径中的通配符
应用程序上下文构造函数值中的资源路径可以是简单路径(如 如前所示),每个目标都有一个到目标器的一对一映射, 或者,可以包含特殊前缀或内部 Ant 样式模式 (通过使用 Spring 的实用程序进行匹配)。后者都是有效的 通配符。Resourceclasspath*:PathMatcher
此机制的一个用途是当您需要执行组件样式的应用程序组装时。都 组件可以将上下文定义片段发布到已知位置路径,并且, 当使用前缀相同的路径创建最终应用程序上下文时,将自动选取所有组件片段。classpath*:
请注意,此通配符特定于在应用程序上下文中使用资源路径 构造函数(或直接使用实用程序类层次结构时)并且 在施工时解决。它与类型本身无关。 您不能使用前缀来构造实际值,因为 一个资源一次只指向一个资源。PathMatcherResourceclasspath*:Resource
蚂蚁风格图案
路径位置可以包含 Ant 样式模式,如以下示例所示:
当路径位置包含 Ant 样式模式时,解析器将遵循更复杂的模式 尝试解析通配符的过程。它产生一条通往 最后一个非通配符段并从中获取 URL。如果此网址不是网址或 特定于容器的变体(例如在 WebLogic、WebSphere 等中), AIS从中获取并用于通过遍历通配符来解析通配符 文件系统。对于 jar URL,解析器要么从中获取 a,要么手动解析 jar URL,然后遍历 用于解析通配符的 JAR 文件的内容。Resourcejar:zip:wsjarjava.io.File.JarURLConnection
对可移植性的影响
如果指定的路径已经是 URL(隐式,因为基是文件系统的路径,或者显式地),则通配符保证 以完全便携的方式工作。fileResourceLoader
如果指定的路径是位置,则解析程序必须获取最后一个 通过调用的非通配符路径段 URL。从此 只是路径的一个节点(不是末尾的文件),它实际上是未定义的(在javadoc中)在这种情况下返回的URL类型。在实践中, 它始终表示目录(类路径资源 解析为文件系统位置)或某种 jar URL(类路径资源所在的位置 解析为 JAR 位置)。尽管如此,此操作仍存在可移植性问题。classpathClassloader.getResource()ClassLoaderjava.io.File
如果为最后一个非通配符段获取了 jar URL,则解析器必须能够 从中获取或手动解析 jar URL,以便能够 遍历 JAP 的内容并解析通配符。这在大多数环境中都有效 但在其他方面失败,我们强烈建议资源的通配符解析 来自 jar 在您依赖它之前,请在您的特定环境中进行彻底测试。.JarURLConnection
前缀classpath*:
构造基于 XML 的应用程序上下文时,位置字符串可以使用 特殊前缀,如以下示例所示:classpath*:
此特殊前缀指定与给定名称匹配的所有类路径资源 必须获得(在内部,这基本上是通过调用 to 发生的),然后合并以形成最终应用程序 上下文定义。ClassLoader.getResources(…)
您还可以将前缀与模式组合在 位置路径的其余部分(例如,)。在此 在这种情况下,解决策略相当简单:Acall是 在最后一个非通配符路径段上使用,以获取 类装入器层次结构,然后,关闭每个资源,相同的分辨率 前面描述的策略用于通配符子路径。classpath*:PathMatcherclasspath*:META-INF/*-beans.xmlClassLoader.getResources()PathMatcher
与通配符有关的其他注意事项
请注意,当与 Ant 风格的模式结合使用时,只能工作 在模式开始之前至少有一个根目录,除非实际 目标文件驻留在文件系统中。这意味着模式(例如可能不会从jar文件的根目录中检索文件,而只是 从展开目录的根目录。classpath*:classpath*:*.xml
Spring 检索类路径条目的能力源于 JDK 的方法,该方法只返回 空字符串(指示要搜索的潜在根)。Spring 评估 jar 文件中的运行时配置和清单 以及,但这并不能保证导致可移植行为。ClassLoader.getResources()URLClassLoaderjava.class.path
蚂蚁风格的模式与资源不能保证找到匹配 资源(如果要搜索的根包在多个类路径位置中可用)。 请考虑以下资源位置示例:classpath:
现在考虑一个 Ant 风格的路径,有人可能会使用它来尝试查找该文件:
这样的资源可能只存在于类路径中的一个位置,但是当路径如 前面的示例用于尝试解决它,解析器在(第一个) 返回的网址。如果此基本包节点存在于 多个位置,所需的资源可能不存在于第一个位置 找到位置。因此,在这种情况下,您应该更喜欢使用 相同的 Ant 样式模式,它搜索包含基本包的所有类路径位置:getResource("com/mycompany");ClassLoaderclasspath*:com.mycompanyclasspath*:com/mycompany/**/service-context.xml
2.8.3.注意事项FileSystemResource
A那不附加到一个(那 是,当 AI 不是实际时)对待 绝对和相对路径如您所期望。相对路径相对于 当前工作目录,而绝对路径相对于 文件系统。FileSystemResourceFileSystemApplicationContextFileSystemApplicationContextResourceLoader
然而,出于向后兼容性(历史)的原因,当是时,这会发生变化。强制所有附加实例 将所有位置路径视为相对路径,无论它们是否以前导斜杠开头。 实际上,这意味着以下示例是等效的:FileSystemApplicationContextResourceLoaderFileSystemApplicationContextFileSystemResource
以下示例也是等效的(即使它们不同是有意义的,作为一个 情况是相对的,另一个是绝对的):
实际上,如果您需要真正的绝对文件系统路径,则应避免使用 绝对路径与索兰德 强制使用 aby 使用 URL 前缀。以下示例 演示如何执行此操作:FileSystemResourceFileSystemXmlApplicationContextUrlResourcefile:
3. 验证、数据绑定和类型转换
将验证视为业务逻辑有利有弊,Spring 提供 一种不排除其中任何一个的验证(和数据绑定)设计。 具体而言,验证不应绑定到 Web 层,而应易于本地化, 并且应该可以插入任何可用的验证器。考虑到这些关切, 弹簧提供了既基本又非常可用的契约 在应用程序的每一层中。Validator
数据绑定对于让用户输入动态绑定到域非常有用 应用程序的模型(或用于处理用户输入的任何对象)。春天 提供了恰如其分的名字来做到这一点。和 弥补 包装,主要用于但不 仅限于 Web 图层。DataBinderValidatorDataBindervalidation
这是Spring框架中的一个基本概念,并且在很多中使用 的地方。但是,您可能不需要直接使用。但是,由于这是参考文档,因此我们认为某些解释 可能是有序的。我们在本章中解释,因为,如果你是 要使用它,您最有可能在尝试将数据绑定到对象时这样做。BeanWrapperBeanWrapperBeanWrapper
Spring's和较低级别都使用实现来解析和格式化属性值。Theandtypes是JavaBeans规范的一部分,也是 在本章中解释。Spring 3 引入了一个软件包,它提供了一个 通用类型转换工具,以及更高级别的“格式”包 设置 UI 字段值的格式。您可以将这些包用作实现的更简单的替代方法。本章还将讨论它们。DataBinderBeanWrapperPropertyEditorSupportPropertyEditorPropertyEditorSupportcore.convertPropertyEditorSupport
Spring 通过设置基础结构和适配器支持 Java Bean 验证 春天自己的合同。应用程序可以全局启用一次 Bean 验证, 如Java Bean 验证中所述,并将其专门用于所有验证 需要。在 Web 层中,应用程序可以进一步注册每个控制器本地 Spring实例,如配置DataBinder 中所述,它可以 对于插入自定义验证逻辑很有用。ValidatorValidatorDataBinder
3.1. 使用 Spring 的验证器接口进行验证
Spring 具有可用于验证对象的接口。该接口通过使用对象来工作,以便在验证时, 验证程序可以向对象报告验证失败。ValidatorValidatorErrorsErrors
请考虑以下小型数据对象示例:
下一个示例通过实现 以下两种接口方法:Personorg.springframework.validation.Validator
-
supports(Class):这可以验证所提供的实例吗?ValidatorClass -
validate(Object, org.springframework.validation.Errors):验证给定对象 并且,在出现验证错误的情况下,将那些注册到给定对象中。Errors
实现 ay 相当简单,特别是当你知道 Spring 框架也提供的辅助类时。以下 示例实现for实例:ValidatorValidationUtilsValidatorPerson
类上的方法用于 如果属性为空字符串,则拒绝该属性。看看ValidationUtilsjavadoc 以查看除了前面显示的示例之外,它还提供了哪些功能。staticrejectIfEmpty(..)ValidationUtilsnamenull
虽然当然可以实现单个类来验证每个 在富对象中的嵌套对象中,最好封装验证 每个嵌套对象类在其自己的实现中的逻辑。一个简单的 “富”对象的示例是由两个属性(第一个和第二个名称)和一个 complexObject.objects 组成的。 可以独立于对象使用,因此已实现区别。如果您希望重用包含的逻辑 在课堂内无需诉诸复制和粘贴,您可以 依赖注入或实例化你的, 如以下示例所示:ValidatorValidatorCustomerStringAddressAddressCustomerAddressValidatorCustomerValidatorAddressValidatorAddressValidatorCustomerValidator
验证错误将报告给传递给验证器的对象。在这种情况下 Spring Web MVC,您可以使用标签来检查错误消息,但是 您也可以自己检查对象。有关 它提供的方法可以在javadoc中找到。Errors<spring:bind/>Errors
3.2. 将代码解析为错误消息
我们介绍了数据绑定和验证。本节介绍输出相应的消息 到验证错误。在上一节所示的示例中, 我们拒绝了Theandfields。如果我们想使用 a 输出错误消息,我们可以使用我们在拒绝字段时提供的错误代码来实现 (在本例中为“姓名”和“年龄”)。当您调用(直接或间接地,通过使用 例如,类)或其他方法之一 从接口,底层实现不仅注册了代码 传入,但也注册了许多额外的错误代码。确定接口注册哪些错误代码。默认情况下,使用,它(例如)不仅注册消息 使用您提供的代码,但也注册包含您传递的字段名称的消息 到拒绝方法。因此,如果您通过使用拒绝字段, 除了代码,Spring 还寄存沙(第一个包含字段名称,第二个包含类型 的领域)。这样做是为了方便开发人员确定错误消息。nameageMessageSourceValidationUtilsrejectValuerejectErrorsMessageCodesResolverErrorsDefaultMessageCodesResolverrejectValue("age", "too.darn.old")too.darn.oldtoo.darn.old.age
可以找到有关和默认策略的更多信息 在 MessageCodesResolver 和DefaultMessageCodesResolver 的 javadoc 中, 分别。MessageCodesResolver
3.3. Bean 操作和BeanWrapper
该软件包遵循JavaBeans标准。 JavaBean是一个具有默认无参数构造函数的类,它遵循 一种命名约定,其中(例如)命名的属性将 有一个二传手方法和一个吸气手方法。为 有关 JavaBeans 和规范的更多信息,请参阅JavaBeans。org.springframework.beansbingoMadnesssetBingoMadness(..)getBingoMadness()
bean 包中一个非常重要的类是接口及其 相应的实现 ()。正如引用自javadoc的,提供了设置和获取属性值的功能(单独或在 批量),获取属性描述符,并查询属性以确定它们是否 可读或可写。此外,还提供对嵌套属性的支持, 启用将子属性上的属性设置为无限深度。它还支持添加标准JavaBeansand的能力,而无需在目标类中支持代码。 最后但并非最不重要的一点是,提供对设置索引属性的支持。 通常不由应用程序代码直接使用,而由和使用。BeanWrapperBeanWrapperImplBeanWrapperBeanWrapperBeanWrapperPropertyChangeListenersVetoableChangeListenersBeanWrapperBeanWrapperDataBinderBeanFactory
作品的方式部分由它的名字表示:它包裹着一个豆子 对该 Bean 执行操作,例如设置和检索属性。BeanWrapper
3.3.1. 设置和获取基本属性和嵌套属性
设置和获取属性是通过 的 and重载方法变体完成的。请参阅他们的 Javadoc 详。下表显示了这些约定的一些示例:setPropertyValuegetPropertyValueBeanWrapper
Table 11. Examples of properties
表达 | 解释 |
| 指示与理论方法对应的属性。 |
| 指示对应于 (例如)理论方法。 |
| 指示索引属性的第三个元素。索引属性 可以是类型、或其他自然顺序集合。 |
| 指示由属性的键索引的映射条目的值。 |
(如果您不打算使用 直接的。如果您只使用 and 和它们的默认实现,则应跳到属性编辑器部分。BeanWrapperDataBinderBeanFactory
以下两个示例类使用 get 和 set 性能:BeanWrapper
以下代码片段显示了如何检索和操作某些 实例化和的属性:CompanyEmployee
3.3.2. 内置实现PropertyEditor
弹簧使用a的概念来实现anand a之间的转换。它可以很方便 以不同于对象本身的方式表示属性。例如,a可以用人类可读的方式表示(如:),而 我们仍然可以将人类可读的形式转换回原始日期(或者,甚至 更好的是,将以人类可读形式输入的任何日期转换回对象)。这 行为可以通过注册类型的自定义编辑器来实现。在 aor 上注册自定义编辑器, 或者,在特定的 IoC 容器中(如上一章所述),给出它 有关如何将属性转换为所需类型的知识。有关更多信息,请参阅 Oracle 的java.beans 包的 javadoc。PropertyEditorObjectStringDateString'2007-14-09'Datejava.beans.PropertyEditorBeanWrapperPropertyEditor
在 Spring 中使用属性编辑的几个示例:
- 在 bean 上设置属性是通过使用实现来完成的。 当您使用您声明的某个 Bean 的属性值时 在 XML 文件中,Spring (如果相应属性的 setter 具有 aparameter)用于尝试将参数解析为 aobject。
PropertyEditorStringClassClassEditorClass - 在 Spring 的 MVC 框架中解析 HTTP 请求参数是通过使用各种类型来完成的 的实现,您可以在所有子类中手动绑定。
PropertyEditorCommandController
Spring 有许多内置的实现,让生活变得轻松。 它们都位于包装中。默认情况下,大多数(但不是全部,如下表所示)由注册者注册。如果属性编辑器可以以某种方式进行配置,则可以 仍然注册您自己的变体以覆盖默认变体。下表描述了 Spring 提供的各种实现:PropertyEditororg.springframework.beans.propertyeditorsBeanWrapperImplPropertyEditor
表 12.内置实现PropertyEditor
类 | 解释 |
| 字节数组的编辑器。将字符串转换为其相应的字节 交涉。默认注册者。 |
| 将表示类的字符串分析为实际类,反之亦然。当一个 找不到类,阿尼斯扔了。默认情况下,注册者。 |
| 属性的可自定义属性编辑器。默认情况下,可以通过将注册的自定义实例注册为 自定义编辑器。 |
| 集合的属性编辑器,将任何源转换为给定的目标类型。 |
| 可定制的属性编辑器,支持自定义。不 默认注册。必须根据需要使用适当的格式进行用户注册。 |
| 任何子类的可自定义属性编辑器,例如,,,或。默认情况下,注册者但可以由 将其自定义实例注册为自定义编辑器。 |
| 将字符串解析为对象。默认情况下,注册者。 |
| 单向属性编辑器,可以采用字符串并生成(通过 中间和)可以直接将属性设置为字符串。请注意,默认用法不会关闭 为你。默认情况下,注册者。 |
| 可以将字符串解析为对象,反之亦然(字符串格式与方法相同)。还接受空格作为分隔符,作为下划线的替代项。 默认情况下,注册者。 |
| 可以将字符串解析为对象,反之亦然。 |
| 可以将字符串(使用类的javadoc中定义的格式格式化)转换为对象。默认情况下,已注册 由。 |
| 修剪字符串的属性编辑器。(可选)允许转换空字符串 变成一个值。默认情况下未注册 — 必须由用户注册。 |
| 可以将 URL 的字符串表示形式解析为实际对象。 默认情况下,注册者。 |
弹簧使用设置属性的搜索路径 可能需要的编辑器。搜索路径还包括, 包括诸如、和大多数类型的实现 基元类型。另请注意,标准的 JavaBeans 基础架构 自动发现类(无需注册它们) 显式)如果它们与它们处理的类位于同一包中并且具有相同的 名称为该类,附加。例如,可以有以下内容 类和包结构,这足以使类 识别并用作 for 类型属性。java.beans.PropertyEditorManagersun.bean.editorsPropertyEditorFontColorPropertyEditorEditorSomethingEditorPropertyEditorSomething
请注意,您也可以在此处使用标准的JavaBeans机制。 (此处在一定程度上描述)。这 下面的示例使用该机制使用关联类的属性显式注册一个或多个实例:BeanInfoBeanInfoPropertyEditor
引用类的以下 Java 源代码 关联 a与类的属性:SomethingBeanInfoCustomNumberEditorageSomething
注册其他自定义实现PropertyEditor
当将 bean 属性设置为字符串值时,Spring IoC 容器最终使用 标准JavaBeans实现,用于将这些字符串转换为复杂类型的 财产。Spring 预注册了许多自定义实现(例如,到 将表示为字符串的类名转换为对象)。此外 Java的标准JavaBeanslookup机制允许afor类被适当地命名,并与类放在同一个包中。 它提供支持,以便可以自动找到它。PropertyEditorPropertyEditorClassPropertyEditorPropertyEditor
如果需要注册其他习俗,有几种机制是 可用。最手动的方法,通常不方便或 推荐,是使用接口的方法,假设你有偏好。 另一个(稍微方便一些)机制是使用特殊的豆子工厂 后处理器调用。虽然你可以使用bean工厂后处理器 通过实现,具有 嵌套属性设置,因此我们强烈建议您将它与 一起使用,在那里您可以以类似于任何其他 Bean 和 可以自动检测和应用的地方。PropertyEditorsregisterCustomEditor()ConfigurableBeanFactoryBeanFactoryCustomEditorConfigurerBeanFactoryCustomEditorConfigurerApplicationContext
请注意,所有 Bean 工厂和应用程序上下文都会自动使用许多 内置属性编辑器,通过使用 ATO进行 处理属性转换。寄存器的标准属性编辑器在上一节中列出。 此外,还覆盖或添加其他编辑器来处理 以适合特定应用程序上下文类型的方式进行资源查找。BeanWrapperBeanWrapperApplicationContext
标准 JavaBeans 实例用于转换属性值 表示为属性的实际复杂类型的字符串。您可以使用豆厂后处理器方便地添加 支持对 AN 的其他实例。PropertyEditorCustomEditorConfigurerPropertyEditorApplicationContext
考虑以下示例,该示例定义了一个调用的用户类 另一个调用的类,它需要设置为属性:ExoticTypeDependsOnExoticTypeExoticType
正确设置后,我们希望能够将类型属性分配为 字符串,转换为实际实例。以下 Bean 定义显示了如何设置此关系:PropertyEditorExoticType
实现可能类似于以下内容:PropertyEditor
最后,下面的示例演示如何使用 newwith 注册,然后可以根据需要使用它:CustomEditorConfigurerPropertyEditorApplicationContext
用PropertyEditorRegistrar
向 Spring 容器注册属性编辑器的另一种机制是 创建和使用 a。此接口在以下情况下特别有用 您需要在几种不同情况下使用同一组属性编辑器。 您可以编写相应的注册器并在每种情况下重用它.实例与调用的接口结合使用,该接口由 Spring(and) 实现。实例特别方便 与(此处所述)一起使用时,它公开了一个属性 已添加调用实例 以这种方式可以轻松共享和 弹簧 MVC 控制器。此外,它避免了自定义同步的需要 编辑器:Ais 希望为每次创建 Bean 尝试创建新实例。PropertyEditorRegistrarPropertyEditorRegistrarPropertyEditorRegistryBeanWrapperDataBinderPropertyEditorRegistrarCustomEditorConfigurersetPropertyEditorRegistrars(..)PropertyEditorRegistrarCustomEditorConfigurerDataBinderPropertyEditorRegistrarPropertyEditor
以下示例演示如何创建自己的实现:PropertyEditorRegistrar
另请参阅示例实现。请注意,在方法的实现中,它如何创建每个属性编辑器的新实例。org.springframework.beans.support.ResourceEditorRegistrarPropertyEditorRegistrarregisterCustomEditors(..)
下一个示例演示如何配置 aand 注入实例 我们的进入它:CustomEditorConfigurerCustomPropertyEditorRegistrar
最后(有点偏离本章的重点)对于那些你们 使用Spring 的 MVC Web 框架,使用 ain 与数据绑定 Web 控制器结合使用可以非常方便。以下 示例使用 ain 实现 anmethod:PropertyEditorRegistrarPropertyEditorRegistrar@InitBinder
这种注册方式可以导致简洁的代码(实现 的方法只有一行长),并允许将公共注册代码封装在一个类中,然后在尽可能多的控制器之间共享 根据需要。PropertyEditor@InitBinderPropertyEditor
3.4. 弹簧类型转换
Spring 3 引入了一个提供常规类型转换的包 系统。系统定义一个SPI来实现类型转换逻辑和一个API 在运行时执行类型转换。在 Spring 容器中,您可以使用此系统 作为转换外部化 Bean 属性值的实现的替代方法 字符串到所需的属性类型。您还可以在 需要类型转换的应用程序。core.convertPropertyEditor
3.4.1. 转换器 SPI
实现类型转换逻辑的 SPI 很简单,并且是强类型的,如下所示 接口定义显示:
要创建自己的转换器,请实现接口并参数化为要转换的类型以及要转换为的类型。您也可以透明地应用这样的 转换器,如果集合或数组需要 转换为数组或集合,前提是委托数组或集合 转换器也已注册(默认情况下注册)。ConverterSTSTDefaultConversionService
对于每个调用 to,源参数保证不为 null。如果转换失败,您可能会引发任何未经检查的异常。具体来说,它应该抛出 anto 报告无效的源值。 注意确保您的实现是线程安全的。convert(S)ConverterIllegalArgumentExceptionConverter
包中提供了几种转换器实现,作为 一种便利。其中包括从字符串到数字和其他常见类型的转换器。 下面的清单显示了类,这是一个典型的实现:core.convert.supportStringToIntegerConverter
3.4.2. 使用ConverterFactory
当您需要集中整个类层次结构的转换逻辑时 (例如,转换 FromtoObjects 时),可以实现,如以下示例所示:StringEnumConverterFactory
将 S 参数化为要转换的类型,将 R 参数化为定义的基本类型 可以转换为的类的范围。然后实施, 其中 T 是 R 的子类。getConverter(Class<T>)
以你为例:StringToEnumConverterFactory
3.4.3. 使用GenericConverter
当您需要复杂的实现时,请考虑使用接口。使用更灵活但键入较少的签名 比,支持在多个源和 目标类型。此外,还提供可用的源和目标字段 实现转化逻辑时可以使用的上下文。这样的上下文让 类型转换由字段批注或 字段签名。以下清单显示了以下接口定义:ConverterGenericConverterConverterGenericConverterGenericConverterGenericConverter
要实现 a,已返回支持的 源→目标类型对。然后实现以包含转换逻辑。源提供 访问保存正在转换的值的源字段。目标提供对要在其中设置转换值的目标字段的访问。GenericConvertergetConvertibleTypes()convert(Object, TypeDescriptor, TypeDescriptor)TypeDescriptorTypeDescriptor
ais 一个在 Java 数组之间转换的转换器的一个很好的例子 和一个集合。这种内省声明的字段 用于解析集合的元素类型的目标集合类型。这让每个 元素在 集合在目标字段上设置。GenericConverterArrayToCollectionConverter
用ConditionalGenericConverter
有时,您希望 a仅在特定条件成立时才运行。为 例如,您可能希望仅在存在特定批注时才运行 在目标字段中,或者您可能希望仅在特定方法运行时运行 (例如 amethod)在目标上定义,class.is 与接口的联合,允许您定义此类自定义匹配条件:ConverterConverterConverterstatic valueOfConditionalGenericConverterGenericConverterConditionalConverter
ais anthat 转换的一个很好的例子 在持久性实体标识符和实体引用之间。仅当目标实体类型声明静态查找器方法(例如,)时,此类匹配才可能匹配。您可以在实现中执行这样的查找器方法检查。ConditionalGenericConverterIdToEntityConverterIdToEntityConverterfindAccount(Long)matches(TypeDescriptor, TypeDescriptor)
3.4.4. 接口ConversionService
ConversionService定义一个统一的 API,用于在 运行。转换器通常在以下外观界面后面运行:
大多数实现也实现,其中 提供用于注册转换器的 SPI。在内部,实现委托给其注册的转换器以执行类型转换逻辑。ConversionServiceConverterRegistryConversionService
在 适用于 在大多数环境中使用。提供方便的工厂 创建通用配置。ConversionServicecore.convert.supportGenericConversionServiceConversionServiceFactoryConversionService
3.4.5. 配置ConversionService
Ais 一个无状态对象,设计用于在应用程序实例化 启动,然后在多个线程之间共享。在 Spring 应用程序中,您通常 为每个 Spring 容器 (OR) 配置 a实例。 弹簧拾起它,并在键入时使用它 转换需要由框架执行。您也可以将其注入到任何 bean 中并直接调用它。ConversionServiceConversionServiceApplicationContextConversionServiceConversionService
要使用 Spring 注册默认值,请添加以下 Bean 定义 与 Anof:ConversionServiceidconversionService
默认值可以在字符串、数字、枚举、集合、 地图和其他常见类型。用您的补充或覆盖默认转换器 自己的自定义转换器,设置属性。属性值可以实现 任何,,或接口。ConversionServiceconvertersConverterConverterFactoryGenericConverter
在Spring MVC应用程序中使用a也很常见。请参阅Spring MVC章节中的转换和格式化。ConversionService
在某些情况下,您可能希望在转换过程中应用格式。有关使用的详细信息,请参阅FormatterRegistrySPI。FormattingConversionServiceFactoryBean
3.4.6. 以编程方式使用ConversionService
要以编程方式使用 ainstance,您可以注入对 就像你对任何其他豆子一样。以下示例演示如何执行此操作:ConversionService
对于大多数用例,您可以使用指定的方法,但是 不适用于更复杂的类型,例如参数化元素的集合。 例如,如果要以编程方式将 aof转换为 aof, 您需要提供源和目标类型的正式定义。converttargetTypeListIntegerListString
幸运的是,提供了各种选项来使操作变得简单, 如以下示例所示:TypeDescriptor
请注意,自动注册以下转换器: 适用于大多数环境。这包括集合转换器、标量 转换器和基本到转换器。您可以注册相同的转换器 与 anyby 在类上使用静态方法。DefaultConversionServiceObjectStringConverterRegistryaddDefaultConvertersDefaultConversionService
值类型的转换器对数组和集合重用,因此 无需创建特定的转换器即可从 AOF 转换为 AOF,前提是标准集合处理是合适的。CollectionSCollectionT
3.5. 弹簧字段格式化
如上一节所述,core.convert是一个 通用型转换系统。它提供了一个统一的 API 作为 以及用于从一种类型实现转换逻辑的强类型SPI。 到另一个。Spring 容器使用此系统绑定 Bean 属性值。在 此外,Spring 表达式语言 (SpEL) 和使用此系统来 绑定字段值。例如,当 SpEL 需要强制 ato ato 完成尝试,系统执行强制。ConversionServiceConverterDataBinderShortLongexpression.setValue(Object bean, Object value)core.convert
现在考虑典型客户端环境的类型转换要求,例如 网络或桌面应用程序。在此类环境中,通常转换自以支持客户端回发过程,以及转换回 查看渲染过程。此外,您经常需要本地化值。越多 通用SPI不满足此类格式要求 径直。为了直接解决这些问题,Spring 3 引入了一个方便的 SPI,它 为客户端环境提供简单而可靠的实现替代方案。StringStringStringcore.convertConverterFormatterPropertyEditor
通常,当您需要实现通用类型时,可以使用 SPI。 转换逻辑 — 例如,用于在 A 和 A 之间进行转换。 当您在客户端环境(如 Web 应用程序),并且需要解析和打印本地化的字段值。为两个 SPI 提供统一的类型转换 API。Converterjava.util.DateLongFormatterConversionService
3.5.1. SPIFormatter
实现字段格式逻辑的 SPI 很简单且是强类型的。这 以下清单显示了接口定义:FormatterFormatter
Formatter从和构建块接口扩展。这 以下清单显示了这两个接口的定义:PrinterParser
若要创建自己的接口,请实现前面所示的接口。 参数化为要格式化的对象类型,例如,。实现打印实例的操作 显示在客户端区域设置中。实现从客户端区域设置返回的格式化表示形式中解析实例的操作。你应该抛出一个或一个解析尝试失败。拿 注意确保您的实现是线程安全的。FormatterFormatterTjava.util.Dateprint()Tparse()TFormatterParseExceptionIllegalArgumentExceptionFormatter
为了方便起见,子包提供了几种实现。 该包提供,和格式使用a的对象。 该包提供 ato 格式对象 一个。formatFormatternumberNumberStyleFormatterCurrencyStyleFormatterPercentStyleFormatterNumberjava.text.NumberFormatdatetimeDateFormatterjava.util.Datejava.text.DateFormat
下面是一个示例实现:DateFormatterFormatter
Spring 团队欢迎社区驱动的贡献。请参阅GitHub 要贡献的问题。Formatter
3.5.2. 注释驱动的格式化
可以按字段类型或注记配置字段格式。绑定 对 A 的注释,实现。以下 列表显示了接口的定义:FormatterAnnotationFormatterFactoryAnnotationFormatterFactory
要创建实现,请执行以下操作:
- 将参数化 A 作为要关联的字段 格式逻辑 — 例如。
annotationTypeorg.springframework.format.annotation.DateTimeFormat - 已返回可以使用批注的字段类型。
getFieldTypes() - 返回 a以打印带批注字段的值。
getPrinter()Printer - Havereturn ato parse afor an annotated field。
getParser()ParserclientValue
以下示例实现将注释绑定到格式化程序,以使数字样式或模式 指定:AnnotationFormatterFactory@NumberFormat
要触发格式设置,您可以使用@NumberFormat对字段进行批注,如下所示 示例显示:
格式注释 API
包中存在可移植格式注释 API。您可以使用 to 格式化字段,例如 and、andto format、,(用于毫秒时间戳)以及 JSR-310。org.springframework.format.annotation@NumberFormatNumberDoubleLong@DateTimeFormatjava.util.Datejava.util.CalendarLongjava.time
以下示例用于将 aas 格式化为 ISO 日期 (年-月-日):@DateTimeFormatjava.util.Date
3.5.3. SPIFormatterRegistry
这是一个用于注册格式化程序的SPI,并 适用于 大多数环境。您可以通过编程或声明方式配置此变体 作为春豆,例如通过使用。因为这个 实现也实现,可以直接配置它 用于 Spring's and the Spring Expression Language (SpEL)。FormatterRegistryFormattingConversionServiceFormatterRegistryFormattingConversionServiceFactoryBeanConversionServiceDataBinder
以下清单显示了 SPI:FormatterRegistry
如前面的清单所示,您可以按字段类型或批注注册格式化程序。
SPI 允许您集中配置格式规则,而不是 在控制器之间复制此类配置。例如,您可能希望 强制所有日期字段都以某种方式格式化,或者字段具有特定的格式 批注以某种方式格式化。使用共享,您可以定义 这些规则一次,只要需要格式化,就会应用它们。FormatterRegistryFormatterRegistry
3.5.4. SPIFormatterRegistrar
FormatterRegistrar是一个 SPI,用于通过 格式化程序注册表。以下清单显示了其接口定义:
在注册多个相关转换器时很有用,并且 给定格式类别(如日期格式)的格式化程序。它也可以是 在声明性注册不足的情况下很有用 - 例如,当格式化程序 需要在不同于其拥有者的特定字段类型下编制索引,当 注册 A/对。下一节提供了有关以下内容的更多信息 转换器和格式化程序注册。FormatterRegistrar<T>PrinterParser
3.5.5. 在 Spring MVC 中配置格式化
请参阅Spring MVC章节中的转换和格式化。
3.6. 配置全局日期和时间格式
默认情况下,未批注的日期和时间字段转换自 字符串通过使用样式。如果您愿意,可以通过以下方式更改此设置 定义您自己的全局格式。@DateTimeFormatDateFormat.SHORT
为此,请确保 Spring 不会注册默认格式化程序。相反,请注册 在以下人员的帮助下手动格式化程序:
-
org.springframework.format.datetime.standard.DateTimeFormatterRegistrar -
org.springframework.format.datetime.DateFormatterRegistrar
例如,以下 Java 配置注册全局格式:yyyyMMdd
如果您更喜欢基于 XML 的配置,则可以使用 a.以下示例演示如何执行此操作:FormattingConversionServiceFactoryBean
请注意,在 Web 中配置日期和时间格式时,还需要注意其他事项 应用。请参阅WebMVC转换和格式化或WebFlux 转换和格式化。
版本 5.3.23
















