Spring缓存机制的理解

Wesley13
• 阅读 672

在Spring缓存机制中,包括了两个方面的缓存操作:1.缓存某个方法返回的结果;2.在某个方法执行前或后清空缓存。

下面写两个类来模拟Spring的缓存机制:

Spring缓存机制的理解

package com.sin90lzc.java.test;

/**
 * 一个简单的Dao接口,我们要对这个接口的方法提供缓存的功能
 * @author Tim
 *
 */
public interface Dao {
    Object select();
    void save(Object obj);
}

Spring缓存机制的理解

Spring缓存机制的理解

package com.sin90lzc.java.test;

import java.util.HashMap;
import java.util.Map;
/**
 * 实现缓存功能,在Spring中,该类可以看作是Advice
 * @author Tim
 *
 */
public class Cache {
    private static final Map<String, Object> cache = new HashMap<String, Object>();
    
    /**
     * 把对象添加到缓存中去
     * @param key
     * @param value
     */
    public void checkIn(String key, Object value) {
        if (!cache.containsKey(key)) {
            cache.put(key, value);
        }
    }

    /**
     * 从缓存中找对象
     * @param key
     * @return
     */
    public Object checkOut(String key) {
        if (cache.containsKey(key)) {
            return cache.get(key);
        }
        return null;
    }
    
    /**
     * 在方法执行前清除缓存
     */
    public void clearCacheBeforeMethod(){
        cache.clear();
    }
    
    /**
     * 在方法执行后清除缓存
     */
    public void clearCacheAfterMethod(){
        cache.clear();
    }
}

Spring缓存机制的理解

Spring缓存机制的理解

package com.sin90lzc.java.test;

/**
 * Dao的代理对象,它不仅仅完成主要的查询,存储操作,还实现了缓存
 * @author Tim
 *
 */
public class DaoProxy implements Dao {
    private Cache cache;//该对象实现了缓存的功能
    private Dao daoImpl;//完成主要查询,存储操作的Dao实现类,注意,这是一个Dao的实现类

    public Object select() {
        //在执行方法前,尝试从缓存中取出结果并返回,如果没找到,则执行实际的操作。
        Object obj = cache.checkOut("DaoProxy.select");
        boolean hasCache = false;
        if (obj != null) {
            hasCache = true;
            return obj;
        }
        
        //实际的查询操作
        obj = daoImpl.select();
        
        //如果在缓存中找不到该方法的结果,缓存该结果
        if (!hasCache) {
            cache.checkIn("DaoProxy.select", obj);
        }
        return obj;
    }

    @Override
    public void save(Object obj) {
        //在执行方法前清除缓存
        cache.clearCacheBeforeMethod();
        //实际的操作
        daoImpl.save(obj);
        //在执行方法后清除缓存
        cache.clearCacheAfterMethod();
    }

    public void setCache(Cache cache) {
        this.cache = cache;
    }

    public void setDao(Dao dao) {
        this.daoImpl = dao;
    }

}

Spring缓存机制的理解

从代码中可以看到,真正完成缓存功能的类是Cache,真正完成Dao(数据的增删查改)功能的类是Dao的实现类,这就是实现了实际业务(Dao)与功能(缓存)的分离。实际的Dao操作与缓存功能是如何结合起来的呢?这就是通过代理对象。我们可以注意到ProxyDao的真正身份也是一个Dao,是它把Dao操作与缓存结合起来的。这三个类恰恰说明了AOP的本质。

2.EHCache

Spring仅仅是提供了对缓存的支持,但它并没有任何的缓存功能的实现,spring使用的是第三方的缓存框架来实现缓存的功能。其中,spring对EHCache提供了很好的支持。下面我们以EHCache为例来介绍spring的缓存配置。

在介绍Spring的缓存配置之前,我们先看一下EHCache是如何配置。

Spring缓存机制的理解

<?xml version="1.0" encoding="UTF-8" ?>
<ehcache>
    <!-- 定义默认的缓存区,如果在未指定缓存区时,默认使用该缓存区 -->
    <defaultCache maxElementsInMemory="500" eternal="true"
        overflowToDisk="false" memoryStoreEvictionPolicy="LFU">
    </defaultCache>
    <!-- 定义名字为"dao.select"的缓存区 -->
    <cache name="dao.select" maxElementsInMemory="500" eternal="true"
        overflowToDisk="false" memoryStoreEvictionPolicy="LFU" />
</ehcache>

Spring缓存机制的理解

3.Spring缓存机制中的Advice

由于Spring的缓存机制是基于Spring的AOP,那么在Spring Cache中应该存在着一个Advice。没错,在Spring Cache中的Advice是存在的,它就是org.springframework.cache.Cache。我们看一下它的接口定义:

Spring缓存机制的理解

/*
 * Copyright 2002-2011 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.cache;

/**
 * Interface that defines the common cache operations.
 *
 * <b>Note:</b> Due to the generic use of caching, it is recommended that
 * implementations allow storage of <tt>null</tt> values (for example to
 * cache methods that return {@code null}).
 *
 * @author Costin Leau
 * @since 3.1
 */
public interface Cache {

    /**
     * Return the cache name.
     */
    String getName();

    /**
     * Return the the underlying native cache provider.
     */
    Object getNativeCache();

    /**
     * Return the value to which this cache maps the specified key. Returns
     * <code>null</code> if the cache contains no mapping for this key.
     * @param key key whose associated value is to be returned.
     * @return the value to which this cache maps the specified key,
     * or <code>null</code> if the cache contains no mapping for this key
     */
    ValueWrapper get(Object key);

