Why JNDI resource can only be called once in Tomcat?

…衆ロ難τιáo~ 提交于 2020-01-06 16:01:32

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!