记一次Maven项目改造成SpringBoot项目的过程实践

目录
  • 背景概述
  • 过程
    • 加依赖
    • 修改main方法所在类
    • 引入数据库依赖
    • 启动类上加入mapper扫描
    • 添加application.yml
    • sqlSessionFactory空指针异常分析
    • 改造MybatisSessionFactory类
  • 改造前的执行流程
  • 改造后的执行流程
  • 总结
  • 扩展
  • 参考

背景概述

团队有一个项目,是maven构建的普通Java项目。

项目没有使用spring,用到了mysql、mybatis,还有其他大数据技术,比如flink、pulsar。

项目里连接数据库的部分,需要用到多个配置文件,一个是mybatis配置文件,一个是数据库配置文件。如果用SpringBoot可以简化为一个application.yml文件。

项目里打包方式复杂,依赖一个maven-assemble的插件,打出的包是两个jar,出现过由于配置文件读取方式的错误,导致jar包还运行不了。使用这个插件打包,还需要写一个自定义的配置文件,配置各个资源打包的参数。如果用SpringBoot,直接引入spring-boot-maven-plugin,打出的就是可执行jar包,不需要繁琐的配置,不需要自己写读取配置的代码。

为什么要改造成SpringBoot项目呢,因为SpringBoot

  • 简化配置,不用写这么多配置文件
  • 自动配置,引入starter依赖,可以自动把默认配置配好
  • 内嵌web容器
  • 自动版本管理,maven和starter配置使用
  • 生态集成容易,如果项目想要集成另外的能力,引一些starter依赖,少量的配置就可以快速接入

此外也是一次技术提升的机会,技术的优势,SpringBoot早就熟烂了。 所以打算改造成SpringBoot项目。

过程

加依赖

改造过程一步步来, 先把SpringBootStarter引入进来

<properties>
    <spring-boot.version>2.3.0.RELEASE</spring-boot.version>
</properties>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
    </dependency>
    <!-- 此处省略其他的依赖 -->
