jersey + grizzly + hk2:依赖注入,但不注入资源

2023-11-27

跟进Jersey + HK2 + Grizzly:注入EntityManager的正确方法?,我想了解如何在类中使用依赖注入不是球衣资源.

例如,我可能在 ExecutorService 中运行后台任务,并且它们可能需要 EntityManager。如果我尝试@Inject将 EntityManager 放入类中,没有任何反应。将其注入@Path-带注释的球衣资源类,注入效果很好。

该应用程序作为独立的 JVM 运行,而不是在 Java EE 应用程序服务器上运行。

Update:我创建了一个测试场景来证明我的意思。该代码运行一个带有 Jersey 资源的独立 Grizzly 服务器以及 ExecutorService。 ACallable提交给ExecutorService。

将 EntityManager 注入到资源中可以正常工作,但不能注入到 Callable 中。 EntityManager 仍然存在null.

请告知代码是否保存在这里比放在 github 上更好。


因此,要真正了解 HK2 的工作原理,您应该熟悉它ServiceLocator。它类似于SpringApplicationContext,它是 DI 框架的主要容器。

在独立应用程序中,您可以简单地通过执行以下操作来引导 DI 容器

ServiceLocatorFactory locatorFactory = ServiceLocatorFactory.getInstance();
ServiceLocator serviceLocator = locatorFactory.create("TestLocator");
ServiceLocatorUtilities.bind(serviceLocator, new EntityManagerProvider());

现在你的EntityManagerProvider已注册到容器中。您可以查找EntityManager简单地通过做

EntityManager em = serviceLocator.getService(EntityManager.class);

现在为了能够利用容器的注入,服务需要由容器来管理。例如说你有这个

public class BackgroundTask implements Callable<String> {

    @Inject
    EntityManager em;

    @Override
    public String call() throws Exception {
        ...
}

你实际上是这样做的。问题是,BackgroundTask不受容器管理。因此,即使在独立的引导程序中(如上面的三行代码),实例化任务

BackgroundTask task = new BackgroundTask();

就注入而言,什么都不做,因为任务类不是由容器管理的,and你正在自己创造它。如果您希望对其进行管理,可以通过几种方法将其注册到容器中。您已经发现了一个(使用AbstractBinder)并将活页夹注册到ServiceLocator。然后,您不必自己实例化该类,而只需请求它,就像EntityManager上面的例子。

或者您可以简单地显式注入任务,即

BackgroundTask task = new BackgroundTask(); 
serviceLocator.inject(task);

这样做的目的是让定位器查找EntityManager并将其注入到您的任务中。

那么这一切如何与泽西岛相适应呢? Jersey(部分)在运行时处理服务查找和资源注入。这就是它在您的 Jersey 应用程序中起作用的原因。当。。。的时候EntityManager如果需要,它会查找服务并将其注入到资源实例中。

因此,下一个问题是,如果任务在 Jersey 应用程序范围之外运行,如何注入任务?在大多数情况下,以上内容几乎就是其要点。泽西岛有自己的ServiceLocator,并且尝试获取对它的引用并不容易。我们可以给泽西岛our ServiceLocator,但泽西岛最终仍然创造了它own定位器并将填充它our定位器。所以最终仍然会有两个定位器。您可以在下面的重构代码中看到我的意思的示例,其中它检查了ServiceLocatorFeature.

但如果您确实想提供ServiceLocator对于 Jersey,您可以将其传递给 Grizzly 服务器工厂方法

server = GrizzlyHttpServerFactory.createHttpServer(
        URI.create(BASE_URI),
        config, 
        serviceLocator
);

现在您仍然可以在泽西岛之外使用您的定位器。老实说,在这种情况下,你可以not完全涉及 Jersey 并保留您自己的定位器,然后注册EntityManagerProvider与泽西岛和你的ServiceLocator。除了额外的代码行之外,我认为它没有太大区别。从功能上来说,我没有看到任何变化。

要了解有关 HK2 的更多信息,我强烈建议彻底阅读用户指南。您将了解大量有关 Jersey 幕后情况的信息,并了解可合并到 Jersey 应用程序中的功能。

以下是测试的完整重构。我其实并没有改变太多。我所做的任何改变都在上面讨论过。

public class DependencyInjectionTest {

    private final ServiceLocatorFactory locatorFactory
            = ServiceLocatorFactory.getInstance();
    private ServiceLocator serviceLocator;

    private final static String BASE_URI = "http://localhost:8888/";
    private final static String OK = "OK";
    private HttpServer server;
    private ExecutorService backgroundService;

    public class EntityManagerProvider extends AbstractBinder
            implements Factory<EntityManager> {

        private final EntityManagerFactory emf;

        public EntityManagerProvider() {
            emf = Persistence.createEntityManagerFactory("derbypu");
        }

        @Override
        protected void configure() {
            bindFactory(this).to(EntityManager.class);
            System.out.println("EntityManager binding done");
        }

        @Override
        public EntityManager provide() {
            EntityManager em = emf.createEntityManager();
            System.out.println("New EntityManager created");
            return em;
        }

        @Override
        public void dispose(EntityManager em) {
            em.close();
        }
    }

