Servlets 在由许多servlet扩展的基础servlet中,在WEB-INF中只加载一次自定义XML文件

Servlets 在由许多servlet扩展的基础servlet中,在WEB-INF中只加载一次自定义XML文件,servlets,Servlets,我有一个普通的JavaEEWeb应用程序,它不使用任何类似Struts、JSF等框架。在这个Web应用程序中,我有一个自定义XML(custom config.XML)文件 其中包含特定于该应用程序的配置列表。我不想在web.xml文件中提及此配置信息。现在当容器第一次 初始化任何servlet,我需要读取custom config.xml文件中提到的配置信息。为了实现这一点,我创建了一个自定义Servlet类,比如CustomServlet,它 扩展自HttpServlet,我的所有servl

我有一个普通的
JavaEE
Web应用程序,它不使用任何类似
Struts
JSF
等框架。在这个Web应用程序中,我有一个自定义XML(
custom config.XML
)文件 其中包含特定于该应用程序的配置列表。我不想在
web.xml
文件中提及此配置信息。现在当容器第一次 初始化任何servlet,我需要读取
custom config.xml
文件中提到的配置信息。为了实现这一点,我创建了一个自定义Servlet类,比如
CustomServlet
,它 扩展自
HttpServlet
,我的所有servlet都将扩展frm this
CustomServlet
。因此,当Serlvet类加载时,我的
CustomServlet
类也将加载

在我的
CustomServlet
类中,我有一个静态方法,该方法将加载
custom config.xml
文件并理解本文中提到的配置

我有两个问题。 这是正确的方法吗?或者我应该把它放在
CustomServlet
类的
init()方法中吗?

如何从类路径加载
custom config.xml
文件?我无法使用
ServletConfig.getResourceAsStream()
,因为我正在尝试从静态方法加载
custom config.xml

首先,为什么要使用静态方法加载xml文件?静态方法属于类而不属于对象。在super类中有一个默认构造函数,并使其能够加载xml

public abstract class BaseServlet extends HttpServlet{

public Base(){
loadXml();
}
private void loadXml(){
...
}
}

public class Servlet1 extends BaseServlet {
...
}

如果xml是类路径,那么可以使用FileInputStream()加载xml文件。

首先,为什么要使用静态方法加载xml文件?静态方法属于类而不属于对象。在super类中有一个默认构造函数,并使其能够加载xml

public abstract class BaseServlet extends HttpServlet{

public Base(){
loadXml();
}
private void loadXml(){
...
}
}

public class Servlet1 extends BaseServlet {
...
}

如果xml是类路径,则可以使用FileInputStream()加载xml文件。

在静态方法中加载没有意义。从那里无法获取
ServletContext
。你需要用这种方法来做。您可以使用一个
静态原子布尔
来检查它是否已经加载到当前JVM中

public abstract class CustomServlet extends HttpServlet {

    private static AtomicBoolean loaded = new AtomicBoolean();

    @Override
    public void init() throws ServletException { 
        if (!loaded.getAndSet(true)) {
            InputStream input = getServletContext().getResourceAsStream("/WEB-INF/custom-config.xml");
            // ...
        }
    }

    // ...
}
或者,使用
ServletContextListener

@WebListener
public class Config implements ServletContextListener {

    @Override
    public void contextInitialized(ServletContextEvent event) {
        InputStream input = event.getServletContext().getResourceAsStream("/WEB-INF/custom-config.xml");
        // ...
    }

    // ...
}
您可以将解析后的XML结果放在应用程序范围中,使其可供所有servlet使用

另见:

用静态方法做这件事毫无意义。从那里无法获取
ServletContext
。你需要用这种方法来做。您可以使用一个
静态原子布尔
来检查它是否已经加载到当前JVM中

public abstract class CustomServlet extends HttpServlet {

    private static AtomicBoolean loaded = new AtomicBoolean();

    @Override
    public void init() throws ServletException { 
        if (!loaded.getAndSet(true)) {
            InputStream input = getServletContext().getResourceAsStream("/WEB-INF/custom-config.xml");
            // ...
        }
    }

    // ...
}
或者,使用
ServletContextListener

@WebListener
public class Config implements ServletContextListener {

    @Override
    public void contextInitialized(ServletContextEvent event) {
        InputStream input = event.getServletContext().getResourceAsStream("/WEB-INF/custom-config.xml");
        // ...
    }

    // ...
}
您可以将解析后的XML结果放在应用程序范围中,使其可供所有servlet使用

另见:


为什么它需要是一个静态方法?我想的是,当CustomServlet类第一次被类装入器装入内存时,只需要执行一次。因此,您认为servlet是在每个HTTP请求上新创建/初始化的,而不是在应用程序启动时只初始化一次?servlet应该只初始化一次。但我将拥有多个从这个CustomServlet类扩展而来的servlet。我认为CustomServlet的init()方法将再次被调用。如果我的理解错了,请纠正我。哦,那样。您可以添加一个
静态AtomicBoolean
或继续使用
ServletContextListener
方法。我已经编辑了答案。为什么它需要是一个静态方法呢?我认为这只需要在CustomServlet类第一次被类装入器装入内存时执行一次。所以,您认为servlet是在每个HTTP请求上新创建/初始化的,而不是在应用程序启动时只初始化一次?servlet应该只初始化一次。但我将拥有多个从这个CustomServlet类扩展而来的servlet。我认为CustomServlet的init()方法将再次被调用。如果我的理解错了,请纠正我。哦,那样。您可以添加一个
静态AtomicBoolean
或继续使用
ServletContextListener
方法。我已经编辑了答案。你最后的陈述值得投反对票。此外,在构造函数中执行此任务不允许您使用
ServletContext#getResourceAsStream()
。您的上一条语句值得投反对票。此外,在构造函数中执行此操作不允许您使用
ServletContext#getResourceAsStream()
。非常感谢您的指导。我需要解析的结果在所有servlet中都可用,并且需要基于XML创建一些类级变量。第一种方法应该是合适的,对吗?我更喜欢
ServletContextListener
方法。执行原子/同步/静态操作总是很棘手。“在适当的时候做一次”更容易。只要将它存储在应用程序范围中,并在必要时从那里检索(当然可以使用(静态)帮助器方法)。如果XML文件以Javabean的风格转换(例如JAXB可以这样做),并通过
getServletContext().setAttribute(“config”,config)
存储在应用程序范围中,然后你应该能够在EL中轻松访问它,例如,
${config.foo}
等等。哦,太好了。。我们正在使用JAXB访问XML文档。非常感谢您的指导。我需要解析的结果在所有servlet中都可用,并且需要基于XML创建一些类级变量。第一种方法应该是合适的,对吗?我更喜欢
ServletContextListener
方法。执行原子/同步/静态操作总是很棘手。“在适当的时候做一次”更容易。只需将其存储在应用程序范围中,并在必要时从中检索(当然,您可以使用(stat