Spring(二十二)Spring MVC 对Tomcat 的 Servlet,Filter和Listener 组装分析
博主从Spring Boot 去看Spring MVC 启动过程,而Spring Boot 默认集成了内置的tomcat容器,所以分析Spring MVC ,中间还夹着挺多Tomcat逻辑。Java web中有三大组件:ServletFilterListener记得开始学习Java Web时候,就是通过这几个入门的,定义Servlet用于处理Http请求,定义Filter来对请求进行拦截,而使用S
博主从Spring Boot 去看Spring MVC 启动过程,而Spring Boot 默认集成了内置的tomcat容器,所以分析Spring MVC ,中间还夹着挺多Tomcat逻辑。
Java web中有三大组件:
- Servlet
- Filter
- Listener
记得开始学习Java Web
时候,就是通过这几个入门的,定义Servlet
用于处理Http请求,定义Filter
来对请求进行拦截,而使用ServletContextListener
来监听容器创建和销毁动作。
本文主要基于Tomcat来分析。
在Spring Boot 中,如果要定义这三种组件,可以这样进行:
- 使用
@ServletComponentScan("com.anla.springwebmvc.servlet")
开启对自定义Servlet包扫描 - 对三种组件,相应使用
@WebServlet
、@WebFilter
、@WebListener
进行配置,而后实现相应javax提供接口(HttpServlet
、Filter
、ServletContextListener
)。
例如加上一个自定义Servlet写法:
@WebServlet(urlPatterns = "/myservlelt")
public class MyServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setCharacterEncoding("UTF-8");
response.setHeader("Content-type","text/html;charset=utf-8");
response.getWriter().println("my springboot servlet……测试在Spring Boot自定义Servlet");
response.getWriter().flush();
response.getWriter().close();
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request,response);
}
}
ServletComponentScan
使用了 ServletComponentScan
注解,然后我们当然会看这个扫描做了什么事。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(ServletComponentScanRegistrar.class)
public @interface ServletComponentScan {
而在 ServletComponentScanRegistrar
中,通过registerBeanDefinitions
注册了一个bean ServletComponentRegisteringPostProcessor
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
Set<String> packagesToScan = getPackagesToScan(importingClassMetadata);
if (registry.containsBeanDefinition(BEAN_NAME)) {
updatePostProcessor(registry, packagesToScan);
}
else {
addPostProcessor(registry, packagesToScan);
}
}
BEAN_NAME 为:servletComponentRegisteringPostProcessor
再看看 ServletComponentRegisteringPostProcessor
:
class ServletComponentRegisteringPostProcessor implements BeanFactoryPostProcessor, ApplicationContextAware {
它是一个 BeanFactoryPostProcessor
,所以应该是Spring 扫描完Configuration 类后,直接就会轮到 它,看看重写的方法:
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
// 只有是内置服务器,才会执行
if (isRunningInEmbeddedWebServer()) {
// 构造扫描器,过滤WebServlet,WebFilter,WebListener 三种
ClassPathScanningCandidateComponentProvider componentProvider = createComponentProvider();
for (String packageToScan : this.packagesToScan) {
// 具体扫描动作
scanPackage(componentProvider, packageToScan);
}
}
}
判断扫描规则,而后调用 scanPackage
对注解上传入的报名进行依次扫描:
private void scanPackage(ClassPathScanningCandidateComponentProvider componentProvider, String packageToScan) {
for (BeanDefinition candidate : componentProvider.findCandidateComponents(packageToScan)) {
if (candidate instanceof ScannedGenericBeanDefinition) {
for (ServletComponentHandler handler : HANDLERS) {
// 依次判断类型
handler.handle(((ScannedGenericBeanDefinition) candidate),
(BeanDefinitionRegistry) this.applicationContext);
}
}
}
}
- 对
componentProvider.findCandidateComponents(packageToScan)
扫描到的所有信息进行过滤。 - HANDLERS 中存储着三种类型handler
WebServletHandler
、WebFilterHandler
、WebListenerHandler
,分别用于解析三种类型组件。
如果发现是对应类型Bean,则将其作为相应bean注册进容器。
分别看这三个Handler
的doHandle
方法:
WebFilterHandler
@Override
public void doHandle(Map<String, Object> attributes, ScannedGenericBeanDefinition beanDefinition,
BeanDefinitionRegistry registry) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(FilterRegistrationBean.class);
builder.addPropertyValue("asyncSupported", attributes.get("asyncSupported"));
builder.addPropertyValue("dispatcherTypes", extractDispatcherTypes(attributes));
builder.addPropertyValue("filter", beanDefinition);
builder.addPropertyValue("initParameters", extractInitParameters(attributes));
String name = determineName(attributes, beanDefinition);
builder.addPropertyValue("name", name);
builder.addPropertyValue("servletNames", attributes.get("servletNames"));
builder.addPropertyValue("urlPatterns", extractUrlPatterns(attributes));
registry.registerBeanDefinition(name, builder.getBeanDefinition());
}
WebListenerHandler
@Override
protected void doHandle(Map<String, Object> attributes, ScannedGenericBeanDefinition beanDefinition,
BeanDefinitionRegistry registry) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(ServletListenerRegistrationBean.class);
builder.addPropertyValue("listener", beanDefinition);
registry.registerBeanDefinition(beanDefinition.getBeanClassName(), builder.getBeanDefinition());
}
WebServletHandler
@Override
public void doHandle(Map<String, Object> attributes, ScannedGenericBeanDefinition beanDefinition,
BeanDefinitionRegistry registry) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(ServletRegistrationBean.class);
builder.addPropertyValue("asyncSupported", attributes.get("asyncSupported"));
builder.addPropertyValue("initParameters", extractInitParameters(attributes));
builder.addPropertyValue("loadOnStartup", attributes.get("loadOnStartup"));
String name = determineName(attributes, beanDefinition);
builder.addPropertyValue("name", name);
builder.addPropertyValue("servlet", beanDefinition);
builder.addPropertyValue("urlMappings", extractUrlPatterns(attributes));
builder.addPropertyValue("multipartConfig", determineMultipartConfig(beanDefinition));
registry.registerBeanDefinition(name, builder.getBeanDefinition());
}
即通过注解中传入的参数,分别传入到BeanDefinition
中,对应三种bean分别为:
ServletRegistrationBean
、FilterRegistrationBean
、ServletListenerRegistrationBean
。
到目前为止,Spring 对 Servlet
、Filter
、Listener
组装已经结束,就是将他们按照特定类型放入到Spring 容器中。
下篇文章,将看看Spring 何时使用他们,敬请期待。
觉得博主写的有用,不妨关注博主公众号: 六点A君。
哈哈哈,一起研究Spring:
更多推荐
所有评论(0)