Spring 框架的核心技术(三)
1.13. 环境抽象
环境界面 是集成在容器中的抽象,它对两个键进行建模 应用程序环境的各个方面:配置文件和属性。
概要文件是要注册到 Bean 定义的命名逻辑组 仅当给定配置文件处于活动状态时,容器。可以将 Bean 分配给配置文件 无论是在 XML 中定义还是使用批注定义。对象的作用与 与配置文件的关系在于确定哪些配置文件(如果有)当前处于活动状态, 以及默认情况下哪些配置文件(如果有)应处于活动状态。Environment
属性在几乎所有应用中都起着重要作用,可能源于 各种来源:属性文件、JVM 系统属性、系统环境 变量、JNDI、servlet 上下文参数、临时对象、对象等 上。对象与属性相关的角色是提供 用户具有方便的服务界面,用于配置属性源和解析 他们的属性。Properties
Map
Environment
1.13.1. Bean 定义配置文件
Bean 定义概要文件在核心容器中提供了一种机制,允许 在不同环境中注册不同的豆子。“环境”这个词, 对不同的用户可能意味着不同的事情,此功能可以帮助许多人 用例,包括:
- 在开发中处理内存中的数据源与查找相同的数据源 在 QA 或生产环境中来自 JNDI 的数据源。
- 仅在将应用程序部署到 性能环境。
- 为客户 A 与客户注册 Bean 的自定义实现 B 部署。
考虑实际应用中需要 a 的第一个用例。在测试环境中,配置可能类似于以下内容:DataSource
现在考虑如何将此应用程序部署到 QA 或生产环境中 环境,假设应用程序的数据源已注册 使用生产应用程序服务器的 JNDI 目录。乌尔豆 现在看起来像下面的列表:dataSource
问题是如何根据 当前环境。随着时间的推移,Spring用户已经设计了许多方法来 完成此操作,通常依赖于系统环境变量的组合 和包含解析令牌的 XML 语句 到正确的配置文件路径,具体取决于环境的值 变量。Bean 定义概要文件是一个核心容器功能,它提供 解决这个问题。
${placeholder}
如果我们概括前面特定于环境的 Bean 示例中所示的用例 定义,我们最终需要在 某些上下文,但在其他上下文中则不然。你可以说你想注册一个 情况 A 中 Bean 定义的某些配置文件和情况 A 中的不同配置文件 情况B.我们首先更新我们的配置以反映这种需求。
用@Profile
@Profile注释允许您指示组件符合注册条件 当一个或多个指定的配置文件处于活动状态时。使用前面的示例,我们 可以按如下方式重写配置:dataSource
配置文件字符串可能包含简单的配置文件名称(例如)或 配置文件表达式。配置文件表达式允许更复杂的配置文件逻辑 表示(例如,)。以下运算符在 配置文件表达式:production
production & us-east
-
!
:配置文件的逻辑“非” -
&
:配置文件的逻辑“和” -
|
:配置文件的逻辑“或”
您可以用作目的的元注释 创建自定义组合注释。以下示例定义了一个自定义批注,您可以将其用作直接替换:@Profile
@Production
@Profile("production")
@Profile
也可以在方法级别声明为仅包含一个特定的 Bean 的配置类(例如,对于特定 Bean 的替代变体),作为 以下示例显示:
XML Bean 定义概要文件
XML 对应项是元素的属性。我们前面的示例 可以在两个 XML 文件中重写配置,如下所示:profile
也可以避免在同一文件中拆分和嵌套元素, 如以下示例所示:
已约束为仅允许此类元素,例如 文件中的最后一个。这应该有助于提供灵活性而不会产生 XML 文件中杂乱无章。spring-bean.xsd
激活配置文件
现在我们已经更新了我们的配置,我们仍然需要指示 Spring 哪个 配置文件处于活动状态。如果我们现在开始我们的示例应用程序,我们将看到 抛出,因为容器找不到 春豆命名。NoSuchBeanDefinitionException
dataSource
激活配置文件可以通过多种方式完成,但最直接的是 它以编程方式针对可通过 a 获得的 API。以下示例演示如何执行此操作:Environment
ApplicationContext
此外,您还可以通过属性以声明方式激活配置文件,该属性可以通过系统环境指定 变量、JVM 系统属性、servlet 上下文参数,甚至作为 JNDI 中的条目(参见属性源抽象)。在集成测试中,活动 可以通过在模块中使用注释来声明配置文件(请参阅使用环境配置文件进行上下文配置)。spring.profiles.active
web.xml
@ActiveProfiles
spring-test
请注意,配置文件不是“非此即彼”的命题。您可以激活多个 一次配置文件。以编程方式,您可以向接受 varargs 的方法提供多个配置文件名称。以下示例 激活多个配置文件:setActiveProfiles()
String…
声明性地,可以接受以逗号分隔的配置文件名称列表, 如以下示例所示:spring.profiles.active
默认配置文件
默认配置文件表示默认启用的配置文件。考虑 以下示例:
如果没有活动配置文件,则创建配置文件。你可以看到这个 作为为一个或多个 Bean 提供缺省定义的一种方法。如果有的话 配置文件已启用,则默认配置文件不适用。dataSource
您可以使用 理论,声明性地,通过使用属性。setDefaultProfiles()
Environment
spring.profiles.default
1.13.2.抽象PropertySource
Spring 的抽象提供了对可配置的搜索操作 属性源的层次结构。请考虑以下列表:Environment
在前面的片段中,我们看到了一种高级方法,询问 Spring 的属性是否为 为当前环境定义。为了回答这个问题,对象执行 搜索一组属性源对象。A是对任何键值对源的简单抽象,并且 Spring 的标准环境配置了两个 PropertySource 对象——一个代表一组 JVM 系统属性。 () 和一个表示系统环境变量集 ().my-property
Environment
PropertySource
System.getProperties()
System.getenv()
具体来说,当你使用 时,如果系统属性或环境变量存在于 运行。StandardEnvironment
env.containsProperty("my-property")
my-property
my-property
最重要的是,整个机制是可配置的。也许您有一个自定义来源 要集成到此搜索中的属性。为此,请实施 并实例化您自己的并将其添加到集合中对于 当前。以下示例演示如何执行此操作:PropertySource
PropertySources
Environment
爪哇岛
科特林
在前面的代码中,已添加具有最高优先级的 搜索。如果它包含属性,则检测并返回该属性,以支持 任何其他财产。MutablePropertySourcesAPI 公开了许多方法,这些方法允许精确操作一组 属性源。MyPropertySource
my-property
my-property
PropertySource
1.13.3. 使用@PropertySource
@PropertySource注释为添加 ato Spring 提供了一种方便的声明性机制。PropertySource
Environment
给定一个包含键值对的文件, 以下类以这样的方式使用 调用返回:app.properties
testbean.name=myTestBean
@Configuration
@PropertySource
testBean.getName()
myTestBean
资源位置中存在的任何占位符都是 针对已针对 环境,如以下示例所示:${…}
@PropertySource
假设它已经存在于其中一个属性源中 已注册(例如,系统属性或环境变量),占位符为 解析为相应的值。如果没有,则使用 作为默认值。如果未指定默认值且无法解析属性,则引发 anis 。my.placeholder
default/path
IllegalArgumentException
1.13.4. 语句中的占位符解析
从历史上看,元素中占位符的值只能针对 JVM 系统属性或环境变量。情况已不再如此。因为 抽象集成在整个容器中,很容易 通过它路由占位符解析。这意味着您可以配置 以您喜欢的任何方式解决过程。您可以更改搜索的优先级 系统属性和环境变量或完全删除它们。您还可以添加您的 酌情拥有组合的属性来源。Environment
具体来说,无论属性定义在哪里,以下语句都有效,只要它在:customer
Environment
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。ApplicationContext
ApplicationContext
LoadTimeWeaverAware
1.15. 的附加功能ApplicationContext
如本章引言中所讨论的,该包提供了管理和操作 bean 的基本功能,包括在 程序化方式。该包添加了ApplicationContext接口,该接口除了扩展其他接口外,还扩展了该接口 在更多应用程序中提供附加功能的接口 面向框架的风格。许多人使用他们的完全 声明式时尚,甚至不是以编程方式创建它,而是依赖于 支持类,例如自动实例化 Java EE Web 应用程序正常启动过程的一部分。org.springframework.beans.factory
org.springframework.context
BeanFactory
ApplicationContext
ContextLoader
ApplicationContext
为了以更面向框架的风格增强功能,上下文 包还提供以下功能:BeanFactory
- 通过界面访问 i18n 风格的消息。
MessageSource
- 通过界面访问资源,例如 URL 和文件。
ResourceLoader
- 事件发布,即实现接口的 bean, 通过使用接口。
ApplicationListener
ApplicationEventPublisher
- 加载多个(分层)上下文,让每个上下文都集中在一个上下文上 特定层,例如应用程序的Web层,通过接口。
HierarchicalBeanFactory
1.15.1. 国际化使用MessageSource
该接口扩展了一个调用的接口, 因此,提供了国际化(“i18n”)功能。Spring 还提供了接口,可以分层解析消息。 这些接口共同为Spring 效果消息提供了基础。 分辨率。在这些接口上定义的方法包括:ApplicationContext
MessageSource
HierarchicalMessageSource
-
String getMessage(String code, Object[] args, String default, Locale loc)
:基本 用于从中检索消息的方法。未找到消息时 对于指定的区域设置,将使用默认消息。传入的任何参数都将成为 替换值,使用标准提供的功能 图书馆。MessageSource
MessageFormat
-
String getMessage(String code, Object[] args, Locale loc)
:本质上与 以前的方法,但有一个区别:无法指定默认消息。如果 找不到消息,AI 已抛出。NoSuchMessageException
-
String getMessage(MessageSourceResolvable resolvable, Locale locale)
:所有属性 上述方法中使用的也包装在名为的类中,可以与此方法一起使用。MessageSourceResolvable
加载 anis 时,它会自动搜索上下文中定义的 abean。豆子必须有名字。如果这样的豆子 找到,则对上述方法的所有调用都将委托给消息源。如果没有 找到消息源,尝试查找包含 同名豆。如果是这样,它将使用该豆子作为。如果找不到任何消息源,则实例化 emptyis 以便能够接受对 上面定义的方法。ApplicationContext
MessageSource
messageSource
ApplicationContext
MessageSource
ApplicationContext
DelegatingMessageSource
Spring 提供了三种实现,和。所有这些都实现为了做嵌套 消息。Theis 很少使用,但提供了编程方式 将消息添加到源。以下示例显示:MessageSource
ResourceBundleMessageSource
ReloadableResourceBundleMessageSource
StaticMessageSource
HierarchicalMessageSource
StaticMessageSource
ResourceBundleMessageSource
该示例假定您在类路径中调用和定义了三个资源包。任何解析消息的请求都是 以 JDK 标准方式处理,通过对象解析消息。对于 本示例的目的,假设上述两个资源包文件的内容 具体如下:format
exceptions
windows
ResourceBundle
下一个示例显示用于运行该功能的程序。 请记住,所有实现也是实现,因此可以强制转换为接口。MessageSource
ApplicationContext
MessageSource
MessageSource
上述程序的结果输出如下:
总而言之,theis 在一个调用的文件中定义,其中 存在于类路径的根目录中。底比亚的定义是指 通过其属性的资源包数。这三个文件 在列表中传递给属性作为文件存在于您的根目录 类路径和分别被调用、和。MessageSource
beans.xml
messageSource
basenames
basenames
format.properties
exceptions.properties
windows.properties
下一个示例显示传递给消息查找的参数。这些参数是 转换为对象并插入到查找消息的占位符中。String
调用该方法的结果输出如下所示:execute()
关于国际化(“i18n”),Spring 的各种实现遵循与标准 JDK 相同的语言环境解析和回退规则。简而言之,继续示例定义 以前,如果要解析针对英国 () 区域设置的邮件,则 将分别创建调用、和的文件。MessageSource
ResourceBundle
messageSource
en-GB
format_en_GB.properties
exceptions_en_GB.properties
windows_en_GB.properties
通常,区域设置解析由 应用。在以下示例中,(英国)消息所针对的区域设置 已解决是手动指定的:
运行上述程序的结果输出如下:
您还可以使用接口获取对已定义的任何内容的引用。在实现接口的 an 中定义的任何 Bean 都注入了 创建并配置 Bean 时的应用程序上下文。MessageSourceAware
MessageSource
ApplicationContext
MessageSourceAware
MessageSource
1.15.2. 标准和自定义事件
事件处理是通过类和接口提供的。如果将实现接口的 Bean 部署到上下文中,则每次发布到 bean 时,都会通知该 Bean。 本质上,这是标准的观察者设计模式。ApplicationContext
ApplicationEvent
ApplicationListener
ApplicationListener
ApplicationEvent
ApplicationContext
下表描述了 Spring 提供的标准事件:
Table 7. Built-in Events
事件 | 解释 |
| 在初始化或刷新时发布(例如,由 在界面上使用方法)。 这里,“初始化”意味着加载了所有 bean,检测到后处理器 bean 并激活,单例被预先实例化,并且对象是 准备使用。只要上下文尚未关闭,就可以触发刷新 多次,前提是选择的人实际上支持这样的 “热”刷新。例如,支持热刷新,但不支持。 |
| 当使用接口上的方法启动时发布。在这里,“已启动”表示 allbean 接收到明确的启动信号。通常,此信号用于重新启动 bean 在显式停止后,但它也可用于启动尚未停止的组件 配置为自动启动(例如,尚未启动的组件 初始化)。 |
| 当使用接口上的方法停止时发布。在这里,“停止”意味着所有豆子接收到明确的停止信号。停止的上下文可以通过调用重新启动。 |
| 使用方法关闭时发布 在接口上或通过 JVM 关闭挂钩。这里 “关闭”意味着所有单例豆将被销毁。一旦上下文关闭, 它已达到其生命周期的终点,无法刷新或重新启动。 |
| 一个特定于 Web 的事件,告知所有 bean HTTP 请求已得到服务。这 事件在请求完成后发布。此活动仅适用于 使用 Spring 的 Web 应用程序。 |
| 的子类添加了特定于 Servlet 的上下文信息。 |
您还可以创建和发布自己的自定义事件。以下示例显示 扩展 Spring 基类的简单类:ApplicationEvent
若要发布自定义项,请在 上调用该方法。通常,这是通过创建一个实现的类并将其注册为 Spring Bean 来完成的。以下 示例显示了这样的类:ApplicationEvent
publishEvent()
ApplicationEventPublisher
ApplicationEventPublisherAware
在配置时,Spring 容器会检测到实现并自动调用。实际上,传入的参数是 Spring 容器本身。您正在通过其接口与应用程序上下文进行交互。EmailService
ApplicationEventPublisherAware
setApplicationEventPublisher()
ApplicationEventPublisher
要接收自定义,您可以创建一个实现的类并将其注册为 Spring Bean。以下示例 显示这样的类:ApplicationEvent
ApplicationListener
请注意,它通常使用您的类型进行参数化 自定义事件(在前面的示例中)。这意味着该方法可以保持类型安全,避免任何向下转换的需要。 您可以根据需要注册任意数量的事件侦听器,但请注意,默认情况下,事件 侦听器同步接收事件。这意味着该方法 阻止,直到所有侦听器完成事件处理。这样做的一个优点 同步和单线程方法是,当侦听器收到事件时,它 如果事务上下文是 可用。如果需要另一种事件发布策略,请参阅 javadoc 对于 Spring 的应用程序事件多播器接口 和SimpleApplicationEventMulticaster实现,用于配置选项。ApplicationListener
BlockedListEvent
onApplicationEvent()
publishEvent()
以下示例显示了用于注册和配置每个 上面的类:
把它们放在一起,当憨豆的方法 调用,如果有任何应阻止的电子邮件,则发布 typeis 的自定义事件。Thebean被注册为anand接收,此时它可以 通知相关方。sendEmail()
emailService
BlockedListEvent
blockedListNotifier
ApplicationListener
BlockedListEvent
基于注释的事件侦听器
您可以使用注释在受管 Bean 的任何方法上注册事件侦听器。可以重写如下:@EventListener
BlockedListNotifier
方法签名再次声明它侦听的事件类型, 但是,这一次,使用灵活的名称并且没有实现特定的侦听器接口。 只要实际事件类型,也可以通过泛型缩小事件类型的范围 解析其实现层次结构中的泛型参数。
如果您的方法应该侦听多个事件,或者如果您想定义它而不使用 参数,事件类型也可以在注释本身上指定。这 以下示例演示如何执行此操作:
还可以使用属性添加其他运行时筛选 定义SpEL表达式的注释,该注释应匹配 实际调用特定事件的方法。condition
以下示例显示了如何重写我们的通知程序,使其仅在事件的属性等于时调用:content
my-event
每个表达式根据专用上下文进行评估。下表列出了 提供给上下文的项,以便您可以将它们用于条件事件处理:SpEL
Table 8. Event SpEL available metadata
名字 | 位置 | 描述 | 例 |
事件 | 根对象 | 实际的。 | |
参数数组 | 根对象 | 用于调用方法的参数(作为对象数组)。 | |
参数名称 | 评估背景 | 任何方法参数的名称。如果由于某种原因名称不可用 (例如,因为编译的字节码中没有调试信息),单个 参数也可以使用语法 其中代表 参数索引(从 0 开始)。 | |
请注意,这使您可以访问基础事件,即使您的方法 签名实际上是指已发布的任意对象。#root.event
如果需要发布一个事件作为处理另一个事件的结果,则可以更改 方法签名以返回应发布的事件,如以下示例所示:
该方法在它处理的每个方法上都会发布一个新内容。如果需要发布多个事件,可以返回 或事件数组。handleBlockedListEvent()
ListUpdateEvent
BlockedListEvent
Collection
异步侦听器
如果希望特定侦听器异步处理事件,则可以重用常规@Async支持。 以下示例演示如何执行此操作:
使用异步事件时请注意以下限制:
- 如果异步事件侦听器引发 ,则不会传播到 访客。有关更多详细信息,请参阅AsyncUncaughtExceptionHandler。
Exception
- 异步事件侦听器方法无法通过返回 价值。如果需要发布另一个事件作为处理的结果,请注入应用程序事件发布者以手动发布事件。
对侦听器进行排序
如果需要先调用一个侦听器,然后再调用另一个侦听器,则可以将注释添加到方法声明中,如以下示例所示:@Order
通用事件
您还可以使用泛型来进一步定义事件的结构。请考虑使用 anwhereis 创建的实际实体的类型。例如,您 可以创建以下侦听器定义以仅接收 a:EntityCreatedEvent
T
EntityCreatedEvent
Person
由于类型擦除,仅当触发的事件解析泛型时,这才有效 事件侦听器筛选的参数(即类似参数)。class PersonCreatedEvent extends EntityCreatedEvent
在某些情况下,如果所有事件都遵循相同的内容,这可能会变得非常乏味 结构(如前面示例中的事件)。在这种情况下, 你可以实现引导框架超越运行时的内容 环境提供。以下事件演示如何执行此操作:ResolvableTypeProvider
1.15.3. 方便访问低级资源
为了以最佳方式使用和理解应用程序上下文,您应该熟悉 你自己与春天的抽象,如参考资料中所述。Resource
应用程序上下文是一个,可用于加载对象。 A本质上是JDKclass的一个功能更丰富的版本。 事实上,thewrap 的实现是一个实例,其中 适当。Acan 从几乎任何位置获取低级资源 透明时尚,包括从类路径、文件系统位置、任何位置 可以使用标准 URL 和其他一些变体进行描述。如果资源位置 字符串是一条没有任何特殊前缀的简单路径,这些资源来自哪里 特定于并适合实际的应用程序上下文类型。ResourceLoader
Resource
Resource
java.net.URL
Resource
java.net.URL
Resource
您可以配置部署到应用程序上下文中的 Bean 以实现特殊的 回调接口,,在 自动回调 初始化时间与应用程序上下文本身作为传入。 还可以公开用于访问静态资源的类型属性。 它们像任何其他属性一样注入其中。您可以将这些属性指定为简单路径,并依赖于这些文本的自动转换 字符串到实际对象,当部署 Bean 时。ResourceLoaderAware
ResourceLoader
Resource
Resource
String
Resource
提供给构造函数的一个或多个位置路径实际上是 资源字符串,并以简单形式根据特定 上下文实现。例如对待一个简单的 作为类路径位置的位置路径。您还可以使用位置路径(资源字符串) 使用特殊前缀强制从类路径或 URL 加载定义, 无论实际上下文类型如何。ApplicationContext
ClassPathXmlApplicationContext
1.15.4. 应用程序启动跟踪
管理Spring应用程序的生命周期,并提供丰富的 围绕组件的编程模型。因此,复杂的应用程序可以具有相同的功能 复杂的组件图和启动阶段。ApplicationContext
使用特定指标跟踪应用程序启动步骤有助于了解位置 在启动阶段花费了时间,但它也可以用作更好的方法 从整体上了解上下文生命周期。
(及其子类)与 an 一起检测,它收集有关各个启动阶段的数据:AbstractApplicationContext
ApplicationStartup
StartupStep
- 应用程序上下文生命周期(基本包扫描、配置类管理)
- Bean 生命周期(实例化、智能初始化、后处理)
- 应用程序事件处理
下面是以下检测的示例:AnnotationConfigApplicationContext
应用程序上下文已通过多个步骤进行检测。 记录后,可以使用特定工具收集,显示和分析这些启动步骤。 有关现有启动步骤的完整列表,您可以查看专用附录部分。
默认实现是无操作变体,以实现最小的开销。 这意味着默认情况下,在应用程序启动期间不会收集任何指标。 Spring 框架附带了一个使用 Java Flight Recorder 跟踪启动步骤的实现:要使用此变体,您必须配置它的实例 一旦它被创建出来。ApplicationStartup
FlightRecorderApplicationStartup
ApplicationContext
如果开发人员提供自己的子类,或者他们希望收集更精确的数据,他们也可以使用该基础结构。ApplicationStartup
AbstractApplicationContext
要开始收集自定义,组件可以直接从应用程序上下文中获取实例,使其组件实现, 或要求在任何注射点上的类型。StartupStep
ApplicationStartup
ApplicationStartupAware
ApplicationStartup
1.15.5. 方便的应用程序Web 应用程序的上下文实例化
例如,您可以使用 a.当然,您也可以创建实例 通过使用其中一个实现以编程方式。ApplicationContext
ContextLoader
ApplicationContext
ApplicationContext
您可以使用 anby 注册,因为 以下示例显示:ApplicationContext
ContextLoaderListener
侦听器检查参数。如果参数没有 存在,侦听器用作默认值。当 参数确实存在,侦听器通过使用预定义的参数来分隔 分隔符(逗号、分号和空格),并将值用作位置 搜索应用程序上下文。还支持 Ant 样式路径模式。 示例是(对于名称以 和 结尾的所有文件,驻留在目录中)和(对于任何子目录中的所有此类文件)。contextConfigLocation
/WEB-INF/applicationContext.xml
String
/WEB-INF/*Context.xml
Context.xml
WEB-INF
/WEB-INF/**/*Context.xml
WEB-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。ApplicationContext
ApplicationContext
ApplicationContext
RAR 部署非常适合不需要 HTTP 入口点但不需要 HTTP 入口点但 而是仅包含消息终结点和计划作业。在这种情况下,豆子可以 使用应用程序服务器资源,例如 JTA 事务管理器和 JNDI 绑定的 JDBC 实例和 JMS实例,还可以注册 该平台的JMX服务器 - 全部通过Spring的标准事务管理和JNDI。 和JMX支持设施。应用程序组件也可以与应用程序交互 服务器的JCA通过Spring的抽象。DataSource
ConnectionFactory
WorkManager
TaskExecutor
请参阅SpringContextResourceAdapter类的 javadoc,了解 RAR 部署中涉及的配置详细信息。
对于将Spring ApplicationContext简单部署为Java EE RAR文件:
- 包 所有应用程序类都放入一个 RAR 文件(这是一个标准 JAR 文件,具有不同的 文件扩展名)。
- 将所有必需的库 JAR 添加到 RAR 存档的根目录中。
- 添加部署描述符(如SpringContextResourceAdapter 的 javadoc 所示) 以及相应的 Spring XML Bean 定义文件(通常)。
META-INF/ra.xml
META-INF/applicationContext.xml
- 将生成的 RAR 文件拖放到您的 应用程序服务器的部署目录。
1.16. 接口BeanFactory
TheAPI 为 Spring 的 IoC 功能提供了底层基础。 它的具体合约主要用于与Spring的其他部分集成,并且 相关第三方框架及其实现 是更高级别的容器中的密钥委托。BeanFactory
DefaultListableBeanFactory
GenericApplicationContext
BeanFactory
相关接口(如,,)是其他框架组件的重要集成点。 通过不需要任何注释甚至反射,它们允许非常有效的 容器与其组件之间的交互。应用程序级 bean 可以 使用相同的回调接口,但通常更喜欢声明性依赖项 而是通过注释或编程配置进行注入。BeanFactoryAware
InitializingBean
DisposableBean
请注意,coreAPI 级别及其实现不会对配置格式或任何 要使用的组件注释。所有这些口味都是通过扩展进入的 (如桑德)和 对共享对象进行操作作为核心元数据表示形式。 这就是Spring的容器如此灵活和可扩展的本质。BeanFactory
DefaultListableBeanFactory
XmlBeanDefinitionReader
AutowiredAnnotationBeanPostProcessor
BeanDefinition
1.16.1.或?BeanFactory
ApplicationContext
本节介绍容器级别之间的差异以及对引导的影响。BeanFactory
ApplicationContext
除非你有充分的理由不这样做,否则你应该使用 an,它的子类作为自定义引导的常见实现。这些是主要条目 指向 Spring 的核心容器,用于所有常见目的:加载配置 文件, 触发类路径扫描, 以编程方式注册 Bean 定义 和带注释的类,以及(从 5.0 开始)注册函数式 Bean 定义。ApplicationContext
GenericApplicationContext
AnnotationConfigApplicationContext
因为 a 包含 a 的所有功能,所以它是 通常建议在平原上,除非已满 需要控制 Bean 加工。在一个(如实现)中,检测到几种 bean 按照约定(即按 Bean 名称或按 Bean 类型 — 特别是后处理器), 而普通人对任何特殊的豆子都不可知。ApplicationContext
BeanFactory
BeanFactory
ApplicationContext
GenericApplicationContext
DefaultListableBeanFactory
对于许多扩展容器功能,例如注释处理和 AOP 代理, BeanPostProcessor扩展点是必不可少的。 如果您仅使用普通处理器,则此类后处理器不会 默认情况下被检测并激活。这种情况可能会令人困惑,因为 您的 Bean 配置实际上没有任何问题。相反,在这种情况下, 容器需要通过其他设置完全引导。DefaultListableBeanFactory
下表列出了 and 接口和实现提供的功能。BeanFactory
ApplicationContext
Table 9. Feature Matrix
特征 | | |
Bean 实例化/连接 | 是的 | 是的 |
集成的生命周期管理 | 不 | 是的 |
自动注册 | 不 | 是的 |
自动注册 | 不 | 是的 |
便捷的访问(用于国际化) | 不 | 是的 |
内置发布机制 | 不 | 是的 |
要显式注册 Bean 后处理器, 您需要以编程方式调用,如以下示例所示:DefaultListableBeanFactory
addBeanPostProcessor
要应用于平原, 您需要调用 itsMethod,如以下示例所示:BeanFactoryPostProcessor
DefaultListableBeanFactory
postProcessBeanFactory
在这两种情况下,显式注册步骤都不方便,即 为什么各种变体比普通的 Spring-Spring支持的应用程序更受欢迎,尤其是当 依靠实例进行扩展 典型企业设置中的容器功能。ApplicationContext
DefaultListableBeanFactory
BeanFactoryPostProcessor
BeanPostProcessor
2. 资源
本章介绍 Spring 如何处理资源以及如何在 春天。它包括以下主题:
- 介绍
- 资源接口
- 内置资源实现
- 资源加载器接口
- 资源模式解析器接口
- 资源加载器感知接口
- 作为依赖项的资源
- 应用程序上下文和资源路径
2.1. 简介
Java 的标准类和各种 URL 前缀的标准处理程序, 不幸的是,不足以满足所有获得低级资源的机会。为 例如,没有可用于访问 需要从类路径或相对于 a 获取的资源。虽然可以为专用前缀注册新的处理程序(类似于前缀的现有处理程序,例如),但这通常是 相当复杂,界面仍然缺乏一些理想的功能, 例如用于检查所指向的资源是否存在的方法。java.net.URL
URL
ServletContext
URL
http:
URL
2.2. 界面Resource
位于包装中的弹簧接口是 旨在成为更强大的接口,用于抽象对低级资源的访问。这 以下列表提供了界面的概述。有关更多详细信息,请参阅资源javadoc。Resource
org.springframework.core.io.
Resource
如接口的定义所示,它扩展了接口。以下清单显示了接口的定义:Resource
InputStreamSource
InputStreamSource
界面中一些最重要的方法是:Resource
-
getInputStream()
:查找并打开资源,返回 从资源读取。预计每次调用都会返回一个新的。调用方负责关闭流。InputStream
InputStream
-
exists()
:返回指示此资源是否实际存在于 物理形式。boolean
-
isOpen()
:返回指示此资源是否表示句柄 与开放的溪流。如果,无法多次读取并且 必须只读取一次,然后关闭以避免资源泄漏。返回 所有常用的资源实现,但 除外。boolean
true
InputStream
false
InputStreamResource
-
getDescription()
:返回此资源的说明,用于错误 使用资源时的输出。这通常是完全限定的文件名或 资源的实际 URL。
其他方法允许您获取表示 资源(如果基础实现兼容并支持 功能)。URL
File
接口的某些实现还实现了扩展的WritableResource接口 支持写入的资源。Resource
Spring 本身广泛使用抽象,作为 需要资源时的许多方法签名。某些 Spring API 中的其他方法 (例如各种实现的构造函数)以朴素或简单的形式用于创建适合 该上下文实现或通过路径上的特殊前缀,让 调用方指定必须创建和使用特定实现。Resource
ApplicationContext
String
Resource
String
Resource
虽然接口在 Spring 和 Spring 中大量使用,但它实际上是 非常方便在您自己的代码中单独用作通用实用程序类,以便访问 资源,即使你的代码不知道或不关心 Spring 的任何其他部分。 虽然这会将您的代码与 Spring 耦合,但它实际上只将其耦合到这一小组 实用程序类,作为更有能力的替代和可以是 被认为等同于您用于此目的的任何其他库。Resource
URL
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访问资源等。java.net.URL
String
file:
https:
ftp:
由 Java 代码显式使用构造函数创建的 Ais 但在调用采用用于表示路径的参数的 API 方法时,通常会隐式创建。对于后一种情况,JavaBeans最终决定创建哪种类型的of。如果路径字符串包含 众所周知(对属性编辑器,即)前缀(例如),它创建一个 适合该前缀。但是,如果它无法识别 前缀,它假定字符串是标准 URL 字符串并创建一个。UrlResource
UrlResource
String
PropertyEditor
Resource
classpath:
Resource
UrlResource
2.3.2. ClassPathResource
此类表示应从类路径获取的资源。它使用 线程上下文类装入器、给定类装入器或给定的类 加载资源。
此实现支持解析为 aif 类路径 资源驻留在文件系统中,但对于驻留在 jar 并且尚未扩展(通过 servlet 引擎或任何环境) 到文件系统。为了解决这个问题,各种实现始终支持 分辨率为 A。Resource
java.io.File
Resource
java.net.URL
AI 由 Java 代码显式使用构造函数创建,但在调用采用用于表示路径的参数的 API 方法时,通常是隐式创建的。对于后一种情况,JavaBeans识别字符串路径上的特殊前缀和 在这种情况下创建。ClassPathResource
ClassPathResource
String
PropertyEditor
classpath:
ClassPathResource
2.3.3. FileSystemResource
这是句柄的实现。它还支持句柄,应用Spring的标准基于字符串的路径。 转换,但通过 API 执行所有操作。对于纯基支持,请使用 arather.support resolution as aand as a。Resource
java.io.File
java.nio.file.Path
java.nio.file.Files
java.nio.path.Path
PathResource
FileSystemResource
File
URL
2.3.4. PathResource
这是句柄的实现,执行所有 通过 API 进行操作和转换。它支持分辨率作为 aand 由于 AAAND 还有效地实现了 extendedinterface.is 一个纯粹的替代方案 不同的行为。Resource
java.nio.file.Path
Path
File
URL
WritableResource
PathResource
java.nio.path.Path
FileSystemResource
createRelative
2.3.5. ServletContextResource
这是对解释 相关 Web 应用程序的根目录中的相对路径。Resource
ServletContext
它始终支持流访问和 URL 访问,但仅允许访问 当 Web 应用程序存档展开并且资源在物理上位于 文件系统。它是否已扩展并在文件系统上或被访问 直接从JAR或其他地方(如数据库)实际上是 依赖于 Servlet 容器。java.io.File
2.3.6. InputStreamResource
Anis aimplementation为一个给定的。它 仅当没有适用的特定实现时,才应使用。在 特别是,在可能的情况下首选任何基于文件的实现。InputStreamResource
Resource
InputStream
Resource
ByteArrayResource
Resource
与其他实现相比,这是 已打开的资源。因此,它返回自。如果出现以下情况,请勿使用它 您需要将资源描述符保留在某个位置,或者如果您需要读取流 多次。Resource
true
isOpen()
2.3.7. ByteArrayResource
这是给定字节数组的实现。它为给定的字节数组创建 a。Resource
ByteArrayInputStream
它对于从任何给定的字节数组加载内容很有用,而不必求助于 一次性使用。InputStreamResource
2.4. 界面ResourceLoader
该接口旨在由可以返回的对象实现 (即加载)实例。以下清单显示了接口定义:ResourceLoader
Resource
ResourceLoader
所有应用程序上下文都实现接口。因此,所有 应用程序上下文可用于获取实例。ResourceLoader
Resource
调用特定应用程序上下文和位置路径时 指定没有特定的前缀,你得到的 atype 是 适用于该特定应用程序上下文。例如,假设以下内容 针对实例运行的代码片段:getResource()
Resource
ClassPathXmlApplicationContext
针对 a,该代码返回 a。如果 对 ainstance 运行相同的方法,它会 返回 A。对于 a,它将返回 a。它同样会为每个上下文返回适当的对象。ClassPathXmlApplicationContext
ClassPathResource
FileSystemXmlApplicationContext
FileSystemResource
WebApplicationContext
ServletContextResource
因此,您可以以适合特定应用程序的方式加载资源 上下文。
另一方面,您也可以强制使用,无论 应用程序上下文类型,通过指定特殊前缀,如下所示 示例显示:ClassPathResource
classpath:
同样,您可以通过指定任何标准前缀来强制使用 ato。以下示例使用和前缀:UrlResource
java.net.URL
file
https
下表总结了将对象转换为对象的策略:String
Resource
Table 10. Resource strings
前缀 | 例 | 解释 |
类路径: | | 从类路径加载。 |
文件: | | 从文件系统加载为 a。另请参阅文件系统资源警告。 |
https: | | 加载为 a。 |
(无) | | 取决于标的物。 |
2.5. 界面ResourcePatternResolver
接口是接口的扩展 它定义了解析位置模式的策略(例如,Ant 样式路径) 模式)进入对象。ResourcePatternResolver
ResourceLoader
Resource
如上所示,此接口还定义了特殊资源前缀 对于类路径中的所有匹配资源。请注意,资源位置为 在这种情况下,预期为没有占位符的路径 — 例如,。JAR 文件或类路径中的不同目录可以 包含具有相同路径和相同名称的多个文件。有关更多详细信息,请参阅应用程序上下文构造函数资源路径中的通配符及其小节 在通配符支持上,带有源前缀。classpath*:
classpath*:/config/beans.xml
classpath*:
可以检查传入的(例如,通过ResourceLoaderAware语义提供的传入)是否 它也实现了这个扩展接口。ResourceLoader
PathMatchingResourcePatternResolver
是一个可用的独立实现 在阿南德之外也用于 填充豆 properties.is 能够 将指定的资源位置路径解析为一个或多个匹配对象。 源路径可以是与目标具有一对一映射的简单路径,也可以包含特殊前缀和/或内部 Ant 风格的正则表达式(使用 Spring 的实用程序匹配)。后者都是有效的 通配符。ApplicationContext
ResourceArrayPropertyEditor
Resource[]
PathMatchingResourcePatternResolver
Resource
Resource
classpath*:
org.springframework.util.AntPathMatcher
2.6. 界面ResourceLoaderAware
接口是一个特殊的回调接口,用于标识 希望提供参考的组件。以下列表 显示了接口的定义:ResourceLoaderAware
ResourceLoader
ResourceLoaderAware
当类实现和部署到应用程序上下文中时 (作为 Spring 管理的 bean),它被应用程序识别为 上下文。然后,应用程序上下文调用, 提供自身作为参数(请记住,Spring 中的所有应用程序上下文都实现了 界面)。ResourceLoaderAware
ResourceLoaderAware
setResourceLoader(ResourceLoader)
ResourceLoader
由于 anis a,bean 还可以实现接口并使用提供的应用程序上下文直接到 加载资源。但是,一般来说,如果您只需要使用专用界面,最好使用专用界面。代码将仅与资源加载耦合 接口(可以被认为是一个实用程序接口),而不是整个 Springinterface。ApplicationContext
ResourceLoader
ApplicationContextAware
ResourceLoader
ApplicationContext
在应用程序组件中,您还可以依赖自动布线 实现接口的替代方法。传统和自动配线模式(如自动配线协作者中所述) 能够为 构造函数参数或 分别是二传手方法参数。实现更大的灵活性(包括能够 自动连线字段和多参数方法),请考虑使用基于注释的 自动接线功能。在这种情况下,它们会自动连接到一个字段中, 构造函数参数,或期望类型尽可能长的方法参数 因为有问题的字段、构造函数或方法带有注释。 有关详细信息,请参阅使用@Autowired。ResourceLoader
ResourceLoaderAware
constructor
byType
ResourceLoader
ResourceLoader
ResourceLoader
@Autowired
2.7. 资源作为依赖关系
如果 Bean 本身要通过某种排序确定并提供资源路径 在动态过程中,Bean 使用 theorInterface 加载资源可能是有意义的。例如,考虑加载 某种模板,其中所需的特定资源取决于 用户的角色。如果资源是静态的,则完全消除接口(或接口)的使用是有意义的,具有 Bean 公开了它需要的属性,并期望它们被注入其中。ResourceLoader
ResourcePatternResolver
ResourceLoader
ResourcePatternResolver
Resource
然后注入这些属性变得微不足道的是,所有应用程序上下文 注册并使用特殊的JavaBeans,它可以转换路径 到对象。例如,下面的类具有类型的属性。PropertyEditor
String
Resource
MyBean
template
Resource
在 XML 配置文件中,可以使用简单的 该资源的字符串,如以下示例所示:template
请注意,资源路径没有前缀。因此,由于应用程序上下文 本身将用作,资源通过 a、a 或 a 加载,具体取决于 应用程序上下文的确切类型。ResourceLoader
ClassPathResource
FileSystemResource
ServletContextResource
如果需要强制使用特定类型,可以使用前缀。这 以下两个示例演示如何强制 Aand A( 后者用于访问文件系统中的文件):Resource
ClassPathResource
UrlResource
如果重构类以用于注释驱动的配置,则 路径可以存储在名为 — 例如, 在提供给 Spring 的属性文件中(参见环境抽象)。然后,可以使用属性占位符通过注释引用模板路径(请参阅使用@Value)。春天会 检索模板路径的值作为字符串,并特殊遗嘱 将字符串转换为要注入到构造函数中的对象。 下面的示例演示如何实现此目的。MyBean
myTemplate.txt
template.path
Environment
@Value
PropertyEditor
Resource
MyBean
如果我们想支持在同一路径下发现多个模板 类路径中的位置(例如,在类路径中的多个 JAR 中)我们可以 使用 specialprefix 和通配符将 akey 定义为。如果我们按如下方式重新定义类, Spring 会将模板路径模式转换为对象数组 可以注入到构造函数中。classpath*:
templates.path
classpath*:/config/templates/*.txt
MyBean
Resource
MyBean
爪哇岛
科特林
2.8. 应用程序上下文和资源路径
本节介绍如何使用资源(包括快捷方式)创建应用程序上下文 适用于 XML、如何使用通配符以及其他详细信息。
2.8.1. 构建应用程序上下文
应用程序上下文构造函数(用于特定应用程序上下文类型)通常 将字符串或字符串数组作为资源的位置路径,例如 构成上下文定义的 XML 文件。
当这样的位置路径没有前缀时,从 该路径和用于加载 Bean 定义取决于并且适用于 特定的应用程序上下文。例如,请考虑以下示例,该示例将创建一个:Resource
ClassPathXmlApplicationContext
Bean 定义是从类路径加载的,因为 ais 使用。但是,请考虑以下示例,该示例将创建一个:ClassPathResource
FileSystemXmlApplicationContext
现在,从文件系统位置加载 Bean 定义(在本例中,相对于 当前工作目录)。
请注意,在 位置路径覆盖默认类型“已创建”以装入 Bean 定义。请考虑以下示例:classpath
Resource
使用 从类路径加载 Bean 定义。 但是,它仍然是一个。如果随后将其用作 ,则任何不带前缀的路径仍被视为文件系统路径。FileSystemXmlApplicationContext
FileSystemXmlApplicationContext
ResourceLoader
构造实例 — 快捷方式ClassPathXmlApplicationContext
公开许多构造函数以启用 方便的实例化。基本思想是,您只能提供一个字符串数组 仅包含 XML 文件本身的文件名(不带前导路径) 信息),并提供 a。然后派生 来自所提供类的路径信息。ClassPathXmlApplicationContext
Class
ClassPathXmlApplicationContext
请考虑以下目录布局:
以下示例显示了 ainstance 如何由 在文件名和(位于 类路径)可以实例化:ClassPathXmlApplicationContext
services.xml
repositories.xml
请参阅ClassPathXmlApplicationContextjavadoc 以获取有关各种构造函数的详细信息。
2.8.2. 应用程序上下文构造函数资源路径中的通配符
应用程序上下文构造函数值中的资源路径可以是简单路径(如 如前所示),每个目标都有一个到目标器的一对一映射, 或者,可以包含特殊前缀或内部 Ant 样式模式 (通过使用 Spring 的实用程序进行匹配)。后者都是有效的 通配符。Resource
classpath*:
PathMatcher
此机制的一个用途是当您需要执行组件样式的应用程序组装时。都 组件可以将上下文定义片段发布到已知位置路径,并且, 当使用前缀相同的路径创建最终应用程序上下文时,将自动选取所有组件片段。classpath*:
请注意,此通配符特定于在应用程序上下文中使用资源路径 构造函数(或直接使用实用程序类层次结构时)并且 在施工时解决。它与类型本身无关。 您不能使用前缀来构造实际值,因为 一个资源一次只指向一个资源。PathMatcher
Resource
classpath*:
Resource
蚂蚁风格图案
路径位置可以包含 Ant 样式模式,如以下示例所示:
当路径位置包含 Ant 样式模式时,解析器将遵循更复杂的模式 尝试解析通配符的过程。它产生一条通往 最后一个非通配符段并从中获取 URL。如果此网址不是网址或 特定于容器的变体(例如在 WebLogic、WebSphere 等中), AIS从中获取并用于通过遍历通配符来解析通配符 文件系统。对于 jar URL,解析器要么从中获取 a,要么手动解析 jar URL,然后遍历 用于解析通配符的 JAR 文件的内容。Resource
jar:
zip:
wsjar
java.io.File
java.net.JarURLConnection
对可移植性的影响
如果指定的路径已经是 URL(隐式,因为基是文件系统的路径,或者显式地),则通配符保证 以完全便携的方式工作。file
ResourceLoader
如果指定的路径是位置,则解析程序必须获取最后一个 通过调用的非通配符路径段 URL。从此 只是路径的一个节点(不是末尾的文件),它实际上是未定义的(在javadoc中)在这种情况下返回的URL类型。在实践中, 它始终表示目录(类路径资源 解析为文件系统位置)或某种 jar URL(类路径资源所在的位置 解析为 JAR 位置)。尽管如此,此操作仍存在可移植性问题。classpath
Classloader.getResource()
ClassLoader
java.io.File
如果为最后一个非通配符段获取了 jar URL,则解析器必须能够 从中获取或手动解析 jar URL,以便能够 遍历 JAP 的内容并解析通配符。这在大多数环境中都有效 但在其他方面失败,我们强烈建议资源的通配符解析 来自 jar 在您依赖它之前,请在您的特定环境中进行彻底测试。java.net.JarURLConnection
前缀classpath*:
构造基于 XML 的应用程序上下文时,位置字符串可以使用 特殊前缀,如以下示例所示:classpath*:
此特殊前缀指定与给定名称匹配的所有类路径资源 必须获得(在内部,这基本上是通过调用 to 发生的),然后合并以形成最终应用程序 上下文定义。ClassLoader.getResources(…)
您还可以将前缀与模式组合在 位置路径的其余部分(例如,)。在此 在这种情况下,解决策略相当简单:Acall是 在最后一个非通配符路径段上使用,以获取 类装入器层次结构,然后,关闭每个资源,相同的分辨率 前面描述的策略用于通配符子路径。classpath*:
PathMatcher
classpath*:META-INF/*-beans.xml
ClassLoader.getResources()
PathMatcher
与通配符有关的其他注意事项
请注意,当与 Ant 风格的模式结合使用时,只能工作 在模式开始之前至少有一个根目录,除非实际 目标文件驻留在文件系统中。这意味着模式(例如可能不会从jar文件的根目录中检索文件,而只是 从展开目录的根目录。classpath*:
classpath*:*.xml
Spring 检索类路径条目的能力源于 JDK 的方法,该方法只返回 空字符串(指示要搜索的潜在根)。Spring 评估 jar 文件中的运行时配置和清单 以及,但这并不能保证导致可移植行为。ClassLoader.getResources()
URLClassLoader
java.class.path
蚂蚁风格的模式与资源不能保证找到匹配 资源(如果要搜索的根包在多个类路径位置中可用)。 请考虑以下资源位置示例:classpath:
现在考虑一个 Ant 风格的路径,有人可能会使用它来尝试查找该文件:
这样的资源可能只存在于类路径中的一个位置,但是当路径如 前面的示例用于尝试解决它,解析器在(第一个) 返回的网址。如果此基本包节点存在于 多个位置,所需的资源可能不存在于第一个位置 找到位置。因此,在这种情况下,您应该更喜欢使用 相同的 Ant 样式模式,它搜索包含基本包的所有类路径位置:getResource("com/mycompany");
ClassLoader
classpath*:
com.mycompany
classpath*:com/mycompany/**/service-context.xml
2.8.3.注意事项FileSystemResource
A那不附加到一个(那 是,当 AI 不是实际时)对待 绝对和相对路径如您所期望。相对路径相对于 当前工作目录,而绝对路径相对于 文件系统。FileSystemResource
FileSystemApplicationContext
FileSystemApplicationContext
ResourceLoader
然而,出于向后兼容性(历史)的原因,当是时,这会发生变化。强制所有附加实例 将所有位置路径视为相对路径,无论它们是否以前导斜杠开头。 实际上,这意味着以下示例是等效的:FileSystemApplicationContext
ResourceLoader
FileSystemApplicationContext
FileSystemResource
以下示例也是等效的(即使它们不同是有意义的,作为一个 情况是相对的,另一个是绝对的):
实际上,如果您需要真正的绝对文件系统路径,则应避免使用 绝对路径与索兰德 强制使用 aby 使用 URL 前缀。以下示例 演示如何执行此操作:FileSystemResource
FileSystemXmlApplicationContext
UrlResource
file:
3. 验证、数据绑定和类型转换
将验证视为业务逻辑有利有弊,Spring 提供 一种不排除其中任何一个的验证(和数据绑定)设计。 具体而言,验证不应绑定到 Web 层,而应易于本地化, 并且应该可以插入任何可用的验证器。考虑到这些关切, 弹簧提供了既基本又非常可用的契约 在应用程序的每一层中。Validator
数据绑定对于让用户输入动态绑定到域非常有用 应用程序的模型(或用于处理用户输入的任何对象)。春天 提供了恰如其分的名字来做到这一点。和 弥补 包装,主要用于但不 仅限于 Web 图层。DataBinder
Validator
DataBinder
validation
这是Spring框架中的一个基本概念,并且在很多中使用 的地方。但是,您可能不需要直接使用。但是,由于这是参考文档,因此我们认为某些解释 可能是有序的。我们在本章中解释,因为,如果你是 要使用它,您最有可能在尝试将数据绑定到对象时这样做。BeanWrapper
BeanWrapper
BeanWrapper
Spring's和较低级别都使用实现来解析和格式化属性值。Theandtypes是JavaBeans规范的一部分,也是 在本章中解释。Spring 3 引入了一个软件包,它提供了一个 通用类型转换工具,以及更高级别的“格式”包 设置 UI 字段值的格式。您可以将这些包用作实现的更简单的替代方法。本章还将讨论它们。DataBinder
BeanWrapper
PropertyEditorSupport
PropertyEditor
PropertyEditorSupport
core.convert
PropertyEditorSupport
Spring 通过设置基础结构和适配器支持 Java Bean 验证 春天自己的合同。应用程序可以全局启用一次 Bean 验证, 如Java Bean 验证中所述,并将其专门用于所有验证 需要。在 Web 层中,应用程序可以进一步注册每个控制器本地 Spring实例,如配置DataBinder 中所述,它可以 对于插入自定义验证逻辑很有用。Validator
Validator
DataBinder
3.1. 使用 Spring 的验证器接口进行验证
Spring 具有可用于验证对象的接口。该接口通过使用对象来工作,以便在验证时, 验证程序可以向对象报告验证失败。Validator
Validator
Errors
Errors
请考虑以下小型数据对象示例:
下一个示例通过实现 以下两种接口方法:Person
org.springframework.validation.Validator
-
supports(Class)
:这可以验证所提供的实例吗?Validator
Class
-
validate(Object, org.springframework.validation.Errors)
:验证给定对象 并且,在出现验证错误的情况下,将那些注册到给定对象中。Errors
实现 ay 相当简单,特别是当你知道 Spring 框架也提供的辅助类时。以下 示例实现for实例:Validator
ValidationUtils
Validator
Person
类上的方法用于 如果属性为空字符串,则拒绝该属性。看看ValidationUtilsjavadoc 以查看除了前面显示的示例之外,它还提供了哪些功能。static
rejectIfEmpty(..)
ValidationUtils
name
null
虽然当然可以实现单个类来验证每个 在富对象中的嵌套对象中,最好封装验证 每个嵌套对象类在其自己的实现中的逻辑。一个简单的 “富”对象的示例是由两个属性(第一个和第二个名称)和一个 complexObject.objects 组成的。 可以独立于对象使用,因此已实现区别。如果您希望重用包含的逻辑 在课堂内无需诉诸复制和粘贴,您可以 依赖注入或实例化你的, 如以下示例所示:Validator
Validator
Customer
String
Address
Address
Customer
AddressValidator
CustomerValidator
AddressValidator
AddressValidator
CustomerValidator
验证错误将报告给传递给验证器的对象。在这种情况下 Spring Web MVC,您可以使用标签来检查错误消息,但是 您也可以自己检查对象。有关 它提供的方法可以在javadoc中找到。Errors
Errors
3.2. 将代码解析为错误消息
我们介绍了数据绑定和验证。本节介绍输出相应的消息 到验证错误。在上一节所示的示例中, 我们拒绝了Theandfields。如果我们想使用 a 输出错误消息,我们可以使用我们在拒绝字段时提供的错误代码来实现 (在本例中为“姓名”和“年龄”)。当您调用(直接或间接地,通过使用 例如,类)或其他方法之一 从接口,底层实现不仅注册了代码 传入,但也注册了许多额外的错误代码。确定接口注册哪些错误代码。默认情况下,使用,它(例如)不仅注册消息 使用您提供的代码,但也注册包含您传递的字段名称的消息 到拒绝方法。因此,如果您通过使用拒绝字段, 除了代码,Spring 还寄存沙(第一个包含字段名称,第二个包含类型 的领域)。这样做是为了方便开发人员确定错误消息。name
age
MessageSource
ValidationUtils
rejectValue
reject
Errors
MessageCodesResolver
Errors
DefaultMessageCodesResolver
rejectValue("age", "too.darn.old")
too.darn.old
too.darn.old.age
too.darn.old.age.int
可以找到有关和默认策略的更多信息 在 MessageCodesResolver 和DefaultMessageCodesResolver 的 javadoc 中, 分别。MessageCodesResolver
3.3. Bean 操作和BeanWrapper
该软件包遵循JavaBeans标准。 JavaBean是一个具有默认无参数构造函数的类,它遵循 一种命名约定,其中(例如)命名的属性将 有一个二传手方法和一个吸气手方法。为 有关 JavaBeans 和规范的更多信息,请参阅JavaBeans。org.springframework.beans
bingoMadness
setBingoMadness(..)
getBingoMadness()
bean 包中一个非常重要的类是接口及其 相应的实现 ()。正如引用自javadoc的,提供了设置和获取属性值的功能(单独或在 批量),获取属性描述符,并查询属性以确定它们是否 可读或可写。此外,还提供对嵌套属性的支持, 启用将子属性上的属性设置为无限深度。它还支持添加标准JavaBeansand的能力,而无需在目标类中支持代码。 最后但并非最不重要的一点是,提供对设置索引属性的支持。 通常不由应用程序代码直接使用,而由和使用。BeanWrapper
BeanWrapperImpl
BeanWrapper
BeanWrapper
BeanWrapper
PropertyChangeListeners
VetoableChangeListeners
BeanWrapper
BeanWrapper
DataBinder
BeanFactory
作品的方式部分由它的名字表示:它包裹着一个豆子 对该 Bean 执行操作,例如设置和检索属性。BeanWrapper
3.3.1. 设置和获取基本属性和嵌套属性
设置和获取属性是通过 的 and重载方法变体完成的。请参阅他们的 Javadoc 详。下表显示了这些约定的一些示例:setPropertyValue
getPropertyValue
BeanWrapper
Table 11. Examples of properties
表达 | 解释 |
| 指示与理论方法对应的属性。 |
| 指示对应于 (例如)理论方法。 |
| 指示索引属性的第三个元素。索引属性 可以是类型、或其他自然顺序集合。 |
| 指示由属性的键索引的映射条目的值。 |
(如果您不打算使用 直接的。如果您只使用 and 和它们的默认实现,则应跳到属性编辑器部分。BeanWrapper
DataBinder
BeanFactory
以下两个示例类使用 get 和 set 性能:BeanWrapper
以下代码片段显示了如何检索和操作某些 实例化和的属性:Company
Employee
3.3.2. 内置实现PropertyEditor
弹簧使用a的概念来实现anand a之间的转换。它可以很方便 以不同于对象本身的方式表示属性。例如,a可以用人类可读的方式表示(如:),而 我们仍然可以将人类可读的形式转换回原始日期(或者,甚至 更好的是,将以人类可读形式输入的任何日期转换回对象)。这 行为可以通过注册类型的自定义编辑器来实现。在 aor 上注册自定义编辑器, 或者,在特定的 IoC 容器中(如上一章所述),给出它 有关如何将属性转换为所需类型的知识。有关更多信息,请参阅 Oracle 的java.beans 包的 javadoc。PropertyEditor
Object
String
Date
String
'2007-14-09'
Date
java.beans.PropertyEditor
BeanWrapper
PropertyEditor
在 Spring 中使用属性编辑的几个示例:
- 在 bean 上设置属性是通过使用实现来完成的。 当您使用您声明的某个 Bean 的属性值时 在 XML 文件中,Spring (如果相应属性的 setter 具有 aparameter)用于尝试将参数解析为 aobject。
PropertyEditor
String
Class
ClassEditor
Class
- 在 Spring 的 MVC 框架中解析 HTTP 请求参数是通过使用各种类型来完成的 的实现,您可以在所有子类中手动绑定。
PropertyEditor
CommandController
Spring 有许多内置的实现,让生活变得轻松。 它们都位于包装中。默认情况下,大多数(但不是全部,如下表所示)由注册者注册。如果属性编辑器可以以某种方式进行配置,则可以 仍然注册您自己的变体以覆盖默认变体。下表描述了 Spring 提供的各种实现:PropertyEditor
org.springframework.beans.propertyeditors
BeanWrapperImpl
PropertyEditor
表 12.内置实现PropertyEditor
类 | 解释 |
| 字节数组的编辑器。将字符串转换为其相应的字节 交涉。默认注册者。 |
| 将表示类的字符串分析为实际类,反之亦然。当一个 找不到类,阿尼斯扔了。默认情况下,注册者。 |
| 属性的可自定义属性编辑器。默认情况下,可以通过将注册的自定义实例注册为 自定义编辑器。 |
| 集合的属性编辑器,将任何源转换为给定的目标类型。 |
| 可定制的属性编辑器,支持自定义。不 默认注册。必须根据需要使用适当的格式进行用户注册。 |
| 任何子类的可自定义属性编辑器,例如,,,或。默认情况下,注册者但可以由 将其自定义实例注册为自定义编辑器。 |
| 将字符串解析为对象。默认情况下,注册者。 |
| 单向属性编辑器,可以采用字符串并生成(通过 中间和)可以直接将属性设置为字符串。请注意,默认用法不会关闭 为你。默认情况下,注册者。 |
| 可以将字符串解析为对象,反之亦然(字符串格式与方法相同)。还接受空格作为分隔符,作为下划线的替代项。 默认情况下,注册者。 |
| 可以将字符串解析为对象,反之亦然。 |
| 可以将字符串(使用类的javadoc中定义的格式格式化)转换为对象。默认情况下,已注册 由。 |
| 修剪字符串的属性编辑器。(可选)允许转换空字符串 变成一个值。默认情况下未注册 — 必须由用户注册。 |
| 可以将 URL 的字符串表示形式解析为实际对象。 默认情况下,注册者。 |
弹簧使用设置属性的搜索路径 可能需要的编辑器。搜索路径还包括, 包括诸如、和大多数类型的实现 基元类型。另请注意,标准的 JavaBeans 基础架构 自动发现类(无需注册它们) 显式)如果它们与它们处理的类位于同一包中并且具有相同的 名称为该类,附加。例如,可以有以下内容 类和包结构,这足以使类 识别并用作 for 类型属性。java.beans.PropertyEditorManager
sun.bean.editors
PropertyEditor
Font
Color
PropertyEditor
Editor
SomethingEditor
PropertyEditor
Something
请注意,您也可以在此处使用标准的JavaBeans机制。 (此处在一定程度上描述)。这 下面的示例使用该机制使用关联类的属性显式注册一个或多个实例:BeanInfo
BeanInfo
PropertyEditor
引用类的以下 Java 源代码 关联 a与类的属性:SomethingBeanInfo
CustomNumberEditor
age
Something
注册其他自定义实现PropertyEditor
当将 bean 属性设置为字符串值时,Spring IoC 容器最终使用 标准JavaBeans实现,用于将这些字符串转换为复杂类型的 财产。Spring 预注册了许多自定义实现(例如,到 将表示为字符串的类名转换为对象)。此外 Java的标准JavaBeanslookup机制允许afor类被适当地命名,并与类放在同一个包中。 它提供支持,以便可以自动找到它。PropertyEditor
PropertyEditor
Class
PropertyEditor
PropertyEditor
如果需要注册其他习俗,有几种机制是 可用。最手动的方法,通常不方便或 推荐,是使用接口的方法,假设你有偏好。 另一个(稍微方便一些)机制是使用特殊的豆子工厂 后处理器调用。虽然你可以使用bean工厂后处理器 通过实现,具有 嵌套属性设置,因此我们强烈建议您将它与 一起使用,在那里您可以以类似于任何其他 Bean 和 可以自动检测和应用的地方。PropertyEditors
registerCustomEditor()
ConfigurableBeanFactory
BeanFactory
CustomEditorConfigurer
BeanFactory
CustomEditorConfigurer
ApplicationContext
请注意,所有 Bean 工厂和应用程序上下文都会自动使用许多 内置属性编辑器,通过使用 ATO进行 处理属性转换。寄存器的标准属性编辑器在上一节中列出。 此外,还覆盖或添加其他编辑器来处理 以适合特定应用程序上下文类型的方式进行资源查找。BeanWrapper
BeanWrapper
ApplicationContext
标准 JavaBeans 实例用于转换属性值 表示为属性的实际复杂类型的字符串。您可以使用豆厂后处理器方便地添加 支持对 AN 的其他实例。PropertyEditor
CustomEditorConfigurer
PropertyEditor
ApplicationContext
考虑以下示例,该示例定义了一个调用的用户类 另一个调用的类,它需要设置为属性:ExoticType
DependsOnExoticType
ExoticType
正确设置后,我们希望能够将类型属性分配为 字符串,转换为实际实例。以下 Bean 定义显示了如何设置此关系:PropertyEditor
ExoticType
实现可能类似于以下内容:PropertyEditor
最后,下面的示例演示如何使用 newwith 注册,然后可以根据需要使用它:CustomEditorConfigurer
PropertyEditor
ApplicationContext
用PropertyEditorRegistrar
向 Spring 容器注册属性编辑器的另一种机制是 创建和使用 a。此接口在以下情况下特别有用 您需要在几种不同情况下使用同一组属性编辑器。 您可以编写相应的注册器并在每种情况下重用它.实例与调用的接口结合使用,该接口由 Spring(and) 实现。实例特别方便 与(此处所述)一起使用时,它公开了一个属性 已添加调用实例 以这种方式可以轻松共享和 弹簧 MVC 控制器。此外,它避免了自定义同步的需要 编辑器:Ais 希望为每次创建 Bean 尝试创建新实例。PropertyEditorRegistrar
PropertyEditorRegistrar
PropertyEditorRegistry
BeanWrapper
DataBinder
PropertyEditorRegistrar
CustomEditorConfigurer
setPropertyEditorRegistrars(..)
PropertyEditorRegistrar
CustomEditorConfigurer
DataBinder
PropertyEditorRegistrar
PropertyEditor
以下示例演示如何创建自己的实现:PropertyEditorRegistrar
另请参阅示例实现。请注意,在方法的实现中,它如何创建每个属性编辑器的新实例。org.springframework.beans.support.ResourceEditorRegistrar
PropertyEditorRegistrar
registerCustomEditors(..)
下一个示例演示如何配置 aand 注入实例 我们的进入它:CustomEditorConfigurer
CustomPropertyEditorRegistrar
最后(有点偏离本章的重点)对于那些你们 使用Spring 的 MVC Web 框架,使用 ain 与数据绑定 Web 控制器结合使用可以非常方便。以下 示例使用 ain 实现 anmethod:PropertyEditorRegistrar
PropertyEditorRegistrar
@InitBinder
这种注册方式可以导致简洁的代码(实现 的方法只有一行长),并允许将公共注册代码封装在一个类中,然后在尽可能多的控制器之间共享 根据需要。PropertyEditor
@InitBinder
PropertyEditor
3.4. 弹簧类型转换
Spring 3 引入了一个提供常规类型转换的包 系统。系统定义一个SPI来实现类型转换逻辑和一个API 在运行时执行类型转换。在 Spring 容器中,您可以使用此系统 作为转换外部化 Bean 属性值的实现的替代方法 字符串到所需的属性类型。您还可以在 需要类型转换的应用程序。core.convert
PropertyEditor
3.4.1. 转换器 SPI
实现类型转换逻辑的 SPI 很简单,并且是强类型的,如下所示 接口定义显示:
要创建自己的转换器,请实现接口并参数化为要转换的类型以及要转换为的类型。您也可以透明地应用这样的 转换器,如果集合或数组需要 转换为数组或集合,前提是委托数组或集合 转换器也已注册(默认情况下注册)。Converter
S
T
S
T
DefaultConversionService
对于每个调用 to,源参数保证不为 null。如果转换失败,您可能会引发任何未经检查的异常。具体来说,它应该抛出 anto 报告无效的源值。 注意确保您的实现是线程安全的。convert(S)
Converter
IllegalArgumentException
Converter
包中提供了几种转换器实现,作为 一种便利。其中包括从字符串到数字和其他常见类型的转换器。 下面的清单显示了类,这是一个典型的实现:core.convert.support
StringToInteger
Converter
3.4.2. 使用ConverterFactory
当您需要集中整个类层次结构的转换逻辑时 (例如,转换 FromtoObjects 时),可以实现,如以下示例所示:String
Enum
ConverterFactory
将 S 参数化为要转换的类型,将 R 参数化为定义的基本类型 可以转换为的类的范围。然后实施, 其中 T 是 R 的子类。getConverter(Class
以你为例:StringToEnumConverterFactory
3.4.3. 使用GenericConverter
当您需要复杂的实现时,请考虑使用接口。使用更灵活但键入较少的签名 比,支持在多个源和 目标类型。此外,还提供可用的源和目标字段 实现转化逻辑时可以使用的上下文。这样的上下文让 类型转换由字段批注或 字段签名。以下清单显示了以下接口定义:Converter
GenericConverter
Converter
GenericConverter
GenericConverter
GenericConverter
要实现 a,已返回支持的 源→目标类型对。然后实现以包含转换逻辑。源提供 访问保存正在转换的值的源字段。目标提供对要在其中设置转换值的目标字段的访问。GenericConverter
getConvertibleTypes()
convert(Object, TypeDescriptor, TypeDescriptor)
TypeDescriptor
TypeDescriptor
ais 一个在 Java 数组之间转换的转换器的一个很好的例子 和一个集合。这种内省声明的字段 用于解析集合的元素类型的目标集合类型。这让每个 元素在 集合在目标字段上设置。GenericConverter
ArrayToCollectionConverter
用ConditionalGenericConverter
有时,您希望 a仅在特定条件成立时才运行。为 例如,您可能希望仅在存在特定批注时才运行 在目标字段中,或者您可能希望仅在特定方法运行时运行 (例如 amethod)在目标上定义,class.is 与接口的联合,允许您定义此类自定义匹配条件:Converter
Converter
Converter
static valueOf
ConditionalGenericConverter
GenericConverter
ConditionalConverter
ais anthat 转换的一个很好的例子 在持久性实体标识符和实体引用之间。仅当目标实体类型声明静态查找器方法(例如,)时,此类匹配才可能匹配。您可以在实现中执行这样的查找器方法检查。ConditionalGenericConverter
IdToEntityConverter
IdToEntityConverter
findAccount(Long)
matches(TypeDescriptor, TypeDescriptor)
3.4.4. 接口ConversionService
ConversionService
定义一个统一的 API,用于在 运行。转换器通常在以下外观界面后面运行:
大多数实现也实现,其中 提供用于注册转换器的 SPI。在内部,实现委托给其注册的转换器以执行类型转换逻辑。ConversionService
ConverterRegistry
ConversionService
在 thepackage.is 适用于 在大多数环境中使用。提供方便的工厂 创建通用配置。ConversionService
core.convert.support
GenericConversionService
ConversionServiceFactory
ConversionService
3.4.5. 配置ConversionService
Ais 一个无状态对象,设计用于在应用程序实例化 启动,然后在多个线程之间共享。在 Spring 应用程序中,您通常 为每个 Spring 容器 (OR) 配置 a实例。 弹簧拾起它,并在键入时使用它 转换需要由框架执行。您也可以将其注入到任何 bean 中并直接调用它。ConversionService
ConversionService
ApplicationContext
ConversionService
ConversionService
要使用 Spring 注册默认值,请添加以下 Bean 定义 与 Anof:ConversionService
id
conversionService
默认值可以在字符串、数字、枚举、集合、 地图和其他常见类型。用您的补充或覆盖默认转换器 自己的自定义转换器,设置属性。属性值可以实现 任何,,或接口。ConversionService
converters
Converter
ConverterFactory
GenericConverter
在Spring MVC应用程序中使用a也很常见。请参阅Spring MVC章节中的转换和格式化。ConversionService
在某些情况下,您可能希望在转换过程中应用格式。有关使用的详细信息,请参阅FormatterRegistrySPI。FormattingConversionServiceFactoryBean
3.4.6. 以编程方式使用ConversionService
要以编程方式使用 ainstance,您可以注入对 就像你对任何其他豆子一样。以下示例演示如何执行此操作:ConversionService
对于大多数用例,您可以使用指定的方法,但是 不适用于更复杂的类型,例如参数化元素的集合。 例如,如果要以编程方式将 aof转换为 aof, 您需要提供源和目标类型的正式定义。convert
targetType
List
Integer
List
String
幸运的是,提供了各种选项来使操作变得简单, 如以下示例所示:TypeDescriptor
请注意,自动注册以下转换器: 适用于大多数环境。这包括集合转换器、标量 转换器和基本到转换器。您可以注册相同的转换器 与 anyby 在类上使用静态方法。DefaultConversionService
Object
String
ConverterRegistry
addDefaultConverters
DefaultConversionService
值类型的转换器对数组和集合重用,因此 无需创建特定的转换器即可从 AOF 转换为 AOF,前提是标准集合处理是合适的。Collection
S
Collection
T
3.5. 弹簧字段格式化
如上一节所述,core.convert是一个 通用型转换系统。它提供了一个统一的 API 作为 以及用于从一种类型实现转换逻辑的强类型SPI。 到另一个。Spring 容器使用此系统绑定 Bean 属性值。在 此外,Spring 表达式语言 (SpEL) 和使用此系统来 绑定字段值。例如,当 SpEL 需要强制 ato ato 完成尝试,系统执行强制。ConversionService
Converter
DataBinder
Short
Long
expression.setValue(Object bean, Object value)
core.convert
现在考虑典型客户端环境的类型转换要求,例如 网络或桌面应用程序。在此类环境中,通常转换自以支持客户端回发过程,以及转换回 查看渲染过程。此外,您经常需要本地化值。越多 通用SPI不满足此类格式要求 径直。为了直接解决这些问题,Spring 3 引入了一个方便的 SPI,它 为客户端环境提供简单而可靠的实现替代方案。String
String
String
core.convert
Converter
Formatter
PropertyEditor
通常,当您需要实现通用类型时,可以使用 SPI。 转换逻辑 — 例如,用于在 A 和 A 之间进行转换。 当您在客户端环境(如 Web 应用程序),并且需要解析和打印本地化的字段值。为两个 SPI 提供统一的类型转换 API。Converter
java.util.Date
Long
Formatter
ConversionService
3.5.1. SPIFormatter
实现字段格式逻辑的 SPI 很简单且是强类型的。这 以下清单显示了接口定义:Formatter
Formatter
Formatter
从和构建块接口扩展。这 以下清单显示了这两个接口的定义:Printer
Parser
若要创建自己的接口,请实现前面所示的接口。 参数化为要格式化的对象类型,例如,。实现打印实例的操作 显示在客户端区域设置中。实现从客户端区域设置返回的格式化表示形式中解析实例的操作。你应该抛出一个或一个解析尝试失败。拿 注意确保您的实现是线程安全的。Formatter
Formatter
T
java.util.Date
print()
T
parse()
T
Formatter
ParseException
IllegalArgumentException
Formatter
为了方便起见,子包提供了几种实现。 该包提供,和格式使用a的对象。 该包提供 ato 格式对象 一个。format
Formatter
number
NumberStyleFormatter
CurrencyStyleFormatter
PercentStyleFormatter
Number
java.text.NumberFormat
datetime
DateFormatter
java.util.Date
java.text.DateFormat
下面是一个示例实现:DateFormatter
Formatter
Spring 团队欢迎社区驱动的贡献。请参阅GitHub 要贡献的问题。Formatter
3.5.2. 注释驱动的格式化
可以按字段类型或注记配置字段格式。绑定 对 A 的注释,实现。以下 列表显示了接口的定义:Formatter
AnnotationFormatterFactory
AnnotationFormatterFactory
要创建实现,请执行以下操作:
- 将参数化 A 作为要关联的字段 格式逻辑 — 例如。
annotationType
org.springframework.format.annotation.DateTimeFormat
- 已返回可以使用批注的字段类型。
getFieldTypes()
- 返回 a以打印带批注字段的值。
getPrinter()
Printer
- Havereturn ato parse afor an annotated field。
getParser()
Parser
clientValue
以下示例实现将注释绑定到格式化程序,以使数字样式或模式 指定:AnnotationFormatterFactory
@NumberFormat
要触发格式设置,您可以使用@NumberFormat对字段进行批注,如下所示 示例显示:
格式注释 API
包中存在可移植格式注释 API。您可以使用 to 格式化字段,例如 and、andto format、,(用于毫秒时间戳)以及 JSR-310。org.springframework.format.annotation
@NumberFormat
Number
Double
Long
@DateTimeFormat
java.util.Date
java.util.Calendar
Long
java.time
以下示例用于将 aas 格式化为 ISO 日期 (年-月-日):@DateTimeFormat
java.util.Date
3.5.3. SPIFormatterRegistry
这是一个用于注册格式化程序的SPI,并 converters.is 适用于 大多数环境。您可以通过编程或声明方式配置此变体 作为春豆,例如通过使用。因为这个 实现也实现,可以直接配置它 用于 Spring's and the Spring Expression Language (SpEL)。FormatterRegistry
FormattingConversionService
FormatterRegistry
FormattingConversionServiceFactoryBean
ConversionService
DataBinder
以下清单显示了 SPI:FormatterRegistry
如前面的清单所示,您可以按字段类型或批注注册格式化程序。
SPI 允许您集中配置格式规则,而不是 在控制器之间复制此类配置。例如,您可能希望 强制所有日期字段都以某种方式格式化,或者字段具有特定的格式 批注以某种方式格式化。使用共享,您可以定义 这些规则一次,只要需要格式化,就会应用它们。FormatterRegistry
FormatterRegistry
3.5.4. SPIFormatterRegistrar
FormatterRegistrar
是一个 SPI,用于通过 格式化程序注册表。以下清单显示了其接口定义:
在注册多个相关转换器时很有用,并且 给定格式类别(如日期格式)的格式化程序。它也可以是 在声明性注册不足的情况下很有用 - 例如,当格式化程序 需要在不同于其拥有者的特定字段类型下编制索引,当 注册 A/对。下一节提供了有关以下内容的更多信息 转换器和格式化程序注册。FormatterRegistrar
Printer
Parser
3.5.5. 在 Spring MVC 中配置格式化
请参阅Spring MVC章节中的转换和格式化。
3.6. 配置全局日期和时间格式
默认情况下,未批注的日期和时间字段转换自 字符串通过使用样式。如果您愿意,可以通过以下方式更改此设置 定义您自己的全局格式。@DateTimeFormat
DateFormat.SHORT
为此,请确保 Spring 不会注册默认格式化程序。相反,请注册 在以下人员的帮助下手动格式化程序:
-
org.springframework.format.datetime.standard.DateTimeFormatterRegistrar
-
org.springframework.format.datetime.DateFormatterRegistrar
例如,以下 Java 配置注册全局格式:yyyyMMdd
如果您更喜欢基于 XML 的配置,则可以使用 a.以下示例演示如何执行此操作:FormattingConversionServiceFactoryBean
请注意,在 Web 中配置日期和时间格式时,还需要注意其他事项 应用。请参阅WebMVC转换和格式化或WebFlux 转换和格式化。
版本 5.3.23