【小家Spring】SpringBoot中使用Servlet、Filter、Listener三大组件的三种方式以及原理剖析
每篇一句
要么就安逸的穷,要么就拼命的干
前提概要
web开发使用Controller基本能解决大部分的需求,但是有时候我们也需要使用Servlet,因为相对于拦截和监听来说,有时候原生的还是比较好用的。
因此本文就主要介绍web三大组件Servlet、Filter、Listener在SpringBoot中的使用做个介绍。本文重点做使用介绍,以及剖析SpringBoot是如何支持和解析这些方式的
Spring boot 的主 Servlet 为 DispatcherServlet,其默认的url-pattern为“/”。也许我们在应用中还需要定义更多的Servlet,该如何使用SpringBoot来完成呢?
三种方式
本文主要以使用Servelt为例子进行讲解,使用其余组件的方式也差不多。差异性比较大的地方我会尽量指出来,请举一反三
方式一: @ServletComponentScan 扫描的方式(推荐)
看看这个注解的javadoc
* Enables scanning for Servlet components ({@link WebFilter filters}, {@link WebServlet* servlets}, and {@link WebListener listeners}). Scanning is only performed when using an* embedded web server.
从javadoc中可以看出,该扫描的方式只支持嵌入式的web容器
使用此种扫描方式,显然是基于Servlet3.0的注解的方式。而该注解的解析由SpringBoot提供的@ServletComponentScan
来驱动的。
案例如下:
@ServletComponentScan
@SpringBootApplication
public class Boot2Demo1Application {public static void main(String[] args) {SpringApplication.run(Boot2Demo1Application.class, args);}
}/*** @author fangshixiang* @description* @date 2019-01-28 14:39*/
@WebServlet(urlPatterns = "/servlet/demo", asyncSupported = false)
public class DemoServlet extends HttpServlet {@Overridepublic void init() throws ServletException {System.out.println("init my servlet");super.init();}@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {System.out.println("this is my servlet");super.doGet(req, resp);}
}
请求地址:http://localhost:8080/servlet/demo
控制台输出:
init my servlet
this is my servlet
有的朋友可能会问:为毛init方法也是此时才输出呢???为了答疑,这里之直接贴出来答案吧:
init 方法是随 Servlet 实例化而被调用的,因为 load-on-startup 就是用来设置Servlet 实例化时间的。因此,init 方法执行的时刻有两种:
- load-on-startup 的值大于等于0,则伴随 Servlet 实例化后执行。
- load-on-startup 的值小于0 或者 不配置(默认行为), 则在第一次 Servlet 请求的时候执行。
备注:看下面启动日志
2019-01-28 15:51:40.926 INFO 16144 --- [ost-startStop-1] o.s.b.w.servlet.ServletRegistrationBean : Servlet com.sayabc.boot2demo1.servlet.DemoServlet mapped to [/servlet/demo]
可以看出,这种方式的底层原理还是转换成了ServletRegistrationBean,从而交给Spring容器管理了。同理:另外两大组件可以参照这个方式来定义和书写。
此方式优点:
完全还原了源生servlet、filter、listener等功能,程序员自己也很方便的、更加细粒度。
方式二:通过ServletRegistrationBean进行组件注册
依托于SpringBoot提供的三个Bean:
ServletRegistrationBean
FilterRegistrationBean
ServletListenerRegistrationBean
实例代码:
@Beanpublic ServletRegistrationBean MyServlet1() {return new ServletRegistrationBean(new DemoServlet(), "/servlet/*");}
访问路径:http://localhost:8080/servlet/demo
控制台有对应日志输出(显然这种方式,init方法不会再执行了,因为自己new的嘛);
启动日志如下:
2019-01-28 15:59:37.412 INFO 14332 --- [ost-startStop-1] o.s.b.w.servlet.ServletRegistrationBean : Servlet demoServlet mapped to [/servlet/*]
优点:内部可以直接@Autowired注入Spring的Bean,也可配合@Order调整优先级
方式三:@Component
采用此种方式是最简单的方式。Spring Boot也非常友好的给支持了。
示例:
@Component
public class DemoServlet extends HttpServlet {@Overridepublic void init() throws ServletException {System.out.println("init my servlet");super.init();}@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {System.out.println("this is my servlet");super.doGet(req, resp);}
}
日志输出:
2019-01-28 17:20:19.601 INFO 8756 --- [ost-startStop-1] o.s.b.w.servlet.ServletRegistrationBean : Servlet demoServlet mapped to [/]
显然可以看出,直接使用@Component虽然方便,但是无法自定义urlPatterns,还是收到很多局限的。
备注:别想着这么做能达到效果(虽然我建议SpringBoot支持,哈哈)
@Component
@WebServlet(urlPatterns = "/servlet/demo", asyncSupported = false)
public class DemoServlet extends HttpServlet {}
这样直接做是不生效的。还是只能映射到跟路径。因为@WebServlet
等注解是依赖于
@ServletComponentScan
才能驱动的,因此此种方式虽然方便,但是还是有很多局限性的。
但是,但是,对应Filter,一般我们都希望他拦截所有的请求,因此这么来做是很方便的。比如TokenFilter
@Order(1)
@Component
public class TokenFilter implements Filter{}
这样默认拦截的路径为:Mapping filter: 'tokenFilter' to: [/*]
,从而会过滤所有的请求。
小知识点:
< url-pattern>/</url-pattern> 会匹配到/login这样的路径型url,不会匹配到模式为*.jsp这样的后缀型url
< url-pattern>/*</url-pattern> 会匹配所有url:路径型的和后缀型的url(包括/login,*.jsp,*.js和*.html等)
所以如果以后发现总是有404错误的时候,别忘了check一下 /的配置是否是/*.
优点:内部可以直接@Autowired注入Spring的Bean,也可配合@Order调整优先级
简单总结
虽然Spring已经足够强大,几乎可以屏蔽我们对Servlet的Api。(Spring4以及以下版本的底层原理还是Servlet技术,但到了Spring5以后,servlet从必选项已经成为可选项了)
但是有的时候我们自己使用原生的方案更为妥当,因此本文针对于此提出一些方案和原理分析,仅供参考
关注A哥
Author | A哥(YourBatman) |
---|---|
个人站点 | www.yourbatman.cn |
yourbatman@qq.com | |
微 信 | fsx641385712 |
活跃平台
|
|
公众号 | BAT的乌托邦(ID:BAT-utopia) |
知识星球 | BAT的乌托邦 |
每日文章推荐 | 每日文章推荐 |
【小家Spring】SpringBoot中使用Servlet、Filter、Listener三大组件的三种方式以及原理剖析相关推荐
- jupyter notebook python3路径_详解修改Anaconda中的Jupyter Notebook默认工作路径的三种方式...
方式1. 打开Windows的cmd,在cmd中输入jupyter notebook --generate-config如下图: 可以看到路径为D:\Users--找到此路径修改jupyter_not ...
- JavaScript中遍历数组的for for-in和forEach三种方式
JavaScript中遍历数组的for for-in和forEach三种方式 for循环 let arr = [1,2,3,4,5,6];for(let i = 0; i < arr.lengt ...
- JavaScript--------------------jQuery中.bind() .live() .delegate() .on()的区别 和 三种方式写光棒事件 动画...
bind(type,[data],fn) 为每个匹配元素的特定事件绑定事件处理函数. $("a").bind("click",function(){alert( ...
- win下配置的ES中的数据在哪里可以看到?三种方式你看那种更加高大上!!!(win_Elasticsearch)
在上一篇博客<使用logstash将Mysql中的数据导入到ElasticSearch中(详细步骤,win_Elasticsearch)>中我们提到将数据插入到es中,那我怎么知道数据是否 ...
- Struts2中jsp前台传值到action后台的三种方式以及valueStack的使用
struts2中的Action接收表单传递过来的参数有3种方法: 如,登陆表单login.jsp: 1 <form action="login" method="p ...
- Spring学习3 - Bean的属性、DI依赖注入三种方式
文章目录 1. 属性设置 - XML配置文件.以及与其等价的注解形式 2. 依赖注入DI的方式 2.1 属性自动注入 - 不推荐 代码准备阶段 代码测试 2.2 子节点构造器注入 - 不推荐 2.3 ...
- mysql中如何获取字段类型_MySQL获取字段类型的三种方式
1. INFORMATION_SCHEMA.COLUMNS INFORMATION_SCHEMA是每个MySQL实例中的数据库,该实例存储有关MySQL服务器维护的所有其他数据库的信息. 如查询某一个 ...
- 把对象的创建交给spring来管理—— 1.创建bean的三种方式 2.bean对象的作用范围 3.bean对象的生命周期
把对象的创建交给spring来管理 spring对bean的管理细节 1.创建bean的三种方式 2.bean对象的作用范围 3.bean对象的生命周期 创建Bean的三种方式 ...
- 【Linux】部署Springboot项目到Linux服务器以及linux服务器下载文件的三种方式详解
Linux学习之路 初识Linux Linux内核 由芬兰人林纳斯·托瓦兹(Linus Torvalds)在赫尔辛基大学上学时出于个人爱好而编写 Linux 是一套免费使用和自由传播的类Unix操作系 ...
最新文章
- ADO.NET 2.0 - 读者询问能否使用 SqlBulkCopy 对象来大量复制文字文件
- 数据库中的goto语法
- plsqldev远程连接mysql_PLSQL Developer连接远程Oracle数据库
- lucky前面加a还是an_微信昵称前加个“A” 不是微商就是销售?看看这个“A”的含义!...
- C#操作HttpClient工具类库
- 精讲23种设计模式-基于观察者模式~设计异步多渠道群发框架
- 在另一台服务器上还原被误删的 MySQL 数据
- jq点击更多收起效果
- 安卓为什么卡及其解决方案
- Matlab 求全要素生产率,如何用DEAP进行全要素生产率分析
- zzbird的bbsmax出了?
- cad手机看图 android,CAD手机看图
- 教育研究方法 的思维导图
- Gram矩阵计算实例
- 使用spss求标准化的线性回归方程
- 基于触摸屏PLC的温度采集及简单控制
- anaconda安装完怎么打开_10分钟带你安装和配置Anaconda
- detach()函数理解
- Mac IDEA 自带Maven换国内源
- redux的原理、工作流程及其应用