java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Maven改造成SpringBoot项目

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

作者:白云漂

本文主要介绍了Maven项目改造成SpringBoot项目的过程实践,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

背景概述

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

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

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

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

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

此外也是一次技术提升的机会,技术的优势,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;
}

RuleFunction类改造

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

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

改造前的执行流程

改造后的执行流程

总结

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

扩展

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

参考

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

您可能感兴趣的文章:
阅读全文