问题
When I was learning how to use JNDI resources in Tomcat 7, a customized bean factory has been made, called MyBeanFactory
. It provides external resources to my web application. At the first time, we assume that it provides the current system timestamp.
However, I realised that MyBeanFactory
was called only once, at the first request. It seems that the java bean MyBean
had be stored in Tomcat after the first execution. Then MyBean
is reused by every request. No matter when I retape the URL in browser, the response always showed the same timestamp as the first one. Here're a list of elements that might help :
- MyBean: the bean provided by
MyBeanFactory
- MyBeanFactory: the factory implementing
javax.naming.spi.ObjectFactory
- context.xml: the context descriptor for resources, located in META-INF folder
- web.xml: deployment descriptor
- MyAction: the http servlet
- console
Could somebody tell me why MyBeanFactory
is called only once and if it is possible to change this feature ? Because I need to modify the factory to establish a socket with another process in the server. See 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("------");
}
}
Console
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
------
回答1:
The <Resource>
element you present has attributes beyond those documented by Tomcat 8, specifically "factory" and "bar". Perhaps the former attribute is erroneously omitted from the docs, however, because some of the examples use it.
In any event, I would like to draw your attention to the "singleton" attribute. When the value of that attribute is true
(the default), the resource is treated as a singleton, with a single instance maintained by the context and shared among all users. This seems to be the behavior you describe. If you add that attribute to your declaration, with value false
, then each lookup of that resource should retrieve a new instance.
来源:https://stackoverflow.com/questions/34499922/why-jndi-resource-can-only-be-called-once-in-tomcat