关闭 AEM 中的资源解析器对象后会话已关闭

问题描述

我正在尝试关闭我打开的资源解析器,但出现此错误“javax.jcr.RepositoryException:当我关闭资源解析器时,此会话已关闭。实际上,如果您将资源解析器保持打开状态,我看不出任何问题,但我不想在代码中将资源解析器保持打开状态。

serviceParam.put(ResourceResolverFactory.SUBSERVICE,"serviceNew");
        ResourceResolver resourceResolver = null;

        try
        {

            resourceResolver = resourceResolverFactory.getServiceResourceResolver(serviceParam);

            final Configuration configuration = configurationManagerFactory.getConfigurationManager(resourceResolver)
                    .getConfiguration(cloudConfigurationType.getServiceName(),services);

            if (null != configuration)
            {
               return configuration.getContentResource().adaptTo(ValueMap.class);
            }

        } catch (LoginException e)
        {
            // Todo Auto-generated catch block
            e.printstacktrace();
        } finally
        {
            if (resourceResolver != null && resourceResolver.isLive())
            {
                resourceResolver.close();
            }
        }

错误信息:-

org.apache.sling.engine.impl.SlingRequestProcessorImpl service: Uncaught SlingException
java.lang.IllegalArgumentException: javax.jcr.RepositoryException: This session has been closed.
    at org.apache.sling.jcr.resource.internal.JcrValueMap.read(JcrValueMap.java:337) [org.apache.sling.jcr.resource:3.0.16]
    at org.apache.sling.jcr.resource.internal.JcrValueMap.get(JcrValueMap.java:101) [org.apache.sling.jcr.resource:3.0.16]

如果我没有在代码关闭资源解析器,会在日志中观察到许多如下所示的错误消息

 23.12.2020 11:56:30.481 [Apache Sling Resource Resolver Finalizer Thread] INFO o.a.s.r.i.CommonResourceResolverFactoryImpl Unclosed ResourceResolver was created here:
    java.lang.Exception: opening Stacktrace
    at org.apache.sling.resourceresolver.impl.CommonResourceResolverFactoryImpl$ResolverReference.<init>(CommonResourceResolverFactoryImpl.java:540)

真正的问题是,一旦我们关闭资源解析器,会话就会关闭。这是 AEM 代码的问题吗?或者有什么其他方法可以处理这种情况?

解决方法

返回的问题是 ValueMap 对象尝试使用内部创建的 ResourceResolver 动态访问存储库,但该 Resolver 在退出您的方法时已立即关闭(在 finally 块中)。

有不同的解决方案可以克服这个问题,效率更高/更低:

解决方案 1) 当您只需要对 ValueMap 属性进行只读访问时,您可以返回该映射的副本:

  ...
  ValueMap props = configuration.getContentResource().adaptTo(ValueMap.class)
  return (props != null) ? new HashMap<>(props)     // create the copy Map of props
                         : new HashMap<String,Object>(0);

解决方案 2) 不要使用内部创建的“服务用户”ResourceResolver,而是将当前用户的 ResourceResolver 传递到您的方法中,并确保用户具有访问配置节点的权限。

解决方案 3) 创建 get(propertyName)set(propertyName,value) 方法来读/写特定的 Configuration 属性,它们将创建内部 ResourceResolver 并在 get/set 操作后立即关闭它:

  public Object getProp(String name) {
    try(ResourceResolver resolver =  resourceResolverFactory.getServiceResourceResolver(serviceParam)) {
      Configuration configuration = configurationManagerFactory.getConfigurationManager(resolver)
                    .getConfiguration(cloudConfigurationType.getServiceName(),services);
      if (null != configuration){
         return configuration.getContentResource().adaptTo(ValueMap.class).get(name);
      }
    }
  }

解决方案 4) 在某个上层方法中创建服务ResourceResolver,并通过它直到不需要ValueMap:

    ...
    try(ResourceResolver resolver =  resourceResolverFactory.getServiceResourceResolver(serviceParam)) {
      ...
      ValueMap confProps = getConfigProps(resolver,...);  // call your method
      //  use confProps as you wish safely
      ...
    }  // at this place,Resolver is closed and you cannot use confProps any more
  }
    ...

解决方案 5)(解决方案 #4 的极端变体) 在您的类/包启动时创建服务 ResourceResolver 一次,让它一直存在直到应用程序关闭,将其传递给您的方法。 不过,Sling 文档并不完全推荐此变体..

我可以根据需要提供更多样品。

,

嗯,基本上问题是代码。根据定义关闭 ResourceResolver 也会关闭它所基于的会话。 诀窍是在之后关闭它,您不再需要所有依赖对象(例如 ValueMap)。

HTH。