官方文档 - Servlets, Filters, and listeners
@ServletComponentScan(basePackages = “com.atguigu.admin”) :指定原生Servlet组件都放在那里
@WebServlet(urlPatterns = “/my”):效果:直接响应,没有经过Spring的拦截器?
@WebFilter(urlPatterns ={"/css/","/images/"})
@WebListener
MyServlet 类
@WebServlet(urlPatterns = "/my")
public class MyServlet extends HttpServlet {
@Override
protected 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 {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
log.info("MyFilter初始化完成");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
log.info("MyFilter工作");
filterChain.doFilter(servletRequest,servletResponse);
}
@Override
public void destroy() {
log.info("MyFilter销毁");
}
}
监听器
@Slf4j
@WebListener
public class MyServletContextListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
log.info("监听到项目初始化");
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
log.info("监听到项目销毁");
}
}
ServletRegistrationBean, FilterRegistrationBean, and ServletListenerRegistrationBean
可以注解掉前面的3个注解,让后使用RegistrationBean来注册。
@Configuration
public class MyRegistConfig {
@Bean
public ServletRegistrationBean myServlet(){
MyServlet myServlet = new MyServlet();
return new ServletRegistrationBean(myServlet,"/my","/my02");
}
@Bean
public FilterRegistrationBean myFilter(){
MyFilter myFilter = new MyFilter();
// return new FilterRegistrationBean(myFilter,myServlet());
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(myFilter);
filterRegistrationBean.setUrlPatterns(Arrays.asList("/my","/css/*"));
return filterRegistrationBean;
}
@Bean
public ServletListenerRegistrationBean myListener(){
MyServletContextListener mySwervletContextListener = new MyServletContextListener();
return new ServletListenerRegistrationBean(mySwervletContextListener);
}
}
细节:
@Configuration(proxyBeanMethods=false)
public class MyRegistConfig {
这里没有写proxyBeanMethods=false。如果写了说明当前类每次一调用类里面的方法,servlet都会新建一次。比如我们调用MyFilter的时候,servlet就重新new了一下。(proxyBeanMethods=true)它可以保证依赖的组件始终是单实例的。
为什么自己写的@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 incorrectly
return 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并没有被拦截。
默认支持的webServer
<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包存在)
实现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> {
@Override
public void customize(ConfigurableServletWebServerFactory server) {
server.setPort(9000);
}
}
修改配置文件;
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最基本的使用*
4、 WebMvcAutoConfiguration 面的配置要能生效必须@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
5、@EnableWebMvc导致了WebMvcAutoConfiguration没有生效。
场景starter - xxxxAutoConfiguration -导入xx组件-绑定xxxProperties --绑定配置文件项