如何在 REST 调用之前初始化注入值?
How to initialize injected value before REST call?
我有一个依赖于与 HBase 的重量级连接的 JAX-RS 应用程序(运行 Jersey 2 on Tomcat)。我想在我的多个资源应用程序中初始化和重用该连接。我已经设置了一个将连接绑定为单例的活页夹,并使用@Inject 注释将该连接注入到我的资源中。但是,由于在第一次调用服务之前不会发生注入,因此直到那时才初始化连接。
应用程序:
public class MyApplication extends ResourceConfig {
public MyApplication() {
super(MyResource.class);
register(new HbaseBinder());
}
}
活页夹:
public class HbaseBinder extends AbstractBinder {
@Override
protected void configure() {
bindAsContract(HbaseConnection.class).in(Singleton.class);
bind(new HbaseConnection()).to(HbaseConnection.class);
}
}
注入:
@Path("/myResource")
public class MyResource {
@Inject
private HbaseConnection hbaseConnection;
...
}
HBase 连接:
@Singleton
public class HbaseConnection {
public Connection getConnection() throws IOException {
...
}
...
}
我想做的是在应用程序部署时初始化 Singleton,以便它准备好继续对服务的第一次调用。执行此操作的正确方法是什么?
您的 HbaseConnection
被初始化了两次。
- 首先,它会在您的活页夹中初始化(假设您的
MyApplication
class 在您的 web.xml
中注册为 init-param
)
- 然后,当HK2检测到
@Singleton
注解(或执行bindAsContract
指令时)再次初始化
因此,要使您的示例有效,您需要:
- 从您的
HbaseConnection
class 中删除 @Singleton
注释。
- 从您的
HBaseBinder
class 中删除行 bindAsContract(HbaseConnection.class).in(Singleton.class);
MyApplication
的初始化发生在 servlet 容器启动期间(因此 HbaseConnection
的构造),这正是您想要的,对吗?
提供实例(在活页夹中)的是您,而不是 HK2。这就是为什么您不想通过使用 @Singleton
来创建实例来指示它。
活页夹应该是:
public class HbaseBinder extends AbstractBinder {
@Override
protected void configure() {
// just bind is ok
bind(new HbaseConnection()).to(HbaseConnection.class);
}
}
HBase 连接:
// do not annotate with `@Singleton`!
public class HbaseConnection {
public Connection getConnection() throws IOException {
...
}
...
}
感谢您的所有评论和回答。需要以上各项的组合。
部分问题是我使用 @PostConstruct 调用 HbaseConnection.getConnection() 方法时出现未经检查的异常。一旦我摆脱了它,并切换到 Immediate 范围,class 似乎被适当地加载了。这是我的最终解决方案:
public class MyApplication extends ResourceConfig {
@Inject
public MyApplication(ServiceLocator locator) {
super(MyResource.class);
register(new HbaseBinder());
ServiceLocatorUtilities.enableImmediateScope(locator);
}
}
@Path("/myResource")
public class MyResource {
@Inject
private HbaseConnection hbaseConnection;
...
}
public class HbaseBinder extends AbstractBinder {
@Override
protected void configure() {
bindAsContract(HbaseConnection.class).in(Immediate.class);
}
}
@Immediate
public class HbaseConnection {
@PostConstruct
public void postConstruct() {
// Call getConnection(), wrapped in try/catch.
}
public Connection getConnection() throws IOException {
// Get the connection.
}
@PreDestroy
public void preDestroy() {
// Call cleanup(), wrapped in try/catch.
}
public void cleanup() throws IOException {
// Close/cleanup the connection
}
}
现在我唯一的问题是,看起来有些 Threads/ThreadLocals 正在取消部署,但这一定是我正在使用的库中的错误,因为我无法控制它们的生命周期。
12-Feb-2016 14:01:45.054 INFO [ContainerBackgroundProcessor[StandardEngine[Catalina]]] org.apache.catalina.startup.HostConfig.undeploy Undeploying context [/my-resource]
12-Feb-2016 14:01:46.129 WARNING [ContainerBackgroundProcessor[StandardEngine[Catalina]]] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesThreads The web application [my-resource] appears to have started a thread named [ImmediateThread-1455303641406] but has failed to stop it. This is very likely to create a memory leak. Stack trace of thread:
sun.misc.Unsafe.park(Native Method)
java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:215)
java.util.concurrent.SynchronousQueue$TransferQueue.awaitFulfill(SynchronousQueue.java:764)
java.util.concurrent.SynchronousQueue$TransferQueue.transfer(SynchronousQueue.java:695)
java.util.concurrent.SynchronousQueue.poll(SynchronousQueue.java:941)
java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1066)
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1127)
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
java.lang.Thread.run(Thread.java:745)
12-Feb-2016 14:01:46.130 WARNING [ContainerBackgroundProcessor[StandardEngine[Catalina]]] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesThreads The web application [my-resource] appears to have started a thread named [Thread-5] but has failed to stop it. This is very likely to create a memory leak. Stack trace of thread:
sun.net.dns.ResolverConfigurationImpl.notifyAddrChange0(Native Method)
sun.net.dns.ResolverConfigurationImpl$AddressChangeListener.run(ResolverConfigurationImpl.java:144)
12-Feb-2016 14:01:46.134 SEVERE [ContainerBackgroundProcessor[StandardEngine[Catalina]]] org.apache.catalina.loader.WebappClassLoaderBase.checkThreadLocalMapForLeaks The web application [my-resource] created a ThreadLocal with key of type [org.apache.htrace.core.Tracer.ThreadLocalContext] (value [org.apache.htrace.core.Tracer$ThreadLocalContext@2c25bbe0]) and a value of type [org.apache.htrace.core.Tracer.ThreadContext] (value [org.apache.htrace.core.Tracer$ThreadContext@787153ae]) but failed to remove it when the web application was stopped. Threads are going to be renewed over time to try and avoid a probable memory leak.
12-Feb-2016 14:01:46.135 SEVERE [ContainerBackgroundProcessor[StandardEngine[Catalina]]] org.apache.catalina.loader.WebappClassLoaderBase.checkThreadLocalMapForLeaks The web application [my-resource] created a ThreadLocal with key of type [org.apache.hadoop.io.Text] (value [org.apache.hadoop.io.Text@1badb836]) and a value of type [sun.nio.cs.UTF_8.Encoder] (value [sun.nio.cs.UTF_8$Encoder@13652d32]) but failed to remove it when the web application was stopped. Threads are going to be renewed over time to try and avoid a probable memory leak.
12-Feb-2016 14:01:46.136 SEVERE [ContainerBackgroundProcessor[StandardEngine[Catalina]]] org.apache.catalina.loader.WebappClassLoaderBase.checkThreadLocalMapForLeaks The web application [my-resource] created a ThreadLocal with key of type [org.apache.hadoop.hdfs.DFSUtil] (value [org.apache.hadoop.hdfs.DFSUtil@6080a3db]) and a value of type [java.util.Random] (value [java.util.Random@169acbf5]) but failed to remove it when the web application was stopped. Threads are going to be renewed over time to try and avoid a probable memory leak.
12-Feb-2016 14:03:02.383 INFO [Thread-7] org.apache.catalina.loader.WebappClassLoaderBase.checkStateForResourceLoading Illegal access: this web application instance has been stopped already. Could not load [org.apache.hadoop.util.ShutdownHookManager]. The following stack trace is thrown for debugging purposes as well as to attempt to terminate the thread which caused the illegal access.
java.lang.IllegalStateException: Illegal access: this web application instance has been stopped already. Could not load [org.apache.hadoop.util.ShutdownHookManager]. The following stack trace is thrown for debugging purposes as well as to attempt to terminate the thread which caused the illegal access.
at org.apache.catalina.loader.WebappClassLoaderBase.checkStateForResourceLoading(WebappClassLoaderBase.java:1353)
at org.apache.catalina.loader.WebappClassLoaderBase.checkStateForClassLoading(WebappClassLoaderBase.java:1341)
at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1206)
at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1167)
at org.apache.hadoop.util.ShutdownHookManager.getShutdownHooksInOrder(ShutdownHookManager.java:124)
at org.apache.hadoop.util.ShutdownHookManager.run(ShutdownHookManager.java:52)
12-Feb-2016 14:03:02.383 INFO [Thread-4] org.apache.coyote.AbstractProtocol.pause Pausing ProtocolHandler ["http-apr-8080"]
12-Feb-2016 14:03:02.449 INFO [Thread-4] org.apache.coyote.AbstractProtocol.pause Pausing ProtocolHandler ["ajp-apr-8009"]
12-Feb-2016 14:03:02.500 INFO [Thread-4] org.apache.catalina.core.StandardService.stopInternal Stopping service Catalina
12-Feb-2016 14:03:02.530 INFO [Thread-4] org.apache.coyote.AbstractProtocol.stop Stopping ProtocolHandler ["http-apr-8080"]
12-Feb-2016 14:03:02.581 INFO [Thread-4] org.apache.coyote.AbstractProtocol.stop Stopping ProtocolHandler ["ajp-apr-8009"]
我有一个依赖于与 HBase 的重量级连接的 JAX-RS 应用程序(运行 Jersey 2 on Tomcat)。我想在我的多个资源应用程序中初始化和重用该连接。我已经设置了一个将连接绑定为单例的活页夹,并使用@Inject 注释将该连接注入到我的资源中。但是,由于在第一次调用服务之前不会发生注入,因此直到那时才初始化连接。
应用程序:
public class MyApplication extends ResourceConfig {
public MyApplication() {
super(MyResource.class);
register(new HbaseBinder());
}
}
活页夹:
public class HbaseBinder extends AbstractBinder {
@Override
protected void configure() {
bindAsContract(HbaseConnection.class).in(Singleton.class);
bind(new HbaseConnection()).to(HbaseConnection.class);
}
}
注入:
@Path("/myResource")
public class MyResource {
@Inject
private HbaseConnection hbaseConnection;
...
}
HBase 连接:
@Singleton
public class HbaseConnection {
public Connection getConnection() throws IOException {
...
}
...
}
我想做的是在应用程序部署时初始化 Singleton,以便它准备好继续对服务的第一次调用。执行此操作的正确方法是什么?
您的 HbaseConnection
被初始化了两次。
- 首先,它会在您的活页夹中初始化(假设您的
MyApplication
class 在您的web.xml
中注册为init-param
) - 然后,当HK2检测到
@Singleton
注解(或执行bindAsContract
指令时)再次初始化
因此,要使您的示例有效,您需要:
- 从您的
HbaseConnection
class 中删除@Singleton
注释。 - 从您的
HBaseBinder
class 中删除行
bindAsContract(HbaseConnection.class).in(Singleton.class);
MyApplication
的初始化发生在 servlet 容器启动期间(因此 HbaseConnection
的构造),这正是您想要的,对吗?
提供实例(在活页夹中)的是您,而不是 HK2。这就是为什么您不想通过使用 @Singleton
来创建实例来指示它。
活页夹应该是:
public class HbaseBinder extends AbstractBinder {
@Override
protected void configure() {
// just bind is ok
bind(new HbaseConnection()).to(HbaseConnection.class);
}
}
HBase 连接:
// do not annotate with `@Singleton`!
public class HbaseConnection {
public Connection getConnection() throws IOException {
...
}
...
}
感谢您的所有评论和回答。需要以上各项的组合。
部分问题是我使用 @PostConstruct 调用 HbaseConnection.getConnection() 方法时出现未经检查的异常。一旦我摆脱了它,并切换到 Immediate 范围,class 似乎被适当地加载了。这是我的最终解决方案:
public class MyApplication extends ResourceConfig {
@Inject
public MyApplication(ServiceLocator locator) {
super(MyResource.class);
register(new HbaseBinder());
ServiceLocatorUtilities.enableImmediateScope(locator);
}
}
@Path("/myResource")
public class MyResource {
@Inject
private HbaseConnection hbaseConnection;
...
}
public class HbaseBinder extends AbstractBinder {
@Override
protected void configure() {
bindAsContract(HbaseConnection.class).in(Immediate.class);
}
}
@Immediate
public class HbaseConnection {
@PostConstruct
public void postConstruct() {
// Call getConnection(), wrapped in try/catch.
}
public Connection getConnection() throws IOException {
// Get the connection.
}
@PreDestroy
public void preDestroy() {
// Call cleanup(), wrapped in try/catch.
}
public void cleanup() throws IOException {
// Close/cleanup the connection
}
}
现在我唯一的问题是,看起来有些 Threads/ThreadLocals 正在取消部署,但这一定是我正在使用的库中的错误,因为我无法控制它们的生命周期。
12-Feb-2016 14:01:45.054 INFO [ContainerBackgroundProcessor[StandardEngine[Catalina]]] org.apache.catalina.startup.HostConfig.undeploy Undeploying context [/my-resource]
12-Feb-2016 14:01:46.129 WARNING [ContainerBackgroundProcessor[StandardEngine[Catalina]]] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesThreads The web application [my-resource] appears to have started a thread named [ImmediateThread-1455303641406] but has failed to stop it. This is very likely to create a memory leak. Stack trace of thread:
sun.misc.Unsafe.park(Native Method)
java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:215)
java.util.concurrent.SynchronousQueue$TransferQueue.awaitFulfill(SynchronousQueue.java:764)
java.util.concurrent.SynchronousQueue$TransferQueue.transfer(SynchronousQueue.java:695)
java.util.concurrent.SynchronousQueue.poll(SynchronousQueue.java:941)
java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1066)
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1127)
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
java.lang.Thread.run(Thread.java:745)
12-Feb-2016 14:01:46.130 WARNING [ContainerBackgroundProcessor[StandardEngine[Catalina]]] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesThreads The web application [my-resource] appears to have started a thread named [Thread-5] but has failed to stop it. This is very likely to create a memory leak. Stack trace of thread:
sun.net.dns.ResolverConfigurationImpl.notifyAddrChange0(Native Method)
sun.net.dns.ResolverConfigurationImpl$AddressChangeListener.run(ResolverConfigurationImpl.java:144)
12-Feb-2016 14:01:46.134 SEVERE [ContainerBackgroundProcessor[StandardEngine[Catalina]]] org.apache.catalina.loader.WebappClassLoaderBase.checkThreadLocalMapForLeaks The web application [my-resource] created a ThreadLocal with key of type [org.apache.htrace.core.Tracer.ThreadLocalContext] (value [org.apache.htrace.core.Tracer$ThreadLocalContext@2c25bbe0]) and a value of type [org.apache.htrace.core.Tracer.ThreadContext] (value [org.apache.htrace.core.Tracer$ThreadContext@787153ae]) but failed to remove it when the web application was stopped. Threads are going to be renewed over time to try and avoid a probable memory leak.
12-Feb-2016 14:01:46.135 SEVERE [ContainerBackgroundProcessor[StandardEngine[Catalina]]] org.apache.catalina.loader.WebappClassLoaderBase.checkThreadLocalMapForLeaks The web application [my-resource] created a ThreadLocal with key of type [org.apache.hadoop.io.Text] (value [org.apache.hadoop.io.Text@1badb836]) and a value of type [sun.nio.cs.UTF_8.Encoder] (value [sun.nio.cs.UTF_8$Encoder@13652d32]) but failed to remove it when the web application was stopped. Threads are going to be renewed over time to try and avoid a probable memory leak.
12-Feb-2016 14:01:46.136 SEVERE [ContainerBackgroundProcessor[StandardEngine[Catalina]]] org.apache.catalina.loader.WebappClassLoaderBase.checkThreadLocalMapForLeaks The web application [my-resource] created a ThreadLocal with key of type [org.apache.hadoop.hdfs.DFSUtil] (value [org.apache.hadoop.hdfs.DFSUtil@6080a3db]) and a value of type [java.util.Random] (value [java.util.Random@169acbf5]) but failed to remove it when the web application was stopped. Threads are going to be renewed over time to try and avoid a probable memory leak.
12-Feb-2016 14:03:02.383 INFO [Thread-7] org.apache.catalina.loader.WebappClassLoaderBase.checkStateForResourceLoading Illegal access: this web application instance has been stopped already. Could not load [org.apache.hadoop.util.ShutdownHookManager]. The following stack trace is thrown for debugging purposes as well as to attempt to terminate the thread which caused the illegal access.
java.lang.IllegalStateException: Illegal access: this web application instance has been stopped already. Could not load [org.apache.hadoop.util.ShutdownHookManager]. The following stack trace is thrown for debugging purposes as well as to attempt to terminate the thread which caused the illegal access.
at org.apache.catalina.loader.WebappClassLoaderBase.checkStateForResourceLoading(WebappClassLoaderBase.java:1353)
at org.apache.catalina.loader.WebappClassLoaderBase.checkStateForClassLoading(WebappClassLoaderBase.java:1341)
at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1206)
at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1167)
at org.apache.hadoop.util.ShutdownHookManager.getShutdownHooksInOrder(ShutdownHookManager.java:124)
at org.apache.hadoop.util.ShutdownHookManager.run(ShutdownHookManager.java:52)
12-Feb-2016 14:03:02.383 INFO [Thread-4] org.apache.coyote.AbstractProtocol.pause Pausing ProtocolHandler ["http-apr-8080"]
12-Feb-2016 14:03:02.449 INFO [Thread-4] org.apache.coyote.AbstractProtocol.pause Pausing ProtocolHandler ["ajp-apr-8009"]
12-Feb-2016 14:03:02.500 INFO [Thread-4] org.apache.catalina.core.StandardService.stopInternal Stopping service Catalina
12-Feb-2016 14:03:02.530 INFO [Thread-4] org.apache.coyote.AbstractProtocol.stop Stopping ProtocolHandler ["http-apr-8080"]
12-Feb-2016 14:03:02.581 INFO [Thread-4] org.apache.coyote.AbstractProtocol.stop Stopping ProtocolHandler ["ajp-apr-8009"]