定制弹簧范围?

任何人都知道除了Servlet Context Scope和ThreadScope之外的任何其他自定义弹簧范围?

如果您已经制作了一些闭源自定义范围,我真的也有兴趣了解它的作用以及它如何为您服务。 (我想有人会在桌面应用程序中制作一个WindowScope?)

我对所有用例都持开放态度,我希望扩大我的视野。

我们实现了自己的自定义Spring作用域。 我们的许多代码都在相对较低的层次上工作,靠近数据库,并且我们使用自己的数据源,链接,属性等对象模型来维护概念级别。

无论如何,很多bean需要一个所谓的StorageDictionary(这个对象图的封装)来完成他们的工作。 当我们对对象图进行非平凡的更改时,有时需要将字典吹走并重新创建。 因此,我们为字典范围的对象实现了自定义范围,并且给定字典的无效部分涉及清除此自定义范围。 这让Spring为这些对象处理了一种很好的自动缓存forms。 每次都会返回相同的对象,直到字典失效,此时您将获得一个新对象。

这不仅有助于一致性,而且还允许对象本身缓存对字典中实体的引用,只要它们本身可由Spring检索,就可以安全地知道缓存有效。 这反过来让我们将它们构建为不可变对象(只要它们可以通过构造函数注入进行连接),这在任何可能的情况下都是非常好的事情。

这种技术无处不在,并且在很大程度上取决于软件的特性(例如,如果字典经常被修改,这将是非常低效的,并且如果它被更新,那么这将是不必要的并且比直接访问稍微低效)。 但是,它确实帮助我们以一种概念上简单明了的方式将生命周期管理权交给Spring,在我看来相当优雅。

在我的公司中,我们创建了两个自定义作用域,一个将使用Thread或Request,另一个将使用Thread或Session。 这个想法是单个作用域可以用于作用域bean,而不必根据执行环境(JUnit或Servlet容器)更改配置。 当您在Quartz中运行项目并且不再具有可用的请求或会话范围时,这也非常方便。

背景:

我在一个Web应用程序上工作,该应用程序在同一个servlet上下文中运行4个不同的Web站点。 每个站点都有自己的域名,例如www.examplesite1.com,www.examplesite2.com等。

问题:

站点有时需要从应用程序上下文中自定义bean的自定义实例(通常用于自定义的消息显示或对象的格式化)。

例如,站点1和站点2都使用“standardDateFormatter”bean,站点3使用“usDateFormatter”bean,站点4使用“ukDateFormatter”bean。

解:

我打算使用“网站”范围。

我们有一个这样的网站枚举:

enum Site { SITE1, SITE2, SITE3, SITE4; } 

然后我们有一个filter,使用ThreadLocal在请求的线程中存储其中一个Site值。 这是网站范围的“会话ID”。

然后在app上下文中有一个名为“dateFormatter”的bean,其中’scope =“site”’。 然后,无论我们想要使用日期格式化程序,都将使用用户当前站点的正确格式。

后来添加:

示例代码:

http://github.com/eliotsykes/spring-site-scope

Oracle Coherence 为Spring bean实现了一个数据网格范围 。 把它们加起来:

数据网格Bean是java.io.Serializable Bean实例的代理,该实例存储在非到期的Coherence分布式缓存(称为near-datagridbeans)中。

从来没有使用过它们但它们看起来很酷。

Apache Orchestra提供SpringConversationScope 。

基于Web应用程序的用户区域设置的spring区域设置范围

查看相关的维基页面

在我的公司,我们还实施了弹簧自定义范围。 我们有一个多租户系统,每个客户都可以自定义设置。 我们的基于实例的范围,缓存客户特定的bean。 因此,每次客户的用户登录时,这些设置都会被缓存,并在同一客户的其他用户登录时再次重复使用。

在Spring Batch应用程序中,我们实现了一个项目范围

背景

我们有很多@Service组件,它们根据当前批处理项计算内容。 其中许多人需要相同的工作流程:

  1. 确定相关的项目部分。
  2. 根据项目启动内容。
  3. 对于每个项目部分,计算一些东西(使用东西)。

我们将工作流移动到基类模板方法中,因此子类只实现findItemParts(Item) (执行1和2)和computeSomething(ItemPart) (执行3)。 所以它们变为有状态(在computeSomething需要在findItemParts初始化的东西),并且必须在下一个项目之前清除该状态。

其中一些服务还涉及注入的Spring bean,它们也来自当前项目,之后必须删除。

设计

我们实现了一个AbstractScopeRegisteringItemProcessor ,它注册该项并允许子类注册派生的bean。 在其process方法的末尾,它使用DefaultSingletonBeanRegistry.destroySingleton从其作用域上下文和派生的bean中删除该项。

它是如何运作的

它有效,但有以下问题:

  1. 我们没有设法在没有注册的情况下清理派生的bean(仅基于他们的@Scope )。 具体的处理器必须创建并注册它们。
  2. AbstractScopeRegisteringItemProcessor可以更好地使用组合并动态实现底层处理器的所有接口。 但是,生成的@StepScope bean是声明的返回类型 (即AbstractScopeRegisteringItemProcessorItemProcessor )的代理,没有所需的回调接口。

编辑

在@Eliot Sykes的解决方案和共享代码以及@ Cheetah的BeanDefinition注册的帮助下 ,我能够将注册视为单例bean。 相反, ItemScopeContext (处理器和Scope实现使用的存储;通过静态@Bean方法配置的Java)实现BeanDefinitionRegistryPostProcessor 。 它注册一个FactoryBeangetObject()返回当前项,如果没有则抛出exception。 现在,使用@Scope(scopeName = "Item", proxyMode = ScopedProxyMode.TARGET_CLASS)注释的@Component @Scope(scopeName = "Item", proxyMode = ScopedProxyMode.TARGET_CLASS)可以简单地注入项目,无需注册进行范围最终清理。

所以最后,它确实运作良好。

我曾经使用一种会话范围会话范围内存储一些对象,以便在重新进入同一页面时保留它们,但仅限于单个页面以避免在会话中留下无用的对象。 该实现只是存储了页面URL并清除了每个页面更改的会话范围