37. Spring Boot集成EHCache实现缓存机制【从零开始学Spring Boot】

来源:互联网 发布:张予曦淘宝店换人了? 编辑:程序博客网 时间:2024/05/04 23:53

【本文章是否对你有用以及是否有好的建议,请留言】

写后感:博主写这么一系列文章也不容易啊,请评论支持下。

       如果看过我之前(35)的文章这一篇的文章就会很简单,没有什么挑战性了。

       那么我们先说说这一篇文章我们都会学到的技术点:Spring Data JPA,SpringBoot使用Mysql,Spring MVC,EHCache,Spring Cache等(其中@Cacheable请看上一节的理论知识),具体分如下几个步骤:

(1)新建Maven Java Project

(2)在pom.xml中加入依赖包

(3)编写Spring Boot启动类;

(4)配置application.properties;

(5)编写缓存配置类以及ehcache.xml配置文件;

(6)编写DemoInfo实体类进行测试;

(7)编写持久类DemoInfoRepository;

(8)编写处理类DemoInfoService;

(9)编写DemoInfoController测试类;

(10)运行测试;

 

以上就是具体的步骤了,那么接下来我们一起按照这个步骤来进行实现吧。

 

(1)新建Maven Java Project

       新建一个工程名为spring-boot-ehcache的maven java project。

 

(2)在pom.xml中加入依赖包

       在pom.xml文件中加入相应的依赖包,SpringBoot父节点依赖包;spring boot web支持;缓存依赖spring-context-support;集成ehcache需要的依赖;JPA操作数据库;mysql 数据库驱动,具体pom.xml文件:

<projectxmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

       xsi:schemaLocation="http://maven.apache.org/POM/4.0.0http://maven.apache.org/xsd/maven-4.0.0.xsd">

       <modelVersion>4.0.0</modelVersion>

 

       <groupId>com.kfit</groupId>

       <artifactId>spring-boot-ehcache</artifactId>

       <version>0.0.1-SNAPSHOT</version>

       <packaging>jar</packaging>

 

       <name>spring-boot-ehcache</name>

       <url>http://maven.apache.org</url>

 

       <properties>

              <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

 

              <!-- 配置JDK编译版本. -->

              <java.version>1.8</java.version>

       </properties>

 

 

       <!-- springboot 父节点依赖,

             引入这个之后相关的引入就不需要添加version配置,

               spring boot会自动选择最合适的版本进行添加。

       -->

       <parent>

              <groupId>org.springframework.boot</groupId>

              <artifactId>spring-boot-starter-parent</artifactId>

              <version>1.3.3.RELEASE</version>

       </parent>

 

       <dependencies>

              <!-- 单元测试. -->

              <dependency>

                     <groupId>junit</groupId>

                     <artifactId>junit</artifactId>

                     <scope>test</scope>

              </dependency>

 

              <!-- springboot web支持:mvc,aop... -->

              <dependency>

                     <groupId>org.springframework.boot</groupId>

                     <artifactId>spring-boot-starter-web</artifactId>

              </dependency>

             

              <!--

                    包含支持UI模版(Velocity,FreeMarker,JasperReports),

                    邮件服务,

                    脚本服务(JRuby)

                    缓存Cache(EHCache),

                    任务计划Schedulinguartz)。

               -->

              <dependency>

             <groupId>org.springframework</groupId>

             <artifactId>spring-context-support</artifactId>

           </dependency>

 

              <!-- 集成ehcache需要的依赖-->

              <dependency>

                     <groupId>net.sf.ehcache</groupId>

                     <artifactId>ehcache</artifactId>

              </dependency>

             

              <!-- JPA操作数据库. -->

              <dependency>

             <groupId>org.springframework.boot</groupId>

             <artifactId>spring-boot-starter-data-jpa</artifactId>

           </dependency>

             

              <!-- mysql数据库驱动. -->

              <dependency>

             <groupId>mysql</groupId>

             <artifactId>mysql-connector-java</artifactId>

           </dependency>

          

           <!-- Spring boot单元测试. -->

              <dependency>

            <groupId>org.springframework.boot</groupId>

            <artifactId>spring-boot-starter-test</artifactId>

           <scope>test</scope>

        </dependency>

       </dependencies>

