Spring Boot整合ehcache的详细使用

一、简介

  Ehcache是一种广泛使用的纯Java的进程的开源Java分布式缓存,具有快速、精干等特点,主要面向通用缓存,Java EE和轻量级容器。Ehcache主要基于内存缓存,磁盘缓存为辅。Spring Boot 为我们自动配置了多个 CacheManager 的实现,本文主要还是整合ehcache。
在这里插入图片描述

二、Maven依赖

  因为文章太长,我这里就没有拷贝打包的配置,我这里的SpringBoot的版本是2.5.2,ehcache的版本是2.10.8,至于里面的我使用的druid版本不是我们这里关注的重点。
  打包可以查阅我另一篇:链接: Spring Boot项目常用打包配置.

pom.xml

	<dependency>
	    <groupId>org.springframework.boot</groupId>
	    <artifactId>spring-boot-starter</artifactId>
	    <version>2.5.2</version>
	</dependency>
	
	<dependency>
	    <groupId>org.springframework.boot</groupId>
	    <artifactId>spring-boot-starter-data-jpa</artifactId>
	    <version>2.5.2</version>
	</dependency>
	
	<dependency>
	    <groupId>org.springframework.boot</groupId>
	    <artifactId>spring-boot-starter-web</artifactId>
	    <version>2.5.2</version>
	</dependency>
	
	<dependency>
	    <groupId>org.springframework.boot</groupId>
	    <artifactId>spring-boot-starter-cache</artifactId>
	    <version>2.5.2</version>
	</dependency>

	<!--ehcache-->
	<dependency>
	    <groupId>net.sf.ehcache</groupId>
	    <artifactId>ehcache</artifactId>
	    <version>2.10.8</version>
	</dependency>
	
	<dependency>
	    <groupId>com.alibaba</groupId>
	    <artifactId>druid-spring-boot-starter</artifactId>
	    <version>1.2.6</version>
	</dependency>
	
	<!--mysql连接-->
	<dependency>
	    <groupId>mysql</groupId>
	    <artifactId>mysql-connector-java</artifactId>
	    <version>8.0.26</version>
	    <scope>runtime</scope>
	</dependency>
	
	<dependency>
	    <groupId>com.alibaba</groupId>
	    <artifactId>fastjson</artifactId>
	    <version>1.2.68 </version>
	</dependency>
	
	<!--日志输出-->
	<dependency>
	    <groupId>org.projectlombok</groupId>
	    <artifactId>lombok</artifactId>
	    <version>1.18.20</version>
	</dependency>

本次整合最关键的依赖是下面两个,其他的根据自己的项目需求配置。

	<dependency>
	    <groupId>org.springframework.boot</groupId>
	    <artifactId>spring-boot-starter-cache</artifactId>
	    <version>2.5.2</version>
	</dependency>

	<!--ehcache-->
	<dependency>
	    <groupId>net.sf.ehcache</groupId>
	    <artifactId>ehcache</artifactId>
	    <version>2.10.8</version>
	</dependency>

三、配置类(核心配置)

  我这里写了个配置类,主要是实现自定义缓存数据的key,演示它的用法,你们也可以不写,但是@EnableCaching不能少,如果没有此配置类,可以把注解@EnableCaching放到启动类上,@EnableCaching:表示开启缓存功能,具体的我代码里的注释都很清楚了,可以仔细查阅

3.1 EhcacheConfig

EhcacheConfig.java

package com.alian.ehcache.config;

import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.util.DigestUtils;

import java.nio.charset.StandardCharsets;

@Slf4j
@Configuration
@EnableCaching
public class EhcacheConfig extends CachingConfigurerSupport {

