我想访问一个环境变量,在web.xml中定义,在一个javax WebSocket的实例中,使用jetty9运行。
我可以访问任何servlet中的环境变量,或WebSocket的onOpen
方法,但不能访问WebSocket的onMessage
方法
web.xml:
<env-entry>
<env-entry-name>entry</env-entry-name>
<env-entry-type>java.lang.String</env-entry-type>
<env-entry-value>env value</env-entry-value>
</env-entry>
WebSocket.java:
package com.example;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
@ServerEndpoint("/ws")
public class WebSocket {
public String getEntry(Session session) {
try {
InitialContext ctx = new InitialContext();
return (String) ctx.lookup("java:comp/env/entry");
} catch (NamingException e) {
e.printStackTrace();
return null;
}
}
@OnOpen
public void onOpen(Session session) throws IOException {
String entry = getEntry(session);
System.out.println("onOpen: entry = " + (entry != null ? entry : "Not found"));
}
@OnMessage
public void onMessage(String message, Session session) throws IOException {
String entry = getEntry(session);
System.out.println("onMessage: entry = " + (entry != null ? entry : "Not found"));
}
}
pom.xml:
<dependencies>
<dependency>
<groupId>javax.websocket</groupId>
<artifactId>javax.websocket-api</artifactId>
<version>1.1</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.3</version>
<configuration>
<webappDirectory>${webAppDirectory}</webappDirectory>
</configuration>
</plugin>
</plugins>
</build>
输出:
onOpen: entry = env value
onMessage: entry = Not found
javax.naming.NameNotFoundException; remaining name 'env/entry'
at org.eclipse.jetty.jndi.NamingContext.lookup(NamingContext.java:538)
at org.eclipse.jetty.jndi.NamingContext.lookup(NamingContext.java:569)
at org.eclipse.jetty.jndi.NamingContext.lookup(NamingContext.java:584)
at org.eclipse.jetty.jndi.java.javaRootURLContext.lookup(javaRootURLContext.java:108)
at javax.naming.InitialContext.lookup(InitialContext.java:417)
at com.example.WebSocket.getEntry(WebSocket.java:17)
at com.example.WebSocket.onMessage(WebSocket.java:33)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.eclipse.jetty.websocket.common.events.annotated.CallableMethod.call(CallableMethod.java:70)
at org.eclipse.jetty.websocket.jsr356.annotations.OnMessageTextCallable.call(OnMessageTextCallable.java:60)
at org.eclipse.jetty.websocket.jsr356.annotations.JsrEvents.callText(JsrEvents.java:189)
at org.eclipse.jetty.websocket.jsr356.endpoints.JsrAnnotatedEventDriver.onTextMessage(JsrAnnotatedEventDriver.java:377)
at org.eclipse.jetty.websocket.common.message.SimpleTextMessage.messageComplete(SimpleTextMessage.java:69)
at org.eclipse.jetty.websocket.common.events.AbstractEventDriver.appendMessage(AbstractEventDriver.java:65)
at org.eclipse.jetty.websocket.jsr356.endpoints.JsrAnnotatedEventDriver.onTextFrame(JsrAnnotatedEventDriver.java:359)
at org.eclipse.jetty.websocket.common.events.AbstractEventDriver.incomingFrame(AbstractEventDriver.java:161)
at org.eclipse.jetty.websocket.common.WebSocketSession.incomingFrame(WebSocketSession.java:309)
at org.eclipse.jetty.websocket.common.extensions.ExtensionStack.incomingFrame(ExtensionStack.java:214)
at org.eclipse.jetty.websocket.common.Parser.notifyFrame(Parser.java:220)
at org.eclipse.jetty.websocket.common.Parser.parse(Parser.java:258)
at org.eclipse.jetty.websocket.common.io.AbstractWebSocketConnection.readParse(AbstractWebSocketConnection.java:632)
at org.eclipse.jetty.websocket.common.io.AbstractWebSocketConnection.onFillable(AbstractWebSocketConnection.java:480)
at org.eclipse.jetty.io.AbstractConnection$2.run(AbstractConnection.java:544)
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:635)
at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:555)
at java.lang.Thread.run(Thread.java:748)
答案 0 :(得分:0)
首先,我们需要添加一个自定义的ServletContextListener:
public class Config implements ServletContextListener {
private static final String ATTRIBUTE_NAME = "config";
private String entry;
@Override
public void contextInitialized(ServletContextEvent event) {
ServletContext servletContext = event.getServletContext();
String entryName = servletContext.getInitParameter("entry");
try {
entry = new InitialContext().lookup("java:comp/env/entry");
} catch (NamingException e) {
throw new RuntimeException("Config failed: entry not found", e);
}
servletContext.setAttribute(ATTRIBUTE_NAME, this);
}
@Override
public void contextDestroyed(ServletContextEvent event) {
}
public String getEntry() {
return entry;
}
public static Config getInstance(ServletContext servletContext) {
return (Config) servletContext.getAttribute(ATTRIBUTE_NAME);
}
}
在连接接受时,方法onOpen写一个新的上下文,你可以通过将ServletContext添加到当前上下文的EndpointConfig映射中来简单地传递它
public class ServletSavingContext extends ServerEndpointConfig.Configurator {
@Override
public void modifyHandshake(ServerEndpointConfig config, HandshakeRequest request, HandshakeResponse response) {
HttpSession httpSession = (HttpSession) request.getHttpSession();
config.getUserProperties().put("context", httpSession.getServletContext());
}
}
现在上一堂课:
package com.example;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.EndpointConfig;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
@ServerEndpoint(value = "/ws", configurator = ServletSavingContext.class)
public class WebSocket {
private EndpointConfig config;
@OnOpen
public void onOpen(Session session, EndpointConfig config) throws IOException {
this.config = config;
String entry = Config.getInstance(config.getUserProperties("context")).getEntry();
System.out.println("onOpen: entry = " + (entry != null ? entry : "Not found"));
}
@OnMessage
public void onMessage(String message, Session session) throws IOException {
String entry = Config.getInstance(config.getUserProperties("context")).getEntry();
System.out.println("onMessage: entry = " + (entry != null ? entry : "Not found"));
}
}
一些文档:http://docs.oracle.com/javaee/7/api/javax/websocket/EndpointConfig.html#getUserProperties%28%29
答案 1 :(得分:0)
注意:以下内容可能不是“最佳实践”,可能不能保证在所有容器上都可以使用,但在Tomcat上对我有用,并且可能对其他用户有用吗?
您可以将上下文分配给onOpen
中的实例变量,然后在onMessage
中使用相同的实例变量。
@ServerEndpoint("/ws")
public class WebSocket {
private Context envContext;
public String getEntry(Session session) {
try {
return this.envContext.lookup("entry");
} catch (NamingException e) {
e.printStackTrace();
return null;
}
}
@OnOpen
public void onOpen(Session session) throws IOException {
try {
InitialContext ctx = new InitialContext();
this.envContext = ctx.lookup("java:comp/env");
} catch (NamingException e) {
e.printStackTrace();
return null;
}
String entry = getEntry(session);
System.out.println("onOpen: entry = " + (entry != null ? entry : "Not found"));
}
@OnMessage
public void onMessage(String message, Session session) throws IOException {
String entry = getEntry(session);
System.out.println("onMessage: entry = " + (entry != null ? entry : "Not found"));
}
}
答案 2 :(得分:-2)
这是一种解决方法。我只是用前面存储的变量填充上下文:
@OnMessage
public void onMessage(String message, Session session) throws IOException, NamingException {
// Somewhere after onOpen, populate the context
InitialContext ctx = new InitialContext();
ctx.createSubcontext("java:comp/env");
ctx.bind("java:comp/env/entry", STORED_ENTRY); // Store the variable as an attribute of the WebSocket
String entry = getEntry(session);
System.out.println("onMessage: entry = " + (entry != null ? entry : "Not found"));
}