目录
Spring Boot 注入Servlet、Filter、Listener
官方文档
基本介绍
应用实例1-使用注解方式注入
创建/Servlet_.java
修改Application.java , 加入@ServletComponentScan
完成测试
创建Filter_.java
创建static/css/t.css, 作为测试文件
完成测试, 注意观察后台
注意:
创建Listener_.java
完成测试, 启动项目,观察后台输出
应用实例2-使用RegistrationBean 方式注入
创建RegisterConfig_.java
去掉相关的注解,再次完成测试
注意事项和细节说明
在看看spring 容器的debug 图.
源码分析
Spring Boot 注入Servlet、Filter、Listener
官方文档
文档:
https://docs.spring.io/spring-boot/docs/current/reference/html/features.html#features.develo
ping-web-applications.embedded-container.servlets-filters-listeners
基本介绍
1. 考虑到实际开发业务非常复杂和兼容,Spring-Boot 支持将Servlet、Filter、Listener 注入Spring 容器, 成为Spring bean
2. 也就是说明Spring-Boot 开放了和原生WEB 组件(Servlet、Filter、Listener)的兼容
应用实例1-使用注解方式注入
需求: 演示通过注解方式注入Servlet、Filter、Listener
创建/Servlet_.java
1. 通过继承 HttpServlet 来开发原生的Servlet
2. @WebServlet 标识将 Servlet_ 对象/bean注入到容器
3. (urlPatterns = {"/servlet01","/servlet02"} ,对servlet配置了url-pattern
4. 提示: 注入的原生的Servlet_ 不会被spring-boot的拦截器拦截
5. 对于开发的原生的Servlet ,需要使用 @ServletComponentScan指定要扫描的原生Servlet包, 才会注入到spring 容器.
/**
* 解读
* 1. 通过继承 HttpServlet 来开发原生的Servlet
* 2. @WebServlet 标识将 Servlet_ 对象/bean注入到容器
* 3. (urlPatterns = {"/servlet01","/servlet02"} ,对servlet配置了url-pattern
* 4. 提示: 注入的原生的Servlet_ 不会被spring-boot的拦截器拦截
* 5. 对于开发的原生的Servlet ,需要使用 @ServletComponentScan指定要扫描的原生Servlet包
* , 才会注入到spring 容器
*/
@WebServlet(urlPatterns = {"/servlet01","/servlet02"})
public class Servlet_ extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().write("hello,Servlet_!");
}
}
修改Application.java 加入@ServletComponentScan
//要求扫描com.wyxedu.springboot 包/子包下的原生方式注入的Servlet
@ServletComponentScan(basePackages = "com.wyxedu.springboot")
@SpringBootApplication
public class Application {
public static void main(String[] args) {
ConfigurableApplicationContext ioc =
SpringApplication.run(Application.class, args);
//ioc.stop();
System.out.println("hello");
}
}
完成测试
浏览器http://localhost:8080/servlet01
创建Filter_.java
1. @WebFilter 表示Filter_是一个过滤器,并注入容器
2. urlPatterns = {"/css/*", "/images/*"} 当请求 /css/目录资源或者 /images/目录下资源的时候,会经过该过滤器
3. 我这里是直接放行后,在经过拦截器, 拦截器是否拦截要根据拦截器的拦截规则
/**
* 开发Filter 并注入
*
* 解读
* 1. @WebFilter 表示Filter_是一个过滤器,并注入容器
* 2. urlPatterns = {"/css/*", "/images/*"} 当请求 /css/目录资源或者 /images/目录下资源的时候,会经过该过滤器
* 3. 我这里是直接放行后,在经过拦截器, 拦截器是否拦截要根据拦截器的拦截规则
*/
@Slf4j
@WebFilter(urlPatterns = {"/css/*", "/images/*"})
public class Filter_ implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
log.info("--Filter_ init--");
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
log.info("--Filter_ doFilter--");
//为了方便观察过滤器处理的资源,我们输出一个uri
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
log.info("过滤器处理的uri={}", httpServletRequest.getRequestURI());
//我们直接放行-实际开发中,根据自己的业务来决定如何处理
chain.doFilter(request, response);
}
@Override
public void destroy() {
log.info("--Filter_ destroy--");
}
}
创建static/css/t.css, 作为测试文件
完成测试, 注意观察后台
浏览器: http://localhost:8080/css/t.css
注意:
过滤器配置的urlPatterns 也会经过Spring-Boot 拦截器(根据拦截器的规则)
所以为了看到效果,请在拦截器配置放行/css/**
在servlet 匹配全部是/*, 在Spring-Boot 是/**
创建Listener_.java
@Slf4j
@WebListener
public class Listener_ implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
//这里可以加入项目初始化的相关业务代码
log.info("Listener_ contextInitialized 项目初始化OK~");
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
//这里可以加入相应代码...
log.info("Listener_ contextDestroyed 项目销毁");
}
}
完成测试, 启动项目,观察后台输出
应用实例2-使用RegistrationBean 方式注入
创建RegisterConfig_.java
/**
* RegisterConfig_: 是一个配置类
* proxyBeanMethods = true : 默认是单例返回bean[保证每个@Bean 方法被调用多少次返回的组件都是 单实例的, 是代理方式]
*/
@Configuration(proxyBeanMethods = true)
public class RegisterConfig_ {
//以使用RegistrationBean方式注入
//注入Servlet
@Bean
public ServletRegistrationBean servlet_() {
//创建原生的Servlet对象
Servlet_ servlet_ = new Servlet_();
//把servlet_对象关联到 ServletRegistrationBean 对象
//"/servlet01", "/servlet02" 就是注入的Servlet的url-pattern
return new ServletRegistrationBean(servlet_, "/servlet01", "/servlet02");
}
//注入filter
@Bean
public FilterRegistrationBean filter_() {
Filter_ filter_ = new Filter_();//创建原生的filter
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(filter_);
//设置filter的url-pattern
filterRegistrationBean.setUrlPatterns(Arrays.asList("/css/*", "/images/*"));
return filterRegistrationBean;
}
//注入Listener
@Bean
public ServletListenerRegistrationBean listener_() {
//创建原生的Listener对象
Listener_ listener_ = new Listener_();
return new ServletListenerRegistrationBean(listener_);
}
}
去掉相关的注解,再次完成测试
注意事项和细节说明
请求Servlet 时,为什么不会到达拦截器
1. 请求Servlet 时,不会到达DispatherServlet, 因此也不会达到拦截器
2. 原因分析
√ 注入的Servlet 会存在Spring 容器
√ DispatherServlet 也存在Spring 容器
回忆一下在Javaweb阶段的博客有写Servlet url 匹配的原则,
多个servlet 都能处理到同一层路径, 精确路径 > 最长路径>后缀匹配
在看看spring 容器的debug 图.
在SpringBoot 中, 去调用@Controller 目标方法是按照DispatherServlet 分发匹配的机制, 如果不了解可以去专栏的手写和源码分析去看看手写spring MVC
源码分析
DispatcherServletAutoConfiguration 完成对DispatcherServlet 自动配置