</project>

 

 

(3)编写Spring Boot启动类(com.kfit.App.java);

package com.kfit;

 

importorg.springframework.boot.SpringApplication;

importorg.springframework.boot.autoconfigure.SpringBootApplication;

 

/**

 *

 *

 *@SpringBootApplication申明让spring boot自动给程序进行必要的配置,

 *

@SpringBootApplication

等待于:

@Configuration

@EnableAutoConfiguration

@ComponentScan

 *

 *@author Angel(QQ:412887952)

 *@version v.0.1

 */

@SpringBootApplication

publicclass App {

       publicstatic void main(String[]args) {

              SpringApplication.run(App.class,args);

       }

}

 

 

(4)配置application.properties;

       在application.properties中主要配置数据库连接和JPA的基本配置,具体如下:

Src/main/resouces/application.properties

########################################################

###datasource ,mysql数据库连接配置

########################################################

spring.datasource.url=jdbc:mysql://localhost:3306/test

spring.datasource.username= root

spring.datasource.password= root

spring.datasource.driverClassName=com.mysql.jdbc.Driver

spring.datasource.max-active=20

spring.datasource.max-idle=8

spring.datasource.min-idle=8

spring.datasource.initial-size=10

 

 

 

########################################################

### Java Persistence Api,JPA自动建表操作配置

########################################################

# Specify the DBMS

spring.jpa.database= MYSQL

# Show or not log for each sqlquery

spring.jpa.show-sql= true

# Hibernate ddl auto (create,create-drop, update)

spring.jpa.hibernate.ddl-auto= update

# Naming strategy

spring.jpa.hibernate.naming-strategy=org.hibernate.cfg.ImprovedNamingStrategy

# stripped before adding them tothe entity manager)

spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect

 

 

(5)编写缓存配置类以及ehcache.xml配置文件:

       这个类主要是注册缓存管理对象EhCacheCacheManager、缓存工厂对象EhCacheManagerFactoryBean,具体代码如下:

EhCacheManagerFactoryBean

package com.kfit.config;

 

importorg.springframework.cache.annotation.EnableCaching;

import org.springframework.cache.ehcache.EhCacheCacheManager;

importorg.springframework.cache.ehcache.EhCacheManagerFactoryBean;

importorg.springframework.context.annotation.Bean;

importorg.springframework.context.annotation.Configuration;

importorg.springframework.core.io.ClassPathResource;

 

/**

 *缓存配置.

 *@author Angel(QQ:412887952)

 *@version v.0.1

 */

@Configuration

@EnableCaching//标注启动缓存.

publicclass CacheConfiguration {

      

       /**

        * ehcache主要的管理器

        *@param bean

        *@return

        */

       @Bean

       publicEhCacheCacheManager ehCacheCacheManager(EhCacheManagerFactoryBeanbean){

              System.out.println("CacheConfiguration.ehCacheCacheManager()");

              returnnewEhCacheCacheManager(bean.getObject());

       }

      

       /*

          *据shared与否的设置,

          * Spring分别通过CacheManager.create()

          *或new CacheManager()方式来创建一个ehcache基地.

          *

          *也说是说通过这个来设置cache的基地是这里的Spring独用,还是跟别的(如hibernateEhcache共享)

          *

          */

         @Bean

         public EhCacheManagerFactoryBean ehCacheManagerFactoryBean(){

           System.out.println("CacheConfiguration.ehCacheManagerFactoryBean()");

              EhCacheManagerFactoryBeancacheManagerFactoryBean =newEhCacheManagerFactoryBean ();

           cacheManagerFactoryBean.setConfigLocation (newClassPathResource("conf/ehcache.xml"));

           cacheManagerFactoryBean.setShared(true);

           returncacheManagerFactoryBean;

         }

      

}

 

在src/main/resouces/conf下编写ehcache.xml配置文件,当然这个文件你可以放在其它目录下:

<?xmlversion="1.0"encoding="UTF-8"?>

<ehcachexmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

       xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"

       updateCheck="false">

      

      

       <!--

       diskStore:为缓存路径,ehcache分为内存和磁盘两级,此属性定义磁盘的缓存位置。参数解释如下:

              user.home–用户主目录

              user.dir  –用户当前工作目录

              java.io.tmpdir–默认临时文件路径

             

        -->

       <diskStore path="java.io.tmpdir/Tmp_EhCache"/>

      

       <!--

              defaultCache: 默认缓存策略,当ehcache找不到定义的缓存时,则使用这个缓存策略。只能定义一个。

        -->

        

        <!--

              name:缓存名称。

              maxElementsInMemory:缓存最大数目

              maxElementsOnDisk:硬盘最大缓存个数。 

              eternal:对象是否永久有效,一但设置了,timeout将不起作用。 

              overflowToDisk:是否保存到磁盘,当系统当机时

              timeToIdleSeconds:设置对象在失效前的允许闲置时间(单位:秒)。仅当eternal=false对象不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大。

              timeToLiveSeconds:设置对象在失效前允许存活时间(单位:秒)。最大时间介于创建时间和失效时间之间。仅当eternal=false对象不是永久有效时使用,默认是0.,也就是对象存活时间无穷大。

              diskPersistent:是否缓存虚拟机重启期数据Whether the disk store persists between restarts of the Virtual Machine. Thedefault value is false. 

              diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区。 

              diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒。

              memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。默认策略是LRU(最近最少使用)。你可以设置为FIFO(先进先出)或是LFU(较少使用)。 

        clearOnFlush:内存数量最大时是否清除。

         memoryStoreEvictionPolicy:可选策略有:LRU(最近最少使用,默认策略)、FIFO(先进先出)、LFU(最少访问次数)。

              FIFO,first in firstout,这个是大家最熟的,先进先出。

              LFU, Less FrequentlyUsed,就是上面例子中使用的策略,直白一点就是讲一直以来最少被使用的。如上面所讲,缓存的元素有一个hit属性,hit值最小的将会被清出缓存。

              LRU,Least RecentlyUsed,最近最少使用的,缓存的元素有一个时间戳,当缓存容量满了,而又需要腾出地方来缓存新的元素的时候,那么现有缓存元素中时间戳离当前时间最远的元素将被清出缓存。

       -->

       <defaultCache

              eternal="false"

              maxElementsInMemory="1000"

              overflowToDisk="false"

              diskPersistent="false"

              timeToIdleSeconds="0"

              timeToLiveSeconds="600"

              memoryStoreEvictionPolicy="LRU"/>

 

       <cache

              name="demo"  

              eternal="false"

              maxElementsInMemory="100"

              overflowToDisk="false"

              diskPersistent="false"

              timeToIdleSeconds="0"

              timeToLiveSeconds="300"

              memoryStoreEvictionPolicy="LRU"/>

             

</ehcache>

 

(6)编写DemoInfo实体类进行测试;

在com.kfit.bean下编写DemoInfo实体类进行缓存测试:

package com.kfit.bean;

 

import javax.persistence.Entity;

import javax.persistence.GeneratedValue;

import javax.persistence.Id;

 

/**

 *测试实体类.

 *@author Angel(QQ:412887952)

 *@version v.0.1

 */

@Entity

publicclass DemoInfo {

       @Id @GeneratedValue

       privatelong id;//主键.

       private Stringname;//名称;

       private Stringpwd;//密码;

       privateint state;

       publiclong getId() {

              returnid;

       }

       publicvoid setId(longid) {

              this.id =id;

       }

       public String getName(){

              returnname;

       }

       publicvoid setName(String name) {

              this.name =name;

       }

       public String getPwd(){

              returnpwd;

       }

       publicvoid setPwd(String pwd) {

              this.pwd =pwd;

       }

       publicint getState() {

              returnstate;

       }

       publicvoid setState(intstate) {

              this.state =state;

       }

       @Override

       public StringtoString() {

              return"DemoInfo[id=" + id +", name=" + name +", pwd=" + pwd +", state=" + state +"]";

       }

}

 