    public class BackgroundTask implements Callable<String> {

        @Inject
        EntityManager em;

        @Override
        public String call() throws Exception {
            System.out.println("Background task started");
            Assert.assertNotNull(em);   // will throw exception

            System.out.println("EntityManager is not null");
            return OK;
        }
    }

    public class ServiceLocatorFeature implements Feature {

        @Override
        public boolean configure(FeatureContext context) {
            ServiceLocator jerseyLocator
                    = org.glassfish.jersey.ServiceLocatorProvider
                            .getServiceLocator(context);

            System.out.println("ServiceLocators are the same: "
                    + (jerseyLocator == serviceLocator));

            return true;
        }
    }

    @Path("/test")
    public static class JerseyResource {

        @Inject
        EntityManager em;

        @GET
        @Produces(MediaType.TEXT_PLAIN)
        public Response doGet() {
            System.out.println("GET request received");
            Assert.assertNotNull(em);

            System.out.println("EntityManager is not null");
            return Response.ok()
                    .entity(OK)
                    .build();
        }
    }

    @Before
    public void setUp() {
        serviceLocator = locatorFactory.create("TestLocator");
        ServiceLocatorUtilities.bind(serviceLocator, new EntityManagerProvider());

        System.out.println("Setting up");
        ResourceConfig config = new ResourceConfig();
        config.register(new ServiceLocatorFeature());
        //config.register(new EntityManagerProvider());
        config.register(JerseyResource.class);
        // can't find a better way to register the resource
        //config.registerInstances(JerseyResource.class);   

        server = GrizzlyHttpServerFactory.createHttpServer(
                URI.create(BASE_URI),
                config, serviceLocator
        );

        backgroundService = Executors.newSingleThreadScheduledExecutor();
    }

    @After
    public void tearDown() {
        System.out.println("Shutting down");
        server.shutdownNow();
        backgroundService.shutdownNow();
    }

    @Test
    public void testScheduledBackgroundTask() throws Exception {
        Assert.assertTrue(server.isStarted());

        BackgroundTask task = new BackgroundTask();
        serviceLocator.inject(task);
        Future<String> f = backgroundService.submit(task);
        System.out.println("Background task submitted");

        try {
            Assert.assertEquals(OK, f.get());   // forces Exception
        } catch (ExecutionException | InterruptedException ex) {
            System.out.println("Caught exception " + ex.getMessage());
            ex.printStackTrace();

            Assert.fail();
        }
    }

    @Test
    public void testBackgroundTask() throws Exception {
        Assert.assertTrue(server.isStarted());

        BackgroundTask task = new BackgroundTask();
        serviceLocator.inject(task);
        System.out.println("Background task instantiated");

        Assert.assertEquals(OK, task.call());
    }

    @Test
    public void testResource() {
        Assert.assertTrue(server.isStarted());

        Client client = ClientBuilder.newClient();
        WebTarget target = client.target(BASE_URI);

        Response r = target.path("test")
                .request()
                .get();
        Assert.assertEquals(200, r.getStatus());
        Assert.assertEquals(OK, r.readEntity(String.class));
    }
}

我可能提到的另一件事是你应该只需要一个EntityManagerFactory对于应用程序。创建成本很高,并且每次创建一个EntityManager需要不是一个好主意。查看一种解决方案here.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

jersey + grizzly + hk2:依赖注入,但不注入资源 的相关文章

随机推荐

  • 从类中删除必需的属性,但 MVC3 仍然不会在文本框中没有值的情况下发布表单

    我有课 在某一时刻 我使用 System ComponentModel 将类的属性设置为 Required 好吧 然后我意识到这是没有必要的 我已经删除了所需的属性 但是当我尝试将表单提交到 ActionResult 时 表单不会发布 并且
  • C# - 通过进程名称的一部分来终止进程

    我正在寻找如何在 C 中执行此操作 如下所示 foreach Process proc in Process GetProcessesByName cheatengine x86 64 proc Kill 我正在使用这个语句 但是该程序有不
  • 销毁并重新创建一个对象是否会使指向该对象的所有指针无效?

    这是后续这个问题 假设我有这样的代码 class Class public virtual method this gt Class new this Class Class object new Class object gt metho
  • 检测 Android JNI 代码中的本机内存泄漏

    如何检测Android JNI代码中的内存泄漏 我正在使用弗罗约 2017年更新 valgrind 可用对于安卓 内置的 malloc 调试功能在以下版本中得到了显着扩展 安卓N 对于查找内存泄漏非常有用 您可能需要 exit 应用程序触发
  • iPhone 的动态图标更改

