问题描述
我正在尝试关闭我打开的资源解析器,但出现此错误“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。