(7)编写持久类DemoInfoRepository;

       编写持久类DemoInfoRepository

com.kfit.repository.DemoInfoRepository:

package com.kfit.repository;

 

importorg.springframework.data.repository.CrudRepository;

 

import com.kfit.bean.DemoInfo;

 

/**

 *操作数据库.

 *@author Angel(QQ:412887952)

 *@version v.0.1

 */

publicinterfaceDemoInfoRepository extends CrudRepository<DemoInfo,Long>{

 

}

 

(8)编写处理类DemoInfoService;

       编写增删改查的方法,在这几个方法中都使用注解缓存,进行缓存的创建以及删除,修改等操作:

 com.kfit.service.DemoInfoService

package com.kfit.service;

 

import com.kfit.bean.DemoInfo;

 

import javassist.NotFoundException;

 

publicinterface DemoInfoService{

 

       void delete(Longid);

 

       DemoInfoupdate(DemoInfoupdated) throws NotFoundException;

 

       DemoInfofindById(Long id);

 

       DemoInfosave(DemoInfo demoInfo);

 

}

 

com.kfit.service.impl.DemoInfoServiceImpl:

package com.kfit.service.impl;

 

import javax.annotation.Resource;

 

importorg.springframework.cache.annotation.CacheEvict;

importorg.springframework.cache.annotation.CachePut;

importorg.springframework.cache.annotation.Cacheable;

importorg.springframework.stereotype.Service;

 

import com.kfit.bean.DemoInfo;

import com.kfit.repository.DemoInfoRepository;

import com.kfit.service.DemoInfoService;

 

import javassist.NotFoundException;

 

@Service

publicclass DemoInfoServiceImpl implements DemoInfoService{

      

       //这里的单引号不能少,否则会报错,被识别是一个对象;

       publicstatic final StringCACHE_KEY = "'demoInfo'";

  

        @Resource

        private DemoInfoRepositorydemoInfoRepository;

      

       /**

        * value属性表示使用哪个缓存策略,缓存策略在ehcache.xml

       */

       publicstatic final StringDEMO_CACHE_NAME = "demo";

      

       /**

        *保存数据.

        *@param demoInfo

        */

       @CacheEvict(value=DEMO_CACHE_NAME,key=CACHE_KEY)

       @Override

       public DemoInfosave(DemoInfodemoInfo){

              returndemoInfoRepository.save(demoInfo);

       }

      

       /**

        *查询数据.

        *@param id

        *@return

        */

       @Cacheable(value=DEMO_CACHE_NAME,key="'demoInfo_'+#id")

       @Override

       public DemoInfofindById(Longid){

              System.err.println("没有走缓存!"+id);

              returndemoInfoRepository.findOne(id);

       }

      

       /**

        * http://www.mincoder.com/article/2096.shtml:

        *

        *修改数据.

        *

        *在支持Spring Cache的环境下,对于使用@Cacheable标注的方法,Spring在每次执行前都会检查Cache中是否存在相同key的缓存元素,如果存在就不再执行该方法,而是直接从缓存中获取结果进行返回,否则才会执行并将返回结果存入指定的缓存中。@CachePut也可以声明一个方法支持缓存功能。与@Cacheable不同的是使用@CachePut标注的方法在执行前不会去检查缓存中是否存在之前执行过的结果,而是每次都会执行该方法,并将执行结果以键值对的形式存入指定的缓存中。

 

      @CachePut也可以标注在类上和方法上。使用@CachePut时我们可以指定的属性跟@Cacheable是一样的。

        *

        *@param updated

        *@return

        *

        *@throws NotFoundException

        */

       @CachePut(value = DEMO_CACHE_NAME,key ="'demoInfo_'+#updated.getId()")

       //@CacheEvict(value= DEMO_CACHE_NAME,key = "'demoInfo_'+#updated.getId()")//这是清除缓存.

       @Override

       public DemoInfoupdate(DemoInfoupdated) throws NotFoundException{

              DemoInfodemoInfo =demoInfoRepository.findOne(updated.getId());

              if(demoInfo ==null){

                     throw newNotFoundException("No find");

              }

              demoInfo.setName(updated.getName());

              demoInfo.setPwd(updated.getPwd());

              returndemoInfo;

       }

      

      

       /**

        *删除数据.

        *@param id

        */

       @CacheEvict(value = DEMO_CACHE_NAME,key ="'demoInfo_'+#id")//这是清除缓存.

   @Override

   publicvoid delete(Long id){

              demoInfoRepository.delete(id);

   }

         

      

}

 

