摘要:去年整理过关于JAVA web的一些缓冲知识 今天无疑见翻出这篇笔记 怕以后弄丢了 就在这里记录下吧

JAVA缓存最简单一种实现

创建一个静态的map ConcurrentHashMap 线程安全

本地文件缓存

Ehcache 缓存

jar包

ehcache-core-2.5.2.jar slf4j-api-1.6.1.jar slf4j-jdk14-1.6.1.jar

配置 ehcache.xml

可配置多个cache
通过 Cache sample = cacheManager.getCache(“name”);获取缓存对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?xml version="1.0" encoding="UTF-8"?>  
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
    xsi:noNamespaceSchemaLocation="../bin/ehcache.xsd">  
    <!--  
    name:Cache的唯一标识  
    maxElementsInMemory:内存中最大缓存对象数  
    maxElementsOnDisk:磁盘中最大缓存对象数,若是0表示无穷大  
    eternal:Element是否永久有效,一但设置了,timeout将不起作用  
    overflowToDisk:配置此属性,当内存中Element数量达到maxElementsInMemory时,Ehcache将会Element写到磁盘中  
    timeToIdleSeconds:设置Element在失效前的允许闲置时间。仅当element不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大  
11.    timeToLiveSeconds:设置Element在失效前允许存活时间。最大时间介于创建时间和失效时间之间。仅当element不是永久有效时使用,默认是0.,也就是element存活时间无穷大   
    diskPersistent : 是否持久化磁盘缓存。当这个属性的值为true时,系统在初始化的时候会在磁盘中查找文件名为cache名称,后缀名为index的的文件  
    diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒  
    diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区  
     memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。默认策略是LRU(最近最少使用)。你可以设置为FIFO(先进先出)或是LFU(较少使用)   
    -->  
    <defaultCache overflowToDisk="true" eternal="false"/>  
    <diskStore path="D:/cache" />  
    <!--  
       <cache name="zzugxy" overflowToDisk="true" eternal="false"  
        timeToIdleSeconds="300" timeToLiveSeconds="600" maxElementsInMemory="1000" > 
        maxElementsOnDisk="10" diskPersistent="true" diskExpiryThreadIntervalSeconds="300"  
        diskSpoolBufferSizeMB="100" memoryStoreEvictionPolicy="LRU" />  
    -->  
</ehcache>

JAVA 代码

  • 1.获取CacheManager 对象 不传参数表示默认路径 可以传入文件路径和网络地址

  • 2.CacheManager cacheManager = CacheManager.create();

获取ehcache.xml 文件里配置好的 cache

Cache sample = cacheManager.getCache(“SimplePageCachingFilter”);

  • 3.创建 缓存元素 key 和 val 字面意思

Element element = new Element(“key”, “val”);

  • 4.sample.put(element); 将缓存对象 加入缓存

    通过key获取cache中的 缓存元素

Element result = sample.get(“key”);

注意添加到cache中对象要序列化 实现Serializable接口

通过 次元素 可获取 val等 属性的值

删除缓存

sample.remove(“key”);

sample.removeAll();

获取所有的缓存对象

for (Object key : cache.getKeys()) {

System.out.println(key);

}

得到缓存中的对象数

cache.getSize();

得到缓存对象占用内存的大小

cache.getMemoryStoreSize();

得到缓存读取的命中次数

cache.getStatistics().getCacheHits();

得到缓存读取的错失次数

cache.getStatistics().getCacheMisses();

写入磁盘

cache.flush();

要想把cache真正持久化到磁盘,写程序时必须注意,在是用net.sf.ehcache.Cache的void put (Element element)方法后要使用void flush()方法

创建个缓存

1
2
3
Ehcache cache = new Cache("testCache", 5000, false, false, 5, 2);
sample.add(cache )

Ehcache整合MyBatis

导入 mybatis-ehcache-1.0.0.jar 还有其他myBatis相关包

