如何在Jersey2 ServletContainer中获取HK2 ServiceLocator?

时间:2017-10-19 07:51:40

标签: guice jersey-2.0 hk2

我想让Jersey2和Guice一起合作,这显然相当困难。我已经看到了一些涉及使用HK2-to-Guice桥的解决方案。但该桥依赖于在自定义Jersey2 ServiceLocator的{​​{1}}中获取HK2 init()实例以初始化ServletContainer

GuiceBrige

但不知何故,在泽西岛(2.26)的最新版本中,public class MyServletContainer extends ServletContainer { @Override public void init() { ServiceLocator sloc = getApplicationHandler().getServiceLocator(); ... } } getServiceLocator()不再存在ApplicationHandler。我怎样才能在这种情况下得到它?

2 个答案:

答案 0 :(得分:8)

免责声明:我不使用Guice,所以这不是我测试过的。因此,我不知道OP正在尝试做什么甚至可以工作。我只是回答了如何获取ServiceLocator的主要问题。

正如my comment here中提到的,从2.26开始,泽西岛不再对HK2有 hard 依赖。因此,在整个代码库中,您将不再看到ServiceLocator的引用,而是更高级InjectionManagerInjectionManagerServiceLocator具有相同的目的,但抽象允许依赖注入提供程序的不同实现。这就是为什么在使用2.26时,我们需要添加jersey-hk2依赖项。这是InjectionManager的HK2实现。在此实现中,InjectionManager将在适当的时候将调用委托给基础ServiceLocator

话虽如此,ApplicationHandler让您现在可以访问InjectionManager,而不是ServiceLocatorServiceLocator本身就是一项服务,所以如果你有一个定位器,你可以做以下事情(这是毫无意义的,但它只是表明了我的观点)

ServiceLocator locator = getServiceLocator();
locator = locator.getService(ServiceLocator.class);

这意味着您还可以从InjectionManager获取定位器,InjectionManager im = getApplicationHandler().getInjectionManager(); ServiceLocator locator = im.getInstance(ServiceLocator.class); 只是底层定位器的高级委托人

super.init()

需要指出的一点是,我的免责声明的主要原因是您需要先在init()方法中拨打ApplicationHandler ,否则你当你试图获得init()时会得到一个NPE。这个问题是完成了很多的初始化;几乎整个应用程序都已初始化。因此,尝试添加Guice集成可能会或可能不会太晚。

以下是我见过这种集成的其他地方。而且我相信在ResourceConfig结尾处尝试这样做之前,他们都会被击中。

  • InjectionManager构造函数中,您可以在其中注入Feature
  • InjectionManager中,您可以通过InjectionManagerProvider静态方法获取ComponentProvider
  • 我没有看到任何实现,但我认为桥梁的首选位置是AlertDialog.Builder alert = new AlertDialog.Builder(this); alert.setView(R.layout.activity_alertdialog_date); DatePicker datePicker = (DatePicker) findViewById(R.id.Activity_AlertDialog_SetStartDate); // ... The rest of the AlertDialog, with buttons and all that stuff alert.create().show() ,如the docs中所述。我见过的唯一一个实现是Spring。您可以在jersey-spring4中查看来源。这可能需要更多工作,但我认为这将是最合适的位置,因为它在所有其他先前选项之前被调用。可能不需要它,因为我已经看到其他人可以选择其他两个选项。

答案 1 :(得分:0)

这里有同样的问题。

我最终在全局静态类中注册了从我的 FirebaseJobDispatcher dispatcher = new FirebaseJobDispatcher(new GooglePlayDriver(this)); Job downtimeOverNotificationJob = dispatcher.newJobBuilder() .setService(AppJobService.class) // the JobService that will be called .setTag("my-unique-tag") // uniquely identifies the job .setTrigger(Trigger.executionWindow(20,20)) .build(); dispatcher.mustSchedule(downtimeOverNotificationJob); @Override public boolean onStartJob(JobParameters job) { Toast.makeText(this, "Job started", Toast.LENGTH_SHORT).show(); new Handler(Looper.getMainLooper()).postDelayed(() -> { //Do something after 10000ms stopSelf(); }, 5000); return false; // Answers the question: "Is there still work going on?" } @Override public boolean onStopJob(JobParameters job) { Vibrator v = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE); // Vibrate for 500 milliseconds if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { v.vibrate(VibrationEffect.createOneShot(500,VibrationEffect.DEFAULT_AMPLITUDE)); }else{ //deprecated in API 26 v.vibrate(500); } return false; // Answers the question: "Should this job be retried?" } 子类注入的ServiceLocator,并希望它在正确的时间可用。确实如此,但我不知道使用

可以达到相同的目的
javax.ws.rs.core.Application

那样有点整洁。

另一种方法是将InjectionMananger#getInstance(ServiceLocator.class); 实现的类名放在META-INF / services中。这样,您就可以控制整个应用程序的根服务定位器,直到它到达Jersey。这里的问题是必须重写的单个方法必须返回一个新的ServiceLocatorGenerator对象,但是您不能使用ServiceLocator创建该对象,因为它会导致无限递归。因此,您必须创建并配置一个ServiceLocatorFactory,它非常复杂。但是,存在一个ServiceLocatorImpl,可以简单地从github复制并用作您的实现。您可以在这里将Guice桥接到HK2,然后再进行其他操作。我还没有尝试过,但是很快。