springmvc迁移springboot之路2

1、常规springmvc的流程

1.1springmvc的启动过程

首先,对于一个web应用,其部署在web容器中,web容器提供其一个全局的上下文环境,这个上下文就是ServletContext,其为后面的spring IoC容器提供宿主环境;

其次,在web.xml中会提供有contextLoaderListener。在web容器启动时,会触发容器初始化事件,此时contextLoaderListener会监听到这个事件,其contextInitialized方法会被调用,在这个方法中,spring会初始化一个启动上下文,这个上下文被称为根上下文,即WebApplicationContext,这是一个接口类,确切的说,其实际的实现类是XmlWebApplicationContext。这个就是spring的IoC容器,其对应的Bean定义的配置由web.xml中的context-param标签指定。在这个IoC容器初始化完毕后,spring以WebApplicationContext.ROOTWEBAPPLICATIONCONTEXTATTRIBUTE为属性Key,将其存储到ServletContext中,便于获取;

再次,contextLoaderListener监听器初始化完毕后,开始初始化web.xml中配置的Servlet,这个servlet可以配置多个,以最常见的DispatcherServlet为例,这个servlet实际上是一个标准的前端控制器,用以转发、匹配、处理每个servlet请求。DispatcherServlet上下文在初始化的时候会建立自己的IoC上下文,用以持有spring mvc相关的bean。在建立DispatcherServlet自己的IoC上下文时,会利用WebApplicationContext.ROOTWEBAPPLICATIONCONTEXTATTRIBUTE先从ServletContext中获取之前的根上下文(即WebApplicationContext)作为自己上下文的parent上下文。有了这个parent上下文之后,再初始化自己持有的上下文。这个DispatcherServlet初始化自己上下文的工作在其initStrategies方法中可以看到,大概的工作就是初始化处理器映射、视图解析等。这个servlet自己持有的上下文默认实现类也是mlWebApplicationContext。初始化完毕后,spring以与servlet的名字相关(此处不是简单的以servlet名为Key,而是通过一些转换,具体可自行查看源码)的属性为属性Key,也将其存到ServletContext中,以便后续使用。这样每个servlet就持有自己的上下文,即拥有自己独立的bean空间,同时各个servlet共享相同的bean,即根上下文(第2步中初始化的上下文)定义的那些bean。

1.2spring mvc工作流程图

Spring工作流程描述

1.用户向服务器发送请求,请求被Spring前端控制Servelt DispatcherServlet捕获;

2. DispatcherServlet对请求URL进行解析,得到请求资源标识符(URI)。然后根据该URI,调用HandlerMapping获得该Handler配置的所有相关的对象(包括Handler对象以及Handler对象对应的拦截器),最后以HandlerExecutionChain对象的形式返回;

3. DispatcherServlet根据获得的Handler,选择一个合适的HandlerAdapter。(附注:如果成功获得HandlerAdapter后,此时将开始执行拦截器的preHandler(...)方法)

4.提取Request中的模型数据,填充Handler入参,开始执行Handler(Controller)。 在填充Handler的入参过程中,根据你的配置,Spring将帮你做一些额外的工作:

HttpMessageConveter:将请求消息(如Json、xml等数据)转换成一个对象,将对象转换为指定的响应信息

数据转换:对请求消息进行数据转换。如String转换成Integer、Double等

数据根式化:对请求消息进行数据格式化。如将字符串转换成格式化数字或格式化日期等;

数据验证: 验证数据的有效性(长度、格式等),验证结果存储到BindingResult或Error中;

5.  Handler执行完成后,向DispatcherServlet返回一个ModelAndView对象;

6.根据返回的ModelAndView,选择一个适合的ViewResolver(必须是已经注册到Spring容器中的ViewResolver)返回给DispatcherServlet;

7. ViewResolver结合Model和View,来渲染视图

8.将渲染结果返回给客户端。

2springboot搭建

2.1选取ide工具

下图是spring官网提供的ide工具

要创建springboot项目可以下载spring官网提供的sts这款IDE,自动集成了创建boot项目所需的插件,当然对使用eclipse的开发者也可以安装对应系统的插件进行构建boot项目。

2.2创建项目

File> New > Spring Starter Project

Next> Finish

项目创建完成:

可以看出,项目源码就一个Java类,在pom.xml中有spring-boot-starter-web的依赖。

SpringBootSampleApplication.java

packageorg.springboot.sample;

importorg.springframework.boot.SpringApplication;

importorg.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication

publicclass SpringBootSampleApplication {

public static void main(String[] args) {

SpringApplication.run(SpringBootSampleApplication.class,args);

}

}

pom.xml


4.0.0

org.springboot.sample

spring-boot-sample

0.0.1-SNAPSHOT

jar

spring-boot-sample

Spring Boot Sample WebApplication

org.springframework.boot

spring-boot-starter-parent

1.3.1.RELEASE


UTF-8

1.8

org.springframework.boot

spring-boot-starter-web

org.springframework.boot

spring-boot-starter-test

test

org.springframework.boot

spring-boot-maven-plugin

这样就完成了项目的创建,下面我们创建一个HelloController.java定义3个方法

packageorg.springboot.sample.controller;

importjava.util.ArrayList;

