给大家聊一聊云收藏从 Spring Boot 1.0 升级到 2.0 所踩的坑

先给大家晒一下云收藏的几个数据,作为一个 Spring Boot 的开源项目(https://github.com/cloudfavorites/favorites-web)目前在 Github 上面已经有1600多个 Star,如果按照 SpringBoot 标签进行筛选的话也可以排到第五位。

当云收藏1.0开发完成之后,同步将云收藏部署到了服务器上,申请了一个域名www.favorites.ren方便大家使用,到目前为止:网站的注册用户4000多人,共计收藏文章100000多条,在百度上搜索:云收藏,排在第一的就是云收藏的官网。2年多的时间这个数据其实也并不是很耀眼,但是作为一个学习 Spring Boot 的开源软件来讲,已经不错了。

云收藏的部署之路也挺曲折,刚开始的时候部署在我以前公司的服务器上,后来离职的时候在阿里云买了个1核1G的云服务器,因为安装了 Mysql、Redis、还有其它小软件导致服务器非常卡,那段时间访问云收藏的时候需要等待2-3秒才会有响应。

终于有一天自己也不能忍了,花钱把服务器升级到2核2G,访问速度虽有所提升但还是很不理想,那段时间工作很忙也没时间优化。网站的 Bug 也是一片,有时候还会突然中断服务几个小时,流失了一大批用户,甚至有人在 Github 上面留言说:看来微笑哥已经放弃云收藏了,我看了之后只能苦笑。

到了今年 Spring Boot 2.0 发布的时候,我就计划着把云收藏全面升级到2.0,顺便做一些优化让访问速度快一点。但一拖就是2个月,终于在前几个周末抽出了一点时间,将云收藏升级到了 Spring Boot 2.0 同时修复了一批显而易见的 Bug ,使用 Nginx 将静态图片等资源做了代理,当这些工作完全做完的时候,云收藏的访问速度明显得到了提升,大家可以访问www.favorites.ren体验一下。

将云收藏从 Spring Boot 1.0 升级到 2.0 的时候也遇到了一些问题,在修改的过程中记录下来,今天整理一下分享出来,方便后续升级的朋友少踩一些坑。

1、第一个问题:启动类报错

Spring Boot 部署到 Tomcat 中去启动时需要在启动类添加SpringBootServletInitializer,2.0 和 1.0 有区别。

// 1.0
import org.springframework.boot.web.support.SpringBootServletInitializer;
// 2.0
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; @SpringBootApplication
public class UserManageApplication extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(UserManageApplication.class);
} public static void main(String[] args) throws Exception {
SpringApplication.run(UserManageApplication.class, args);
}
}

这个问题好解决只需要重新导包就行。

2、日志类报错:Spring Boot 2.0 默认不包含 log4j,建议使用 slf4j 。

import org.apache.log4j.Logger;
protected Logger logger = Logger.getLogger(this.getClass());

改为:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
protected Logger logger = LoggerFactory.getLogger(this.getClass());

这个也比较好改动,就是需要替换的文件比较多。

3、Spring Boot 2.0 去掉了findOne()方法。

以前的findOne()方法其实就是根据传入的 Id 来查找对象,所以在 Spring Boot 2.0 的 Repository 中我们可以添加findById(long id)来替换使用。

例如:

User user=userRepository.findOne(Long id)

改为手动在userRepository手动添加findById(long id)方法,使用时将findOne()调用改为findById(long id)

User user=userRepository.findById(long id)

delete()方法和findOne()类似也被去掉了,可以使用deleteById(Long id)来替换,还有一个不同点是deleteById(Long id)默认实现返回值为void

Long deleteById(Long id);

改为

//delete 改为 void 类型
void deleteById(Long id);

当然我们还有一种方案可以解决上述的两种变化,就是自定义 Sql,但是没有上述方案简单不建议使用。

@Query("select t from Tag t where t.tagId = :tagId")
Tag getByTagId(@Param("tagId") long tagId);

4、云收藏升级到 2.0 之后,插入数据会报错,错误信息如下:

org.springframework.dao.DataIntegrityViolationException: could not execute statement; SQL [n/a]; constraint [PRIMARY]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement
....
Caused by: org.hibernate.exception.ConstraintViolationException: could not execute statement
...
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry '299' for key 'PRIMARY'

这个问题稍稍花费了一点时间,报错提示的是主键冲突,跟踪数据库的数据发现并没有主键冲突,最后才发现是 Spring Boot 2.0 需要指定主键的自增策略,这个和 Spring Boot 1.0 有所区别,1.0 会使用默认的策略。

@Id
@GeneratedValue(strategy= GenerationType.IDENTITY)
private long id;

改动也比较简单,需要在所有的主键上面显示的指明自增策略。

5、Thymeleaf 3.0 默认不包含布局模块。

