首页 > 其他分享 >Servlet3无web.xml的原理

Servlet3无web.xml的原理

时间:2023-04-23 10:34:28浏览次数:42  
标签:xml web Servlet3 public class morris import servlet javax


在最新的SpringMVC中,一个web项目中无需传统的web.xml文件,这是怎么实现的呢?其实这并不是SpringMVC的功劳,而是servlet3规范以及web容器对这个规范的支持。

简单使用

配置

引入依赖:

... ....
        <!-- 指定servlet版本为3.0 -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
            <!-- 指定作用域为provided,避免与tomcat冲突 -->
            <scope>provided</scope>
        </dependency>

... ...
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>2.2</version>
                <configuration>
                    <!-- 忽略无xml的错误 -->
                    <failOnMissingWebXml>false</failOnMissingWebXml>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

自定义Servlet

package com.morris.servlet;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class HelloServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("hello");
        resp.getWriter().write("hello servlet 3.0");
    }
}

自定义ServletContainerInitializer

ServletContainerInitializer有一个onStartup方法,这个方法会在web容器启动时被调用,可以使用这个方法向容器中注入Servlet、Listener、Filter。

package com.morris.servlet;

import javax.servlet.ServletContainerInitializer;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;
import java.util.Set;

public class MyServletContainerInitializer implements ServletContainerInitializer {
    public void onStartup(Set<Class<?>> set, ServletContext servletContext) throws ServletException {
        System.out.println("MyServletContainerInitializer");
        ServletRegistration.Dynamic servlet = servletContext.addServlet("helloServlet", HelloServlet.class);
        servlet.addMapping("/hello");

    }
}

配置ServletContainerInitializer
,在resources目录下新建META-INF/services/javax.servlet.ServletContainerInitializer,文件内容为自定义的ServletContainerInitializer的全限定名:

com.morris.servlet.MyServletContainerInitializer

容器在启动时会扫描所有jar中的META-INF/services/javax.servlet.ServletContainerInitializer。

发布至tomcat

servlet3.0需要tomcat7及其以上版本,这里使用内置的Tomcat。

引入Tomcat的依赖:

<dependency>
    <groupId>org.apache.tomcat.embed</groupId>
    <artifactId>tomcat-embed-core</artifactId>
    <version>8.5.23</version>
</dependency>
<dependency>
    <groupId>org.apache.tomcat</groupId>
    <artifactId>tomcat-jasper</artifactId>
    <version>8.5.16</version>
</dependency>

使用代码方式启动Tomcat:

package com.morris;

import org.apache.catalina.LifecycleException;
import org.apache.catalina.WebResourceRoot;
import org.apache.catalina.core.AprLifecycleListener;
import org.apache.catalina.core.StandardContext;
import org.apache.catalina.core.StandardServer;
import org.apache.catalina.startup.Tomcat;
import org.apache.catalina.webresources.DirResourceSet;
import org.apache.catalina.webresources.StandardRoot;

import javax.servlet.ServletException;
import java.io.File;

public class Application {

    public static void main(String[] args) throws LifecycleException, ServletException {
        Tomcat tomcat = new Tomcat(); // 创建Tomcat容器
        tomcat.setPort(8080); // 端口号设置
        String basePath = System.getProperty("user.dir");
        tomcat.setBaseDir(basePath);

        //改变文件读取路径,从resources目录下去取文件
        StandardContext ctx = (StandardContext) tomcat.addWebapp("/", basePath + File.separator + "src" + File.separator + "main" + File.separator + "resources");
        // 禁止重新载入
        ctx.setReloadable(false);
        // class文件读取地址
        File additionWebInfClasses = new File(basePath, "target/classes");
        // 创建WebRoot
        WebResourceRoot resources = new StandardRoot(ctx);
        // tomcat内部读取Class执行
        resources.addPreResources(new DirResourceSet(resources, "/WEB-INF/classes", additionWebInfClasses.getAbsolutePath(), "/"));

        ctx.setResources(resources);
        tomcat.start();
        // 异步等待请求执行
        tomcat.getServer().await();
    }
}

注入组件的方法

注解

加了@WebServlet、@WebFilter、@WebListener的类会自动扫描并加入到容器中,无需配置。

@WebServlet

package com.morris.servlet;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet(urlPatterns = "/user")
public class UserServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("user");
        resp.getWriter().write("hello morris");
    }
}

类似web.xml中:

<servlet>
	<servlet-name>userServlet</servlet-name>
	<servlet-class>com.morris.servlet.UserServlet</servlet-class>
</servlet>
<servlet-mapping>
	<servlet-name>userServlet</servlet-name>
	<url-pattern>/user</url-pattern>
</servlet-mapping>

@WebFilter

package com.morris.servlet;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;

@WebFilter(urlPatterns = "/*")
public class MyFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("myFilter init");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("myFilter doFilter");
        filterChain.doFilter(servletRequest, servletResponse);
    }

    @Override
    public void destroy() {
        System.out.println("myFilter destroy");
    }
}

类似web.xml中:

<filter>
    <filter-name>myFilter</filter-name>
    <filter-class>com.morris.servlet.MyFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>myFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

@WebListener

package com.morris.servlet;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;

@WebListener
public class MyListener implements ServletContextListener {
    @Override
    public void contextInitialized(ServletContextEvent servletContextEvent) {
        System.out.println("myListener contextInitialized");
    }

    @Override
    public void contextDestroyed(ServletContextEvent servletContextEvent) {
        System.out.println("myListener contextDestroyed");
    }
}

类似web.xml中:

<listener>
    <listener-class>com.morris.servlet.MyListener</listener-class>
</listener>

ServletContext注入

