天天看點

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