2016-02-11 5 views
1

У меня есть приложение JAX-RS (работает Джерси 2 на Tomcat), которое полагается на супертяжелое соединение с HBase. Я хочу инициализировать и повторно использовать это соединение во всем приложении для нескольких ресурсов. Я установил Binder, который связывает соединение как Singleton, и использовал аннонт @Inject, чтобы вставить это соединение в мой ресурс. Однако, поскольку инъекция не происходит до первого вызова службы, соединение не инициализируется до тех пор.Как инициализировать введенное значение перед вызовом 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

Я бы предположил, что он инициализируется при его создании. Это потому, что все приложение Джерси не загружается до первого запроса, или просто соединение не загружается до первого запроса? –

+0

Я знаю, что приложение загружается, потому что мне удалось добавить ServletContextListener, и он запускается во время развертывания. Но соединение HBase не получает экземпляр до времени впрыска, который не будет до первого вызова конечной точки myResource. –

+0

Попытайтесь использовать [Immediate Scope] (http://stackoverflow.com/a/28123656/2587435) –

ответ

1

Спасибо за все комментарии и ответы. Требуется сочетание вышеуказанного.

Часть вопроса заключалась в том, что я использовал метод @PostConstruct для вызова метода HbaseConnection.getConnection(), который имел неконтролируемое исключение.Как только я избавился от этого и переключился на область Immediate, класс, похоже, загружен соответствующим образом. Вот мое окончательное решение:

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 или в Джерси? –

0

Ваш HbaseConnection получает инициализацию дважды.

  • сначала инициализируется в вашем вяжущего (при условии, MyApplication класс зарегистрирован как init-param в вашем web.xml)
  • , а затем, он еще раз, когда HK2 обнаруживает @Singleton аннотацию инициализирует (или когда он переходит в bindAsContract инструкцию)

в результате, чтобы сделать ваш пример работы, вам необходимо:

  1. удалить @Singleton аннотация из вашего HbaseConnection класс.
  2. удалить линии bindAsContract(HbaseConnection.class).in(Singleton.class); из вашего HBaseBinder класса

Инициализация MyApplication происходит во время запуска сервлета контейнера (таким образом, строительство 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. –

Смежные вопросы