    /**
     * 自定义缓存数据 key 生成策略
     * target: 类
     * method: 方法
     * params: 参数
     *
     * @return KeyGenerator
     * 注意: 该方法只是声明了key的生成策略,还未被使用,需在@Cacheable注解中指定keyGenerator
     * 如: @Cacheable(value = "key", keyGenerator = "keyGenerator")
     */
    @Override
    @Primary
    @Bean
    public KeyGenerator keyGenerator() {
        //new了一个KeyGenerator对象,采用lambda表达式写法
        //类名+方法名+参数列表的类型+参数值,然后再做md5转16进制作为key
        //使用冒号(:)进行分割,可以很多显示出层级关系
        return (target, method, params) -> {
            StringBuilder strBuilder = new StringBuilder();
            strBuilder.append(target.getClass().getName());
            strBuilder.append(":");
            strBuilder.append(method.getName());
            for (Object obj : params) {
                if (obj != null) {
                    strBuilder.append(":");
                    strBuilder.append(obj.getClass().getName());
                    strBuilder.append(":");
                    strBuilder.append(JSON.toJSONString(obj));
                }
            }
            //log.info("ehcache key str: " + strBuilder.toString());
            String md5DigestAsHex = DigestUtils.md5DigestAsHex(strBuilder.toString().getBytes(StandardCharsets.UTF_8));
            log.info("ehcache key md5DigestAsHex: " + md5DigestAsHex);
            return md5DigestAsHex;
        };
    }

}

3.2 ehcache.xml

  我这里也认真整理了下ehcache的配置,详细的解释都在下面的xml里。我这里就简单提几个点。

  • defaultCache一定要配置一个
  • 如果是要持久化到磁盘,则可以配置diskStore,路径可以是系统的也可以是自定义的
  • eternal如果配置为true,则timeToIdleSeconds和timeToLiveSeconds不会生效
  • timeToLiveSeconds的值要比timeToIdleSeconds才有意义
  • maxElementsInMemory、diskSpoolBufferSizeMB、maxElementsOnDisk等配置需要根据自己服务器的资源合理配置
  • memoryStoreEvictionPolicy策略可以根据自己业务调整
<?xml version="1.0" encoding="UTF-8"?>
<ehcache updateCheck="false" name="defaultCache">

    <!--
       diskStore:为缓存路径,ehcache分为内存和磁盘两级,此属性定义磁盘的缓存位置,可以自定义目录,确保用户有权限即可。参数解释如下:
       user.home – 用户主目录
       user.dir  – 用户当前工作目录
       java.io.tmpdir – 默认临时文件路径
     -->
    <!--    <diskStore path="java.io.tmpdir"/> -->
    <diskStore path="C:/Users/admin/ehcache/"/>

    <!-- maxElementsInMemory:内存中最大缓存对象数,根据服务器资源配置 -->
    <!-- eternal: 默认为false,设置true表示对象永不过期,此时会忽略timeToIdleSeconds和timeToLiveSeconds属性, -->
    <!-- maxElementsOnDisk:硬盘中最大缓存对象数,若是0表示无穷大 -->
    <!-- overflowToDisk:true表示当内存缓存的对象数目达到了maxElementsInMemory界限后,会把溢出的对象写到硬盘缓存中。
    注意:如果缓存的对象要写入到硬盘中的话,则该对象必须实现了Serializable接口才行。-->
    <!-- diskSpoolBufferSizeMB:磁盘缓存区大小,默认为30MB。每个Cache都应该有自己的一个缓存区。-->
    <!-- diskPersistent:是否缓存虚拟机重启期数据  -->
    <!-- diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认为120秒 -->

    <!-- timeToIdleSeconds: 设定允许对象处于空闲状态的最长时间,单位(秒)。自对象最近一次被访问后,
    空闲时间超过了timeToIdleSeconds属性值,这个对象就会过期,如果该属性值为0,则对象无限期地处于空闲状态
    EHCache将把它从缓存中清空。只有当eternal属性为false,该属性才有效。
    -->

    <!-- timeToLiveSeconds:设定允许对象存在于缓存中的最长时间,单位(秒)。自对象被存放到缓存中后,
    在缓存中的时间超过了timeToLiveSeconds属性值,这个对象就会过期,如果该属性值为0,则对象无限期地存在于缓存中。
    EHCache将把它从缓存中清除。只有当eternal属性为false,该属性才有效。timeToLiveSeconds必须大于timeToIdleSeconds属性,才有意义 -->

    <!-- memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。
    可选策略有:LRU(最近最少使用,默认策略)、FIFO(先进先出)、LFU(最少访问次数)。-->

    <!-- 默认缓存 -->
    <defaultCache
            maxElementsInMemory="10000"
            eternal="false"
            overflowToDisk="false"
            diskSpoolBufferSizeMB="50"
            timeToIdleSeconds="300"
            timeToLiveSeconds="600"
            maxElementsOnDisk="10000000"
            diskExpiryThreadIntervalSeconds="120"
            memoryStoreEvictionPolicy="LRU">

        <persistence strategy="localTempSwap"/>
    </defaultCache>

    <cache name="employee_all"
           maxElementsInMemory="100"
           eternal="false"
           overflowToDisk="true"
           timeToIdleSeconds="300"
           timeToLiveSeconds="600"
           memoryStoreEvictionPolicy="LRU"/>

    <cache name="employee_info"
           maxElementsInMemory="1000"
           eternal="false"
           overflowToDisk="true"
           timeToIdleSeconds="300"
           timeToLiveSeconds="600"
           memoryStoreEvictionPolicy="LRU"/>

