Springboot2Web原生组件注入
官方文档 - Servlets, Filters, and listeners
使用原生的注解Servlet API
@ServletComponentScan(basePackages = “com.atguigu.admin”) :指定原生Servlet组件都放在那里
@WebServlet(urlPatterns = “/my”):效果:直接响应,没有经过Spring的拦截器?
@WebFilter(urlPatterns ={"/css/","/images/"})
@WebListener
MyServlet 类
@WebServlet(urlPatterns = "/my")
public class MyServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {resp.getWriter().write("6666");}
}
主配置类
//可以将自己写的servlet扫描进来
@ServletComponentScan(basePackages = "com.yujie")
@SpringBootApplication
public class Boot05WebAdminApplication {public static void main(String[] args) {SpringApplication.run(Boot05WebAdminApplication.class, args);}
}
过滤器
@Slf4j
//拦截css下的所有内容
//注意:*是servlet写法,**是spring写法
@WebFilter(urlPatterns ={"/css/*","/images/*"})
public class MyFilter implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {log.info("MyFilter初始化完成");}@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {log.info("MyFilter工作");filterChain.doFilter(servletRequest,servletResponse);}@Overridepublic void destroy() {log.info("MyFilter销毁");}
}
监听器
@Slf4j
@WebListener
public class MyServletContextListener implements ServletContextListener {@Overridepublic void contextInitialized(ServletContextEvent sce) {log.info("监听到项目初始化");}@Overridepublic void contextDestroyed(ServletContextEvent sce) {log.info("监听到项目销毁");}
}
Spring方式注入使用RegistrationBean
ServletRegistrationBean, FilterRegistrationBean, and ServletListenerRegistrationBean
可以注解掉前面的3个注解,让后使用RegistrationBean来注册。
@Configuration
public class MyRegistConfig {@Beanpublic ServletRegistrationBean myServlet(){MyServlet myServlet = new MyServlet();return new ServletRegistrationBean(myServlet,"/my","/my02");}@Beanpublic FilterRegistrationBean myFilter(){MyFilter myFilter = new MyFilter();
// return new FilterRegistrationBean(myFilter,myServlet());FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(myFilter);filterRegistrationBean.setUrlPatterns(Arrays.asList("/my","/css/*"));return filterRegistrationBean;}@Beanpublic ServletListenerRegistrationBean myListener(){MyServletContextListener mySwervletContextListener = new MyServletContextListener();return new ServletListenerRegistrationBean(mySwervletContextListener);}
}
细节:
@Configuration(proxyBeanMethods=false)
public class MyRegistConfig {
这里没有写proxyBeanMethods=false。如果写了说明当前类每次一调用类里面的方法,servlet都会新建一次。比如我们调用MyFilter的时候,servlet就重新new了一下。(proxyBeanMethods=true)它可以保证依赖的组件始终是单实例的。
【源码分析】DispatcherServlet注入原理
为什么自己写的@WebServlet(urlPatterns = “/my”):不会经过spring的拦截器。
根据上面的分析,我们系统中有两个servlet,一个MyServlet,处理的路径是/my。DispatcherServlet处理的路径是/
我们可以分析它的注入原理
org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration配置类
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass(DispatcherServlet.class)
@AutoConfigureAfter(ServletWebServerFactoryAutoConfiguration.class)
public class DispatcherServletAutoConfiguration {/** The bean name for a DispatcherServlet that will be mapped to the root URL "/"*/public static final String DEFAULT_DISPATCHER_SERVLET_BEAN_NAME = "dispatcherServlet";/** The bean name for a ServletRegistrationBean for the DispatcherServlet "/"*/public static final String DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME = "dispatcherServletRegistration";@Configuration(proxyBeanMethods = false)@Conditional(DefaultDispatcherServletCondition.class)@ConditionalOnClass(ServletRegistration.class)@EnableConfigurationProperties(WebMvcProperties.class)protected static class DispatcherServletConfiguration {//创建DispatcherServlet类的Bean@Bean(name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)public DispatcherServlet dispatcherServlet(WebMvcProperties webMvcProperties) {DispatcherServlet dispatcherServlet = new DispatcherServlet();dispatcherServlet.setDispatchOptionsRequest(webMvcProperties.isDispatchOptionsRequest());dispatcherServlet.setDispatchTraceRequest(webMvcProperties.isDispatchTraceRequest());dispatcherServlet.setThrowExceptionIfNoHandlerFound(webMvcProperties.isThrowExceptionIfNoHandlerFound());dispatcherServlet.setPublishEvents(webMvcProperties.isPublishRequestHandledEvents());dispatcherServlet.setEnableLoggingRequestDetails(webMvcProperties.isLogRequestDetails());return dispatcherServlet;}@Bean@ConditionalOnBean(MultipartResolver.class)@ConditionalOnMissingBean(name = DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME)public MultipartResolver multipartResolver(MultipartResolver resolver) {// Detect if the user has created a MultipartResolver but named it incorrectlyreturn resolver;}}@Configuration(proxyBeanMethods = false)@Conditional(DispatcherServletRegistrationCondition.class)@ConditionalOnClass(ServletRegistration.class)@EnableConfigurationProperties(WebMvcProperties.class)@Import(DispatcherServletConfiguration.class)protected static class DispatcherServletRegistrationConfiguration {//注册DispatcherServlet类@Bean(name = DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME)@ConditionalOnBean(value = DispatcherServlet.class, name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)public DispatcherServletRegistrationBean dispatcherServletRegistration(DispatcherServlet dispatcherServlet,WebMvcProperties webMvcProperties, ObjectProvider<MultipartConfigElement> multipartConfig) {DispatcherServletRegistrationBean registration = new DispatcherServletRegistrationBean(dispatcherServlet,webMvcProperties.getServlet().getPath());registration.setName(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME);registration.setLoadOnStartup(webMvcProperties.getServlet().getLoadOnStartup());multipartConfig.ifAvailable(registration::setMultipartConfig);return registration;}}...}
扩展: DispatchServlet如何注册进来
容器中自动配置了DispatcherServlet 属性绑定到WebMvcProperties; 对应的配置文件配置项是
spring.mvc。
通过ServletRegistrationBean 把DispatcherServlet配置进来。
默认映射的是/路径。
Tomcat-Servlet;
多个Servlet都能处理到同一层路径, 精确优选原则
A: /my/
B: /my/1
上图中发送/my,按照精确优先原则,来到Tomcat处理。而只有我们触发spring流程,才会有拦截器的作用。所以上面我们自己写的servlet并没有被拦截。
嵌入式Servlet容器
1.切换嵌入式Servlet容器
默认支持的webServer
- Tomcat, Jetty, or Undertow
- ServletWebServerApplicationContext 容器启动寻找ServletwebServerFactory并引导创建服务器
切换服务器
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><exclusions><exclusion><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-tomcat</artifactId></exclusion></exclusions>
</dependency>
原理
SpringBoot应用启动发现当前是Web应用。web场景包-导入tomcat
web应用会创建一个web版的ioc容器 ServletWebServerApplicationContext
ServletWebServerApplicationContext 启动的时候寻找ServletWebServerFactory
(Servlet的web服务器工厂—> Servlet 的web服 务器)
SpringBoot底层默认有很多的WebServerI厂; TomCatServletWebServerFactory,lu.com
JettyServletWebServerFactory, or UndertowServletWebServerFactory
底层直接会有一个自动配置类。ServletWebServerFactoryAutoConfiguration
ServletWebServerFactoryAutoConfiguration导入了ServletWebServerFactoryConfiguration
(配置类)
ServletWebServerFactoryConfiguration 配置类根据动态判断系统中到底导入了那个Web服务器
的包。(默认 是web- starter导入tomcat包),容器中就有TomcatServletWebServerFactory
TomcatServletWebServerFactory 创建出Tomcat服务器并启动; TomcatWebServer. 的构造器拥有
初始化方法initialize—this . tomcat. start();
内嵌服务器,就是手动把启动服务器的代码调用(tomcat 核心jar包存在)
2.定制Servlet容器
实现WebServerFactoryCustomizer
把配置文件的值和ServletWebServerFactory进行绑定
修改配置文件server.xxx
直接自定义ConfigurableServletWebServerFactory
xxxxxCustomizer:定制化器,可以改变xxx的默认规则
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory;
import org.springframework.stereotype.Component;@Component
public class CustomizationBean implements WebServerFactoryCustomizer<ConfigurableServletWebServerFactory> {@Overridepublic void customize(ConfigurableServletWebServerFactory server) {server.setPort(9000);}}
定制化原理
1.定制化的常见方式
修改配置文件;
xxxxxCustomizer;
编写自定义的配置类xxxConfiguration; + @Bean替换、增加容器中默认组件;视图解析器
Web应用编写-个配置类实现WebMvcConfigurer即可定制化web功能; + @Bean给容器中再扩展一 些组件
@Configuration
public class AdminWebConfig implements WebMvcConfigurer
@EnableWebMvc + WebMvcConfigurer一@Bean可以全面接管SpringMVC,所有规则全部自己重新
配置;实现定制和扩展功能
原理
1、WebMvcAutoConfiguration 默认的SpringMVC的自动配置功能类。静态资源、欢迎页…
2、一旦使用@EnableWebMvC、。会@Import(DelegatingWebMvcConfiguration.class)
3、 DelegatingWebMvcConfiguration 的作用,只保证SpringMVC最基本的使用*
- 把所有系统中的WebMvcConfigurer过来。所有功能的定制都是这些WebMvcConfigurer合起来
一起生效 - 自动配置了一些非常底层的组件。RequestMappingHandlerMapping、 这些组件依赖的组件都是
从容器中获取 - public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport
4、 WebMvcAutoConfiguration 面的配置要能生效必须@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
5、@EnableWebMvc导致了WebMvcAutoConfiguration没有生效。
2.原理分析套路
场景starter - xxxxAutoConfiguration -导入xx组件-绑定xxxProperties --绑定配置文件项
Springboot2Web原生组件注入相关推荐
- [SpringBoot2]原生组件注入_原生注解与Spring方式注入
1.使用Servlet API @ServletComponentScan(basePackages = "com.atguigu.admin") :指定原生Servlet组件都放 ...
- SpringBoot Web原生组件注入(Servlet、Filter、Listener)
一.使用原生Servlet API(推荐) @Slf4j @WebFilter(urlPatterns={"/css/*","/images/*"}) //my ...
- 002 第一季SpringBoot2核心技术-核心功能:配置文件、Web开发(原生组件)、数据访问、单元测试、指标监控、原理解析:@Value、命令行参数、手动获取bean、自定义starter
三.核心技术之- ->核心功能 1. 配置文件 1.1 文件类型 1.1.1 properties 同以前的properties用法 优先级高于yml的方式. 1.1.2 yaml 1) 简介 ...
- 微信小程序原生组件swiper在mpvue工程中使用注意事项
时下微信小程序开发框架中mpvue是主流的选择之一.其中,免不了还要使用部分小程序原生的组件.swiper组件几乎成为典型小程序界面的必备组成组件之一.但是,我在试用中遇到一个典型问题,很多相关网页中 ...
- 微信小程序中WebView中原生组件限制问题解析
背景 在微信的文档中有一个章节说明了『 原生组件的使用限制 』有这么一段话 『由于原生组件脱离在 WebView 渲染流程外,因此在使用时有以下限制:原生组件的层级是最高的,所以页面中的其他组件无论设 ...
- 组件注入 # 注入的属性_注入域对象而不是基础结构组件
组件注入 # 注入的属性 依赖注入是Java(以及许多其他编程语言)中广泛使用的软件设计模式,用于实现控制反转 . 它提高了可重用性,可测试性,可维护性,并有助于构建松耦合的组件. 如今,依赖注入是将 ...
- Spring IOC容器组件注入的几种方式
整理一下之前Spring的学习笔记,大致有一下几种Spring注入到容器中的方法: 1).配置在xml的方式. 2).开启包扫描@ComponentScan使用@Component,@Service, ...
- ReactNative 踩坑之 iOS 原生组件
iOS 中Undefined symbols for architecture x86_64 在原生 iOS 开发中,这个错误信息,应该或多或少的会碰到过: Undefined symbols for ...
- RN 封装 Android原生组件
RN 封装 Android原生组件 背景 当在React Native暂时未提供部分原生功能或者模块,我们需要复用部分原生代码时,比如复用一个原生方法,此时就需要将原生方法进行封装,暴露出一个接口来让 ...
最新文章
- 一封会笑死人的校园情书
- 瓜分百万奖金 | 科大讯飞A.I.开发者大赛医疗赛道
- 单片机基础课程有哪些?
- Spring容器和Bean加载
- 工作286:v-model没有值会报错
- OpenCL 与 CUDA
- 怎么在html中加入相对链接,html直接跳转超链接 html中怎么实现同一页面超级链接...
- PyTorch 学习笔记(六):PyTorch的十八个损失函数
- 一文详解 Java 的八大基本类型!
- lLinux系统安全sudo+pam
- centos6.5 搭建时间服务器
- cydia红字解决方法(cydia安装软件时出现红字怎么解决)
- java 雪崩效应,七、微服务架构中的“雪崩效应”
- 金融安全资讯精选 2017年第二期:金融网络安全和反欺诈方法论_金融新兴技术成熟度几何?...
- linux单进程最大内存,x64 Linux中的单进程最大可能内存
- [IOS/Swift]'Project Name' was compiled with optimization
- 中央C到底是C几?什么是科学音高记谱法?
- 张小军详解华为区块链政务应用,指出区块链的应用领域正从金融向全领域拓展...
- 前端面试之移动端适配篇(转载)
- 嵌入式软件工程师是前端还是后端_嵌入式软件工程师与软件工程师的区别
热门文章
- 三星Galaxy A80首款保护壳曝光:配件厂商这样解难题
- IComparable和Icomparer接口
- python群发邮箱软件_maily:命令行邮件(批量)发送工具
- python ax.imshow_python – Matplotlib imshow / matshow在情节上显...
- 学labview的都是什么人_为什么学美术的人,从来都不曾后悔?
- nvidia cuda工具包更新9.0版本记录
- 导入工程后 报错 The import javax.faces cannot be resolved 解决办法
- qt connect函数_Qt 串口上位机开发Rice 上位机 学习开发
- 95-10-150-启动-FetchManager
- 【Clickhouse】mutation 操作