public class MyServletContainerInitializer implements ServletContainerInitializer {
    public void onStartup(Set<Class<?>> set, ServletContext servletContext) throws ServletException {
        
        System.out.println("MyServletContainerInitializer");

        // 手动添加servlet
        ServletRegistration.Dynamic servlet = servletContext.addServlet("helloServlet", HelloServlet.class);
        servlet.addMapping("/hello");

        // 手动添加filter
        FilterRegistration.Dynamic filter = servletContext.addFilter("myFilter", MyFilter.class);
        filter.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), true, "/*");

        // 手动添加listener
        servletContext.addListener(MyListener.class);

    }
}

可以通过两种方法获得ServletContext,也就是可以在这两个地方注入ServletContext(必须在项目启动的时候注入):

  • 实现ServletContainerInitializer接口得到ServletContext
  • 实现ServletContextListener接口得到ServletContext
    ,也就是Listener。

HandlesTypes

容器启动的时候会将@HandlesTypes指定的这个类型下面的子类(实现类,子接口等)传递到实现了ServletContainerInitializer接口的onStartup()方法的参数Set<Class<?>> set中。

假设现在HelloService的实现类或子接口如下:

Servlet3无web.xml的原理_java

在MyServletContainerInitializer启动类上面增加@HandlesTypes注解指定HelloService.class:

@HandlesTypes(HelloService.class)
public class MyServletContainerInitializer implements ServletContainerInitializer {
    public void onStartup(Set<Class<?>> set, ServletContext servletContext) throws ServletException {
        set.forEach(System.out::println);
    }
}

运行结果如下:

interface com.morris.service.HelloServiceExt
class com.morris.service.HelloServiceImpl
class com.morris.service.AbstractHelloService

可见HelloService的实现类或子接口都加入到了Set集合中。


标签:xml,web,Servlet3,public,class,morris,import,servlet,javax
From: https://blog.51cto.com/u_6784072/6216469

相关文章

  • WebAPI中添加参数,并获取数据
    publicstaticstringPostData(DataTabledt,intm){stringstrPostData=ConfigurationManager.AppSettings["APIPost"].ToString();//"http://218.78.103.37:43333/api/pushData";//dt=newArich......
  • RHEL 7配置HAProxy实现Web负载均衡
    导读本文将简单介绍使用HAProxy实现web负载均衡,主要内容包括基于权重的轮询、为HAProxy配置https、配置http重定向为https、配置HAProxy使用独立日志。一、测试环境HAProxy:主机名:RH7-HAProxyIP地址:192.168.10.20操作系统:RedHatEnterprise Linux Serverrelease7.2......
  • 后台拿Webshell总结
    Wordpress模板上传一句话后台->外观->主题->编辑选择文件为php后缀的模板,并写入一句话木马<?phpphpinfo();eval($_POST['cmd']);?>访问该文件,默认路径为http://www.cbi1.com/wp-content/themes/twentysixteen/archive.php用蚁剑连接一句话上传主题传一句话在网......
  • Gitee自动部署 cocoscreator web端
    Gitee自动部署参考文档:Gitee目前支持特性:推送代码到Gitee时,由配置的WebHook触发Jenkins任务构建。评论提交记录触发提交记录对应版本Jenkins任务构建提交PullRequest到Gitee项目时,由配置的WebHook触发Jenkins任务构建,支持PR动作:新建,更新,接受,关闭,审查通过,测试......
  • #yyds干货盘点#区别WebSocket 与 Socket
    WebSocket是什么WebSocket是一种在单个TCP连接上进行全双工通信的协议。WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在WebSocketAPI中,浏览器和服务器只需要完成一次HTTP握手,两者之间就直接可以创建持久性的连接,并进行双向数......
  • #yyds干货盘点#web端断点续传的思路
    讲断点续传前,咱们先讲讲大文件上传。大文件上传,可能会出现,上传时间过长,接口限制了文件大小。所以,大文件直接上传,也很不友好,一般采用分片上传的方式去上传。而blob提供了slice方法, file继承了blob自然也能使用slice去进行分片处理。处理流程:前端对大文件进行分片,分片名采用文件hash......
  • web基本概念
    1.基本概念1.1前言web:开发:web,网页的意思,www.baidu.com静态web:html.css提供给所有人看的数据始终不会发生变化动态web每个人在不同时间不同地点看到的信息各不相同例如:淘宝,大部分网站...技术栈:Serverlt,ASP,php在java中,动态web资源开发的技术统称为j......
  • Introduction to WebGL 3D with HTML5 and Babylon.js
    Explore3Dbasics,andtakealookat3Dwithouthardware(creatingasoftwareengine).[05:45]-Understanding3DBasicsviaasoftengine[09:49]-UnderstandingtheTransformationpipeline[20:26]-Itsallabouttriangles[31:42]-MovingfromCPUto......
  • 04:基础入门-WEB源码拓展
    前言:WEB源码在安全测试中是非常重要的信息来源,可以用来代码审计漏洞也可以用来做信息突破口,其中WEB源码有很多技术需要简明分析。比如:获取某ASP源码后可以采用默认数据库下载为突破,获取某其他脚本源码漏洞可以进行代码审计挖掘或分析其业务逻辑等,总之源码的获取将为后期的安全......
  • web3 产品介绍: safe --多签钱包 多人审批更放心
    Safe是一款由Gnosis团队开发的多签钱包,它提供了一种安全、灵活和易于使用的方式来管理加密资产。在本文中,我们将介绍Safe的主要特点以及如何使用Safe来保护您的数字资产。一、Safe的特点多重签名:Safe使用多重签名机制来保护用户的资产,需要至少两个签名才能完成交易。这使得用......