实战:自定义简易版SpringBoot


一、功能要求

自定义简易版SpringBoot,实现SpringBoot MVC及内嵌Tomcat启动、DispatcherServlet注册和组件扫描功能

程序通过main方法启动,可以自动启动tomcat服务器可以自动创建和加载DispatcherServlet组件到ServletContext中可以自动通过@ComponentScan扫描Controller等组件Controller组件可以处理浏览器请求,返回响应结果

二、实现思路分析

传统SpringMVC框架web.xml的配置内容:

<web-app><!-- 初始化Spring上下文 --><listener><listener-class>org.springframework.web.context.ContextLoaderListener</listener-class></listener><!-- 指定Spring的配置文件 --><context-param><param-name>contextConfigLocation</param-name><param-value>/WEB-INF/app-context.xml</param-value></context-param><!-- 初始化DispatcherServlet --><servlet><servlet-name>app</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><init-param><param-name>contextConfigLocation</param-name><param-value></param-value></init-param><load-on-startup>1</load-on-startup></servlet><servlet-mapping><servlet-name>app</servlet-name><url-pattern>/app/*</url-pattern></servlet-mapping>
</web-app>

Spring官方文档中给出了基于Servlet3.0规范如何使用Java代码实现web.xml配置的example

public class MyWebApplicationInitializer implements WebApplicationInitializer {@Overridepublic void onStartup(ServletContext servletCxt) {// Load Spring web application configuration//通过注解的方式初始化Spring的上下文AnnotationConfigWebApplicationContext ac = new AnnotationConfigWebApplicationContext();//注册spring的配置类(替代传统项目中xml的configuration)ac.register(AppConfig.class);ac.refresh();// Create and register the DispatcherServlet//基于java代码的方式初始化DispatcherServletDispatcherServlet servlet = new DispatcherServlet(ac);ServletRegistration.Dynamic registration = servletContext.addServlet("app", servlet);registration.setLoadOnStartup(1);registration.addMapping("/app/*");}
}
  1. 当实现了Servlet3.0规范的容器(比如Tomcat7及以上版本)启动时

    • 会通过SPI扩展机制自动扫描所有jar包里META-INF/services/javax.servlet.ServletContainerInitializer文件中指定的全路径类(该类需实现ServletContainerInitializer接口)

    • Servlet3.0+容器启动时将自动扫描类路径,以查找Spring的WebApplicationInitializer接口的所有实现类

    • 将实现类放置到一个set集合中,提供给ServletContainerInitializer中onStartup的第一个参数使用

  2. 实例化ServletContainerInitializer实现类
  3. 回调类中的onStartup方法
  4. 在onStartup方法中(形参webAppInitializerClasses 已经封装了WebApplicationInitializer接口的所有实现类),可以回调WebApplicaitonInitializer的onStartup方法
  5. 在WebApplicaitonInitializer的onStartup方法中 进行传统SpringMVC框架web.xml的 内容配置

三、编码(实现方式一:使用框架的SpringServletContainerInitializer)

(1)创建maven工程,导入以下依赖:

    <dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-web</artifactId><version>5.0.8.RELEASE</version></dependency><dependency><groupId>org.apache.tomcat.embed</groupId><artifactId>tomcat-embed-core</artifactId><version>8.5.32</version></dependency><dependency><groupId>org.apache.tomcat.embed</groupId><artifactId>tomcat-embed-jasper</artifactId><version>8.5.32</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.0.8.RELEASE</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>5.0.8.RELEASE</version></dependency></dependencies>

(2)创建SpringApplication类,编写run方法(方法中要求完成tomcat的创建及启动)

public class SpringApplication {public static void run(){//创建tomcat实例Tomcat tomcat = new Tomcat();//设置tomcat端口tomcat.setPort(8888);try {//设置项目文件路径(完成一些自动配置,否则SpringServletContainerInitializer的onStartup方法可能不执行)tomcat.addWebapp("/", "G:\\");//启动tomcattomcat.start();// 监听关闭端口,阻塞式。没有这一句,方法执行完会直接结束tomcat.getServer().await();} catch (LifecycleException e) {e.printStackTrace();} catch (ServletException e) {e.printStackTrace();}}
}

(3)创建spring的配置类 AppConfig该类上要通过@ComponentScan来进行包扫描

@Configuration
@ComponentScan("com.dabing")
public class AppConfig {{System.out.println("ComponentScan...........");}
}

(4)创建MyWebApplicationInitializer实现WebApplicationInitializer接口,重写onstartup方法(WebApplicationInitializer实现web.xml的配置)

public class MyWebApplicationInitializer implements WebApplicationInitializer {public void onStartup(ServletContext servletContext) throws ServletException {System.out.println("初始化 MyWebApplicationInitializer");//通过注解的方式初始化Spring的上下文AnnotationConfigWebApplicationContext ac = new AnnotationConfigWebApplicationContext();//注册spring的配置类(替代传统项目中xml的configuration)ac.register(AppConfig.class);// Create and register the DispatcherServlet//基于java代码的方式初始化DispatcherServletDispatcherServlet servlet = new DispatcherServlet(ac);ServletRegistration.Dynamic registration = servletContext.addServlet("/", servlet);registration.setLoadOnStartup(1);registration.addMapping("/*");}
}

(5)编写一个Controller测试类及目标方法,响应输出“hello”即可

@RestController
public class TestController {@RequestMapping("/test/hello")public String test(){System.out.println("--- hello ---");return "hello";}}

(6)编写一个启动类Main,通过执行main方法启动服务

public class Main {public static void main(String[] args) {SpringApplication.run();}
}

(7)通过浏览器对目标方法进行方法

四、扩展:验证当实现了Servlet3.0规范的容器启动时 会通过SPI扩展机制 自动扫描 所有jar包里 META-INF/services/javax.servlet.ServletContainerInitializer 文件中指定的全路径类

自定义MySpringServletContainerInitializer 进行验证

(1)创建maven工程,导入以下依赖:

    <dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-web</artifactId><version>5.0.8.RELEASE</version></dependency><dependency><groupId>org.apache.tomcat.embed</groupId><artifactId>tomcat-embed-core</artifactId><version>8.5.32</version></dependency><dependency><groupId>org.apache.tomcat.embed</groupId><artifactId>tomcat-embed-jasper</artifactId><version>8.5.32</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.0.8.RELEASE</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>5.0.8.RELEASE</version></dependency></dependencies>

(2)创建SpringApplication 类,编写run方法(方法中要求完成tomcat的创建及启动)

public class SpringApplication {public static void run(){//创建tomcat实例Tomcat tomcat = new Tomcat();//设置tomcat端口tomcat.setPort(8888);try {//设置项目文件路径tomcat.addWebapp("/", "G:\\");//启动tomcattomcat.start();// 监听关闭端口,阻塞式。没有这一句,方法执行完会直接结束tomcat.getServer().await();} catch (LifecycleException e) {e.printStackTrace();} catch (ServletException e) {e.printStackTrace();}}
}

(3)创建spring的配置类 AppConfig该类上要通过@ComponentScan来进行包扫描

@Configuration
@ComponentScan("com.dabing")
public class AppConfig {{System.out.println("ComponentScan...........");}
}

(4)创建MySpringServletContainerInitializer,实现ServletContainerInitializer接口,重写onstartup方法,方法中调用第4步中MyWebApplicationInitializer的onstartup方法

@HandlesTypes(WebApplicationInitializer.class)
public class MySpringServletContainerInitializer implements ServletContainerInitializer {public void onStartup(Set<Class<?>> webAppInitializerClasses, ServletContext servletContext) throws ServletException {System.out.println("初始化 MySpringServletContainerInitializer");List<WebApplicationInitializer> initializers = new LinkedList<WebApplicationInitializer>();if (webAppInitializerClasses != null) {for (Class<?> waiClass : webAppInitializerClasses) {if (!waiClass.isInterface() && !Modifier.isAbstract(waiClass.getModifiers()) &&WebApplicationInitializer.class.isAssignableFrom(waiClass)) {try {initializers.add((WebApplicationInitializer)ReflectionUtils.accessibleConstructor(waiClass).newInstance());} catch (Throwable ex) {throw new ServletException("Failed to instantiate WebApplicationInitializer class", ex);}}}}if (initializers.isEmpty()) {servletContext.log("No Spring WebApplicationInitializer types detected on classpath");return;}servletContext.log(initializers.size() + " Spring WebApplicationInitializers detected on classpath");AnnotationAwareOrderComparator.sort(initializers);for (WebApplicationInitializer initializer : initializers) {System.out.println("for--------------");initializer.onStartup(servletContext);}}
}

(5)创建文件:META-INF/services/javax.servlet.ServletContainerInitializer,在该文件中配置ServletContainerInitializer的实现类MySpringServletContainerInitializer

com.dabing.web.MySpringServletContainerInitializer

(6)创建MyWebApplicationInitializer实现WebApplicationInitializer接口,重写onstartup方法(WebApplicationInitializer实现web.xml的配置)

public class MyWebApplicationInitializer implements WebApplicationInitializer {public void onStartup(ServletContext servletContext) throws ServletException {System.out.println("初始化 MyWebApplicationInitializer");//通过注解的方式初始化Spring的上下文AnnotationConfigWebApplicationContext ac = new AnnotationConfigWebApplicationContext();//注册spring的配置类(替代传统项目中xml的configuration)ac.register(AppConfig.class);// Create and register the DispatcherServlet//基于java代码的方式初始化DispatcherServletDispatcherServlet servlet = new DispatcherServlet(ac);ServletRegistration.Dynamic registration = servletContext.addServlet("/", servlet);if(registration==null) return;registration.setLoadOnStartup(1);registration.addMapping("/*");}
}

(7)编写一个Controller测试类及目标方法,响应输出“hello”即可

@RestController
public class TestController {@RequestMapping("/test/hello")public String test(){System.out.println("--- hello ---");return "hello";}}

(8)编写一个启动类Main,通过执行main方法启动服务

public class Main {public static void main(String[] args) {SpringApplication.run();}
}

(9)通过浏览器对目标方法进行方法

项目地址

测试demo

实战:自定义简易版SpringBoot相关推荐

  1. 【Opencv实战】简易版“美颜”来啦—再见旧照片,Python一键美颜哦~

    前言

  2. 手写简易版Vue源码之数据响应化的实现

    当前,Vue和React已成为两大炙手可热的前端框架,这两个框架都算是业内一些最佳实践的集合体.其中,Vue最大的亮点和特色就是数据响应化,而React的特点则是单向数据流与jsx. 笔者近期正在研究 ...

  3. springboot整合websocket实现简易版单人聊天

    websockt在作为即时通讯类的聊天方面有较多的应用,其主要的特点就是轻量,使用方便,容易快速上手,通过webscoket整合服务端,就可以实现简单的类似聊天的功能,下面说说springboot整合 ...

  4. Axure 9 实战案例,动态面板的应用 4.1,省市区三级联动下拉菜单(重制简易版)

    前言 Hello!欢迎来到Axure 9 实战案例教程专栏. 本次课程我们继续来学习一下,动态面板的应用.本篇我们来讲解一下,如何绘制省市区联动下拉菜单(重新撰写简易版). 下拉菜单初稿 为了节省时间 ...

  5. 简易版电商推荐系统开发实战Hive

    简易版电商推荐系统开发实战 数据来源 数据转换 Pandas->MySQL 用Sqoop把数据导入Hive 推荐算法 Mahout安装 itembase协同过滤算法 进行推荐 实验结果 这是从H ...

  6. c语言期中项目实战二—简易扫雷,思路分析加代码详细注释

    c语言期中项目实战二-简易扫雷,思路分析+代码详细注释 游戏介绍 项目步骤 模块化编程 设置菜单 设置棋盘 打印棋盘 布置雷 排查雷 总结及总代码和详细注释 游戏介绍 扫雷这个经典游戏,直到现在仍有很 ...

  7. python项目开发实战网盘-python项目开发实战 第2版

    python项目开发实战 第2版是一本Python项目开发流程实战手册,由日本BePROUD股份有限公司编著.本书的内容全部基于python开发事实,全部都是BeProud员工实际尝试.实践过的,可以 ...

  8. 5 拦截器拦截请求路由_手写简易版axios拦截器,实现微信小程序wx.request的封装与拦截...

    前言: axios是一个功能强大的网络请求库,其中拦截器又是axios的精髓.在小程序的开发或者需要手动实现ajax的时候,没有实现对请求的拦截,开发的时候非常不方便,因此手写一个简易版的axios拦 ...

  9. HTML5 Canvas游戏开发实战 PDF扫描版

    HTML5 Canvas游戏开发实战主要讲解使用HTML5 Canvas来开发和设计各类常见游戏的思路和技巧,在介绍HTML5 Canvas相关特性的同时,还通过游戏开发实例深入剖析了其内在原理,让读 ...

最新文章

  1. DeepSpeed超大规模模型训练工具
  2. vue的路由与es6的import, export
  3. REST service 化一个数据系统(REST Service 的最佳实践,第 2 部分)
  4. Docker 部署ELK 日志分析
  5. insert ... on duplicate key update产生death lock死锁原理
  6. 14.1178亿人 流动人口超3亿 “大国普查”这些数据很重要
  7. tree命令生成目录结构
  8. 3项目估算表_浮动油封生产项目可行性研究报告
  9. Task Parallel Library
  10. STM32库中自定义的数据类型
  11. snakeyaml操作yml文件中注释的处理
  12. 如何限定apt-get使用IPv4或IPv6协议下载
  13. html五线谱编辑器,​Notation Pad五线谱乐谱编辑器
  14. mysql routines是什么_MySQL入门:Stored Routines 的变数与流程 - Break易站
  15. 切换输入法半角全角(打开关闭输入法)
  16. 合肥辰工科技有限公司简介及公司产品介绍
  17. python中做为词云轮廓的图片,Python如何生成词云图片
  18. 音乐及游戏爱好者的福利,小鹏P7上新网易云及阴阳师,赶快看看吧
  19. c语言联机游戏,C/C++ 游戏 贪吃蛇双人对战版
  20. STM32CubeMx笔记--P2. LED亮晶晶

热门文章

  1. Nginx+FastCGI支持HTTPS部署过程详述
  2. nginx 网络模型,cpu亲和等优点
  3. iOS 权限判断 跳转对应设置界面
  4. 《深入理解Android:卷III A》一一第3章 深入理解AudioService
  5. [转]UpdatePanel的用法详解
  6. 十字星文化获数千万元A轮融资,腾讯持续下注
  7. Android微信跳一跳,自动跳App实现
  8. Quartz 2 定时任务(一):基本使用指南
  9. KVM之初体验——QEMU安装虚拟机
  10. 炫天塔罗占卜结果......