我有一个JAX-RS应用程序(在Tomcat上运行Jersey 2),它依赖于与HBase的重量级连接。我希望在整个应用程序中初始化并重用该连接以获得多种资源。我已经设置了一个Binder,它将连接绑定为Singleton,并使用@Inject annotaton将该连接注入到我的资源中。但是,由于注入在第一次调用服务之前不会发生,因此在此之前不会初始化连接。
申请表:
public class MyApplication extends ResourceConfig {
public MyApplication() {
super(MyResource.class);
register(new HbaseBinder());
}
}
The Binder:
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,以便它可以第一次调用该服务。这样做的正确方法是什么?
答案 0 :(得分:1)
Thank you for all of the comments and answers. A combination of the above were required.
Part of the issue was that I was using the the @PostConstruct to call the HbaseConnection.getConnection() method had an unchecked exception. Once I got rid of that, and switch to the Immediate scope, the class seems to be loaded appropriately. Here's my final solution:
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
}
}
Now my only problem is that it looks like some Threads/ThreadLocals are being left around on undeployment, but this has to be bugs in the libraries that I'm using as I have no control over their lifecycle.
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$1] (value [org.apache.hadoop.io.Text$1@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$1] (value [org.apache.hadoop.hdfs.DFSUtil$1@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$2]. 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$2]. 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$1.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"]
答案 1 :(得分:0)
您的HbaseConnection
初始化两次。
MyApplication
类已在init-param
中注册为web.xml
)@Singleton
注释时(或当它进行bindAsContract
指令时)它再次初始化因此,要使您的示例正常工作,您需要:
@Singleton
课程中删除HbaseConnection
注释。bindAsContract(HbaseConnection.class).in(Singleton.class);
类HBaseBinder
醇>
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 {
...
}
...
}