</ehcache>

四、服务层(核心使用)

  • @CacheConfig:声明在类上,指定本类上所有使用缓存的方法的缓存名称,如有注解@Cacheable的方法。
  • @Cacheable:使用@Cacheable注解的方法,Spring在每次执行前都会检查Cache中是否存在相同key的缓存元素,如果存在就不再执行该方法,而是直接从缓存中获取结果进行返回,如果存在则执行方法,并将返回结果存入指定的缓存中
  • @CachePut:使用@CachePut注解的方法,Spring在执行前不会去检查缓存中是否存在之前执行过的结果,而是每次都会执行该方法,并将执行结果以键值对的形式存入指定的缓存中
  • @CacheEvict:清除缓存,属性allEntries为true则删除所有缓存,属性beforeInvocation表示缓存的清除是在方法前执行还是方法后执行,默认是为false,方法执行后删除
  • @Caching:分组注解,可以包含多个@Cacheable@CachePut,一般在复杂业务的情况下使用

EmployeeService.java

package com.alian.ehcache.service;

import com.alian.ehcache.domain.TbInfEmployee;
import com.alian.ehcache.respository.EmployeeRespository;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import java.util.Optional;

/**
 * @CacheConfig 注解是声明本类所有方法的缓存名称,如果方法上设置了自己的名称则以方法上名称为准,
 * 比如类上设置了名称employee_info,方法上设置了employee_all,
 * 则最终的名称为employee_all,具体看本类的实例
 */
@CacheConfig(cacheNames = {"employee_info"})
@Slf4j
@Service
public class EmployeeService {

    @Autowired
    private EmployeeRespository employeeRespository;

    /**
     * 查询所有员工信息
     * <p>
     * 这里指定了缓存的名称:employee_all,则最终的缓存名称为employee_all
     * 我这里顺便也实现了自定义的key生成方法keyGenerator
     * <p>
     * cacheNames/value:二选一使用
     * key/keyGenerator:二选一使用
     */
    @Cacheable(cacheNames= "employee_all", keyGenerator = "keyGenerator")
    public Iterable<TbInfEmployee> findAll() {
        log.info("findAll查询数据库");
        return employeeRespository.findAll();
    }

    /**
     * 根据id查询员工信息(id长度为8才缓存)
     * <p>
     * key/keyGenerator:二选一使用
     * condition表示的是条件(为true才缓存)
     */
    @Cacheable(key = "#id", condition = "#id.length()==8")
    public TbInfEmployee findById(String id) {
        log.info("findById查询数据库");
        Optional<TbInfEmployee> optional = employeeRespository.findById(id);
        return optional.orElse(null);
    }

    /**
     * 更加id更新员工工资(员工工资大于0才缓存)
     *
     * @CachePut 缓存的是返回值,所以更新方法的返回值一定要注意
     * <p>
     * key/keyGenerator:二选一使用
     * condition表示的是条件(为true才缓存)
     */
    @CachePut(key = "#id", condition = "#salary>0")
    public TbInfEmployee updateSalaryById(String id, double salary) {
        log.info("updateSalaryById查询数据库");
        Optional<TbInfEmployee> optional = employeeRespository.findById(id);
        if (!optional.isPresent()) {
            return null;
        }
        TbInfEmployee employee = optional.get();
        employee.setSalary(salary);
        employeeRespository.save(employee);
        return employee;
    }

