我应该如何/应该创建自己的 Guice Scope
How / Should I create my own Guice Scope
我们有一个遗留应用程序,我们现在在单个 JVM 中加载它的多个实例。我们现在在新代码中使用 Guice 进行依赖注入,但现在是处理遗留应用程序代码的时候了。
遗留应用程序在许多线程中工作,这些线程是随机创建的(尽管都是通过帮助程序创建的,因此我们可以在那里添加代码),我认为我们需要一个范围来涵盖该应用程序的每个实例。
那么,我应该创建自己的范围吗?我应该如何让它覆盖多个线程?我可以使用应用程序的每个实例所具有的唯一字符串以便在每个线程的开头找到正确的范围吗?
对作用域的需求归结为一个问题:您是否希望能够在您定义的每个环境中注入完全相同的对象实例,但让它们在您定义的环境之间有所不同? -define?(这意味着,对于对象 Foo,每个遗留应用程序实例将收到不同的 Foo,但在该遗留应用程序实例的环境中,如果被请求,您将始终收到相同的 Foo 实例.) 如果是这样,那么作用域就是你想要的。
在范围的设计和实施方面有两个重要的考虑因素:
- 所有范围都实现为可能缓存的提供程序包装器。
- 除了同步单例创建之外,Guice 没有线程的内部概念。
Singleton 作用域只是一个 Provider-wrapper,它创建一次对象并将其永久保存到 return。请求和会话范围仅确定当前请求或会话,将 Provider 包装到 return 同一实例或委托给内部 Provider 以在必要时创建一个新实例。对于无作用域的对象,或假设的 DoNothingScope,不需要包装——您每次都会得到一个新对象,就像普通的 Provider 一样。最后,重要的是,对于 Guice 的 Custom Scopes 页面上的基于线程的作用域示例,作用域只是 return 一个匿名内部提供者,它检查 ThreadLocal<Map<Key, Object>>
到 return 一个现有对象如果需要的话。
您可以使用那个 Custom Scopes 示例作为起点,并进行以下更改:
- 保留
Map<LegacyAppInstance, Map<Key, Object>>
,因为您要关闭应用程序实例而不是线程。您的唯一字符串与密钥一样有效,但我对它的可访问性的详细信息了解不够。
- 您还需要保留一个
ThreadLocal<LegacyAppInstance>
(或 ThreadLocal<String>
),这样您就可以随时确定从 Thread 到旧版应用程序实例的映射。
enter()
和 exit()
将需要进行一些更改:您需要创建一个 enter(LegacyAppInstance)
,您可以从新线程调用它以建立一个 link LegacyAppInstance 的线程。您只需调用 exit
来销毁特定 LegacyAppInstance
的 Map<Key, Object>
,因此所有这些创建的对象都可以被垃圾回收。
- 除此之外,它是一样的:Return 一个 Provider——可能是一个匿名的内部 Provider——它决定你在哪个线程,决定哪个 LegacyAppInstance 正在运行,然后 return 现有实例或根据需要创建新实例。
不要忘记将 Scope 实例本身绑定为单例(toInstance
绑定必须是单例),这样您就可以从线程创建助手获取它。
我们有一个遗留应用程序,我们现在在单个 JVM 中加载它的多个实例。我们现在在新代码中使用 Guice 进行依赖注入,但现在是处理遗留应用程序代码的时候了。
遗留应用程序在许多线程中工作,这些线程是随机创建的(尽管都是通过帮助程序创建的,因此我们可以在那里添加代码),我认为我们需要一个范围来涵盖该应用程序的每个实例。
那么,我应该创建自己的范围吗?我应该如何让它覆盖多个线程?我可以使用应用程序的每个实例所具有的唯一字符串以便在每个线程的开头找到正确的范围吗?
对作用域的需求归结为一个问题:您是否希望能够在您定义的每个环境中注入完全相同的对象实例,但让它们在您定义的环境之间有所不同? -define?(这意味着,对于对象 Foo,每个遗留应用程序实例将收到不同的 Foo,但在该遗留应用程序实例的环境中,如果被请求,您将始终收到相同的 Foo 实例.) 如果是这样,那么作用域就是你想要的。
在范围的设计和实施方面有两个重要的考虑因素:
- 所有范围都实现为可能缓存的提供程序包装器。
- 除了同步单例创建之外,Guice 没有线程的内部概念。
Singleton 作用域只是一个 Provider-wrapper,它创建一次对象并将其永久保存到 return。请求和会话范围仅确定当前请求或会话,将 Provider 包装到 return 同一实例或委托给内部 Provider 以在必要时创建一个新实例。对于无作用域的对象,或假设的 DoNothingScope,不需要包装——您每次都会得到一个新对象,就像普通的 Provider 一样。最后,重要的是,对于 Guice 的 Custom Scopes 页面上的基于线程的作用域示例,作用域只是 return 一个匿名内部提供者,它检查 ThreadLocal<Map<Key, Object>>
到 return 一个现有对象如果需要的话。
您可以使用那个 Custom Scopes 示例作为起点,并进行以下更改:
- 保留
Map<LegacyAppInstance, Map<Key, Object>>
,因为您要关闭应用程序实例而不是线程。您的唯一字符串与密钥一样有效,但我对它的可访问性的详细信息了解不够。 - 您还需要保留一个
ThreadLocal<LegacyAppInstance>
(或ThreadLocal<String>
),这样您就可以随时确定从 Thread 到旧版应用程序实例的映射。 enter()
和exit()
将需要进行一些更改:您需要创建一个enter(LegacyAppInstance)
,您可以从新线程调用它以建立一个 link LegacyAppInstance 的线程。您只需调用exit
来销毁特定LegacyAppInstance
的Map<Key, Object>
,因此所有这些创建的对象都可以被垃圾回收。- 除此之外,它是一样的:Return 一个 Provider——可能是一个匿名的内部 Provider——它决定你在哪个线程,决定哪个 LegacyAppInstance 正在运行,然后 return 现有实例或根据需要创建新实例。
不要忘记将 Scope 实例本身绑定为单例(toInstance
绑定必须是单例),这样您就可以从线程创建助手获取它。