(9)编写DemoInfoController测试类;

编写一个rest进行测试:

com.kfit.controller.DemoInfoController

package com.kfit.controller;

 

import javax.annotation.Resource;

 

importorg.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RestController;

 

import com.kfit.bean.DemoInfo;

import com.kfit.service.DemoInfoService;

 

import javassist.NotFoundException;

 

@RestController

publicclass DemoInfoController {

 

       @Resource

       private DemoInfoServicedemoInfoService;

      

       @RequestMapping("/test")

       public String test(){

             

              //存入两条数据.

          DemoInfo demoInfo = new DemoInfo();

          demoInfo.setName("张三");

          demoInfo.setPwd("123456");

          DemoInfo demoInfo2 = demoInfoService.save(demoInfo);

             

          //不走缓存.

          System.out.println(demoInfoService.findById(demoInfo2.getId()));

          //走缓存.

          System.out.println(demoInfoService.findById(demoInfo2.getId()));

         

         

          demoInfo = new DemoInfo();

          demoInfo.setName("李四");

          demoInfo.setPwd("123456");

          DemoInfo demoInfo3 = demoInfoService.save(demoInfo);

         

          //不走缓存.

          System.out.println(demoInfoService.findById(demoInfo3.getId()));

          //走缓存.

          System.out.println(demoInfoService.findById(demoInfo3.getId()));

         

          System.out.println("============修改数据=====================");

          //修改数据.

          DemoInfo updated = new DemoInfo();

          updated.setName("李四-updated");

          updated.setPwd("123456");

          updated.setId(demoInfo3.getId());

          try {

                     System.out.println(demoInfoService.update(updated));

              }catch(NotFoundExceptione) {

                     e.printStackTrace();

              }

         

          //不走缓存.

          System.out.println(demoInfoService.findById(updated.getId()));

         

              return"ok";

       }

      

      

}

 

(10)运行测试;

运行App.java进行测试,访问:http://127.0.0.1:8080/test 进行测试,主要是观察控制台的打印信息。

Hibernate: insert into demo_info(name, pwd, state) values (?, ?, ?)

没有走缓存!52

DemoInfo [id=52, name=张三, pwd=123456,state=0]

DemoInfo [id=52, name=张三, pwd=123456,state=0]

Hibernate: insert into demo_info(name, pwd, state) values (?, ?, ?)

没有走缓存!53

DemoInfo [id=53, name=李四, pwd=123456,state=0]

DemoInfo [id=53, name=李四, pwd=123456,state=0]

============修改数据=====================

DemoInfo [id=53, name=李四-updated,pwd=123456, state=0]

DemoInfo [id=53, name=李四-updated,pwd=123456, state=0]

C:\Users\ADMINI~1.ANG\AppData\Local\Temp\

Hibernate: insert into demo_info(name, pwd, state) values (?, ?, ?)

没有走缓存!54

DemoInfo [id=54, name=张三, pwd=123456,state=0]

DemoInfo [id=54, name=张三, pwd=123456,state=0]

Hibernate: insert into demo_info(name, pwd, state) values (?, ?, ?)

没有走缓存!55

DemoInfo [id=55, name=李四, pwd=123456,state=0]

DemoInfo [id=55, name=李四, pwd=123456,state=0]

============修改数据=====================

DemoInfo [id=55, name=李四-updated,pwd=123456, state=0]

DemoInfo[id=55, name=李四-updated,pwd=123456, state=0]

 

       好了本篇文章就写到这里吧,打烊休息了,实在是动不了!

2 0