    /**
     * 更加id删除员工
     *
     * @CacheEvict Spring会在调用该方法之前清除缓存中的指定元素
     * allEntries : 为true表示清除value空间名里的所有的数据,默认为false
     * beforeInvocation 缓存的清除是在方法前执行还是方法后执行,默认是为false,方法执行后删除
     * beforeInvocation = false : 方法执行后删除,如果出现异常缓存就不会清除
     * beforeInvocation = true : 方法执行前删除,无论方法是否出现异常,缓存都清除
     */
    @CacheEvict(key = "#id", beforeInvocation = true)
    public boolean deleteById(String id) {
        log.info("deleteById查询数据库");
        try {
//            employeeRespository.deleteById(id);
            log.info("删除成功");
            return true;
        } catch (Exception e) {
            return false;
        }
    }
}

  在这里@CacheConfig(cacheNames = {“employee_info”})或者@Cacheable(cacheNames= “employee_all”, keyGenerator = “keyGenerator”),这里的cacheNames属性值,实际相对一个命名空间,比如在磁盘里就是文件名,key或者keyGenerator实际相当于缓存的key,存在内存或者文件的一个唯一值,所以大家要确保唯一,否则可能导致获取缓存错误。
  @Cacheable或者@CachePut都是将执行结果缓存,像更新语句返回的是影响的行数,比如1,比如你有A方法返回的是个boolean,又想用到缓存,你可以写一个B方法,加上缓存注解,然后用A方法调用B方法则可。

五、实体、持久层、控制层

  这个大家都懂,就不过多解释,也没有详细的做业务逻辑判断,我们的目的还是ehcache的使用。

5.1 实体

TbInfEmployee.java

package com.alian.ehcache.domain;

import lombok.Data;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import java.io.Serializable;
import java.time.LocalDate;
import java.util.Objects;

@Data
@Entity
@Table(name = "tb_inf_employee")
public class TbInfEmployee implements Serializable {

    private static final long serialVersionUID = 1L;

    /**
     * 员工编号
     */
    @Id
    @Column(name = "id")
    private String id = "";

    /**
     * 员工姓名(数据库规范,数据库字段不要命名为name)
     */
    @Column(name = "emp_name")
    private String name = "";

    /**
     * 员工年龄
     */
    @Column(name = "age")
    private int age;

    /**
     * 工资
     */
    @Column(name = "salary")
    private double salary = 0.00;

    /**
     * 部门
     */
    @Column(name = "department")
    private String department = "";

    /**
     * 入职时间
     */
    @Column(name = "hire_date")
    private LocalDate hireDate = LocalDate.of(1970, 1, 1);

    /**
     * 注意:被序列化对象应提供一个无参的构造函数,否则会抛出异常
     */
    public TbInfEmployee() {

    }

}

5.2 持久层

EmployeeRespository.java

package com.alian.ehcache.respository;

import com.alian.ehcache.domain.TbInfEmployee;
import org.springframework.data.repository.PagingAndSortingRepository;

public interface EmployeeRespository extends PagingAndSortingRepository<TbInfEmployee, String> {

}

5.3 控制层

EmployeeController.java

package com.alian.ehcache.controller;

import com.alian.ehcache.domain.TbInfEmployee;
import com.alian.ehcache.service.EmployeeService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;

@Slf4j
@RestController
@RequestMapping("/employee")
public class EmployeeController {

    @Autowired
    private EmployeeService employeeService;

    @ResponseBody
    @RequestMapping(value = "findAll")
    public Iterable<TbInfEmployee> findAll(HttpServletRequest request) {
        log.info("findAll请求时间:{}", LocalDateTime.now());
        Iterable<TbInfEmployee> employees = employeeService.findAll();
        log.info("findAll返回结果:{}", employees);
        log.info("findAll返回时间:{}", LocalDateTime.now());
        return employees;
    }

    @ResponseBody
    @RequestMapping(value = "findById")
    public TbInfEmployee findById(HttpServletRequest request) {
        log.info("findById请求时间:{}", LocalDateTime.now());
        String id = request.getParameter("id");
        TbInfEmployee employee = employeeService.findById(id);
        log.info("findById返回结果:{}", employee);
        log.info("findById返回时间:{}", LocalDateTime.now());
        return employee;
    }

    @ResponseBody
    @RequestMapping(value = "updateSalaryById")
    public TbInfEmployee updateSalaryById(HttpServletRequest request) {
        log.info("updateSalaryById请求时间:{}", LocalDateTime.now());
        String id = request.getParameter("id");
        String salaryStr = request.getParameter("salary");
        double salary = Double.parseDouble(salaryStr);
        TbInfEmployee employee = employeeService.updateSalaryById(id, salary);
        log.info("updateSalaryById返回结果:{}", employee);
        log.info("updateSalaryById返回时间:{}", LocalDateTime.now());
        return employee;
    }

