天天看点

Spring集成ehcache1.导入jar包2.编写ehcache.xml3.修改applicationContext.xml4.使用ehcache5.总结

1.导入jar包

ehcache-core-2.4.5.jar

ehcache-spring-annotations-1.2.0.jar(使用spring注解的形式配置时需要引入的jar包,依赖于guava)

ehcache-web-2.0.4.jar(做页面缓存需要用到)

guava-r09.jar(google推出可以帮助你写出更优雅代码的工具,和apache-commons差不多)

hibernate-ehcache-4.2.21.Final.jar(hibernate对于ehcache的支持)

2.编写ehcache.xml

将下载ehcache时附带的ehcache.xsd引入到工程中,我放在了src/config目录下

在classpath路径下新建xml文件,命名为ehcache.xml,然后其格式可以参考下载ehcache时附带的ehcache.xml,以下是我的配置

<?xml version="1.0" encoding="UTF-8"?>
<!--制定xsd的位置,这个xsd需要自己下载,贼坑,
网上的写的是用http://ehcache.org/ehcache.xsd 但是idea一直在报错,
最新版的是有附带ehcache.xsd的,然后自己加就好了,我发现我用的这个版本的jar如果点开
也有一个ehcache-*的一个配置文件的,里面的ehcache.xsd是可以使用的!但是我死活找不到,
没办法只能自己下载自己加了,网上的方法都没有什么好的,手动大笑-->

<!--updateCheck不要设置为true,否则每一次的开启都会自动检查更新,导致运行很慢-->
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="config/ehcache.xsd"
         updateCheck="false">

    <!--缓存保存地址-->
    <diskStore path="java.io.tmpdir"/>

    <!--默认的缓存配置-->
    <defaultCache
            maxElementsInMemory="10000"
            eternal="false"
            timeToIdleSeconds="30"
            timeToLiveSeconds="30"
            overflowToDisk="false"/>


    <!--自定义缓存配置-->
    <!--
        1.必须要有的属性:
        name: cache的名字,用来识别不同的cache,必须惟一。
        maxElementsInMemory: 内存管理的缓存元素数量最大限值。
        maxElementsOnDisk: 硬盘管理的缓存元素数量最大限值。默认值为0,就是没有限制。
        eternal: 设定元素是否持久话。若设为true,则缓存元素不会过期。
        overflowToDisk: 设定是否在内存填满的时候把数据转到磁盘上。
        2.下面是一些可选属性:
        timeToIdleSeconds: 设定元素在过期前空闲状态的时间,只对非持久性缓存对象有效。默认值为0,值为0意味着元素可以闲置至无限长时间。
        timeToLiveSeconds: 设定元素从创建到过期的时间。其他与timeToIdleSeconds类似。
        diskPersistent: 设定在虚拟机重启时是否进行磁盘存储,默认为false.(我的直觉,对于安全小型应用,宜设为true)。
        diskExpiryThreadIntervalSeconds: 访问磁盘线程活动时间。
        diskSpoolBufferSizeMB: 存入磁盘时的缓冲区大小,默认30MB,每个缓存都有自己的缓冲区。
        memoryStoreEvictionPolicy: 元素逐出缓存规则。共有三种,Recently Used (LRU)最近最少使用,为默认。
        First In First Out (FIFO),先进先出。Less Frequently Used(specified as LFU)最少使用
    -->
    <cache name="sampleCache"
           maxElementsInMemory="10000"
           maxElementsOnDisk="1000"
           eternal="false"
           overflowToDisk="true"
           diskSpoolBufferSizeMB="20"
           timeToIdleSeconds="300"
           timeToLiveSeconds="600"
           memoryStoreEvictionPolicy="LFU" />
</ehcache>
           

3.修改applicationContext.xml

修改applicationContext.xml用来集成ehcache。

<!--开启ehcache注解扫描-->
    <ehcache:annotation-driven />

    <!--ehcache工厂的配置-->
    <bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
        <property name="configLocation" value="classpath:ehcache.xml"/>
    </bean>
    <!--配置cache-manager-->
    <ehcache:config cache-manager="cacheManager">
        <ehcache:evict-expired-elements interval="60" />
    </ehcache:config>
           

