Tomcat 通过执行程序访问时上下文为空且可运行
Tomcat context is empty when accessed via executor and runnable
您好,我在 apache-tomee-plus-8.0.1 上有一个 Web 应用程序 运行。我的问题是关于从自定义执行程序中的可运行对象获取环境变量。变量定义在 /conf/context.xml:
<?xml version="1.0" encoding="UTF-8"?>
<Context>
<!-- Default set of monitored resources. If one of these changes, the -->
<!-- web application will be reloaded. -->
<WatchedResource>WEB-INF/web.xml</WatchedResource>
<WatchedResource>WEB-INF/tomcat-web.xml</WatchedResource>
<WatchedResource>${catalina.base}/conf/web.xml</WatchedResource>
<!-- disable the scan in order to avoid errors at startup due to ora18n.jar-->
<JarScanner scanManifest="false" scanClassPath="false" scanBootstrapClassPath="false"></JarScanner>
<!-- base64 from user:pass -->
<Environment name="myCreds"
value="toto" type="java.lang.String" />
</Context>
我用来获取变量“myCreds”的函数
private static String getCredentialsFromContext() throws NamingException {
Context initialContext = new InitialContext();
Context environmentContext = (Context) initialContext.lookup("java:comp/env");
return (String) environmentContext.lookup("myCreds");
}
此函数通过 JAX-RS 端点调用,该端点用于启动服务器应用程序的长时间后台维护任务。后台任务的进度随后可在另一个端点上获得。
如果我这样做
@GET
@Path("/testOK")
public static String testOK() {
return getCredentialsFromContext(); // works fine
}
但是当我使用执行程序时,查找失败并显示
javax.naming.NameNotFoundException:名称 [comp/env] 未在此上下文中绑定。找不到 [comp].
private static ExecutorService index_executor;
@GET
@Path("/testKO")
public static Response testKO() {
if (index_executor == null){
index_executor = Executors.newFixedThreadPool(5);
}
index_executor.submit(new Runnable() {
@Override
public void run() {
System.out.println(getCredentialsFromContext()); // FAIL
}
});
return Response.ok.build()
}
从可运行对象调用时,InitialContext 似乎不一样。我想避免通过 args 传递“myCreds”的值。我试图在 webapp 的 context.xml 中移动“myCreds”的声明,但它没有帮助。使用 JNDIContext 也会失败。
您了解问题所在以及上下文不同的原因吗?
谢谢:)
JNDI 查找依赖于 运行 线程上的某些上下文信息,通常是上下文 class 加载程序。
在 Java EE/Jakarta EE 服务器上,您不应自己生成新的(非托管)线程,而应使用容器提供的 ManagedExecutorService
。此服务自动从调用线程传播某些类型的上下文:
The types of contexts to be propagated from a contextualizing application component include JNDI naming context, classloader, and security information. Containers must support propagation of these context types.
(Jakarta Concurrency Specification,强调我的)
您可以使用 @Resource
注释注入 ManagedExecutorService
:
@Resource
private ManagedExecutorService executorService;
在 Wildfly 上使用 ManagedExecutorService
,但在 TomEE 上有一个错误阻止命名上下文的传播:JAX-RS 资源使用 CxfContainerClassLoader
作为上下文 classloader,它包装了真正的 classloader,防止它传播到托管线程。
解决方法包括暂时切换到包装的 classloader:
final ClassLoader tccl = Thread.currentThread().getContextClassLoader();
if (tccl instanceof org.apache.openejb.util.classloader.Unwrappable) {
final ClassLoader cl = ((org.apache.openejb.util.classloader.Unwrappable) tccl).unwrap();
Thread.currentThread().setContextClassLoader(cl);
}
executorService.submit(...);
Thread.currentThread().setContextClassLoader(tccl);
编辑:实际上,将JAX-RS资源标记为@Stateless
就足以正确传播JNDI命名上下文。
您好,我在 apache-tomee-plus-8.0.1 上有一个 Web 应用程序 运行。我的问题是关于从自定义执行程序中的可运行对象获取环境变量。变量定义在 /conf/context.xml:
<?xml version="1.0" encoding="UTF-8"?>
<Context>
<!-- Default set of monitored resources. If one of these changes, the -->
<!-- web application will be reloaded. -->
<WatchedResource>WEB-INF/web.xml</WatchedResource>
<WatchedResource>WEB-INF/tomcat-web.xml</WatchedResource>
<WatchedResource>${catalina.base}/conf/web.xml</WatchedResource>
<!-- disable the scan in order to avoid errors at startup due to ora18n.jar-->
<JarScanner scanManifest="false" scanClassPath="false" scanBootstrapClassPath="false"></JarScanner>
<!-- base64 from user:pass -->
<Environment name="myCreds"
value="toto" type="java.lang.String" />
</Context>
我用来获取变量“myCreds”的函数
private static String getCredentialsFromContext() throws NamingException {
Context initialContext = new InitialContext();
Context environmentContext = (Context) initialContext.lookup("java:comp/env");
return (String) environmentContext.lookup("myCreds");
}
此函数通过 JAX-RS 端点调用,该端点用于启动服务器应用程序的长时间后台维护任务。后台任务的进度随后可在另一个端点上获得。 如果我这样做
@GET
@Path("/testOK")
public static String testOK() {
return getCredentialsFromContext(); // works fine
}
但是当我使用执行程序时,查找失败并显示 javax.naming.NameNotFoundException:名称 [comp/env] 未在此上下文中绑定。找不到 [comp].
private static ExecutorService index_executor;
@GET
@Path("/testKO")
public static Response testKO() {
if (index_executor == null){
index_executor = Executors.newFixedThreadPool(5);
}
index_executor.submit(new Runnable() {
@Override
public void run() {
System.out.println(getCredentialsFromContext()); // FAIL
}
});
return Response.ok.build()
}
从可运行对象调用时,InitialContext 似乎不一样。我想避免通过 args 传递“myCreds”的值。我试图在 webapp 的 context.xml 中移动“myCreds”的声明,但它没有帮助。使用 JNDIContext 也会失败。 您了解问题所在以及上下文不同的原因吗?
谢谢:)
JNDI 查找依赖于 运行 线程上的某些上下文信息,通常是上下文 class 加载程序。
在 Java EE/Jakarta EE 服务器上,您不应自己生成新的(非托管)线程,而应使用容器提供的 ManagedExecutorService
。此服务自动从调用线程传播某些类型的上下文:
The types of contexts to be propagated from a contextualizing application component include JNDI naming context, classloader, and security information. Containers must support propagation of these context types.
(Jakarta Concurrency Specification,强调我的)
您可以使用 @Resource
注释注入 ManagedExecutorService
:
@Resource
private ManagedExecutorService executorService;
在 Wildfly 上使用 ManagedExecutorService
,但在 TomEE 上有一个错误阻止命名上下文的传播:JAX-RS 资源使用 CxfContainerClassLoader
作为上下文 classloader,它包装了真正的 classloader,防止它传播到托管线程。
解决方法包括暂时切换到包装的 classloader:
final ClassLoader tccl = Thread.currentThread().getContextClassLoader();
if (tccl instanceof org.apache.openejb.util.classloader.Unwrappable) {
final ClassLoader cl = ((org.apache.openejb.util.classloader.Unwrappable) tccl).unwrap();
Thread.currentThread().setContextClassLoader(cl);
}
executorService.submit(...);
Thread.currentThread().setContextClassLoader(tccl);
编辑:实际上,将JAX-RS资源标记为@Stateless
就足以正确传播JNDI命名上下文。