这个问题比较尴尬,当我将 Pom 包升级到 2.0 之后,访问首页的时候一片空白什么都没有,查看后台也没有任何的报错信息,首先尝试着跟踪了 http 请求,对比了一下也没有发现什么异常,在查询 Thymeleaf 3.0 变化时才发现:Spring Boot 2.0 中spring-boot-starter-thymeleaf 包默认并不包含布局模块,需要使用的时候单独添加,添加布局模块如下:

<dependency>
<groupId>nz.net.ultraq.thymeleaf</groupId>
<artifactId>thymeleaf-layout-dialect</artifactId>
</dependency>

改完之后再访问首页,一切正常,但是回头查看日志信息发现有一个告警信息:

2018-05-10 10:47:00.029  WARN 1536 --- [nio-8080-exec-2] n.n.u.t.decorators.DecoratorProcessor    : The layout:decorator/data-layout-decorator processor has been deprecated and will be removed in the next major version of the layout dialect.  Please use layout:decorate/data-layout-decorate instead to future-proof your code.  See https://github.com/ultraq/thymeleaf-layout-dialect/issues/95 for more information.
2018-05-10 10:47:00.154 WARN 1536 --- [nio-8080-exec-2] n.n.u.t.expressions.ExpressionProcessor : Fragment expression "layout" is being wrapped as a Thymeleaf 3 fragment expression (~{...}) for backwards compatibility purposes. This wrapping will be dropped in the next major version of the expression processor, so please rewrite as a Thymeleaf 3 fragment expression to future-proof your code. See https://github.com/thymeleaf/thymeleaf/issues/451 for more information.

跟踪地址看了一下,大概的意思是以前布局的标签已经过期了,推荐使用新的标签来进行页面布局,解决方式也比较简单,修改以前的布局标签 layout:decoratorlayout:decorate即可。

6、分页组件PageRequest变化。

在 Spring Boot 2.0 中 ,方法new PageRequest(page, size, sort) 已经过期不再推荐使用,推荐使用以下方式来构建分页信息:

Pageable pageable =PageRequest.of(page, size, Sort.by(Sort.Direction.ASC,"id"));

跟踪了一下源码发现PageRequest.of()方法,内部还是使用的new PageRequest(page, size, sort),只是最新的写法更简洁一些。

public static PageRequest of(int page, int size, Sort sort) {
return new PageRequest(page, size, sort);
}

7、关联查询时候组合返回对象的默认值有变化。

在使用 Spring Boot 1.0 时,使用 Jpa 关联查询时我们会构建一个接口对象来接收结果集,类似如下:

public interface CollectView{
Long getId();
Long getUserId();
String getProfilePicture();
String getTitle();
}

在使用 Spring Boot 1.0 时,如果没有查询到对应的字段会返回空,在 Spring Boot 2.0 中会直接报空指针异常,对结果集的检查会更加严格一些。

8、其它优化

前段时间在学习 Docker ,给云收藏添加了 Docker 、Docker Compose 支持让部署的时候更简单一些;同时修复了一些 bug,对于明显很消耗资源的功能进行了改进,部分功能添加了容错性;本次部署的时候使用了 Nginx 作为反向代理,因为使用了 WebJars 暂时不能使用 Nginx 代理 Js,所以将除过 Js 以外的其它资源都配置了缓存,;数据库由 Mysql 换成了 Mariadb。

以上就是云收藏从 Spring Boot 1.0 到 2.0 所做的一些小改进,做完这些工作之后惊喜的发现云收藏的访问速度比以前快了很多,虽然还有很大的优化空间,但日常使用基本上不会体验到太大的延迟。Spring Boot 2.0 中 Thymeleaf 默认使用了 3.0 ,数据库连接池默认使用了 Hikari ,这两个组件在性能上有很大的提升,同时也是提升云收藏访问速度的因素之一。

未来云收藏还会持续升级,后续会规划一些面向程序员的新功能,敬请期待!