配置完这个之后,整个applicationContext.xml长这样

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:jpa="http://www.springframework.org/schema/data/jpa"
       xmlns:ehcache="http://ehcache-spring-annotations.googlecode.com/svn/schema/ehcache-spring"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
       http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
       http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-1.2.xsd
       http://ehcache-spring-annotations.googlecode.com/svn/schema/ehcache-spring http://ehcache-spring-annotations.googlecode.com/svn/schema/ehcache-spring/ehcache-spring-1.1.xsd">

    <!--自动扫描包-->
    <context:component-scan base-package="cn.limbo">
        <!--不要将Controller扫进来,否则aop无法使用-->
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>

    <!--使Aspect注解起作用,自动为匹配的类生成代理对象-->
    <aop:aspectj-autoproxy proxy-target-class="true"/>

    <!--开启ehcache注解扫描-->
    <ehcache:annotation-driven />

    <!--ehcache工厂的配置-->
    <bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
        <property name="configLocation" value="classpath:ehcache.xml"/>
    </bean>
    <!--配置cache-manager-->
    <ehcache:config cache-manager="cacheManager">
        <ehcache:evict-expired-elements interval="60" />
    </ehcache:config>



    <!--引入properties-->
    <context:property-placeholder location="classpath:hibernate.properties"/>

    <!--配置数据源-->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="user" value="${dataSource.username}"/>
        <property name="password" value="${dataSource.password}"/>
        <property name="jdbcUrl" value="${dataSource.url}"/>
        <property name="driverClass" value="${dataSource.driverClassName}"/>
    </bean>

    <!--<!–sessionFactory–>-->
    <!--<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">-->
    <!--<!– 配置数据源属性 –>-->
    <!--<property name="dataSource" ref="dataSource"/>-->
    <!--<!– 配置扫描的实体包(pojo) –>-->
    <!--<property name="namingStrategy">-->
    <!--<bean class="org.hibernate.cfg.ImprovedNamingStrategy"/>-->
    <!--</property>-->
    <!--<property name="packagesToScan" value="cn.limbo.entity"/>-->

    <!--<property name="hibernateProperties">-->
    <!--<props>-->
    <!--<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</prop>-->
    <!--<prop key="hibernate.show_sql">true</prop>-->
    <!--<prop key="hibernate.format_sql">true</prop>-->
    <!--<prop key="hibernate.hbm2ddl.auto">update</prop>-->
    <!--</props>-->
    <!--</property>-->
    <!--</bean>-->

    <bean id="persistenceProvider"
          class="org.hibernate.ejb.HibernatePersistence"/>

    <bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
        <property name="database" value="MYSQL"/>
    </bean>

    <bean id="jpaDialect" class="org.springframework.orm.jpa.vendor.HibernateJpaDialect"/>

    <!--jpa工厂-->
    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <!--数据源-->
        <property name="dataSource" ref="dataSource"/>
        <!--持久层提供者-->
        <property name="persistenceProvider" ref="persistenceProvider"/>
        <!--适配器-->
        <property name="jpaVendorAdapter" ref="jpaVendorAdapter"/>

        <property name="jpaDialect" ref="jpaDialect"/>

        <property name="jpaProperties">
            <props>
                <prop key="hibernate.dialect">${dataSource.dialect}</prop>
                <prop key="hibernate.connection.driver_class">${dataSource.driverClassName}</prop>
                <prop key="hibernate.max_fetch_depth">3</prop>
                <prop key="hibernate.jdbc.fetch_size">18</prop>
                <prop key="hibernate.jdbc.batch_size">10</prop>
                <prop key="hibernate.hbm2ddl.auto">${dataSource.hbm2ddl.auto}</prop>
                <prop key="hibernate.show_sql">${dataSource.show_sql}</prop>
                <prop key="hibernate.format_sql">${dataSource.format_sql}</prop>
                <!--做bean validation的也就是对你的输入的数据进行语义的验证-->
                <prop key="javax.persistence.validation.mode">none</prop>
            </props>
        </property>

        <property name="packagesToScan">
            <list>
                <value>cn.limbo.entity</value>
            </list>
        </property>
    </bean>

    <jpa:repositories base-package="cn.limbo.dao"
                      entity-manager-factory-ref="entityManagerFactory"
                      transaction-manager-ref="transactionManager"/>

    <!-- 配置Hibernate 的事物管理器 -->
    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory"/>
    </bean>


    <tx:annotation-driven transaction-manager="transactionManager"/>
</beans>
           

4.使用ehcache

配置完成之后使用ehcache就比较简单了,只要在需要缓存的地方加上@Cacheable标签就好了

但是需要注意的是,最好是在做查询的方法里使用ehcache,在做增删改的时候要清除缓存,这点比较重要,否则在并发情况下会出现数据的脏读和幻读之类的东西

一般在dao中的service层引入ehcache,使用方法如下:

package cn.limbo.service.impl;

import cn.limbo.dao.UserDao;
import cn.limbo.entity.User;
import cn.limbo.service.UserService;
import com.googlecode.ehcache.annotations.Cacheable;
import com.googlecode.ehcache.annotations.TriggersRemove;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

/**
 * Created by limbo on 2016/11/26.
 */
@Service("userService")
@Transactional
public class UserServiceImpl implements UserService{

    @Autowired
    private UserDao userDao;


    @Override
    @Cacheable(cacheName = "sampleCache")
    public User getUserByID(int ID) {
        return userDao.getUserByID(ID);
    }

    @Override
    @Cacheable(cacheName = "sampleCache")
    public List<User> getAllUsers() {
        return userDao.getAllUsers();
    }

    @Override
    @TriggersRemove(cacheName="sampleCache",removeAll=true)//清除缓存
    public void addUser(String name,String password) {
        User user = new User(name,password);
        userDao.save(user);
    }

    @Override
    @TriggersRemove(cacheName="sampleCache",removeAll=true)//清除缓存
    public void deleteUserByID(int ID) {
        userDao.delete(ID);
    }

    @Override
    @TriggersRemove(cacheName="sampleCache",removeAll=true)//清除缓存
    public void updateUser(User user) {
        userDao.update(user.getID(),user.getName(),user.getPassword());
    }

    @Override
    public boolean isExist(String userName) {
        if(userDao.getUserByName(userName) != null)
            return true;
        return false;
    }
}
           

5.总结

发现有两个坑点: 1.ehcache.xsd找不到,一开始网上给的解决方案都是改成http://ehcahce.org/ehcahce.xsd,但是我发现这样还是有问题的,后来发现我下载ehcache的时候附带了ehcahce.xsd,引入就好咯 2.使用cache的时候,@Cacheable(cacheName=""),使用的是在ehcache.xml自定义配置的ehcache名字,而不是在applicationContext.xml里面配置的bean的名字

源码我放到了github上: https://github.com/NetFilx/Google-Authenticator