1
2
3
4
5
6
7
8
9
10
11
<?xml version="1.0" encoding="UTF-8" ?>   
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">  
<mapper namespace="com.qiuqiu.dao.PersonDao">  
    <!-- 以下两个<cache>标签二选一,第一个可以输出日志,第二个不输出日志 -->  
   <cache type="org.mybatis.caches.ehcache.LoggingEhcache"/>  
    <!-- <cache type="org.mybatis.caches.ehcache.EhcacheCache"/> -->  
      
   <select id="selectUserById" parameterType="int" resultType="org.qiuqiu.vo.Person">  
        select * from person where id=#{id}   
    </select>  
</mapper>

通过注释的方式 整合

1
@CacheNamespace(implementation=org.mybatis.caches.ehcache.EhcacheCache.class)

EhcacheCache 实现了 mybatis的 Cache接口

默认获取根目录下的ehcache.xml文件

如果 之前在ehcache.xml 没有配置过 相应的cache

这里会根据 id创建一个cache

id= Dao的地址

在ehcache.xml配置 cache麻烦的话

可以 自定义类 继承EhcacheCache 重写 获取cache 将@CacheNamespace

注解里面的参数传进去 自定义 cache

Ehcache页面缓存

jar包

1
2
3
4
5
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache-web</artifactId>
<version>2.0.4</version>
</dependency>

页面缓存主要用Filter过滤器对请求的url进行过滤,如果该url在缓存中出现。那么页面数据就从缓存对象中获取,并以gzip压缩后返回。其速度是没有压缩缓存时速度的3-5倍,效率相当之高!其中页面缓存的过滤器有CachingFilter,一般要扩展filter或是自定义Filter都继承该CachingFilter

自定义类 继承 SimplePageCachingFilter

重写 doFilter 方法 在里面先判断 是否是要缓存的地址

如果是就调用super.doFilter(request, response, chain);

如果不是就调用chain.doFilter(request, response);

SimplePageCachingFilter里面默认获取 名字SimplePageCachingFilter 的 cache配置

重写 getCacheName方法 设置 cache名字

默认 key :

1
stringBuffer.append(httpRequest.getMethod()).append(httpRequest.getRequestURI()).append(httpRequest.getQueryString())

可以重写 SimplePageCachingFilter 的 calculateKey() 方法 自己定义key

Ehcache Spring 整合

1
2
3
4
5
6
7
8
9
10
11
12
<bean id="defaultCacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
<property name="configLocation" value="classpath:ehcache.xml"></property>
</bean>
<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager">
<property name="cacheManager">
<ref local="defaultCacheManager"/>
</property>
</bean>
<cache:annotation-driven cache-manager="cacheManager"/>

在类或方法上@Cacheable

@Cacheable(value=”cache”)

这个注释的意思是,当调用这个方法的时候,会从一个名叫 cache的缓存中查询,如果没有,则执行实际的方法(即查询数据库),并将执行的结果存入缓存中,否则返回缓存中的对象。

同时 还有@CacheEvict @CachePut 等注解

详解http://wenku.baidu.com/link?url=g5ptu1e1vHrJ2FePys7a9ILMhoI_JkX4-3vX9Ir3VfSiTGuE6eOqEx-DuWGMZBWoIa9zKQ9RmM4eiJw86Q_uXx7U1Ux75X2odvUGxqL8JaW

远程缓存

Memcached

java memcached client

jar包

commons-pool-1.5.6.jar

java_memcached-release_2.6.6.jar

slf4j-api-1.6.1.jar

slf4j-simple-1.6.1.jar

主要是两个类

SockIOPool 和 MemCachedClient

SockIOPool 这个类用来创建管理客户端和服务器通讯连接池

MemCachedClient 缓存的管理

set方法 gei 方法 等

memcached 缓存对象 需要 实现序列化

set方法 gei 方法 等

注:设置有效时间为5秒是

new Date(5000) 不是 new Date(System.currentTimeMillis()+5000) 神逻辑