    我的问题也和其他人之前问过的一样 我发现一旦你设置了应用程序的图标 我们就无法更改应用程序图标动态地 是的 我同意了 如果是这样 我们使用动态图标苹果不接受 但我承认苹果有一些规则和规定 所以这是我的问题 如何动态更改应用程序图标 我不会将
  • AppleScript:获取对象或类的所有属性的列表

    为了存储对象的值以供外部 外部 AS 访问 我需要能够获取该对象的每个属性 然后我尝试将其强制为文本并将其存储在某个地方 如何获取对象拥有的属性列表 作为一个例子 我可以这样写 tell me get properties end tell
  • 定义每个子类定义一次的静态属性的最佳方法是什么?

    我编写了以下控制台应用程序来测试静态属性 using System namespace StaticPropertyTest public abstract class BaseClass public static int MyPrope
  • Android 上的 Eclipse 调试出了什么问题? [复制]

    这个问题在这里已经有答案了 可能的重复 Android 看似无用的调试环境 我显然已经被 Visual Studio 宠坏了 因为虽然我刚刚学习 Android 和 Eclipse 环境 但在 Eclipse 中调试应用程序正在严重损害进一
  • 是什么导致我的函数最后返回 None ? [复制]

    这个问题在这里已经有答案了 我非常简单的 python 函数正在返回None最后 我不太清楚为什么 我看了一些其他的帖子 还是没明白 这是我的代码 def printmult n i 1 while i lt 10 print n i en
  • CSS图灵完备了吗?

    据我所知 CSS 不是图灵完备 但我对 CSS 的了解非常有限 CSS图灵完备了吗 你可以编码Rule 110在 CSS3 中 所以只要您考虑适当的随附 HTML 文件 它就是图灵完备的和用户交互成为CSS 执行 的一部分 A相当好的实施可
  • Java Excel POI 在quartz 多次执行后停止

    我想对此有一些见解 我有一个从数据库读取和写入 Excel 文件的程序 它的执行基于使用 Quartz api 的计时器 并在每周的每个星期二触发 问题是 当我通过安排它每小时执行一次作业来测试它时 程序在写入 Excel 文件的过程中执行
  • WPF 动画窗口可见性更改

    我正在尝试弄清楚如何为 WPF 窗口从 Visibile 到 Hidden 的更改设置动画 我目前让应用程序工作的方式是 窗口通常是隐藏的 当我将鼠标移动到屏幕一侧时 它会弹出 我正在使用布尔值到可见性转换器来执行此操作 但我想要做什么是让
  • R 将时间序列中的重复行与数据表中的不同列类型组合起来

    这个问题是建立在另一个问题的基础上的R 按 ID 将重复行与数据框中不同的列类型组合起来 我有一个带有列的数据表time以及其他一些不同类型的列 因子和数字 这是一个例子 dt lt data table time c 1 1 1 1 1
  • 如何在终端上运行Python脚本?

    我想在终端中运行 Python 脚本 但我不知道如何执行 我已经在目录 User luca Documents python 中保存了一个名为 gameover py 的文件 你需要python安装在您的系统上 然后您可以在终端的正确目录中
  • 设置SplitPane的分隔线位置

    我想将 SplitPane 的分隔线设置为某个默认位置 这不起作用 分隔线保持在中间 public void start Stage primaryStage throws Exception SplitPane splitPane new
  • 是否可以在线构建 Cordova App?

    我正在使用 PhoneGap 框架制作一个应用程序 PhoneGap提供构建服务 http build phonegap com 这使我们能够构建和将应用程序打包到云中 您不需要安装任何本地SDK构建应用程序 有什么办法可以建造科尔多瓦应用
  • Gradle Android 测试不支持过滤器(--tests)

    Gradle Android 测试不支持过滤器 tests gradlew test tests com example test works gradlew connectedAndroidTest tests com example t
  • 在一个 UITableView 问题中调用两个不同的自定义单元格

    我创建了一个自定义单元格 FeatureCell 该单元格中有 5 个图像 将在主视图中调用 但当我调用它时 我得到空行 那么请问我的问题可能出在哪里 我在谷歌上搜索了自定义单元格 并使用了我必须在下面的代码中使用的方式 但没有任何反应 这
  • DataSet 和 DataReader 哪个更好?

    我刚刚看到这个话题 数据表与数据集但这并没有解决我的疑问 让我更好地解释一下 我正在与数据库进行连接 需要在 GridView 中显示结果 我之前使用 VB6 时使用了 RecordSet DataSet 与它非常相似 因此使用 DataS
  • jersey + grizzly + hk2:依赖注入,但不注入资源

    跟进Jersey HK2 Grizzly 注入EntityManager的正确方法 我想了解如何在类中使用依赖注入不是球衣资源 例如 我可能在 ExecutorService 中运行后台任务 并且它们可能需要 EntityManager 如