Spring Boot 2.0 版的开源项目云收藏来了!的更多相关文章

  1. 学习Spring Boot看这两个开源项目就够了!非得值得收藏的资源

    Spring Boot我就不做介绍了,大家都懂得它是一个多么值得我们程序员兴奋的框架. 为什么要介绍这两个开源项目呢? 1.提供了丰富的学习实践案例 2.整合了非常多优质的学习资源 不多说了,直接上链 ...

  2. Spring Boot 2.0(六):使用 Docker 部署 Spring Boot 开源软件云收藏

    云收藏项目已经开源2年多了,作为当初刚开始学习 Spring Boot 的练手项目,使用了很多当时很新的技术,现在看来其实很多新技术是没有必要使用的,但做为学习案例来讲确实是一个绝佳的 Spring ...

  3. Vue+Spring Boot 前后端分离的商城项目开源啦!

    新蜂商城 Vue 移动端版本开源啦! 去年开源新蜂商城项目后,就一直在计划这个项目 Vue 版本的改造,2020 年开始开发并且自己私下一直在测试,之前也有文章介绍过测试过程和存在的问题,修改完成后, ...

  4. spring boot 2.0.0 + shiro + redis实现前后端分离的项目

    简介 Apache Shiro是一个强大且易用的Java安全框架,执行身份验证.授权.密码学和会话管理.使用Shiro的易于理解的API,您可以快速.轻松地获得任何应用程序,从最小的移动应用程序到最大 ...

  5. Spring Boot 2.0系列文章(五):Spring Boot 2.0 项目源码结构预览

    关注我 转载请务必注明原创地址为:http://www.54tianzhisheng.cn/2018/04/15/springboot2_code/ 项目结构 结构分析: Spring-boot-pr ...

  6. Spring Boot 2.0(七):Spring Boot 如何解决项目启动时初始化资源

    在我们实际工作中,总会遇到这样需求,在项目启动的时候需要做一些初始化的操作,比如初始化线程池,提前加载好加密证书等.今天就给大家介绍一个 Spring Boot 神器,专门帮助大家解决项目启动初始化资 ...

  7. Spring Boot 2.0正式发布,新特性解读

    作者|翟永超 Spring Boot 2.0 来啦,有哪些新特性?升级吗? 写在前面 北京时间 3 月 1 日,经过漫长的等待之后,Spring Boot 2.0 正式发布.作为 Spring 生态中 ...

  8. spring boot 2.0.3+spring cloud (Finchley)7、服务链路追踪Spring Cloud Sleuth

    参考:Spring Cloud(十二):分布式链路跟踪 Sleuth 与 Zipkin[Finchley 版] Spring Cloud Sleuth 是Spring Cloud的一个组件,主要功能是 ...

  9. Spring 社区的唯一一个国产开源项目 - Spring Cloud Alibaba 毕业了

    阿里妹导读:一年多前,Java 界最近发生了一件大事,阿里开源 Spring Cloud Alibaba,并推出首个预览版.Spring Cloud 本身是一套微服务规范,并不是一个拿来即可用的框架, ...

随机推荐

  1. Spring Data JPA方法定义规范

    Spring Data Jpa方法定义的规则: (1)简单条件查询 简单条件查询:查询某一个实体类或者集合. 按照Spring Data的规范的规定,查询方法以find | read | get开头, ...

  2. UEditor单个图片上传遇到的问题记录

    查看了ueditor.all.js得源代码发现单图片上传是在选择文件输入框change事件执行表单Submit,但是出现一个问题请求头没有加入Cookie,导致后端身份认证失败,上传最终失败. ued ...

  3. udev和devfs的区别

    devfs(设备文件系统)是由Linux2.4内核引入的,它的出现主要使得设备驱动程序能够自主管理自己的设备文件.具体来说,devfs具有如下优点: 可以通过程序在设备初始化时在/dev目录下创建设备 ...

  4. January 07th, 2018 Week 01st Sunday

    To remember is to disengage from the present. 铭记过去就是放弃当下. To remember the past doesn't mean we would ...

  5. 超详细!Github团队协作教程(Gitkraken版)

    超详细!Github团队协作教程(Gitkraken版) 一.前期工作 1. 在 Github 上创建 organization step1. 登录Github网站,点击右上角头像,选择 " ...

  6. ABAP 内表访问表达式的性能

    内表访问表达式是ABAP 7.4中引入的重要特性,可以使语句变得更加简洁.美观.那么它的读写性能怎么样呢?我进行了一点点测试. 读取 测试代码,使用三种方式读取同一内表,分别是read table关键 ...

  7. JS获取本周、本季度、本月、上月的开始日期、结束日期

    /** * 获取本周.本季度.本月.上月的开始日期.结束日期 */ var now = new Date();                    //当前日期 var nowDayOfWeek = ...

  8. [TJOI2010]分金币

    嘟嘟嘟 看数据范围,就能想到折半搜索. 但怎么搜,必须得想清楚了. 假设金币总数为1000,有20个人,首先搜前10个人,把答案记下来.然后如果在后十个人中搜到了4个人,价值为120,那么我们应该在记 ...

  9. Pollard_Rho大数分解模板题 pku-2191

    题意:给你一个数n,  定义m=2k-1,   {k|1<=k<=n},并且 k为素数;  当m为合数时,求分解为质因数,输出格式如下:47 * 178481 = 8388607 = ( ...

  10. PySpider HTTP 599: SSL certificate problem错误的解决方法

    在用 PySpider 爬取 https 开头的网站的时候遇到了 HTTP 599: SSL certificate problem: self signed certificate in certi ...