更多API http://wenku.baidu.com/link?url=vxMR6BGKj7_8RHMN9H_trAV4p4NVPfVjxSl08uQcL8eooRTk7g1PQVmiqcKP4MQPr5Hm3NsIlEHqdFcPFroddtzHaOliasg5I2MYGjz0XiC

java memcached client 整合spring

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<bean id="sockIOPool" class="com.danga.MemCached.SockIOPool"
factory-method="getInstance" init-method="initialize" destroy-method="shutDown">
<constructor-arg>
<value>neeaMemcachedPool</value>
</constructor-arg>
<property name="servers">
<list>
<value>127.1.0.1:11211</value>
</list>
</property>
<property name="initConn">
<value>10</value>
</property>
<property name="maxConn">
<value>250</value>
</property>
<property name="maintSleep">
<value>30</value>
</property>
<property name="nagle">
<value>false</value>
</property>
<property name="socketTO">
<value>3000</value>
</property>
</bean>
<bean id="memcachedClient" class="com.danga.MemCached.MemCachedClient">
<constructor-arg>
<value>neeaMemcachedPool</value>
</constructor-arg>
</bean>

参考 Ehcache 整合 Spring

org.springframework.cache.ehcache.EhCacheCacheManager 重org.springframework.cache.Cache和 org.springframework.cache.support.AbstractCacheManager

1
2
3
4
5
6
7
<bean id="cacheManager" class="com.dingxin.kunyu.cache.MemcachedCacheManager">
<property name="memcachedClient">
<ref bean="memcachedClient"/>
</property>
</bean>
<cache:annotation-driven cache-manager="cacheManager"/>mybatis和memcached的整合

mybatis和memcached的整合

JAR 包

1
2
3
4
5
<dependency>
<groupId>org.mybatis.caches</groupId>
<artifactId>mybatis-memcached</artifactId>
<version>1.0.0</version>
</dependency>

1
<mapper namespace="org.acme.FooMapper">  <cache type="org.mybatis.caches.memcached.MemcachedCache" />

打印日志

1
<cache type="org.mybatis.caches.memcached.LoggingMemcachedCache" />  ...</mapper>

memcache的配置是根据classpath下的 /memcached.properties 配置的,如果没有使用默

还可以实现 mybatis的 Cache接口 进行整合

使用Simple-Spring-Memcached注解做缓存操作

针对xmemcached 客户端

1
2
3
4
5
6
7
8
9
10
11
<dependency>
<groupId>com.google.code.simple-spring-memcached</groupId>
<artifactId>xmemcached-provider</artifactId>
<version>3.6.0</version>
</dependency>
<!--spymemcached客户端 -->
<dependency>
<groupId>com.google.code.simple-spring-memcached</groupId>
<artifactId>spymemcached-provider</artifactId>
<version>3.6.0</version>
</dependency>

Spring 配置

1
2
<import resource="simplesm-context.xml" />
<aop:aspectj-autoproxy />

http://https://code.google.com/p/simple-spring-memcached/wiki/Getting_Started#@CacheKeyMethod

这里面有针对不同客户端的spring配置

simplesm-context.xml 在simple-spring-memcached-3.4.0.jar 包里

在方法上 使用 @ReadThroughSingleCache

两个参数 namespace key前缀 expiration到期时间

在参数上@ParameterValueKeyProvider 生成key 多个参数时候 需要指定 order 值

注 参数不能带空格 或者空的 会报错

@InvalidateSingleCache

作用:失效Cache中的数据

@UpdateSingleCache

作用:更新Cache中的数据 等等

@CacheKeyMethod 标记做为参数 的对象方法上 调用该方法生产key 不包含此注解则调用 toString方法

xmemcached 客户端

Jar 包