    @ResponseBody
    @RequestMapping(value = "deleteById")
    public boolean deleteById(HttpServletRequest request) {
        log.info("deleteById请求时间:{}", LocalDateTime.now());
        String id = request.getParameter("id");
        boolean b = employeeService.deleteById(id);
        log.info("deleteById返回时间:{}", LocalDateTime.now());
        return b;
    }
}

六、配置文件

application.yml

server:
  port: 8081
  servlet:
    context-path: /ehcache

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    type: com.alibaba.druid.pool.DruidDataSource
    username: test
    password: Test!@34
    url: jdbc:mysql://192.168.0.139:3306/test?characterEncoding=utf8&useUnicode=true&useSSL=false&zeroDateTimeBehavior=convertToNull&autoReconnect=true&allowMultiQueries=true&failOverReadOnly=false&connectTimeout=6000&maxReconnects=5
    initialSize: 5
    minIdle: 5
    maxActive: 20
  cache:
    type: ehcache
    ehcache:
      config: classpath:config/ehcache.xml

七、效果

7.1 请求方法

A:查询所有员工
http://localhost:8081/ehcache/employee/findAll
B:根据员工id查询员工信息
http://localhost:8081/ehcache/employee/findById?id=BAT10003
C:根据员工id更新员工工资
http://localhost:8081/ehcache/employee/updateSalaryById?id=BAT10002&salary=12000.0
D:根据员工id删除员工
http://localhost:8081/ehcache/employee/deleteById?id=BAT10002

7.2 系统启动后

  系统启动后,我们去我们设定的磁盘目录看到生成了三个文件,其中两个文件就是我们配置的缓存的名称。
在这里插入图片描述

7.2 请求A接口两次

  从上面的代码知道我们如果查询了数据,也就是执行了我们的方法,则会打印一行日志。我们先连续请求两次A接口看下效果。下面的结果先记住这个自动缓存的key(我们配置类的keyGenerator方法生成):95727e51954dc63aee9aa97e63a48f01

2021-08-31 15:09:51 506 [http-nio-8081-exec-1] INFO findAll 25:findAll请求时间:2021-08-31T15:09:51.506
2021-08-31 15:09:51 509 [http-nio-8081-exec-1] INFO lambda$keyGenerator$0 52:ehcache key md5DigestAsHex: 95727e51954dc63aee9aa97e63a48f01
2021-08-31 15:09:51 510 [http-nio-8081-exec-1] INFO lambda$keyGenerator$0 52:ehcache key md5DigestAsHex: 95727e51954dc63aee9aa97e63a48f01
2021-08-31 15:09:51 514 [http-nio-8081-exec-1] INFO findAll 39:findAll查询数据库
2021-08-31 15:09:51 827 [http-nio-8081-exec-1] INFO findAll 27:findAll返回结果:[TbInfEmployee(id=BAT10001, name=梁南生, age=27, salary=7000.0, department=研发部, hireDate=2019-07-01), TbInfEmployee(id=BAT10002, name=唐鹏, age=31, salary=25000.0, department=研发部, hireDate=2015-03-01), TbInfEmployee(id=BAT10003, name=王林, age=30, salary=22000.0, department=研发部, hireDate=2015-08-01), TbInfEmployee(id=BAT10004, name=罗考聪, age=35, salary=7000.0, department=测试部, hireDate=2016-11-20), TbInfEmployee(id=BAT10005, name=包雅馨, age=25, salary=7000.0, department=财务部, hireDate=2018-07-01), TbInfEmployee(id=BAT10006, name=朱健儿, age=26, salary=8000.0, department=人事部, hireDate=2019-01-01)]
2021-08-31 15:09:51 828 [http-nio-8081-exec-1] INFO findAll 28:findAll返回时间:2021-08-31T15:09:51.828

