为什么 JNDI 资源在 Tomcat 中只能被调用一次?
Why JNDI resource can only be called once in Tomcat?
学习how to use JNDI resources in Tomcat 7的时候,做了一个定制的bean factory,叫MyBeanFactory
。它为我的网络应用程序提供了外部资源。第一次,我们假设它提供的是当前系统时间戳。
但是,我意识到 MyBeanFactory
在第一次请求时只被调用了一次。似乎 java bean MyBean
在第一次执行后已存储在 Tomcat 中。然后 MyBean
被每个请求重用。无论我何时在浏览器中重新输入 URL,响应总是显示与第一个相同的时间戳。以下是可能有帮助的元素列表:
- MyBean:
MyBeanFactory
提供的bean
- MyBeanFactory:实现
javax.naming.spi.ObjectFactory
的工厂
- context.xml:资源的上下文描述符,位于META-INF文件夹
- web.xml:部署描述符
- MyAction: http servlet
- 控制台
有人能告诉我为什么 MyBeanFactory
只被调用一次吗?是否可以更改此功能?因为我需要修改工厂与服务器中的另一个进程建立套接字。参见 How to serve a socket from a Java EE application?
MyBean
public class MyBean {
private String foo = "Default Foo";
private long bar = 0;
public String getFoo() { return (this.foo); }
public void setFoo(String foo) { this.foo = foo; }
public long getBar() { return (this.bar); }
public void setBar(long bar) { this.bar = bar; }
}
MyBeanFactory
public class MyBeanFactory implements ObjectFactory {
@Override
public Object getObjectInstance(Object obj, Name name, Context nameCtx,
Hashtable<?, ?> environment) throws NamingException {
System.out.println("MyBeanFactory starts");
MyBean bean = new MyBean();
bean.setBar(System.currentTimeMillis());
// Return the customized instance
return bean;
}
}
context.xml
<?xml version="1.0" encoding="UTF-8"?>
<Context
path="/jndi"
reloadable="true"
cachingAllowed="false"
antiResourceLocking="true">
<Resource
name="bean/MyBeanFactory"
auth="Container"
type="com.mycompany.MyBean"
factory="com.mycompany.MyBeanFactory"
bar="23"/>
</Context>
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
id="WebApp_ID"
version="3.1">
<display-name>jndi</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
<servlet>
<servlet-name>action</servlet-name>
<servlet-class>com.mycompany.MyAction</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>action</servlet-name>
<url-pattern>*.action</url-pattern>
</servlet-mapping>
<!--
Apache Tomcat 7: JNDI Resources HOW-TO
https://tomcat.apache.org/tomcat-7.0-doc/jndi-resources-howto.html
-->
<resource-env-ref>
<description>
Object factory for MyBean instances.
</description>
<resource-env-ref-name>
bean/MyBeanFactory
</resource-env-ref-name>
<resource-env-ref-type>
com.mycompany.MyBean
</resource-env-ref-type>
</resource-env-ref>
</web-app>
MyAction
public class MyAction extends HttpServlet {
// ...
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("doGet");
response.getWriter()
.append("Hello coming from ")
.append(request.getRequestURI());
Context initCtx = null;
try {
System.out.println("initCtx");
initCtx = new InitialContext();
} catch (NamingException e) {
e.printStackTrace();
}
Context envCtx = null;
try {
System.out.println("envCtx");
envCtx = (Context) initCtx.lookup("java:comp/env");
} catch (NamingException e) {
e.printStackTrace();
}
MyBean bean;
try {
System.out.println("lookup");
bean = (MyBean) envCtx.lookup("bean/MyBeanFactory");
response.getWriter()
.append("foo = " + bean.getFoo() + ", ")
.append("bar = " + bean.getBar() + ";");
} catch (NamingException e) {
e.printStackTrace();
}
System.out.println("------");
}
}
控制台
Dec 28, 2015 7:41:03 PM org.apache.catalina.startup.Catalina start
INFO: Server startup in 412 ms
doGet
initCtx
envCtx
lookup
MyBeanFactory starts // called only once
------
doGet
initCtx
envCtx
lookup
------
doGet
initCtx
envCtx
lookup
------
您提供的 <Resource>
元素具有超出 documented by Tomcat 8 的属性,特别是 "factory" 和 "bar"。然而,也许文档中错误地省略了前一个属性,因为一些示例使用了它。
无论如何,我想提请您注意 "singleton" 属性。当该属性的值为 true
(默认值)时,资源将被视为单例,具有由上下文维护并在所有用户之间共享的单个实例。这似乎是您描述的行为。如果将该属性添加到声明中,其值为 false
,则该资源的每次查找都应检索一个新实例。
学习how to use JNDI resources in Tomcat 7的时候,做了一个定制的bean factory,叫MyBeanFactory
。它为我的网络应用程序提供了外部资源。第一次,我们假设它提供的是当前系统时间戳。
但是,我意识到 MyBeanFactory
在第一次请求时只被调用了一次。似乎 java bean MyBean
在第一次执行后已存储在 Tomcat 中。然后 MyBean
被每个请求重用。无论我何时在浏览器中重新输入 URL,响应总是显示与第一个相同的时间戳。以下是可能有帮助的元素列表:
- MyBean:
MyBeanFactory
提供的bean
- MyBeanFactory:实现
javax.naming.spi.ObjectFactory
的工厂
- context.xml:资源的上下文描述符,位于META-INF文件夹
- web.xml:部署描述符
- MyAction: http servlet
- 控制台
有人能告诉我为什么 MyBeanFactory
只被调用一次吗?是否可以更改此功能?因为我需要修改工厂与服务器中的另一个进程建立套接字。参见 How to serve a socket from a Java EE application?
MyBean
public class MyBean {
private String foo = "Default Foo";
private long bar = 0;
public String getFoo() { return (this.foo); }
public void setFoo(String foo) { this.foo = foo; }
public long getBar() { return (this.bar); }
public void setBar(long bar) { this.bar = bar; }
}
MyBeanFactory
public class MyBeanFactory implements ObjectFactory {
@Override
public Object getObjectInstance(Object obj, Name name, Context nameCtx,
Hashtable<?, ?> environment) throws NamingException {
System.out.println("MyBeanFactory starts");
MyBean bean = new MyBean();
bean.setBar(System.currentTimeMillis());
// Return the customized instance
return bean;
}
}
context.xml
<?xml version="1.0" encoding="UTF-8"?>
<Context
path="/jndi"
reloadable="true"
cachingAllowed="false"
antiResourceLocking="true">
<Resource
name="bean/MyBeanFactory"
auth="Container"
type="com.mycompany.MyBean"
factory="com.mycompany.MyBeanFactory"
bar="23"/>
</Context>
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
id="WebApp_ID"
version="3.1">
<display-name>jndi</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
<servlet>
<servlet-name>action</servlet-name>
<servlet-class>com.mycompany.MyAction</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>action</servlet-name>
<url-pattern>*.action</url-pattern>
</servlet-mapping>
<!--
Apache Tomcat 7: JNDI Resources HOW-TO
https://tomcat.apache.org/tomcat-7.0-doc/jndi-resources-howto.html
-->
<resource-env-ref>
<description>
Object factory for MyBean instances.
</description>
<resource-env-ref-name>
bean/MyBeanFactory
</resource-env-ref-name>
<resource-env-ref-type>
com.mycompany.MyBean
</resource-env-ref-type>
</resource-env-ref>
</web-app>
MyAction
public class MyAction extends HttpServlet {
// ...
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("doGet");
response.getWriter()
.append("Hello coming from ")
.append(request.getRequestURI());
Context initCtx = null;
try {
System.out.println("initCtx");
initCtx = new InitialContext();
} catch (NamingException e) {
e.printStackTrace();
}
Context envCtx = null;
try {
System.out.println("envCtx");
envCtx = (Context) initCtx.lookup("java:comp/env");
} catch (NamingException e) {
e.printStackTrace();
}
MyBean bean;
try {
System.out.println("lookup");
bean = (MyBean) envCtx.lookup("bean/MyBeanFactory");
response.getWriter()
.append("foo = " + bean.getFoo() + ", ")
.append("bar = " + bean.getBar() + ";");
} catch (NamingException e) {
e.printStackTrace();
}
System.out.println("------");
}
}
控制台
Dec 28, 2015 7:41:03 PM org.apache.catalina.startup.Catalina start
INFO: Server startup in 412 ms
doGet
initCtx
envCtx
lookup
MyBeanFactory starts // called only once
------
doGet
initCtx
envCtx
lookup
------
doGet
initCtx
envCtx
lookup
------
您提供的 <Resource>
元素具有超出 documented by Tomcat 8 的属性,特别是 "factory" 和 "bar"。然而,也许文档中错误地省略了前一个属性,因为一些示例使用了它。
无论如何,我想提请您注意 "singleton" 属性。当该属性的值为 true
(默认值)时,资源将被视为单例,具有由上下文维护并在所有用户之间共享的单个实例。这似乎是您描述的行为。如果将该属性添加到声明中,其值为 false
,则该资源的每次查找都应检索一个新实例。