将google guice应用于方法依赖项

时间:2012-10-05 08:07:04

标签: java guice

考虑以下servlet代码:

public class AddDevice extends JsonServlet {
    private static final long serialVersionUID = 1L;

    @Override
    protected void doGet(final JsonServletRequest request,
            final JsonServletResponse response) throws ServletException,
            IOException {
        try {
            final DeviceEntity device = new DeviceEntity();

            device.type =
                    FleetManagerDatabaseHelper
                            .deviceTypesAccessor()
                            .queryForId(Integer.valueOf(
                                    request.getParameter(DeviceTypeEntity._ID)));

            device.sn = request.getParameter(DeviceEntity._SN);
            device.status = Long.valueOf(0);

            FleetManagerDatabaseHelper.devicesAccessor().create(device);
        }
        catch (final SQLException e) {
            throw new ServletException("device already exists");
        }
    }
}

此代码取决于DeviceEntity和FleetManagerDatabaseHelper类。 现在,我想编写一个测试,检查创建的实体是否填充了正确的类型,sn和状态值。 为此,我可以创建一个FleetManagerDatabaseHelperMockup类。

如果您在最小的变化中如何应用Google Guice(或其他内容)?

1 个答案:

答案 0 :(得分:1)

您的第一步是设计依赖注入 - 避免构造函数和静态方法,而是接受您需要的实例。看起来这些类型是Provider<DeviceEntity>DevicesAccessorDeviceTypesAccessor

Providera very simple Guice interface,它通过单个无参数方法get()提供其类型参数中任何类的实例。如果您已绑定Foo,Guice会自动知道如何绑定Provider<Foo>。如果您的实例很昂贵,或者在servlet的生命周期内需要多个实例,那么它非常有用。(正如您所做的那样)。

重构依赖注入后,您的类将如下所示:

public class AddDevice extends JsonServlet {
  private static final long serialVersionUID = 1L;

  private final Provider<DeviceEntity> deviceEntityProvider;
  private final DevicesAccessor devicesAccessor;
  private final DeviceTypesAccessor deviceTypesAccessor;

  @Inject
  public AddDevice(Provider<DeviceEntity> deviceEntityProvider,
      DevicesAccessor devicesAccessor,
      DeviceTypesAccessor deviceTypesAccessor>) {
    this.deviceEntityProvider = deviceEntityProvider;
    this.devicesAccessor = devicesAccessor;
    this.deviceTypesAccessor = deviceTypesAccessor;
  }

  @Override
  protected void doGet(final JsonServletRequest request,
      final JsonServletResponse response) throws ServletException,
      IOException {
    try {
      final DeviceEntity device = deviceEntityProvider.get();

      device.type = deviceTypesAccessor.queryForId(
          Integer.valueOf(request.getParameter(DeviceTypeEntity._ID)));
      device.sn = request.getParameter(DeviceEntity._SN)
      device.status = Long.valueOf(0);

      devicesAccessor.create(device);
    } catch (final SQLException e) {
      throw new ServletException("device already exists");
    }
  }
}

此时,通过传入跟踪其返回的实例的Provider以及模拟的DevicesAccessor和模拟的DeviceTypesAccessor来编写测试非常容易。 (我推荐Mockito。)如果您编写自己的Provider界面并删除@Inject,则甚至不需要使用Guice;在测试中,您可以继续使用该构造函数,但是您希望使用以下构造函数来满足Java EE:

public AddDevice() {
  this(new NewDeviceEntityProvider(),
      FleetManagerDatabaseHelper.deviceTypesAccessor(),
      FleetManagerDatabaseHelper.devicesAccessor());
}

private class NewDeviceEntityProvider implements Provider<DeviceEntity> {
  @Override public DeviceEntity get() {
    return new DeviceEntity();
  }
}

但如果您确实想使用Guice删除该样板,只需编写一个Guice Module。您的模块需要将DeviceTypesAccessor和DevicesAccessor绑定到FleetManagerDatabaseHelper将返回的实例; Guice会看到DeviceEntity有一个无参数构造函数,并且能够自动注入DeviceEntityProvider<DeviceEntity>。 (如果您希望我扩展Module的外观,请发表评论。)

希望这有帮助!