1
2
3
4
5
<dependency>
<groupId>com.googlecode.xmemcached</groupId>
<artifactId>xmemcached</artifactId>
<version>2.0.0</version>
</dependency>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
MemcachedClientBuilder builder = new XMemcachedClientBuilder(
AddrUtil.getAddresses("127.1.0.1:11211"), new int[] { 1, 1, 1, 1 }
//设置连接池大小,即客户端个数
builder.setConnectionPoolSize(50);
//宕机报警
builder.setFailureMode(true);
//使用二进制文件
builder.setCommandFactory(new BinaryCommandFactory());
MemcachedClient memcachedClient = null;
try {
memcachedClient = builder.build();
try {
memcachedClient.set("zlex", 36000, "set/get");
memcachedClient.get("zlex",);
} catch (TimeoutException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (MemcachedException e) {
e.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();}

API http://www.tuicool.com/articles/qMnQVfe

Redis

1
<dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.0.0</version> </dependency>

Jedis客户端

连接池配置

1
2
3
4
5
6
7
8
//连接池配置
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxTotal(10);
config.setMaxIdle(50);//设置最大空闲数
config.setBlockWhenExhausted(false);
config.setMaxWaitMillis(timeout);//设置超时时间
config.setMinEvictableIdleTimeMillis(30000);

更多参数 详解 http://shift-alt-ctrl.iteye.com/blog/1885910

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//获得连接池
JedisPool pool == new JedisPool(config, host, port, timeout)
//jedisPool对象 可以通过spring 进行封装
//获得Jedis
Jedis client = jedisPool.getResource();
try{
client.set("k1", "v1");
client.expire("k1", time) //设置有效时间
client.get("k1"); //获取值
client.del("k1"); //删除值
}catch(Exception e){
e.printStackTrace();
}finally{
jedisPool.returnResource(client); //必须 释放对象池
}

更多API http://tool.oschina.net/uploads/apidocs/

Redis的key和value都支持二进制安全的字符串

保存对象 需要 序列化对象

序列化工具

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class SerializeUtil {
public static byte[] serialize(Object object) {
ObjectOutputStream oos = null;
ByteArrayOutputStream baos = null;
try {
//序列化
baos = new ByteArrayOutputStream();
oos = new ObjectOutputStream(baos);
oos.writeObject(object);
byte[] bytes = baos.toByteArray();
return bytes;
} catch (Exception e) {
}
return null;
}
public static Object unserialize(byte[] bytes) {
ByteArrayInputStream bais = null;
try {
//反序列化
bais = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(bais);
return ois.readObject();
} catch (Exception e) {
}
return null;
}
}

Spring Data Redis

在Jedis的基础上,提供了对Redis访问的进一步封装。使用SDR,不在需要手动维护连接的建立、释放,对对象序列化提供了默认实现

SDR依赖的的是Spring的高版本3.x

1
2
3
4
5
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
<version>1.5.2.RELEASE</version>
</dependency>

Spring 配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!--定义连接工厂-->
<bean id = "jedisConnectionFactory"
class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
<constructor-arg index="0" ref="jedisPoolConfig"/>
<property name="hostName" value="${redis.host}"/>
<property name="port" value="${redis.port}"/>
<property name="timeout" value="${redis.timeout}"/>
<property name="password" value="${redis.password}"/>
</bean>
<!--定义redisTemplate:提供了对Jedis进行的通用API操作。-->
<bean id = "redisTemplate"
class="org.springframework.data.redis.core.RedisTemplate">
<property name="connectionFactory" ref="jedisConnectionFactory"/>
<property name="keySerializer">
<bean class="org.springframework.data.redis.serializer.StringRedisSerializer"></bean>
</property>
</bean>

SDR默认采用JDK的序列化机制 使用JdkSerializationRedisSerializer类,进行对象和byte[]之间的相互转换,就像上面的序列化代码

这里是设置 keySerializer 为StringRedisSerializer 所以使用字符串形式的key

1
2
3
redisTemplate.opsForValue().set(key, value);
redisTemplate.opsForValue().get(key);
redisTemplate.delete(key);

更多api
http://docs.spring.io/spring-data/redis/docs/1.0.x/api/org/springframework/data/redis/core/RedisTemplate.html

Redis 整合 MyBatis

自定义类 继承myBatis 的cache接口 http://www.tuicool.com/articles/j2AzA3