ehcache:
实体对象,要序列化(与sring整合)
@Builder
@Data
public class User implements Serializable {
private Long id;
private String name;
}
单独使用:
1.引入依赖
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>2.10.6</version>
</dependency>
2.ehcache.xml编写
<?xml version="1.0" encoding="utf-8" ?>
<ehcache
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://www.ehcache.org/ehcache.xsd">
<diskStore path="java.io.tmpdir"/>
<cache
name="user_cache"
maxEntriesLocalHeap="1000"
eternal="false"
timeToIdleSeconds="600"
timeToLiveSeconds="6000"
maxElementsOnDisk="10000000"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU"
statistics="true"
>
<persistence strategy="localTempSwap"/>
</cache>
</ehcache>
3.api使用
@Test
public void test1(){
String absPath = "D:\java\idea\IdeaProject2\cache\echache\src\main\resources\ehcache\ehcache.xml";
CacheManager cacheManager = CacheManager.create(absPath);
String[] cacheNames = cacheManager.getCacheNames();
System.out.println("获取到的cache的名字:" + Arrays.toString(cacheNames));
Cache userCache = cacheManager.getCache("user_cache");
User user = User.builder().id(123L).name("WMH").build();
Element element = new Element(user.getId(),user);
userCache.put(element);
Element resultEle = userCache.get(123L);
System.out.println("获取到的resultEle:" + resultEle);
System.out.println("获取到的resultEle的Value:" + resultEle.getObjectValue());
}
与spring集成:
ehcache与spring的集成方式:
- 1.AnnotationConfigApplicationContext
- 2.xml
spring的缓存抽象的方式
- 1.编程式操作
- 2.使用注解 如@Cacheable
序列化报错解决方式:
- 1.不序列化到磁盘,在ehcache.xml添加配置
- 2.序列化到磁盘:user实现序列化接口
引入spring的cache支持
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
</dependency>
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
</dependency>
<dependency>
<groupId>cn.pomit</groupId>
<artifactId>Mybatis</artifactId>
<version>${project.version}</version>
</dependency>
编程式操作:
1.ehcache.xml配置文件同上,配置cache信息(实体类不序列化到磁盘)
<persistence strategy="none"/>
2.spring-ehcache.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:cache="http://www.springframework.org/schema/cache"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/cache
http://www.springframework.org/schema/cache/spring-cache-4.0.xsd">
<bean
id="ehCacheManager"
class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
<property name="configLocation" value="classpath:ehcache/ehcache.xml"/>
</bean>
<bean id="ehCacheCacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager">
<property name="cacheManager" ref="ehCacheManager"/>
<property name="transactionAware" value="true"/>
</bean>
<cache:annotation-driven proxy-target-class="true" cache-manager="ehCacheCacheManager"/>
</beans>
3.测试使用
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(value = {"classpath:ehcache/spring-ehcache.xml"})
public class SpringEhcacheTest {
@Resource
private CacheManager cacheManager;
@Test
public void test1(){
Cache userCache = cacheManager.getCache("user_cache");
User user = User.builder().id(123L).name("WMH").build();
userCache.put(user.getId(),user);
System.out.println("获取的对象:"+userCache.get(123L,User.class));
}
}
注解式使用:
1.ehcache.xml 文件同上,spring-ehcache.xml,需要注入serviceImpl,也可改为config类
<?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:cache="http://www.springframework.org/schema/cache"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/cache
http://www.springframework.org/schema/cache/spring-cache-4.0.xsd ">
<bean id="ehCacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
<property name="configLocation" value="classpath:ehcache/ehcache.xml"/>
</bean>
<bean id="concurrentMapCacheManager" class="org.springframework.cache.concurrent.ConcurrentMapCacheManager">
<property name="cacheNames">
<list>
<value>user_cache</value>
<value>store_cache</value>
</list>
</property>
</bean>
<cache:annotation-driven proxy-target-class="true" cache-manager="concurrentMapCacheManager"/>
<bean class="com.suisui.service.impl.UserServiceImpl"/>
</beans>
2.serviceImpl实现类
@CacheConfig(cacheNames = {"user_cache"})
public class UserServiceImpl implements UserService {
@Override
@Cacheable(key="#id")
public User getById(Long id) {
System.out.println("模拟查询数据库");
User user = User.builder().id(id).name("哇哈哈").build();
return user;
}
}
测试使用:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(value = {"classpath:ehcache/spring-ehcache.xml"})
public class SpringEhcacheTest {
@Resource
private CacheManager cacheManager;
@Resource
private UserService userService;
@Test
public void test2(){
User byId = userService.getById(3L);
System.out.println("信息:"+byId);
System.out.println("信息2:"+userService.getById(3L));
System.out.println("信息3:"+userService.getById(3L));
}
}
与springboot集成:
ehcache与springboot整合
- 1.在application.yml中指定ehcache的配置文件
- 2.启动类加@EnableCaching
1.配置文件
spring:
cache:
ehcache:
config: classpath:ehcache/ehcache.xml(同上)
2.添加注解@EnableCaching启用注解
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
@EnableCaching
public class SpringBootEhcache {
public static void main(String[] args) {
SpringApplication.run(SpringApplication.class,args);
}
}
3.serviceImpl编写
@Service
public class UserServiceImpl implements UserService {
@Override
public User getById(Long id) {
System.out.println("模拟查询数据库");
User user = User.builder().id(id).name("哇哈哈").build();
return user;
}
}
3.使用
@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringBootEhcacheTest {
@Resource
private CacheManager cacheManager;
@Resource
private UserService userService;
@Test
public void test1(){
System.out.println(cacheManager.getClass());
User byId = userService.getById(3L);
System.out.println(byId);
System.out.println(userService.getById(3L));
System.out.println(userService.getById(3L));
}
}
guava cache:
引入依赖
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>29.0-jre</version>
</dependency>
单独使用:
单独使用guava的cache,有两种
- 1.com.google.common.cache.LocalCache.LocalLoadingCache
特点:缓存中获取不到值,会根据指定的loader进行加载后自动放入缓存 - 2.com.google.common.cache.LocalCache.LocalManualCache
特点:类似ehcache
public class LoadingCacheTest {
@Test
public void test1() throws Exception {
LoadingCache<Long, User> loadingCache = CacheBuilder.newBuilder()
.concurrencyLevel(8)
.initialCapacity(60)
.maximumSize(10)
.expireAfterWrite(3, TimeUnit.SECONDS)
.recordStats()
.removalListener(new RemovalListener<Long, User>() {
@Override
public void onRemoval(RemovalNotification<Long, User> notification) {
Long key = notification.getKey();
RemovalCause cause = notification.getCause();
System.out.println("key:" + key+",被移出缓存,原因:"+cause);
}
})
.build(new CacheLoader<Long, User>() {
@Override
public User load(Long key) throws Exception {
System.out.println("去存储中加载");
User user = User.builder().id(key).name("哇哈哈").build();
return user;
}
});
for (long i = 0; i < 20; i++) {
User user = loadingCache.getUnchecked(999L);
System.out.println(user);
TimeUnit.SECONDS.sleep(1);
}
System.out.println("统计信息"+loadingCache.stats().toString());
}
}
spring/springboot集成:
spring或者springboot集成任何第三方框架:
- 1.xml或者在@Configuration中@bean
- 2.springboot:stater或@Configuration中@bean注入
1.编写GuavaCacheManager
public class GuavaCacheManager extends AbstractCacheManager {
@Override
protected Collection<? extends Cache> loadCaches() {
com.google.common.cache.Cache<Object,Object> userCache = CacheBuilder.newBuilder()
.maximumSize(100)
.build();
GuavaCache guavaUsercache = new GuavaCache("user_cache", userCache);
Collection<Cache> caches = new LinkedHashSet();
caches.add(guavaUsercache);
return caches;
}
}
2.GuavaCache 编写
public class GuavaCache implements Cache {
private String cacheName;
private com.google.common.cache.Cache<Object,Object> internalCache;
public GuavaCache(String cacheName, com.google.common.cache.Cache<Object, Object> internalCache) {
this.cacheName = cacheName;
this.internalCache = internalCache;
}
@Override
public String getName() {
return cacheName;
}
@Override
public Object getNativeCache() {
return internalCache;
}
@Override
public ValueWrapper get(Object key) {
Object obj = internalCache.getIfPresent(key);
if(obj != null){
return new SimpleValueWrapper(obj);
}
return null;
}
@Override
public <T> T get(Object key, Class<T> aClass) {
throw new RuntimeException("参考get实现");
}
@Override
public <T> T get(Object key, Callable<T> callable) {
throw new RuntimeException("参考get实现");
}
@Override
public void put(Object key, Object value) {
internalCache.put(key,value);
}
@Override
public void evict(Object key) {
internalCache.invalidate(key);
}
@Override
public void clear() {
internalCache.invalidateAll();
}
}
3.spring-guava-cache.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:cache="http://www.springframework.org/schema/cache"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/cache
http://www.springframework.org/schema/cache/spring-cache-4.0.xsd">
<bean id="guavaCacheManager" class="com.suisui.guava.GuavaCacheManager"></bean>
<cache:annotation-driven proxy-target-class="true" cache-manager="guavaCacheManager"/>
<bean class="com.suisui.service.impl.UserServiceImpl"/>
</beans>
4.UserServiceImpl编写
@Service
@CacheConfig(cacheNames = {"user_cache"})
public class UserServiceImpl implements UserService {
@Override
@Cacheable(key="#id")
public User getById(Long id) {
System.out.println("模拟查询数据库");
User user = User.builder().id(id).name("哇哈哈").build();
return user;
}
}
5.测试
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(value = {"classpath:guava/spring-guava-cache.xml"})
public class SpringGuavaCacheTest {
@Resource
private GuavaCacheManager cacheManager;
@Resource
private UserService userService;
@Test
public void test1(){
System.out.println(cacheManager.getClass());
User byId = userService.getById(3L);
System.out.println(byId);
System.out.println(userService.getById(3L));
System.out.println(userService.getById(3L));
}
}
自定义KeyGenerator:
1.编写MyKeyGenerator
public class MyKeyGenerator implements KeyGenerator {
@Override
public Object generate(Object target, Method method, Object... params) {
StringBuilder finalKey = new StringBuilder();
finalKey.append(target.getClass().getName()).append(".")
.append(method.getName()).append(".");
if(params == null || params.length == 0){
return finalKey.append(0).toString();
}
for(Object param :params){
if(param == null){
finalKey.append("null");
}else if(ClassUtils.isPrimitiveArray(param.getClass())){
int length = Array.getLength(param);
for (int i = 0; i < length; i++) {
finalKey.append(Array.get(param,i)).append(",");
}
}else if(ClassUtils.isPrimitiveOrWrapper(param.getClass()) || param instanceof String){
finalKey.append(param);
}else{
String paramStr = JSON.toJSONString(param);
long murmurHash = Hashing.murmur3_128().hashString(paramStr, StandardCharsets.UTF_8).asLong();
finalKey.append(murmurHash);
}
finalKey.append("-");
}
System.out.println("最终的Key: "+finalKey);
return finalKey;
}
}
2.spring-guava-cache.xml(指定KeyGenerator)
<?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:cache="http://www.springframework.org/schema/cache"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/cache
http://www.springframework.org/schema/cache/spring-cache-4.0.xsd">
<bean id="guavaCacheManager" class="com.suisui.guava.GuavaCacheManager"></bean>
<bean id="keyGenerator" class="com.suisui.key.MyKeyGenerator"></bean>
<cache:annotation-driven proxy-target-class="true" cache-manager="guavaCacheManager" key-generator="keyGenerator"/>
<bean class="com.suisui.service.impl.UserServiceImpl"/>
</beans>
3.UserServiceImpl编写
@Service
@CacheConfig(cacheNames = {"user_cache"})
public class UserServiceImpl implements UserService {
@Override
@Cacheable
public User getUser(User queryParam, int[] arr,String str) {
System.out.println("模拟查询数据库--测试自定义keyGenerator");
User user = User.builder().id(99L).name("java 数据").build();
return user;
}
}
4.测试自定义keyGenerator
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(value = {"classpath:ehcache/spring-guava-cache.xml"})
public class SpringGuavaCacheTest {
@Resource
private GuavaCacheManager cacheManager;
@Resource
private UserService userService;
@Test
public void test2(){
User queryParam = User.builder().id(66L).name("碎金").build();
int[] arr = new int[2];
arr[0] = 1;
arr[1] = 2;
String str = "abc";
User user = userService.getUser(queryParam, arr,str);
System.out.println(user);
System.out.println(userService.getUser(queryParam, arr,str));
System.out.println(userService.getUser(queryParam, arr,str));
}
}
自定义缓存
缓存应具备的功能:
1.最大能放多少个,溢出淘汰的机制:FIFO,LRU,LFU
- 淘汰最先放入缓存的数据,即FIFO(First In First Out)
- 淘汰最久未使用的数据,即 LRU(Least Recently Used)
- 淘汰使用频率低的数据,即LFO(Least Frequently Used)
2.过期需要清除 3.内存敏感(不能因为缓存的原因导致业余程序的OOM) 4.线程的安全 5.统计命中率 6.序列化扩展
LRU淘汰策略的实现
基于LinkedHashMap实现
LinkedHashMap测试:
@Test
public void test1(){
LinkedHashMap<String, String> linkedHashMap = new LinkedHashMap<>(16,0.75f,true);
linkedHashMap.put("a","a_value");
linkedHashMap.put("b","b_value");
linkedHashMap.put("c","c_value");
System.out.println(linkedHashMap);
String bValue = linkedHashMap.get("b");
System.out.println("b的值:" + bValue);
System.out.println(linkedHashMap);
}
1.缓存功能接口
public interface Cache {
void put(Object key,Object value);
void remove(Object key,Object value);
void clear();
Object get(Object key);
int size();
}
2.基于LinkedHashMap实现缓存:
public class CacheVersion1 implements Cache {
private int capacity;
private InternalCache internalCache;
public CacheVersion1(int capacity) {
this.capacity = capacity;
internalCache = new InternalCache(capacity);
}
private static class InternalCache extends LinkedHashMap<Object,Object>{
private int capacity;
public InternalCache(int capacity) {
super(16,0.75f,true);
this.capacity = capacity;}
@Override
protected boolean removeEldestEntry(Map.Entry<Object, Object> eldest) {
return size() > capacity;
}
}
@Override
public void put(Object key, Object value) {
internalCache.put(key,value);
}
@Override
public void remove(Object key, Object value) {
internalCache.remove(key,value);
}
@Override
public void clear() {
internalCache.clear();
}
@Override
public Object get(Object key) {
return internalCache.get(key);
}
@Override
public int size() {
return internalCache.size();
}
@Override
public String toString() {
return "CacheVersion1{" +
"capacity=" + capacity +
", internalCache=" + internalCache +
'}';
}
}
3.测试
@Test
public void test2(){
CacheVersion1 cache = new CacheVersion1(3);
cache.put("a","a_value");
cache.put("b","b_value");
cache.put("c","c_value");
System.out.println(cache);
String bValue = (String)cache.get("b");
System.out.println("b的值:"+bValue);
System.out.println(cache);
}
基于LinkedList实现
缓存接口同上,基于LinkedList实现缓存:
public class CacheVersion2 implements Cache {
private int capacity;
private LinkedList<Object> keyList;
private Map<Object,Object> internalCache;
public CacheVersion2(int capacity) {
this.capacity = capacity;
internalCache = new HashMap<>();
keyList = new LinkedList<>();
}
@Override
public void put(Object key, Object value) {
if(size() == capacity){
Object firstKey = keyList.removeFirst();
internalCache.remove(firstKey);
}
keyList.addLast(key);
internalCache.put(key,value);
}
@Override
public void remove(Object key, Object value) {
keyList.remove(key);
internalCache.remove(key,value);
}
@Override
public void clear() {
keyList.clear();
internalCache.clear();
}
@Override
public Object get(Object key) {
boolean removeResult = keyList.remove(key);
if(removeResult){
Object value = internalCache.get(key);
keyList.addLast(key);
return value;
}
return null;
}
@Override
public int size() {
return keyList.size();
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
for (Object key : keyList) {
sb.append("key").append(key).append(",")
.append("value:").append(internalCache.get(key))
.append("-");
}
return sb.toString();
}
}
测试:
@Test
public void test3(){
CacheVersion2 cache = new CacheVersion2(3);
cache.put("a","a_value");
cache.put("b","b_value");
cache.put("c","c_value");
System.out.println(cache);
String bValue = (String)cache.get("b");
System.out.println("b的值:"+bValue);
System.out.println(cache);
cache.put("d","d_value");
System.out.println(cache);
}
内存敏感能力的实现
强引用:只要有引用就不会被回收,基本OOM 软引用:gc且堆内存吃紧时才会被回收(适合) 弱引用:每次gc都会被回收 虚引用:随时都有可能被回收
@Test
public void test() throws InterruptedException {
CacheVersion1 cache = new CacheVersion1(99999);
for (int i = 1; i < Integer.MAX_VALUE; i++) {
Dept dept = new Dept((long)i);
cache.put(dept.getId(),dept);
TimeUnit.SECONDS.sleep(1);
}
}
设置参数: 结果: 内存敏感实现(get()/put()):
public class CacheVersion1final implements Cache {
private int capacity;
private InternalCache internalCache;
public CacheVersion1final(int capacity) {
this.capacity = capacity;
internalCache = new InternalCache(capacity);
}
private static class InternalCache extends LinkedHashMap<Object,Object>{
private int capacity;
public InternalCache(int capacity) {
super(16,0.75f,true);
this.capacity = capacity;}
@Override
protected boolean removeEldestEntry(Map.Entry<Object, Object> eldest) {
return size() > capacity;
}
}
@Override
public void put(Object key, Object value) {
SoftReference<Object> softReference = new SoftReference<>(value);
internalCache.put(key,softReference);
}
@Override
public void remove(Object key, Object value) {
internalCache.remove(key,value);
}
@Override
public void clear() {
internalCache.clear();
}
@Override
public Object get(Object key) {
Object o = internalCache.get(key);
if(o == null){
return null;
}
SoftReference<Object> softReference = (SoftReference<Object>) o;
return softReference.get();
}
@Override
public int size() {
return internalCache.size();
}
@Override
public String toString() {
return "CacheVersion1{" +
"capacity=" + capacity +
", internalCache=" + internalCache +
'}';
}
}
测试弱引用:
@Test
public void test5() throws InterruptedException {
CacheVersion1final cache = new CacheVersion1final(99999);
for (int i = 1; i < Integer.MAX_VALUE; i++) {
System.out.println("放入第"+i+"个");
Dept dept = new Dept((long)i);
cache.put(dept.getId(),dept);
}
}
|