【问题标题】:Jersey and resources managed by Guice泽西岛和 Guice 管理的资源
【发布时间】:2013-11-08 14:06:26
【问题描述】:

我正在开发一个在 OSGI 环境中动态加载 JAX 资源的应用程序。 这些资源由 Guice 管理,在每个 Bundle 中,它们被加载到在核心包上运行的 JAX 应用程序中。

ResourceConfig cfg = new ResourceConfig(context.getConfiguration());
for (Provider<?> r : kb.getResources()) {
  if (!cfg.isRegistered(r.get())) {
    cfg.registerInstances(r.get());
  }
}

context.reload(cfg);

其中 context 是由 Guice 管理的 Jersey ServletContext。

这一切都很完美。 出现问题是因为我们想在加载资源时操纵路径。然后,我们创建我们的 ModelProcessor。

@Override
public ResourceModel processResourceModel(ResourceModel resourceModel, Configuration configuration) {
    logger.info(actualKrundle.getName());
    ResourceModel.Builder newResourceModelBuilder = new ResourceModel.Builder(false);

    for (final Provider<?> r : actualKrundle.getResources()) {
        String name = r.get().getClass().getCanonicalName();
        List<Resource> resources = resourceModel.getResources();
        for (final Resource resource : resources) {
            if (resource.getName().endsWith(name)){
               final Resource.Builder resourceBuilder = Resource.builder(resource);
               //add the bundle name to resource path
               resourceBuilder.path(actualKrundle.getName()+"/"+resource.getPath());

               Resource r1 = resourceBuilder.build();
               newResourceModelBuilder.addResource(r1);
               break;
            }
        }
    }
    return newResourceModelBuilder.build();
}

错误是无法处理注入到资源中的所有依赖项。例如:如果资源注入了日期(@Inject Date 日期),则错误如下:

A MultiException has 1 exceptions.  They are:
1. org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for injection at Injectee(requiredType=Date,parent=ResourceFinder,qualifiers={}),position=-1,optional=false,self=false,unqualified=null,23999364)

        at org.jvnet.hk2.internal.ThreeThirtyResolver.resolve(ThreeThirtyResolver.java:74)[261:org.glassfish.hk2.locator:2.2.0.b21]
        at org.jvnet.hk2.internal.Utilities.justInject(Utilities.java:803)[261:org.glassfish.hk2.locator:2.2.0.b21]
        at org.jvnet.hk2.internal.ServiceLocatorImpl.inject(ServiceLocatorImpl.java:832)[261:org.glassfish.hk2.locator:2.2.0.b21]
        at org.jvnet.hk2.internal.ServiceLocatorImpl.inject(ServiceLocatorImpl.java:822)[261:org.glassfish.hk2.locator:2.2.0.b21]

.... …… ....

我认为错误在于新实例(资源 r1)是由 H2K 而不是 Guice 处理的,并且不能满足您的依赖关系。

我们尝试在 OSGI 环境中使用 guice-bridge 工件,但这会报错:未找到 ServiceLocator 的实现。

但所有依赖项都在类路径中:

karaf@root> la | grep HK2
[ 260] [Active     ] [            ] [   30] HK2 API module (2.2.0.b21)
[ 262] [Active     ] [            ] [   30] HK2 Implementation Utilities (2.2.0.b21)
[ 283] [Active     ] [            ] [   30] HK2 Guice Bridge (2.1.96)
karaf@root> la | grep ServiceLo
[ 261] [Active     ] [            ] [   30] ServiceLocator Default Implementation (2.2.0.b21)
karaf@root> 

那么,如果解决方案是使用 guice-bridge,那么如何更改 guice 管理的资源的路径,这是最好的配置方式吗?

我正在使用球衣 2.4。

谢谢

【问题讨论】:

    标签: jersey osgi guice jersey-2.0 hk2


    【解决方案1】:

    我找到的解决方案(如果不是最好的)是定义一个 CustomServletContext 并使用 guice-bridge 工件,参考 jersey issue tracker 中的 issue HK2-121。 解决办法:

     public class KratosServletContainer extends ServletContainer {
    
         private Injector injector;
    
         @Inject
        KratosServletContainer(Injector injector, ResourceConfig configuration) {
             super(configuration);
             this.injector = injector;
         }
    
         @Override
         protected void init(WebConfig webConfig) throws ServletException {
             super.init(webConfig);
    
             ServiceLocator locator;
             try {
                 Field webComponentField = getClass().getSuperclass()
                         .getDeclaredField("webComponent");
    
                 webComponentField.setAccessible(true);
                 WebComponent webComponent = (WebComponent) webComponentField.get(this);
    
                 Field appHandlerField = webComponent.getClass().getDeclaredField("appHandler");
                 appHandlerField.setAccessible(true);
                 ApplicationHandler appHandler = (ApplicationHandler) appHandlerField.get(webComponent);
                 locator = appHandler.getServiceLocator();
    
             } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | llegalAccessException e) {
                 throw new RuntimeException(e);
             }
    
             GuiceBridge.getGuiceBridge().initializeGuiceBridge(
                     locator);
    
             GuiceIntoHK2Bridge guiceBridge = locator
                     .getService(GuiceIntoHK2Bridge.class);
             guiceBridge.bridgeGuiceInjector(injector);
         } 
    }
    

    例如: 我的资源如下所示:

    @Path("resource") 
    public class ResourceFinder {
    
         private static final Logger logger = Logger.getLogger(ResourceFinder.class.getName());
    
         private Date date;
    
         private final PersistenceManagerService pm;
    
         @Inject
         public ResourceFinder(Date date, PersistenceManagerService pm) {
             this.date = date;
             this.pm = pm;   
         }
    
         @GET
         @Produces(MediaType.APPLICATION_JSON)
         @Path("/suma/{value1}/{value2}")
         @PermitAll
         public String getSuma(@PathParam("value1") int value1,
                 @PathParam("value2") int value2) {
    
             User user = new User();
    
             user.setName("cacho" + value1);
    
    
    
             pm.get().makePersistent(user);
    
             pm.get().flush();
    
             //date was injected by guice
             //pm was injected by guice
    
             return String.valueOf(value1 + value2 + "   "+pm.get()+" "+date);
         } 
    }
    

    方法:

         @Override
         public ResourceModel processResourceModel(ResourceModel resourceModel, Configuration configuration) {
             logger.info(actualKrundle.getName());
             ResourceModel.Builder newResourceModelBuilder = new ResourceModel.Builder(false);
    
             for (final Provider<?> r : actualKrundle.getResources()) {
                 String name = r.get().getClass().getCanonicalName();
                 List<Resource> resources = resourceModel.getResources();
                 for (final Resource resource : resources) {
                     if (resource.getName().endsWith(name)){
                        final Resource.Builder resourceBuilder = Resource.builder(resource);
                        resourceBuilder.path(actualKrundle.getName()+"/"+resource.getPath());
                        Resource r1 = resourceBuilder.build();
                        newResourceModelBuilder.addResource(r1);
                        break;
                     }
                 }
             }
             return newResourceModelBuilder.build();
         }
    

    更改资源的路径,重新创建实例,一切都保持注入...

    【讨论】:

      猜你喜欢
      • 2016-05-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多