2021-08-31 15:10:06 439 [http-nio-8081-exec-2] INFO findAll 25:findAll请求时间:2021-08-31T15:10:06.439
2021-08-31 15:10:06 439 [http-nio-8081-exec-2] INFO lambda$keyGenerator$0 52:ehcache key md5DigestAsHex: 95727e51954dc63aee9aa97e63a48f01
2021-08-31 15:10:06 440 [http-nio-8081-exec-2] INFO findAll 27:findAll返回结果:[TbInfEmployee(id=BAT10001, name=梁南生, age=27, salary=7000.0, department=研发部, hireDate=2019-07-01), TbInfEmployee(id=BAT10002, name=唐鹏, age=31, salary=25000.0, department=研发部, hireDate=2015-03-01), TbInfEmployee(id=BAT10003, name=王林, age=30, salary=22000.0, department=研发部, hireDate=2015-08-01), TbInfEmployee(id=BAT10004, name=罗考聪, age=35, salary=7000.0, department=测试部, hireDate=2016-11-20), TbInfEmployee(id=BAT10005, name=包雅馨, age=25, salary=7000.0, department=财务部, hireDate=2018-07-01), TbInfEmployee(id=BAT10006, name=朱健儿, age=26, salary=8000.0, department=人事部, hireDate=2019-01-01)]
2021-08-31 15:10:06 440 [http-nio-8081-exec-2] INFO findAll 28:findAll返回时间:2021-08-31T15:10:06.440

7.3 不同参数请求B接口多次

  我们继续根据不同的参数请求B方法,结果和上面差不多,第一次都是查数据库,后面都没有查数据库,都是从缓存获取的,我们最终看下磁盘的文件
在这里插入图片描述
  我们发现文件有了大小了,实际上第一个文件employee_all.data,也有内容只是里面的内容不足1kb,我们用记事本打开看看,看到了我们一个熟悉的key95727e51954dc63aee9aa97e63a48f01,实际上打开另外一个文件也能看到我们其他方法定义的key。
在这里插入图片描述

八、部署路径(linux部署)

  其实从上面的结果我们也知道,我们SpringBoot已经完成了ehcache的整合。为啥还要来这个部署路径?从上面我们也知道ehcache.xml的路径是:classpath:config/ehcache.xml,在本地怎么改动配置文件都可以跑,把项目部署到linux,你可能会遇到配置不生效,或者是找不到配置文件的情况。下面几种方法可以帮到你。

8.1 配置文件打包到jar

在这里插入图片描述
  这样打包怎么都能用,唯一不好的就是如果要改缓存的时间或者策略,我们需要重新打包,并且实际中,我们都会把配置和jar分开,放到和jar同级目录的config下,那就看第二种办法。

8.2 打包增加classpath

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-jar-plugin</artifactId>
    <version>3.2.0</version>
    <configuration>
        <archive>
            <!-- 为true时生成的jar中,包含pom.xml和pom.properties这两个文件 -->
            <addMavenDescriptor>false</addMavenDescriptor>
            <!-- 生成MANIFEST.MF的设置,用的是spring boot打包可以不配置manifest -->
            <manifest></manifest>
            <manifestEntries>
                <!-- 在Class-Path下添加配置文件的路径,一般是引入外部配置文件,或者是没有把配置文件打到jar包里,
                     配置的路径是相对你所要运行的jar所在的目录如:比如我的jar同级目录有个config放了资源文件ehcache.xml
                     你配置的是"./",则你配置的路径为classpath:config/ehcache.xml
                     配置的是"./config",则你配置的路径为classpath:ehcache.xml
                     可以配置多个,用空格隔开就行-->
                <Class-Path>./</Class-Path>
            </manifestEntries>
        </archive>
        <!--排除配置的资源文件,具体的你可以根据自己的项目修改,“**/”表示任意目录下的某个(某些)文件-->
        <excludes>
            <exclude>**/application.yml</exclude>
            <exclude>**/logback.xml</exclude>
<!--                        <exclude>config</exclude>
            <exclude>config/ehcache.xml</exclude>-->
        </excludes>
    </configuration>
</plugin>

  这里关键在用:<Class-Path>./</Class-Path>,如果你是其他路径,可以看我的注释。也可以查阅我另一篇:链接: Spring Boot项目常用打包配置.

8.3 执行命令增加-Dloader.path

  假设你的项目打包结果为ehcache.jar,存放所有配置文件包括ehcache.xml都存放在目录config下,ehcache.jar和config在/opt目录下,你的脚本则为:

cd /opt/
java -Dloader.path=/opt/ -jar ehcache.jar config/application.yml

以上三种办法都可以实现你的部署,但是我推荐你使用第二种方式。

  • 8
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值