2016-02-11 18 views
1

我有一個依賴於HBase的重量級連接的JAX-RS應用程序(在Tomcat上運行Jersey 2)。我想在我的應用程序中爲多個資源初始化和重用該連接。我已經建立了一個將單連接綁定到連接的Binder,並使用@Inject annotaton將該連接注入到我的資源中。但是,由於在第一次調用服務之前不會發生注入,因此直到此時纔會初始化連接。如何在REST調用之前初始化注入值?

的應用:

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,這樣它就可以開始第一次調用服務。什麼是正確的方法來做到這一點?

+0

我會想象它會初始化時,你實例化它。是否因爲整個Jersey應用程序在第一個請求之前不加載,或者只有在第一個請求之前連接沒有加載? –

+0

我知道應用程序被加載,因爲我已經能夠添加一個ServletContextListener,並且它在部署時被執行。但是HBase連接直到注入時纔會被實例化,直到第一次調用myResource端點。 –

+0

嘗試和使用[立即作用域](http://stackoverflow.com/a/28123656/2587435) –

回答

1

感謝您所有的意見和答案。上述的組合是必需的。

問題的一部分是我使用@PostConstruct來調用HbaseConnection.getConnection()方法有一個未經檢查的異常。一旦我擺脫了這一點,並切換到立即範圍,類似乎被適當加載。這是我的最終解決方案:

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 
    } 
} 

現在我唯一的問題是,它看起來像某些線程/ 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 [[email protected]]) and a value of type [org.apache.htrace.core.Tracer.ThreadContext] (value [[email protected]]) 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 [[email protected]]) and a value of type [sun.nio.cs.UTF_8.Encoder] (value [[email protected]]) 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 [[email protected]]) and a value of type [java.util.Random] (value [[email protected]]) 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"] 
+0

正如我在上面的評論中所說的,直接範圍留下了線程。如果你願意,你可以看看它,併爲改進後的HK2作出貢獻。 :)通過https://java.net/jira/browse/JERSEY-2291(至少從球衣方面)追蹤它。 –

+0

@peeskillet我不明白你的觀點。布賴恩說,線程留在解僱部分,我說,這不是一個簡單的解決方案,我也鼓勵他爲hk2做出貢獻。是的,這就是爲什麼它沒有在澤西默認啓用的原因。 –

+0

@peeskillet你是誰?您是否參與了JAX-RS社區或Jersey開發? –

0

您的HbaseConnection被初始化兩次。

  • 首先,它在粘合劑初始化(設置你的MyApplication類是在你的web.xml註冊爲init-param
  • 然後,它當HK2檢測@Singleton註釋再次初始化(或者當它前進的bindAsContract指令)

其結果是,使您的工作例如,你需要:

  1. 從您的HbaseConnection類中刪除@Singleton註釋。
  2. 刪除線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 { 
     ... 
    } 
    ... 
} 
+0

這有效,但如果我想在容器關閉之前使用PreDestroy註釋來清理連接,該怎麼辦?看起來我的PreDestroy是不會被調用的,除非HbaseConnection是用Singleton註解的。 –

相關問題