</dependencies>

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>${spring-boot.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <version>2.3.12.RELEASE</version>
            <configuration>
                <mainClass>com.xxx.pulsar.PulsarMain</mainClass>
            </configuration>
            <executions>
                <execution>
                    <id>repackage</id>
                    <goals>
                        <goal>repackage</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.8.0</version>
            <configuration>
                <source>1.8</source>
                <target>1.8</target>
            </configuration>
        </plugin>
    </plugins>
</build>

修改main方法所在类

在原先的main方法上加上注解

引入数据库依赖

首先把main函数中配置的数据库连接硬编码删除,后面将要使用application.yml来配置

<!-- mybatis-plus -->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.4.1</version>
</dependency>
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid-spring-boot-starter</artifactId>
    <version>1.1.13</version>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.27</version>
    <exclusions>
        <exclusion>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-core</artifactId>
        </exclusion>
        <exclusion>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-api</artifactId>
        </exclusion>
    </exclusions>
</dependency>

启动类上加入mapper扫描

@MapperScan("com.xxx.pulsar.mapper")

添加application.yml

# 端口
server:
  port: 8001

mybatis:
  # mapper映射文件
  mapper-locations: classpath:mapper/*.xml

spring:
  application:
    # 应用名称
    name: pulsar_demo
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    druid:
      driverClassName: com.mysql.cj.jdbc.Driver
      url: jdbc:mysql://localhost:3306/db_test?useUnicode=true&characterEncoding=UTF8&zeroDateTimeBehavior=CONVERT_TO_NULL&useSSL=false&allowPublicKeyRetrieval=true
      username: root
      password: 123456
      initial-size: 10
      max-active: 100
      min-idle: 10
      max-wait: 60000
      pool-prepared-statements: true
      max-pool-prepared-statement-per-connection-size: 20
      time-between-eviction-runs-millis: 60000
      min-evictable-idle-time-millis: 60000
      max-evictable-idle-time-millis: 300000
      validation-query: SELECT 1 FROM DUAL
      # validation-query-timeout: 5000
      test-on-borrow: false
      test-on-return: false
      test-while-idle: true
      connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
      #filters: #配置多个英文逗号分隔(统计,sql注入,log4j过滤)
      filters: stat,wall
      stat-view-servlet:
        enabled: true
        url-pattern: /druid/*

sqlSessionFactory空指针异常分析

启动测试,报错,数据库连接的地方报sqlSessionFactory空指针异常

查看错误堆栈,项目启动的时候,会从RuleFunction这个类的构造函数里面开始初始化资源。

setFields和setExtInfo这两个方法写在构造函数中,在类初始化时,就会调用,从数据库查初始化资源,

这两个方法内部会去查数据库获取基础资源,见下图

RuleFunction初始化时,Spring还没有帮我们将MybatisSessionFactory类实例化,所以报了空指针异常。

改造MybatisSessionFactory类

改造前的MybatisSessionFactory类代码如下

public class MybatisSessionFactory {

    private volatile static SqlSessionFactory sqlSessionFactory;

    private MybatisSessionFactory() {}

    public static void init(String configStr, Properties prop) {
        if (sqlSessionFactory == null) {
            synchronized (MybatisSessionFactory.class) {
                if (sqlSessionFactory == null) {
                    InputStream is = new ByteArrayInputStream(configStr.getBytes());
                    sqlSessionFactory = new SqlSessionFactoryBuilder().build(is, prop);
                }
            }
        }
    }

    public interface Action<RESULT, MAPPER> {
        RESULT action(MAPPER mapper);
    }

    public static <MAPPER, RESULT> RESULT query(Class<MAPPER> mapperClass, Action<RESULT, MAPPER> action) {
        if (sqlSessionFactory == null) {
            throw new NullPointerException("Mybatis未初始化");
        }
        try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
            MAPPER mapper = sqlSession.getMapper(mapperClass);
            return action.action(mapper);
        }
    }

}

这个MybatisSessionFactory类,是在main方法中去初始化的,main方法中调用MybatisSessionFactory.init方法,传入配置文件和配置参数,从而初始化SqlSesstionFactory。

改造的过程中,我们把main方法中调用MybatisSessionFactory.init方法给删除了,导致SqlSesstionFactory未初始化。

为什么不在main方法中调用MybatisSessionFactory.init,从而初始化SqlSesstionFactory?因为我希望通过Spring注入和管理SqlSesstionFactory的对象。

在static工具类方法里调用Spring托管的bean对象[1]

这里遇到一个问题,注意SqlSessionFactory声明方式上用了static关键字。即这个属性是类的,不是对象的。生命周期比较早,在类初始化时就会初始化。

private volatile static SqlSessionFactory sqlSessionFactory;

我使用下面的方式,在MybatisSessionFactory类中加入下面代码,并在MybatisSessionFactory类上加注解@Component。

@Autowired
private SqlSessionFactory sqlSessionFactory1;

@PostConstruct
public void update(){
    sqlSessionFactory = sqlSessionFactory1;
}
  • 首先使用@Autowired注入SqlSessionFactory
  • 使用@PostConstruct修饰update方法,方法名任意,不能有参数。这样是为了保证这个顺序:依赖注入之后,才执行update方法。该注解的方法在整个Bean初始化中的执行顺序:Constructor(构造方法) -> @Autowired(依赖注入) -> @PostConstruct(注释的方法)

RuleFunction类改造

还要改一个地方,初始化数据库资源的入口方法是在RuleFunction类的构造函数中调用的。由于构造函数会先于依赖注入执行,需要把setFields和setExtInfo这两个方法提取出来,且需要在依赖注入后执行。

修改成如下,并在RuleFunction类上加注解@Component。

改造前的执行流程

  • main方法内部调用MybatisSessionFactory的init方法
  • MybatisSessionFactory的init方法中new一个SqlSessionFactory
  • RuleFunction初始化时,调用自身构造方法
  • RuleFunction调用MybatisSessionFactory的query方法查询数据库

改造后的执行流程

  • PulsarMain和MybatisSessionFactory是松耦合的,
  • MybatisSessionFactory初始化时,因为通过@Autowired注解注入了SqlSessionFactory,所以需要初始化SqlSessionFactory,SqlSessionFactory初始化过程中会去使用配置文件中的数据库连接参数初始化。
  • MybatisSessionFactory初始化完成后,由于MybatisSessionFactory.update方法使用了@PostConstruct注解,会执行update方法,将SqlSessionFactory赋值给静态属性sqlSessionFactory。
  • 后续RuleFunction的setFields方法执行过程中,就可以使用MybatisSessionFactory的query方法查询数据库了

总结

这次改造过程,对类加载过程、对象的实例化、static关键字、spring bean的生命周期有了更深入的理解。

  • 类加载过程,会初始化调用static修饰的属性、方法、代码块

    • 类加载过程[2]:加载、链接、初始化
    • 其中链接的过程:验证、准备、解析
  • 类初始化后,可以通过new关键字实例化一个对象,其它方式:通过反射api实例化
  • spring bean的生命周期[3]:实例化、属性赋值、初始化、销毁

扩展

对于这个问题抽象一下:Spring项目中,如果需要在一个类初始化时加载数据库资源,可以有哪些方式?

参考

到此这篇关于记一次Maven项目改造成SpringBoot项目的过程实践的文章就介绍到这了,更多相关Maven改造成SpringBoot项目内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • springboot+maven快速构建项目的示例代码

    最近公司运用springboot构建项目,确实比ssh搭建要快很多. 1.首先要下载maven,用maven管理项目很方便,下载完maven配置好环境,maven我就不细说了. 2.创建一个maven项目,pom.xml文件里面写这些: <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:sche

  • SpringBoot+Maven 多模块项目的构建、运行、打包实战

    本篇文章主要介绍了SpringBoot+Maven 多模块项目的构建.运行.打包,分享给大家,具体如下: 项目使用的工具: IntelliJ IDEA JDK 1.8 apache-maven-3.3.9 项目的目录: 主项目 springboot-multi 子模块 entity.dao.service.web 一.使用IDEA创建一个SpringBoot项目 : File -> new -> Project 项目名称为springboot-multi 二.删除项目中的src目录,把pom.

  • IDEA创建SpringBoot的maven项目的方法步骤

    记录IDEA编程工具创建SpringBoot的maven项目过程: 新建项目 选择maven项目及JDK,点击下一步: 选择好项目路径,输入项目名称,点击完成就可以啦: 创建完成效果: 配置pom.xml文件 新建项目需要引入springboot的依赖,这里选择2.4.4版本. 完整pom文件如下: <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.ap

  • Maven搭建springboot项目的方法步骤

    Maven搭建springboot项目 本文是基于Windows 10系统环境,使用Maven搭建springboot项目 Windows 10 apache-maven-3.6.0 IntelliJ IDEA 2018.3.4 x64 一.springboot项目搭建 (1) 新建目录 在某个可用目录下,新建一个文件夹,本文新建目录为 D:\demo\zs200 (2) 创建maven父工程zs200a-parent 填写项目maven坐标 填写项目名称和路径 (2) maven父工程zs20

  • SpringBoot使用Maven插件进行项目打包的方法

    SpringBoot自带Tomcat,所以我们的项目可以单独部署,不需要依赖Window.Linux系统中的服务器,所以打包出来的Jar包是可以直接运行的.Windows中直接cmd命令行模式下,cd切换到jar路径中,使用java 命令运行jart包,Linux环境也是一样的命令,如下图: 现在我们开始打包,我介绍两种方式,不管那种方式首先先在项目Pom.xml文件中引入Maven插件. <build> <plugins> <!-- 设置jdk版本为1.8 --> &

  • SpringBoot创建maven多模块项目实战代码

    工作中一直都是一个人奋战一人一个项目,使用maven管理,看这个也挺好,但是总感觉没有充分发挥maven的功能,于是研究了一下这个,网上关于这个的文章很多,虽然不是很好,但我从中收获了很多,在这集百家所长,写一份实战记录,大家跟着我一块做吧! 声明:构建多模块不是最难的,难点是如果把多模块打包成一个执行jar. SpringBoot官方推崇的是富jar,也就是jar文件启动项目,所以如果在这里打war包我不具体介绍,如果需要的朋友可以给我留言,我回复. 建议clone项目后,在看教程(有不足的地

  • 在SpringBoot项目中利用maven的generate插件

    使用maven 插件 generate生成MyBatis相关文件 在项目中增加 maven 依赖 - mybatis-spring-boot-starter - mysql-connector-java - mybatis-generator-maven-plugin 插件 自动读取 resources 下的generatorConfig.xml 文件 <?xml version="1.0" encoding="UTF-8"?> <project

  • 使用maven开发springboot项目时pom.xml常用配置(推荐)

    如题,记录一些平常开发用的pom文件细节 1.使用parent父类引用,解决依赖版本号不确定时自动匹配的问题 <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.7.RELEASE</version> <relativePath/>

  • springboot maven 项目打包jar 最后名称自定义的教程

    maven 文件打包,输入 :package -Dmaven.test.skip=true 进行打包, 一般生成的jar 文件 名称是项目名+版本号这样的 如何在pom.xml 中加入finalname 属性,就可以获得稳定的jar 名称 <build> <finalName>pay</finalName> <plugins> <plugin> <groupId>org.springframework.boot</groupId

  • 记一次Maven项目改造成SpringBoot项目的过程实践

    目录 背景概述 过程 加依赖 修改main方法所在类 引入数据库依赖 启动类上加入mapper扫描 添加application.yml sqlSessionFactory空指针异常分析 改造MybatisSessionFactory类 改造前的执行流程 改造后的执行流程 总结 扩展 参考 背景概述 团队有一个项目,是maven构建的普通Java项目. 项目没有使用spring,用到了mysql.mybatis,还有其他大数据技术,比如flink.pulsar. 项目里连接数据库的部分,需要用到多

  • 如何把springboot jar项目 改为war项目

    这篇文章主要介绍了如何把springboot jar项目 改为war项目,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 启动类JeewxBootApplication 添加继承SpringBootServletInitializer 重写实现 @SpringBootApplication public class JeewxBootApplication extends SpringBootServletInitializer { public

  • SpringBoot项目改为SpringCloud项目使用nacos作为注册中心的方法

    本章讲解的是在不改变原有业务的情况下将springboot改为springcloud项目使用nacos作为注册中心 首先在官网下载好nacos注册中心,在bin目录中startup.cmd文件为启动命令默认端口号是8888 接下来修改原有项目依赖 在父依赖模块添加springcloud依赖版本,若没有父依赖直接在项目指定也一样 首先指定版本 <properties> <cloud.version>Hoxton.RELEASE</cloud.version> <al

  • Jenkins自动部署SpringBoot项目实践教程

    目录 1.Jenkins安装 2.Jenkins插件安装 3.点击添加凭据 4.Jenkins环境配置 4.1.全局配置 4.2.系统配置 5.Jenkins自动部署SpringBoot项目 6.遇到问题 7.用到的命令 1.Jenkins安装 下载jenkins安装包,maven安装包:打开xftp将安装包上传到服务器:弄maven镜像:进入maven的conf文件夹,vim打开setting.xml文件添加阿里云镜像:wq!保存退出. <!-- 阿里镜像仓库 --> <mirrors

  • eclipse启动一个Springboot项目

    目录 1.准备一个Springboot项目 2.配置好maven 3.导入Springboot项目 4.导入项目的maven依赖 5.安装Springboot环境 6.eclipse安装git插件 7.总结 8.参考资料 1.准备一个Springboot项目 2.配置好maven 注:本地的maven-repository默认路径是在系统盘的.m文件夹.如果想要修改可参考: eclipse修改maven仓库的位置 其实就是改一下maven-config中的setting.xml 3.导入Spri

  • SpringBoot项目运行jar包启动的步骤流程解析

    SpringBoot项目在开发中,方便快捷,有一点原因就是SpringBoot项目可以打jar包运行:把jar包直接扔服务器上,然后运行jar包就能访问项目接口了.下面介绍SpringBoot项目打jar包运行的步骤流程: 一.我们所熟悉的是在开发环境下,直接用开发工具来运行那个启动类,然后就能启动这个项目: 开发环境下启动项目 二. SpringBoot项目打jar包方法: [1]在cmd界面中,进入项目的本地存储地址 cmd命令下进入项目地址 [2]运行maven的打包命令,mvn clea

  • IDEA使用Gradle构建SpringBoot项目工程的详细教程

    背景 最近在研究搭建spring源码调试环境时,接触到到gradle项目构建工具.由于之前习惯于maven项目的构建,故通过此文记录相关gradle的项目构建知识. Gradle Gradle是一个构建工具,用于管理项目依赖和构建项目工程.Gradle抛弃了Maven的基于XML的繁琐配置,采用特定语言Groovy的配置,大大简化了构建代码的行数. 项目结构 Plugin Sample pluginManagement { repositories { gradlePluginPortal()

  • 如何创建SpringBoot项目

    1.SpringBoot介绍 SpringBoot本身就是为了简单.快速开发Spring框架项目而生的,在maven的基础上,对已有的maven gav进行了封装,他的问世对Java开发者的好处不言而喻, 他的好处胜金这里随便列举几条: 1.自动配置,无需xml配置,通过jar以来自动识别: 2.通过起步(Starter)依赖集成第三方库,开箱即用: 3.内嵌Servlet容器,无需war包部署: 4.内置健康检测.度量指标功能: 5.提供all-in-one打包插件. 优点太多,不再一一列举,

  • springboot项目整合druid数据库连接池的实现

    Druid连接池是阿里巴巴开源的数据库连接池项目,后来贡献给Apache开源: Druid的作用是负责分配.管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个: Druid连接池内置强大的监控功能,其中的StatFilter功能,能采集非常完备的连接池执行信息,方便进行监控,而监控特性不影响性能. Druid连接池内置了一个监控页面,提供了非常完备的监控信息,可以快速诊断系统的瓶颈. SpringBoot 1.x版本默认使用的的tomcat的jdbc连接池,由

  • Maven项目改为spring boot项目的方法图解

    目录树 •新建Maven项目及步骤 •修改方法 •启动测试 新建Maven项目及步骤 我这里是从创建开始讲,使用的工具是Idea2017版本.如果是已经创建了Maven,想改为spring boot项目的请直接跳到[修改方法] 1.点击右上角的File,出来的列表选择New Object: 2.选择Maven,勾选Create from archetype,选择quickstart 3.输入GroupId与ArtifactId,Version版本号自己看着怎么顺眼怎么改:其中GroupId为包名

随机推荐