• 动态加载及Servlet容器加载


    动态加载

    动态加载是 Servlet 3.0 中的新特性,它可以实现在不重启 Web 应用的情况下加载新的 Web 对象(Servlet、Filter、Listener)。

    为了实现动态加载的第一种方式:创建 Web 对象和注册 Web 对象到 ServletContext 中分步进行

    ServletContext 接口增加了如下方法,用于动态创建 Web 对象:

    <T extends Servlet> T createServlet(java.lang.Class<T> c)  throws ServletException  // 
    <T extends Filter> T createFilter(java.lang.Class<T> c) throws ServletException  // 
    <T extends java.util.EventListener> T createListener(java.lang.Class<T> c) throws ServletException  // 

    例如,如果MyServlet是一个直接或者间接继承 javax.servlet.Servlet 的类,那么就可以通过 createServlet 的方法初始化它:

    Servlet myServlet = servletContext.createServlet(MyServlet.class);  // 这里使用了反射技术 

    在创建了 Web 对象之后,可以通过 ServletContext 中的如下方法把它注册到 ServletContext 中

    ServletRegistration.Dynamic addServlet(java.lang.String servletName, Servlet servlet) //  
    FilterRegistration.Dynamic addFilter(java.lang.String filterName, Filter filter)  //  
    <T extends java.util.EventListener> void addListener(T t)  //  

    实现动态加载的第二种方式:创建 Web 对象和注册 Web 对象到 ServletContext 中一步完成

    使用 ServletContext 中的如下方法

    ServletRegistration.Dynamic addServlet(java.lang.String servletName, java.lang.Class<? extends Servlet> servletClass)
    ServletRegistration.Dynamic addServlet(java.lang.String servletName, java.lang.String className)
    
    FilterRegistration.Dynamic addFilter(java.lang.String filterName, java.lang.Class<? extends Filter> filterClass)
    FilterRegistration.Dynamic addFilter(java.lang.String filterName, java.lang.String className)
    
    void addListener(java.lang.Class<? extends java.util.EventListener> listenerClass)
    void addListener(java.lang.String className)

    要创建或者增加Listener,传递给第一个 addListener 方法的类需要实现以下的一个或者多个接口

    ServletContextAttributeListener
    ServletRequestListener
    ServletRequestAttributeListener
    HttpSessionListener
    HttpSessionAttributeListener

    如果 ServletContext 是用于 ServletContextInitializer 中的 onStartup 方法的参数,那么 Listener 也需要实现 ServletContextListener

    动态加载实例

    package app14a.servlet;
    
    import java.io.IOException;
    import java.io.PrintWriter;
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    public class FirstServlet extends HttpServlet {       // 一个 Servlet,该 Servlet 没有使用 @WebServlet 注解,也没有使用部署描述符来声明。
        private static final long serialVersionUID = 1L;  // 而是通过使用 Listener 来动态创建、注册、绑定这个 Servlet 并让其生效的。
        private String name;
        
        public void setName(String name) {
            this.name = name;
        }
    
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            response.setContentType("text/html");
            PrintWriter writer = response.getWriter();
            writer.println("<html>");
            writer.println("<head>");
            writer.println("<title>First Servlet</title>");
            writer.println("</head>");
            writer.println("<body>");
            writer.println(name);
            writer.println("</body>");
            writer.println("</html>");
        }
    
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            doGet(request, response);
        }
    }
    package app14a.listener;
    
    import javax.servlet.Servlet;
    import javax.servlet.ServletContext;
    import javax.servlet.ServletContextEvent;
    import javax.servlet.ServletContextListener;
    import javax.servlet.ServletRegistration;
    import javax.servlet.annotation.WebListener;
    
    import app14a.servlet.FirstServlet;
    
    @WebListener  // 注解
    public class DynRegListener implements ServletContextListener {  // 监听器
    
        @Override
        public void contextInitialized(ServletContextEvent sce) {  // ServletContext 创建时,容器调用该方法
            ServletContext servletContext = sce.getServletContext();  // 获取 ServletContext 对象实例
            Servlet firstServlet = null;
            try {
                firstServlet = servletContext.createServlet(FirstServlet.class);  // 动态创建 Web 对象
            } catch (Exception e) {
                e.printStackTrace();
            }
            if (firstServlet != null && firstServlet instanceof FirstServlet) {
                ((FirstServlet) firstServlet).setName("Dynamically registered servlet");
            }
            ServletRegistration.Dynamic dynamic = servletContext.addServlet("firstServlet", firstServlet);  // 注册到 ServletContext 中
            dynamic.addMapping("/dynamic");  // 绑定路径
        }
    
        @Override
        public void contextDestroyed(ServletContextEvent sce) {
        }
    }

    测试结果,Servlet 成功注册到了 ServletContext 中,且绑定到 /dynamic 路径

    Servlet容器加载

    Servlet 容器加载器也是 Servlet 3.0 中的新特性,对于框架的开发者来说特别有用。

    Servlet 容器初始化主要是通过 javax.servlet.ServletContainerInitializer 这个接口。该接口只有一个方法 onStartup。

    Servlet 容器中,这个方法在任何 ServletContext 的 Listener 初始化之前都可能会被调用到。

    void onStartup(java.util.Set<java.lang.Class<?>> c, ServletContext ctx) throws ServletException  // 

    ServletContainerInitializer 的实现类必须使用 HandleTypes 的注解,以便让加载器能够识别。

    package app14a.initializer;
    
    import java.util.Set;
    import javax.servlet.ServletContainerInitializer;
    import javax.servlet.ServletContext;
    import javax.servlet.ServletException;
    import javax.servlet.ServletRegistration;
    import javax.servlet.annotation.HandlesTypes;
    import servlet.UsefulServlet;
    
    @HandlesTypes({UsefulServlet.class})  // ServletContainerInitializer 的实现类必须使用该注解
    public class MyServletContainerInitializer implements ServletContainerInitializer {
        @Override
        public void onStartup(Set<Class<?>> classes, ServletContext servletContext) throws ServletException {  // 该方法的主要任务就是注册 Web 对象
            System.out.println("onStartup");
            ServletRegistration registration = servletContext.addServlet("usefulServlet", "servlet.UsefulServlet");  // 创建并注册
            registration.addMapping("/useful");  // 绑定访问路径
            System.out.println("leaving onStartup");
        }
    }

    插件(即 initializer.jar)中的内容

    测试结果,

  • 相关阅读:
    添加egit插件
    Git使用教程
    mysql set names 命令和 mysql字符编码问题
    git常用命令
    前端WEB编辑器-------webstrom
    maven 常见错误解决方法
    java -jar 执行 eclipse export 的 jar 包报错处理
    数据库(DBUtils)
    数据库(JDBC、DBUtils)
    rabbitmq Exchange四种模式
  • 原文地址:https://www.cnblogs.com/0820LL/p/9926738.html
Copyright © 2020-2023  润新知