    /**
     * Associate the specified value with the specified key in this cache.
     * <p>If the cache previously contained a mapping for this key, the old
     * value is replaced by the specified value.
     * @param key the key with which the specified value is to be associated
     * @param value the value to be associated with the specified key
     */
    void put(Object key, Object value);

    /**
     * Evict the mapping for this key from this cache if it is present.
     * @param key the key whose mapping is to be removed from the cache
     */
    void evict(Object key);

    /**
     * Remove all mappings from the cache.
     */
    void clear();


    /**
     * A (wrapper) object representing a cache value.
     */
    interface ValueWrapper {

        /**
         * Return the actual value in the cache.
         */
        Object get();
    }

}

Spring缓存机制的理解

evict,put方法就是Advice的功能方法,或者可以这样去理解。

但spring并不是直接使用org.springframework.cache.Cache,spring把Cache对象交给org.springframework.cache.CacheManager来管理,下面是org.springframework.cache.CacheManager接口的定义:

Spring缓存机制的理解

/*
 * Copyright 2002-2011 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.cache;

import java.util.Collection;

/**
 * A manager for a set of {@link Cache}s.
 *
 * @author Costin Leau
 * @since 3.1
 */
public interface CacheManager {

    /**
     * Return the cache associated with the given name.
     * @param name cache identifier (must not be {@code null})
     * @return associated cache, or {@code null} if none is found
     */
    Cache getCache(String name);

    /**
     * Return a collection of the caches known by this cache manager.
     * @return names of caches known by the cache manager.
     */
    Collection<String> getCacheNames();

}

Spring缓存机制的理解

在spring对EHCache的支持中,org.springframework.cache.ehcache.EhCacheManager就是org.springframework.cache.CacheManager的一个实现

Spring缓存机制的理解

  <!-- 
        该Bean是一个org.springframework.cache.CacheManager对象
        属性cacheManager是一个net.sf.ehcache.CacheManager对象
     -->
    <bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager">
        <property name="cacheManager">
            <bean class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
                <property name="configLocation" value="classpath:ehcache-config.xml"></property>
            </bean>
        </property>
    </bean>

Spring缓存机制的理解

4.基于xml配置方式配置缓存

在上一节中,我们得到了cacheManagr,那么我们就可以对某些方法配置缓存了。下面是基于xml方式的缓存配置

Spring缓存机制的理解

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:cache="http://www.springframework.org/schema/cache"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:aop="http://www.springframework.org/schema/aop" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
     http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
     http://www.springframework.org/schema/context
     http://www.springframework.org/schema/context/spring-context-3.1.xsd
     http://www.springframework.org/schema/cache
     http://www.springframework.org/schema/cache/spring-cache-3.1.xsd
     http://www.springframework.org/schema/aop
     http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
     ">

    <context:component-scan base-package="com.sin90lzc"></context:component-scan>
    <bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager">
        <property name="cacheManager">
            <bean class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
                <property name="configLocation" value="classpath:ehcache-config.xml"></property>
            </bean>
        </property>
    </bean>

    <cache:advice id="cacheAdvice" cache-manager="cacheManager">
        <cache:caching>
            <cache:cacheable cache="dao.select" method="select"
                key="#id" />
            <cache:cache-evict cache="dao.select" method="save"
                key="#obj" />
        </cache:caching>
    </cache:advice>

    <aop:config>
        <aop:advisor advice-ref="cacheAdvice" pointcut="execution(* com.sin90lzc.train.spring_cache.simulation.DaoImpl.*(..))"/>
    </aop:config>
</beans>

Spring缓存机制的理解

5.注解驱动的缓存配置

Spring缓存机制的理解

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:cache="http://www.springframework.org/schema/cache"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
     http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
     http://www.springframework.org/schema/context
     http://www.springframework.org/schema/context/spring-context-3.1.xsd
     http://www.springframework.org/schema/cache
     http://www.springframework.org/schema/cache/spring-cache-3.1.xsd">

    <context:component-scan base-package="com.sin90lzc"></context:component-scan>

    <!-- 
        该Bean是一个org.springframework.cache.CacheManager对象
        属性cacheManager是一个net.sf.ehcache.CacheManager对象
     -->
    <bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager">
        <property name="cacheManager">
            <bean class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
                <property name="configLocation" value="classpath:ehcache-config.xml"></property>
            </bean>
        </property>
    </bean>
    
    <cache:annotation-driven />


</beans>

Spring缓存机制的理解

Spring缓存机制的理解

package com.sin90lzc.train.spring_cache.simulation;

import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Component;


@Component
public class DaoImpl implements Dao {

    /**
     * value定义了缓存区(缓存区的名字),每个缓存区可以看作是一个Map对象
     * key作为该方法结果缓存的唯一标识,
     */
    @Cacheable(value = { "dao.select" },key="#id")
    @Override
    public Object select(int id) {
        System.out.println("do in function select()");
        return new Object();
    }

    @CacheEvict(value = { "dao.select" }, key="#obj")
    @Override
    public void save(Object obj) {
        System.out.println("do in function save(obj)");
    }

}

Spring缓存机制的理解

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
5个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Wesley13 Wesley13
3年前
Java获得今日零时零分零秒的时间(Date型)
publicDatezeroTime()throwsParseException{    DatetimenewDate();    SimpleDateFormatsimpnewSimpleDateFormat("yyyyMMdd00:00:00");    SimpleDateFormatsimp2newS
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
3年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
3年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
11个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这