Spring-web源码解析之Initializer

简介: 基于4.1.7.RELEASESpring-WebApplicationInitializerAbstractContextLoaderInitializer / AbstractDi...

基于4.1.7.RELEASE

Spring-WebApplicationInitializer

AbstractContextLoaderInitializer / AbstractDispatcherServletInitializer / AbstractAnnotationConfigDispatcherServletInitializer

后3个类都是实现了WebApplicationInitializer接口,WebApplicationInitializer接口主要的作用是提供在Servlet 3.0+环境中对于ServletContext的可编程实现,可以跟web.xml混合使用,该接口的实现类会被SpringServletContainerInitializer自动调用,而SpringServletContainerInitializer则会被任意3.0+的Servlet自动启用,可以使用@Order注解来定义WebApplicationInitializer的执行顺序。

值得注意的一点是在tomcat的7.0.14(包含)以下版本时, tomcat会把url :“/”跟DefaultServlet绑定在一起且无法重写绑定关系。


需要注意的方法:

@Override
public void onStartup(ServletContext servletContext) throws ServletException {
   registerContextLoaderListener(servletContext);
}
在初始化Web Application的时候被调用,用于配置相关的ServletContext
在AbstractContextLoaderInitializer里,这里调用了registerContextLoaderListener方法,向其子类提供的WebApplicationContext注册了一个ContextLoaderListener
protected void registerContextLoaderListener(ServletContext servletContext) {
   WebApplicationContext rootAppContext = createRootApplicationContext();
   if (rootAppContext != null) {
      servletContext.addListener(new ContextLoaderListener(rootAppContext));
   }
}

而在AbstractDispatcherServletInitializer类中,onStartup则被重写,调用了本类的registerDispatcherServlet方法,注册了一个默认名字为dispatcher的DispatcherServlet,并且对Servlet进行了一些初始化工作。

protected void registerDispatcherServlet(ServletContext servletContext) {
   String servletName = getServletName();
   WebApplicationContext servletAppContext = createServletApplicationContext();

   DispatcherServlet dispatcherServlet = new DispatcherServlet(servletAppContext);
   ServletRegistration.Dynamic registration = servletContext.addServlet(servletName, dispatcherServlet);
   
   registration.setLoadOnStartup(1);
   registration.addMapping(getServletMappings());
   registration.setAsyncSupported(isAsyncSupported());

   Filter[] filters = getServletFilters();
   if (!ObjectUtils.isEmpty(filters)) {
      for (Filter filter : filters) {
         registerServletFilter(servletContext, filter);
      }
   }

   customizeRegistration(registration);
}

由代码中可以看出,在注册完dispatchServlet之后,设置启动优先级为1表明该Servlet随容器启动而初始化,添加Servlet的URL mapping即web.xml中的url-pattern选项,注册Servlet的filters并且调用了customizeRegistration方法来实现自定义配置ServletContext。其中

getServletName(), customizeRegistration() 可由实现类自己决定是否重写

createServletApplicationContext(),createRootApplicationContext()(继承自AbstractContextLoaderInitializer),getServletMappings()子类必须实现

有一个有意思的现象是在registerServletFilter中添加Filter时

int counter = -1;
while (counter == -1 || registration == null) {
   counter++;
   registration = servletContext.addFilter(filterName + "#" + counter, filter);
   Assert.isTrue(counter < 100,
         "Failed to register filter '" + filter + "'." +
         "Could the same Filter instance have been registered already?");
}

这表明,同一个名称的filter最多只能注册100个。

由于AbstractAnnotationConfigDispatcherServletInitializer继承了AbstractDispatcherServletInitializer,所以它满足了上面要求的createServletApplicationContext(),createRootApplicationContext()两个方法实现,而由于它是一个抽象类,getServletMappings()则被交给它的子类去实现。这两个方法的实现大同小异

Class<?>[] configClasses = getRootConfigClasses();
if (!ObjectUtils.isEmpty(configClasses)) {
   AnnotationConfigWebApplicationContext rootAppContext = new AnnotationConfigWebApplicationContext();
   rootAppContext.register(configClasses);
   return rootAppContext;
}else {
   return null;
}

如上所示,其不同在意获取configClasses的不同之处,一个是获取用于Servlet Application Context的配置,另一个是用于root Application Context的配置,无论是用在哪里,都是由其子类通过注解@Configuration和@Component来标识的。

