除了Servlet Context Scope和ThreadScope之外,还有其他自定义的Spring范围吗?
如果您已经创建了一些闭源的自定义范围,我也很感兴趣听听它是什么以及它对您的工作有何影响。(我想在桌面应用程序中可能会有人制作WindowScope?)
我对所有用例都持开放态度,我希望在这里拓展我的视野。
除了Servlet Context Scope和ThreadScope之外,还有其他自定义的Spring范围吗?
如果您已经创建了一些闭源的自定义范围,我也很感兴趣听听它是什么以及它对您的工作有何影响。(我想在桌面应用程序中可能会有人制作WindowScope?)
我对所有用例都持开放态度,我希望在这里拓展我的视野。
我们实现了自己的定制Spring作用域。我们的很多代码在接近数据库的相对较低层级上工作,并且我们通过自己的数据源、链接、属性等对象模型来维护概念层级。
无论如何,很多bean需要一个所谓的StorageDictionary(这个对象图的封装)来完成它们的工作。当我们对对象图进行非平凡更改时,字典有时需要被清除并重新创建。因此,我们为那些“字典作用域”的对象实现了一个自定义作用域,并且给定字典的失效也涉及到清除这个自定义作用域。这让Spring可以为这些对象处理一种不错的自动缓存。你每次都会得到同一个对象,直到字典失效,此时你会得到一个新的对象。
这不仅有助于一致性,而且还允许对象本身缓存字典中的实体引用,因为它们知道只要它们可以被Spring检索到,缓存就是有效的。这反过来又让我们可以将它们构建为不可变对象(只要它们可以通过构造函数注入进行连接),这是无论在哪里都应该尽可能做到的好事情。
这种技术并不适用于所有情况,它严重依赖于软件的特性(例如,如果字典经常被修改,这将非常低效;如果它从未更新,这将比直接访问略微低效)。然而,它确实帮助我们以概念上简单且我认为相当优雅的方式将生命周期管理交给了Spring。
在我们公司中,我们创建了两个自定义范围,一个将使用线程或请求(Thread or Request),另一个将使用线程或会话(Thread or Session)。这样一来,可以使用单个范围来处理作用域的bean,而无需根据执行环境(JUnit或Servlet容器)更改配置。当使用Quartz运行项目时,没有请求或会话范围可用,因此这也非常方便。
背景:
我在一个单一的Web应用程序上工作,该应用程序在同一Servlet上下文中运行4个不同的网站。每个网站都有自己的域名,例如www.examplesite1.com,www.examplesite2.com等。
问题:
有时,网站需要其自己定制的bean实例来自应用程序上下文(通常用于自定义消息显示或对象格式化)。
例如,假设站点1和2都使用“standardDateFormatter” bean,站点3使用“usDateFormatter” bean,站点4使用“ukDateFormatter” bean。
解决方案:
我计划使用“site”范围。
我们有一个类似这样的Site枚举:
enum Site {
SITE1, SITE2, SITE3, SITE4;
}
然后我们有一个过滤器,使用ThreadLocal将其中一个Site值存储在请求的线程中。这就是站点范围的“会话ID”。
然后,在应用程序上下文中,将有一个名为“dateFormatter”的bean,其'scope="site"'。然后,无论我们想在哪里使用日期格式化程序,都将使用用户当前站点的正确日期格式化程序。
稍后添加:
示例代码在此处:
Apache Orchestra 提供了 SpringConversationScope。
我们有很多@Service
组件,它们根据当前批处理项计算某些东西。其中许多都需要相同的工作流程:
我们将工作流程移动到基类模板方法中,因此子类仅实现findItemParts(Item)
(执行1和2)和computeSomething(ItemPart)
(执行3)。因此,它们变得有状态 (在findItemParts
中初始化的“stuff”在computeSomething
中需要),并且该状态必须在下一项之前清除。
其中一些服务还涉及从当前项目派生的注入Spring bean,之后必须将其删除。
AbstractScopeRegisteringItemProcessor
,它注册了项目并允许子类注册派生bean。在其process
方法结束时,它会从其作用域上下文中删除该项,并使用DefaultSingletonBeanRegistry.destroySingleton
销毁派生bean。
它可以工作,但存在以下问题:
@Scope
)。具体处理器必须创建并注册它们。AbstractScopeRegisteringItemProcessor
最好使用组合并动态实现底层处理器的所有接口。但是,结果的@StepScope
bean是声明返回类型(即AbstractScopeRegisteringItemProcessor
或ItemProcessor
)的代理,没有所需的回调接口。ItemScopeContext
(处理器和 Scope
实现都使用的存储;通过静态的 @Bean
方法进行 Java 配置)实现了 BeanDefinitionRegistryPostProcessor
。它注册了一个 FactoryBean
,其 getObject()
返回当前项或如果没有则抛出异常。现在,使用 @Scope(scopeName = "Item", proxyMode = ScopedProxyMode.TARGET_CLASS)
注释的 @Component
可以简单地注入该项,无需为范围结束时的清理注册。
因此,最终它确实很好地工作了。