importjava.util.HashMap;

importjava.util.List;

importjava.util.Map;

importorg.springframework.web.bind.annotation.RequestMapping;

importorg.springframework.web.bind.annotation.RequestParam;

importorg.springframework.web.bind.annotation.RestController;

@RestController

@RequestMapping("/hello")

publicclass HelloController {

@RequestMapping

public String hello() {

return "Hello Spring-Boot";

}

@RequestMapping("/info")

public Map getInfo(@RequestParamString name) {

Map map = newHashMap<>();

map.put("name", name);

return map;

}

@RequestMapping("/list")

public List>getList() {

List> list= new ArrayList<>();

Map map = null;

for (int i = 1; i <= 5; i++) {

map = new HashMap<>();

map.put("name", "Shanhy-"+ i);

list.add(map);

}

return list;

}

}

然后现在可以直接运行SpringBootSampleApplication的main方法,和执行普通java程序一样。

然后可以看到spring-boot内置server容器(默认为Tomcat),这一切spring-boot都帮我们做好了。

控制台输出内容Started SpringBootSampleApplication in 7.358 seconds (JVM running

for 9.154)表示服务已经启动。

在浏览器输入我们3个请求便可看到结果。http://localhost:8080/hello

输出:HelloSpring-Boothttp://localhost:8080/hello/info?name=shanhy

输出:{“name”:”shanhy”}http://localhost:8080/hello/list

输出:[{“name”:”Shanhy-1”},{“name”:”Shanhy-2”},{“name”:”Shanhy-3”},{“name”:”Shanhy-4”},{“name”:”Shanhy-5”}]

通过我们的Hello实例,相信大家一目了然,可谓spring-boot创建一个项目如此简单,完全可以在几分钟内将服务启动。spring-boot抛弃繁琐的配置,让开发人员更专注与业务逻辑的实现。后面几篇文章将会对spring-boot的多个方面通过实例的方式呈现给大家。

3springboot的运行原理

系统启动类视图如下:

可以发现启动类有个@SpringBootApplication注解,这是一个组合注解,结构如下图:

@SpringBootApplication注解的功能主要由@ EnableAutoCongiguration、@componentScan组成。

@EnableAutoCongiguration负责启动自动配置功能,在main方法中的SpringApplication启动的方法中,如下图:

在SpringApplication启动时,依据@ EnableAutoCongiguration设定的自动配置功能,有一部分功能是去扫描maven内所有jar包下的spring.factories文件,构建成一个配置文件链表,如果系统有引用,则根据条件注解去初始化bean,例如:

@componentScan负责扫描启动类所在package下子package的所有需要实例化的bean的IOC,比如@controller、@service、@Component、@Configuration、@bean等。

boot提供了默认的配置文件:application.xml,集成了各类starter服务的配置属性定制化,简单举几个例子:

日志配置

web服务器配置

模板配置

http编码、json和微服务配置

mvc交互配置

认证配置

还有spring.data.*和spring.datasource.*的异构数据源的配置等等,具体详情参考

http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/

4springmvc迁移springboot

4.1零配置

常规springmvc的整体结构如下图:


springboot的整体结构如下图:


综合对比,springmvc要迁移springboot,首当其中的就是springboot是如何去XML(web.xml和applicationcontext.xml)的。

去web.xml:依赖内置web服务器启动初始化应用的上下文;

去applicationcontext.xml:依赖java注解和条件注解技术,使用自动配置功能实现。

4.2web.xml

对于一些springboot

application.xml中没有的服务,有三种解决方式:

1、自定义starter pom

2、原始方式自己编写服务

3、原始引用XML

对于springboot服务不好用,想进行变更的,boot设计中为它的任何一个服务都提供了可扩展性的方式进行变更,比如如何解决web.xml内配置的filter、Listener、Interceptor等,可通过注解方式(比如@Component、@Configuration)自行扩展对应的服务。

5样例

5.1pom文件配置


5.2application.xml配置

环境分流配置

开启shutdown功能

配置内容

5.3平滑升级


6总结

使用springboot,首选需要判断boot是否提供了服务,boot有一些服务是自动配置加载的,有一些服务是需要enable*打开才能用的,比如定时@EnableScheduling、异步@EnableAsync服务等,如果boot目前还无法定制某项目的个性化服务,可自行扩展,扩展方式参考4.2小节描述内容。

对于jar包版本一致性问题也是同理,先判断boot是否提供了对应的jar服务,决定是否需要自行扩展。

springboot可以导出jar包也可以导出war包,war包基本依赖外部应用服务器,可以利用外部应用服务器的shutdown功能平滑升级。但jar包形式依赖linux sh脚本的运行,基本都会使用kill去暴力杀线程,这是会影响线上业务的,所以为了保证线上线程不会突然崩溃影响业务,sringboot也考虑了这一点,在监控Actuator中提供了优雅的shutdown功能,只要我们在sh脚本中访问线上服务的shutdown地址,即可优雅的关闭线上服务,平滑升级了。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,657评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,662评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,143评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,732评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,837评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,036评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,126评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,868评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,315评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,641评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,773评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,470评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,126评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,859评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,095评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,584评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,676评论 2 351

推荐阅读更多精彩内容