玩转 Spring Boot 入门篇

Posted 一猿小讲

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了玩转 Spring Boot 入门篇相关的知识,希望对你有一定的参考价值。

Spring 颠覆了 Java 企业级项目的开发,使得企业级的开发由重变轻、由繁至简,可谓是为 Java 程序员带来了春天。


Spring Boot 是 Spring 框架对“约定优于配置”理念的最佳实践的产物,带来了自动配置、开箱即用、完善的监控体系等诸多特性,着实让你逃离繁琐的 XML 配置,更加专注于业务逻辑开发,可谓是 Java 程序员的又一春。


坊间传闻:由于 Spring Boot 将 Spring 开发的自动化程度提升到了一个新的高度,正式让 Spring 风云再起;由于 Spring Boot 的魔法(自动配置、内嵌容器、应用监控等)降低研发的难度,横扫 Spring 在你成功路上的绊脚石。官方宣称:Spring Boot 开箱即用,绝对没有代码生成,也不需要 XML 配置


Spring Boot 如此之玄妙?你是否已按捺不住,想要亲自操刀,跃跃欲试?一探究竟?


莫急,先大致了解一下本次分享的内容大纲,然后再磨刀霍霍向 Spring Boot。


1. 磨刀不误砍柴工。


为了后续项目实战的需要,也避免后续因为环境不同而导致的差异化问题,在正式敲开 SpringBoot 大门之前,有必要先统一依赖的研发环境。


  • JDK 版本:java version "1.8.0_251"

  • Maven 版本:Apache Maven 3.3.9

  • Spring Boot 的版本:Spring Boot 2.6.2

  • 开发工具:Intellij IDEA

  • 具体的安装步骤,网上的文章比比皆是,可跟随谷哥或度娘的指示,一步一步傻瓜式的安装操作,相信肯定难不倒你,本文不做赘述。


    接下来花一分钟的时间,快速搭建 Spring Boot 项目。


    2. 快速敲开 Spring Boot 的大门


    2.1. 创建 SpringBoot 项目


    创建 Spring Boot 项目的招式(使用 Spring Initializr 、Spring TooI Suite、InteIIiJ IDEA 等)有很多种,切记不要太在意这些招式,挑花拳绣腿练一练


    花拳:用 Spring Initializr 构建 Spring Boot 项目。


    浏览器直接访问 https://start.spring.io/ 链接,便可打开 Spring Initializer 的 Web 页面。

    虽然成年人不做选择题,但是此时的确需要做如下两个选择:


  • 选择 Java 的版本:与 JDK 安装版本保持一致,本文的实验环境为 JDK 1.8 ,所以选择 8;

  • 选择 Web 依赖包:为了更好体验 Spring Boot,选择添加 Web 依赖。

  • 然后点击“GENERATE”按钮便可生成一个 Spring Boot 项目的压缩包,克制一下好奇心,待练完绣腿再体验 Spring Boot 到底有多神奇。


    绣腿:在 InteIIiJ IDEA 里构建 Spring Boot 项目。


    在 Intellij IDEA 界面中,单击【File】→【New】→【Project】,在弹出的窗口中选择【Spring Initializr】选项,如下图所示。


    确认 Java Version,本次实验环境选择 Java 8,如下图所示。



    选择【Spring Boot Version】,这里按默认版本即可(当前默认版本为 2.6.2),勾选【Web】→【Spring Web】选项,然后单击【Next】按钮,如下图所示。



    点击 Next。



    至此,一个完整的 Spring Boot 项目就创建完成了,但是,如何跑起来呢?


    2.2. 运行 Spring Boot 项目


    方式一:直接运行 main 函数,例如在 IDEA 里运行效果如下。



    方式二:采用 mvnw spring-boot:run 命令执行


    进入 Spring Boot 项目的根目录下,直接运行如下命令

  • ./mvnw spring-boot:run


    方式三:采用 java -jar 命令运行


    此时先对项目进行 maven 编译,打包,然后进入 target 目录,执行如下命令:

  • # java -jar xxx.jarjava -jar demo-0.0.1-SNAPSHOT.jar


    细心的同学会发现控制台日志输出时,会有 Tomcat 以及 8080 端口的身影,这是为什么呢?


    这就展现了一点 Spring Boot 的独特魅力,内嵌了 Tomcat 服务器,运行一个 Java main 函数顺带启动了一个应用服务器,简直太神奇了(本次不深入探究,后面原理篇会细谈)。


    至此,Spring Boot 项目就跑起来了。


    遗憾的是连一行代码都还没有写,这也是 Spring Boot 的魅力所在,让 Java 程序员更专注于业务逻辑开发。


    2.3. 添加业务逻辑


    终于可以写几行代码了,终于可以实现点业务逻辑了。


    自定义需求:提供一个 say 方法,可接受用户输入的参数 name,默认值为 World,然后输出 Hello name!



    实现步骤如上图所示很简单:


  • 提供一个 say 方法,可接受用户输入的参数 name,默认值为 World,然后输出 Hello name!(见上图中标注2)

  • 添加注解 @RestController(见上图中标注1,注解后续会单独讲解)


  • 2.4 跑起来,Try it


    直接浏览器访问 http://localhost:8080/say ,此时参数 name 不传入值,直接展示默认值。


    访问时传入参数值,http://localhost:8080/say?name=Amy此时参数 name 传入 Amy,页面展示如下。



    至此,SpringBoot  的大门已打开,万里长征稳稳踏了一步,接下来再一起看看 Spring Boot 项目的目录结构。


    2.5. Spring Boot 项目的目录结构


  • pom.xml:构建说明文件。/src/main/java:Java 源代码文件。/src/main/resources:所有的资源文件,包括静态资源文件、配置文件、页面文件等。/src/main/resources/static:Web 应用程序的静态内容(js、css、images等)。/src/main/resources/templates:存放呈现模型数据的模板。/src/main/resources/application.properties:配置文件,可以根据需要添加配置属性。/src/test/java:单元测试类 java 源代码。/target:存放编译后的 .class 文件、配置文件以及项目打包后生成的 jar 文件等。


    至此,却有很多疑问涌上心头。


    若同一台服务器上,部署 N 套 Spring Boot 项目,默认开启都是 8080,端口岂不是被占用,何解?


    另外 Spring Boot 还带来了什么好玩的事情呢?下面一起捣腾捣腾、尝试玩一玩 Spring Boot 项目。


    2.6.  玩玩 Spring Boot 项目


    控制台输出截图


    上图是 Spring Boot 项目启动时的控制台日志输出,接下来主要对图中标注的部分进行倒腾替换一下。


    2.6.1. 8080 端口被占用了咋办(控制台输出截图标注 1)?


    同一台服务器上,部署 N 套 Spring Boot 项目,默认开启都是 8080,端口被占用,何解?


    解决方案却很简单,只需在 /src/main/resources 目录的 application.properties 配置文件中自定义 server.port 就可以了,此时把服务启动的端口修改为 8888,配置如下。

  • server.port=8888

    服务跑起来,服务端口成功修改为 8888,效果如下。


    2.6.2. 内嵌的 Tomcat 容器是否可以置换一下(控制台输出截图标注 2)?


    Spring Boot 除了可以选择 Tomcat 容器,还可以选择其它服务器,接下来尝试选择 Jetty 作为内嵌服务器。


    实现方式很简单:

  • 打开 pom.xml 文件,首先排除掉默认的 Tomcat 容器;

  • 然后添加 Jetty 服务器依赖,就 Ok 了。



  • 服务跑起来,Spring Boot 选择的内嵌容器由 Tomcat 成功修改为 Jetty 容器,效果如下。



    2.6.3. 能否定义超级个性 banner (控制台输出截图标注 3)?



    Spring Boot 支持以 txt、gif、jpg、png 为后缀,以 banner 命名的资源文件形式来自定义 banner,例如 banner.txt 或者 banner.jpg。


    实现方式很简单,花拳绣腿而已。


  • 首先打开如下任一网址录入文字,选择个性化的样式,把生成的内容保存到 banner.txt。

  • http://patorjk.com/software/taag/https://www.bootschool.net/ascii
  • 然后把 banner.txt 复制到项目中 src/main/resources 目录下。



  • 服务跑起来,控制台的输出确实个性化了有没有?



    感兴趣的可以考虑找个性化图片,去试试看效果如何。


    3、例行回顾


    本文是 Spring Boot 入门级的讲解,以 Spring 官方文档入门案例作为切入点,主要分享了如下部分:

  • 准备 Spring Boot 项目依赖环境

  • 创建 Spring Boot 项目的两种方式

  • 运行 Spring Boot 项目的三种方法

  • 尝试添加业务逻辑代码,实现了一个 say Hello 的 API

  • Spring Boot 项目的目录结构介绍

  • 尝试修改默认 WEB 端口

  • 尝试修改 Spring Boot 内嵌容器

  • 尝试加入个性化的 Banner


  • 如果是 Java 小白,相信通过这个入门级的项目,能够正式迈入 Spring Boot 的大门,相信程序中的很多注解会让你摸不着头脑,不过这些都可以先忽略,随着后续的逐步深入与练习,这些都会形成肌肉记忆,一切都不是问题。


    如果是 Java 老兵,相信通过这个入门级的项目,能够轻松感受到 Spring Boot 着实去除了繁琐的 XML 配置,使项目更加简洁化、智能化,让 Java 程序员更专注业务逻辑开发,正如 Spring 的 slogan 所言:Spring makes Java simple.  真可谓是 Java 程序员的又一春。



    揭秘本文封面图片,一只奔跑的袋鼠。希望在追逐技术的道路上,我们像袋鼠一样:大胆往前跳,永远后退。

    袋鼠是澳洲的象征物,出现在澳洲国徽中,以及一些澳洲货币图案上。许多澳洲的组织团体,如澳洲航空,也将袋鼠作为其标志。澳大利亚军队的车辆,舰船在海外执行任务时很多时候都会涂上袋鼠标志。

    澳大利亚之所以让袋鼠作为国徽上动物之一,还有一个原因,就是它永远只会往前跳,永远不会后退。希望人们也有像袋鼠一样,永不退缩的精神。

    玩转 Spring Boot 入门篇就写到这里,希望大家能够喜欢。一起聊技术、谈业务、喷架构,少走弯路,不踩大坑,会持续输出更多精彩分享,欢迎关注,敬请期待!

    参考资料:

    https://spring.io/

    https://start.spring.io/

    https://spring.io/projects/spring-boot

    https://github.com/spring-projects/spring-boot

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

    https://stackoverflow.com/questions/tagged/spring-boot

    《Spring Boot实战》《深入浅出Spring Boot 2.x》

    《一步一步学Spring Boot:微服务项目实战(第二版)》

    《Spring Boot揭秘:快速构建微服务体系》

    玩转 Spring Boot 集成篇(任务动态管理代码篇)

    * 定时任务管理**/ @ private TaskInfoService taskInfoService; @ public Result list(@RequestBody TaskInfoReq reqVo) @ public Result edit(@RequestBody TaskInfoReq reqVo) @ public Result pause(Integer taskId) @ public Result add(@RequestBody TaskInfoReq taskInfoReq) @ public Result resume(Integer taskId) @ public Result delete(@RequestBody TaskInfoReq reqVo) com.example.demo.quartz.task;com.example.demo.quartz.entity.TaskInfo;com.example.demo.quartz.utils.SpringContextUtils;com.example.demo.quartz.vo.TaskInfoReq;org.quartz.*;org.slf4j.Logger;org.slf4j.LoggerFactory;org.springframework.beans.factory.annotation.Autowired;org.springframework.stereotype.Component;* 任务管理* 1、添加任务 2、更新任务 3、暂停任务 4、恢复任务**/ Logger LOGGER = LoggerFactory.getLogger(TaskManager.class); String JOB_DEFAULT_GROUP_NAME = String TRIGGER_DEFAULT_GROUP_NAME = Scheduler scheduler; SpringContextUtils springContextUtils; * 添加任务 */ flag = (!CronExpression.isValidExpression(taskInfoReq.getCron())) LOGGER.error( String className = springContextUtils.getBean(taskInfoReq.getJobName()).getClass().getName(); JobDetail jobDetail = JobBuilder.newJob().withIdentity(JobKey(taskInfoReq.getJobName(), JOB_DEFAULT_GROUP_NAME)) .ofType((Class<Job>) Class.forName(className)) .build(); Trigger trigger = TriggerBuilder.newTrigger() .forJob(jobDetail) .withSchedule(CronScheduleBuilder.cronSchedule(taskInfoReq.getCron())) .withIdentity(TriggerKey(taskInfoReq.getJobName(), TRIGGER_DEFAULT_GROUP_NAME)) .build(); scheduler.scheduleJob(jobDetail, trigger); scheduler.start(); (Exception e) LOGGER.error( flag = flag; * 更新任务 */ flag = JobKey jobKey = JobKey(taskInfo.getJobName(), JOB_DEFAULT_GROUP_NAME); TriggerKey triggerKey = TriggerKey(taskInfo.getJobName(), TRIGGER_DEFAULT_GROUP_NAME); JobDetail jobDetail = scheduler.getJobDetail(jobKey); (scheduler.checkExists(jobKey) && scheduler.checkExists(triggerKey)) Trigger newTrigger = TriggerBuilder.newTrigger() .forJob(jobDetail) .withSchedule(CronScheduleBuilder.cronSchedule(taskInfo.getCron())) .withIdentity(triggerKey) .build(); scheduler.rescheduleJob(triggerKey, newTrigger); LOGGER.info( LOGGER.info( (SchedulerException e) LOGGER.error( flag = flag; * 暂停任务 */ scheduler.pauseJob(JobKey.jobKey(taskInfo.getJobName(), JOB_DEFAULT_GROUP_NAME)); LOGGER.info( (SchedulerException e) LOGGER.error( * 恢复任务 */ scheduler.resumeJob(JobKey.jobKey(taskInfo.getJobName(), JOB_DEFAULT_GROUP_NAME)); LOGGER.info( (SchedulerException e) LOGGER.error( com.example.demo.quartz.common.EnumTaskEnable;com.example.demo.quartz.entity.TaskInfo;com.example.demo.quartz.service.TaskInfoService;com.example.demo.quartz.vo.TaskInfoReq;org.quartz.Scheduler;org.quartz.SchedulerException;org.slf4j.Logger;org.slf4j.LoggerFactory;org.springframework.beans.BeanUtils;org.springframework.beans.factory.annotation.Autowired;org.springframework.stereotype.Component;org.springframework.util.StringUtils;javax.annotation.PostConstruct;java.util.List; logger = @ scheduler; @ springJobFactory; @ taskInfoService; @ void start() scheduler.setJobFactory(springJobFactory); (taskInfo : tasks) ( data=new taskInfoService.addJob(data); logger.info( (e) logger.error(e.getMessage(), e); new com.example.demo.quartz.config;org.quartz.spi.TriggerFiredBundle;org.springframework.beans.factory.annotation.Autowired;org.springframework.beans.factory.config.AutowireCapableBeanFactory;org.springframework.scheduling.quartz.AdaptableJobFactory;org.springframework.stereotype.Component;* 解决spring bean注入Job的问题*/ AutowireCapableBeanFactory capableBeanFactory; Object Exception Object jobInstance = capableBeanFactory.autowireBean(jobInstance); jobInstance; ( AUTO_INCREMENT datetime datetime PRIMARY (AUTO_INCREMENT=lombok.Data;java.io.Serializable;java.util.Date;TaskInfo Serializable Integer id; cron; jobName; status; createTime; updateTime; com.example.demo.quartz.common.Result;com.example.demo.quartz.entity.TaskInfo;com.example.demo.quartz.vo.TaskInfoReq;java.util.List;* 定时任务接口**/interface TaskInfoService List<TaskInfo> selectTasks(); com.example.demo.quartz.service.impl;com.example.demo.quartz.common.CodeMsg;com.example.demo.quartz.common.EnumTaskEnable;com.example.demo.quartz.common.ResponseFactory;com.example.demo.quartz.common.Result;com.example.demo.quartz.dao.TaskInfoDao;com.example.demo.quartz.entity.TaskInfo;com.example.demo.quartz.service.TaskInfoService;com.example.demo.quartz.task.TaskManager;com.example.demo.quartz.vo.TaskInfoReq;com.github.pagehelper.PageHelper;com.github.pagehelper.PageInfo;org.quartz.CronExpression;org.slf4j.Logger;org.slf4j.LoggerFactory;org.springframework.beans.BeanUtils;org.springframework.stereotype.Service;org.springframework.transaction.javax.java.util.Date;java.util.List;java.util.Objects;* 定时任务业务实现**/ static Logger LOGGER = LoggerFactory.getLogger(TaskInfoServiceImpl. TaskInfoDao taskInfoDao; TaskManager taskManager; Result selectTaskListByPage(TaskInfoReq taskInfoReq) PageHelper.startPage(taskInfoReq.getPageCurrent(), taskInfoReq.getPageSize()); List<TaskInfo> list = taskInfoDao.selectTaskInfos(taskInfoReq); PageInfo<TaskInfo> pageInfo = new PageInfo<>(list); ResponseFactory.build(pageInfo); Result updateJob(TaskInfoReq taskInfoReq) (!CronExpression.isValidExpression(taskInfoReq.getCron())) LOGGER.error( ResponseFactory.build(CodeMsg.TASK_CRON_ERROR); TaskInfo isExistData = taskInfoDao.selectByJobName(taskInfoReq.getJobName()); ((!Objects.isNull(isExistData)) && (!isExistData.getId().equals(taskInfoReq.getId()))) ResponseFactory.build(CodeMsg.TASK_CRON_DOUBLE); TaskInfo = taskInfoDao.selectByPrimaryKey(taskInfoReq.getId()); (== ResponseFactory.build(CodeMsg.TASK_NOT_EXITES); BeanUtils.copyProperties(taskInfoReq, taskInfoDao.updateByPrimaryKeySelective( (!taskManager.updateJob( ResponseFactory.build(CodeMsg.TASK_EXCEPTION); ResponseFactory.build(); Result pauseJob(Integer taskId) TaskInfo = taskInfoDao.selectByPrimaryKey(taskId); (== ResponseFactory.build(CodeMsg.TASK_NOT_EXITES); (!taskManager.pauseJob( ResponseFactory.build(CodeMsg.TASK_EXCEPTION); taskInfoDao.updateByPrimaryKeySelective( ResponseFactory.build(); Result resumeJob(Integer taskId) TaskInfo = taskInfoDao.selectByPrimaryKey(taskId); (== ResponseFactory.build(CodeMsg.TASK_NOT_EXITES); (!taskManager.resumeJob( ResponseFactory.build(CodeMsg.TASK_EXCEPTION); taskInfoDao.updateByPrimaryKeySelective( ResponseFactory.build(); Result addJob(TaskInfoReq taskInfoReq) (!taskManager.addJob(taskInfoReq)) ResponseFactory.build(CodeMsg.TASK_EXCEPTION); TaskInfo = taskInfoDao.selectByJobName(taskInfoReq.getJobName()); (Objects.isNull( = new TaskInfo(); BeanUtils.copyProperties(taskInfoReq, taskInfoDao.insertSelective( ResponseFactory.build(); ResponseFactory.build(CodeMsg.TASK_CRON_DOUBLE); Result delete(TaskInfoReq reqVo) Result result = (CodeMsg.SUCCESS == result.getCode()) taskInfoDao.deleteByPrimaryKey(reqVo.getId()); ResponseFactory.build(); ResponseFactory.build(CodeMsg.TASK_EXCEPTION); (Exception e) ResponseFactory.build(CodeMsg.TASK_EXCEPTION); List<TaskInfo> selectTasks() taskInfoDao.selectAll(); id, cron, job_name, status, create_time, update_time select from sc_task_info where id = #id,jdbcType=INTEGER delete from sc_task_info where id = #id,jdbcType=INTEGER SELECT LAST_INSERT_ID() insert into sc_task_info (cron, job_name, status, create_time, update_time) values (#cron,jdbcType=VARCHAR, #jobName,jdbcType=VARCHAR, #status,jdbcType=CHAR, #createTime,jdbcType=TIMESTAMP, #updateTime,jdbcType=TIMESTAMP) SELECT LAST_INSERT_ID() insert into sc_task_info cron, job_name, status, create_time, update_time, #cron,jdbcType=VARCHAR, #jobName,jdbcType=VARCHAR, #status,jdbcType=CHAR, #createTime,jdbcType=TIMESTAMP, #updateTime,jdbcType=TIMESTAMP, update sc_task_info cron = #cron,jdbcType=VARCHAR, job_name = #jobName,jdbcType=VARCHAR, status = #status,jdbcType=CHAR, create_time = #createTime,jdbcType=TIMESTAMP, update_time = #updateTime,jdbcType=TIMESTAMP, where id = #id,jdbcType=INTEGER update sc_task_info set cron = #cron,jdbcType=VARCHAR, job_name = #jobName,jdbcType=VARCHAR, status = #status,jdbcType=CHAR, create_time = #createTime,jdbcType=TIMESTAMP, update_time = #updateTime,jdbcType=TIMESTAMP where id = #id,jdbcType=INTEGER select * from sc_task_info where job_name=#jobName select * from sc_task_info select * from sc_task_info lombok.Data;* 任务请求类**/TaskInfoReq Integer id; cron; status; jobName; int pageSize= int pageCurrent=com.example.demo.quartz.common;lombok.Data; code; String msg; Object retData;* 响应工具类*/ Result code, String errmsg) Result result = Result(); result.setCode(code); (errmsg == || errmsg.trim().length() == result.setMsg(CodeMsg.getMsg(code)); result.setMsg(errmsg); result; Result code) commonBuild(code, CodeMsg.getMsg(code)); Result commonBuild(CodeMsg.SUCCESS, Result Result json = commonBuild(CodeMsg.SUCCESS, json.setRetData(data); json; EnumTaskEnable START( STOP( code; msg; EnumTaskEnable(code, msg) getCode() code; com.example.demo.quartz.common;java.util.HashMap;java.util.Map;* 公共返回码*/ Map<Integer, String> MSG = HashMap<Integer, String>(); SUCCESS = ERROR = TASK_NOT_EXITES = TASK_EXCEPTION = TASK_CRON_ERROR = TASK_CRON_DOUBLE = MSG.put(SUCCESS, MSG.put(ERROR, MSG.put(TASK_NOT_EXITES, MSG.put(TASK_EXCEPTION, MSG.put(TASK_CRON_ERROR, MSG.put(TASK_CRON_DOUBLE, String errcode) MSG.get(errcode); com.example.demo.quartz.utils;org.springframework.beans.BeansException;org.springframework.context.ApplicationContext;org.springframework.context.ApplicationContextAware;org.springframework.context.annotation.Lazy;org.springframework.stereotype.Component; ApplicationContext applicationContext; * 实现ApplicationContextAware接口的回调方法,设置上下文环境 * * applicationContext */ SpringContextUtils.applicationContext = applicationContext; * ApplicationContext */ ApplicationContext applicationContext; * 获取对象 * 这里重写了bean方法,起主要作用 * * name * Object 一个以所给名字注册的bean的实例 * BeansException */ <T> (T) applicationContext.getBean(name); (Exception e) <T> applicationContext.getBean(clazz); (Exception e) MySQL 链接信息Mapper资源文件存放的路径Dao 接口文件存放的目录开启 debug,输出 SQL com.example.demo.quartz.task;org.apache.commons.logging.Log;org.apache.commons.logging.LogFactory;org.quartz.JobExecutionContext;org.quartz.JobExecutionException;org.springframework.scheduling.quartz.QuartzJobBean;org.springframework.stereotype.Component;* 定义一个调度器要执行的任务*/ Log logger = LogFactory.getLog(DongAoJob.class); JobExecutionException logger.info( com.example.demo.quartz;org.springframework.boot.SpringApplication;org.springframework.boot.autoconfigure.SpringBootApplication; SpringApplication.run(DemoJobApplication.class, args);


    6. 运行验证


    其实挂个简单页面就能轻松完成页面化配置任务,本次用 Postman 方式直接调用任务管理的 API


    6.1 添加任务



    此时库任务 Id 为7:

    控制台:



    6.2 查询任务


    6.3 编辑任务



    控制台输出:



    6.4 暂停任务

  • http://localhost:15158/task/pause?taskId=7

    6.5 恢复任务

  • http://localhost:15158/task/resume?taskId=7

    7. 例行回顾


    本文是 Spring Boot 项目集成 Quartz 来实现任务的动态管理,主要是代码,感兴趣的可以自行拿去验证改造并用于实践。



    玩转 Spring Boot 集成定时任务篇就写到这里,希望大家能够喜欢。


    一起聊技术、谈业务、喷架构,少走弯路,不踩大坑,会持续输出更多精彩分享,欢迎关注,敬请期待!

    历史系列文章:

    玩转  Spring Boot 入门篇

    玩转 Spring Boot 集成篇(MySQL、Druid、HikariCP

    玩转  Spring Boot 集成篇(MyBatis、JPA、事务支持

    玩转  Spring Boot 集成篇(Redis

    玩转 Spring Boot 集成篇(Actuator、Spring Boot Admin

    玩转 Spring Boot 集成篇(RabbitMQ)

    玩转 Spring Boot 集成篇(@Scheduled、静态、动态定时任务)

    以上是关于玩转 Spring Boot 入门篇的主要内容,如果未能解决你的问题,请参考以下文章

    玩转 Spring Boot 原理篇(源码环境搭建)

    玩转 Spring Boot 原理篇(自动装配源码剖析)

    玩转 Spring Boot 原理篇(核心注解知多少)

    玩转 Spring Boot 集成篇(@Scheduled静态动态定时任务)

    玩转 Spring Boot 原理篇(自动装配前凑之自定义Stater)

    玩转 Spring Boot 原理篇(内嵌Tomcat实现原理&优雅停机源码剖析)