目录
相关文章
|
2月前
|
数据采集 人工智能 Java
1天消化完Spring全家桶文档!DevDocs:一键深度解析开发文档,自动发现子URL并建立图谱
DevDocs是一款基于智能爬虫技术的开源工具,支持1-5层深度网站结构解析,能将技术文档处理时间从数周缩短至几小时,并提供Markdown/JSON格式输出与AI工具无缝集成。
132 1
1天消化完Spring全家桶文档!DevDocs:一键深度解析开发文档,自动发现子URL并建立图谱
|
2月前
|
安全 Java API
深入解析 Spring Security 配置中的 CSRF 启用与 requestMatchers 报错问题
本文深入解析了Spring Security配置中CSRF启用与`requestMatchers`报错的常见问题。针对CSRF,指出默认已启用,无需调用`enable()`,只需移除`disable()`即可恢复。对于`requestMatchers`多路径匹配报错,分析了Spring Security 6.x中方法签名的变化,并提供了三种解决方案:分次调用、自定义匹配器及降级使用`antMatchers()`。最后提醒开发者关注版本兼容性,确保升级平稳过渡。
241 2
|
3月前
|
存储 Java 文件存储
微服务——SpringBoot使用归纳——Spring Boot使用slf4j进行日志记录—— logback.xml 配置文件解析
本文解析了 `logback.xml` 配置文件的详细内容,包括日志输出格式、存储路径、控制台输出及日志级别等关键配置。通过定义 `LOG_PATTERN` 和 `FILE_PATH`,设置日志格式与存储路径;利用 `&lt;appender&gt;` 节点配置控制台和文件输出,支持日志滚动策略(如文件大小限制和保存时长);最后通过 `&lt;logger&gt;` 和 `&lt;root&gt;` 定义日志级别与输出方式。此配置适用于精细化管理日志输出,满足不同场景需求。
261 1
|
2月前
|
前端开发 安全 Java
Spring Boot 便利店销售系统项目分包设计解析
本文深入解析了基于Spring Boot的便利店销售系统分包设计,通过清晰的分层架构(表现层、业务逻辑层、数据访问层等)和模块化设计,提升了代码的可维护性、复用性和扩展性。具体分包结构包括`controller`、`service`、`repository`、`entity`、`dto`、`config`和`util`等模块,职责分明,便于团队协作与功能迭代。该设计为复杂企业级应用开发提供了实践参考。
117 0
|
1月前
|
存储 算法 安全
JWT深度解析:现代Web身份验证的通行证为什么现在都是JWT为什么要restful-优雅草卓伊凡
JWT深度解析:现代Web身份验证的通行证为什么现在都是JWT为什么要restful-优雅草卓伊凡
155 41
JWT深度解析:现代Web身份验证的通行证为什么现在都是JWT为什么要restful-优雅草卓伊凡
|
1月前
|
安全 Java API
Spring Boot 功能模块全解析:构建现代Java应用的技术图谱
Spring Boot不是一个单一的工具,而是一个由众多功能模块组成的生态系统。这些模块可以根据应用需求灵活组合,构建从简单的REST API到复杂的微服务系统,再到现代的AI驱动应用。
269 8
|
2月前
|
Java 关系型数据库 MySQL
深入解析 @Transactional——Spring 事务管理的核心
本文深入解析了 Spring Boot 中 `@Transactional` 的工作机制、常见陷阱及最佳实践。作为事务管理的核心注解,`@Transactional` 确保数据库操作的原子性,避免数据不一致问题。文章通过示例讲解了其基本用法、默认回滚规则(仅未捕获的运行时异常触发回滚)、因 `try-catch` 或方法访问修饰符不当导致失效的情况,以及数据库引擎对事务的支持要求。最后总结了使用 `@Transactional` 的五大最佳实践,帮助开发者规避常见问题,提升项目稳定性与可靠性。
323 12
|
2月前
|
缓存 安全 Java
深入解析HTTP请求方法:Spring Boot实战与最佳实践
这篇博客结合了HTTP规范、Spring Boot实现和实际工程经验,通过代码示例、对比表格和架构图等方式,系统性地讲解了不同HTTP方法的应用场景和最佳实践。
230 5
|
2月前
|
安全 Java 数据安全/隐私保护
Spring Security: 深入解析 AuthenticationSuccessHandler
本文深入解析了 Spring Security 中的 `AuthenticationSuccessHandler` 接口,它用于处理用户认证成功后的逻辑。通过实现该接口,开发者可自定义页面跳转、日志记录等功能。文章详细讲解了接口方法参数及使用场景,并提供了一个根据用户角色动态跳转页面的示例。结合 Spring Security 配置,展示了如何注册自定义的成功处理器,帮助开发者灵活应对认证后的多样化需求。
89 2
|
3月前
|
前端开发 数据安全/隐私保护 CDN
二次元聚合短视频解析去水印系统源码
二次元聚合短视频解析去水印系统源码
108 4

推荐镜像

更多
  • DNS