Open source project springredis

project address:

https://github.com/CarrowZhu/springredis

 

Project Description:

Implement redis caching operations based on spring-data-redis annotations

 

requirement

JDK6 
Spring4

 

Principle & Implementation

1) AOP
2) Implementation refers to Spring's Cache annotation
differences:
1) Support TTL 
2) Support Hash 

 

Configuration instructions

XML configuration file

xsi:schemaLocation=" http://www.siyuan.com/schema/springredis  
http://www.siyuan.com/schema/springredis/springredis.xsd
<springRedis:annotation-driven /> 
property description 
redisTemplate: Advice The redisTemplate to be used, the default is "redisTemplate" 
order: Advice execution order, the default priority is the highest (Ordered.HIGHEST_PRECEDENCE) 
exceptionHandler: beanId, operation exception handler, must implement the interface com.siyuan.springredis.interceptor.SpringRedisExceptionHandler, the default is com.siyuan.springredis.interceptor.LoggerExceptionHandler 

 

annotation

1) @SpringRedisConfig: Class level configuration 
property description 
value: equivalent to redisTemplate 
redisTemplate: (String) redisTemplate to be used in Advice 

2) @SpringRedisValueCache: method level, the data type of the operation is String 
Corresponding operation flow: read cache, hit return, miss -> get data -> cache 
attribute description 
value: equivalent to key 
redisTemplate: (String) redisTemplate to be used in Advice 
condition: (String) Support SpringEL, cache operation condition 
timeout: (long) TTL, <= 0 means never expire, default is 0 
timeUnit: (TimeUnit) TTL unit, default is TimeUnit.MILLISECONDS 
key: (String) Support SpringEL, The key value corresponding to the cache must be provided 
refreshTTL: (boolean) Whether to refresh the TTL when the cache hits, the default is false 

3) @SpringRedisValueEvict: method level, the data type of the operation is String 
Corresponding process: clear cache 
property description 
value: equivalent to key 
redisTemplate: (String) redisTemplate to be used in Advice 
condition: (String) Support SpringEL, cache operation condition 
key : (String) Support SpringEL, cache the corresponding key value, must provide 

4) @SpringRedisHashCache: method level, the data type of the operation is Hash 
Corresponding operation process: similar to @SpringRedisValueCache
property description 
value: equivalent to key 
redisTemplate: (String) redisTemplate to be used in Advice 
condition: (String) Support SpringEL, cache operation Condition 
timeout: (long) TTL, <= 0 means never expires, the default is 0 
timeUnit: (TimeUnit) TTL unit, the default is TimeUnit.MILLISECONDS 
key: (String) SpringEL is supported, the corresponding key value is cached, and 
refreshTTL must be provided: (boolean) Whether to refresh the TTL when the cache hits, the default is false 
hashKey: (String) Support SpringEL, cache the corresponding hashKey value, must provide 

5) @SpringRedisHashEvict: method level, the data type of operation is Hash 
corresponding process: similar to @SpringRedisValueEvict
attribute description 
value: equivalent to key 
redisTemplate: (String) redisTemplate to be used in Advice 
condition: (String) Support SpringEL, cache operation Condition 
key: (String) Support SpringEL, cache the corresponding key value, must provide 
hashKey: (String) Support SpringEL, cache the corresponding hashKey value, must provide 

 

SpringEL

Name > Location > Example 
methodName > root object > #root.methodName 
method > root object > #root.method.name 
target > root object > #root.target 
targetClass > root object > #root.targetClass 
args > root object > #root.args[0] 
argument name > evaluation context > #name (编译时必须保留方法名信息) 
result > evaluation context > #result 

 

Example

1)ApplicationContext-SpringRedis.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:springRedis="http://www.siyuan.com/schema/springredis"
	xmlns:p="http://www.springframework.org/schema/p"
	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-3.0.xsd
       http://www.siyuan.com/schema/springredis
       http://www.siyuan.com/schema/springredis/springredis.xsd">

	<springRedis:annotation-driven />
	<context:component-scan base-package="com.siyuan.springredis" />
	
	<bean id="jedisConnectionFactory"
        class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" />
        
    <bean id="stringRedisSerializer" class="org.springframework.data.redis.serializer.StringRedisSerializer"/>
    <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate"
        p:connection-factory-ref="jedisConnectionFactory" p:key-serializer-ref="stringRedisSerializer">
        <property name="defaultSerializer">
            <bean class="org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer" />
        </property>
    </bean>
    
    <bean id="studentRedisTemplate" class="org.springframework.data.redis.core.RedisTemplate"
        p:connection-factory-ref="jedisConnectionFactory"
        p:key-serializer-ref="stringRedisSerializer"
        p:hash-key-serializer-ref="stringRedisSerializer">
        <property name="defaultSerializer">
            <bean class="org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer">
                <constructor-arg index="0" value="#{T(com.siyuan.springredis.Student)}" />
            </bean>
        </property>
    </bean>
    
</beans>

 2)Student.java

package com.siyuan.springredis;

public class Student {
	
	private Long id;
	
	private String name;
	
	public Student() {
	}
	
	public Student(Long id, String name) {
		this.id = id;
		this.name = name;
	}

	public Long getId() {
		return id;
	}

	public void setId(Long id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((id == null) ? 0 : id.hashCode());
		result = prime * result + ((name == null) ? 0 : name.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Student other = (Student) obj;
		if (id == null) {
			if (other.id != null)
				return false;
		} else if (!id.equals(other.id))
			return false;
		if (name == null) {
			if (other.name != null)
				return false;
		} else if (!name.equals(other.name))
			return false;
		return true;
	}

	@Override
	public String toString() {
		return "Student [id=" + id + ", name=" + name + "]";
	}

}

3)StudentDAO.java 

package com.siyuan.springredis;

public interface StudentDAO {
	
	Student getById(long id);
	
	void updateStudent(Student student);
	
}

4)StudentService.java 

package com.siyuan.springredis;

import java.util.concurrent.TimeUnit;

import org.springframework.stereotype.Service;

import com.siyuan.springredis.annotation.SpringRedisConfig;
import com.siyuan.springredis.annotation.SpringRedisHashCache;
import com.siyuan.springredis.annotation.SpringRedisHashEvict;
import com.siyuan.springredis.annotation.SpringRedisValueCache;
import com.siyuan.springredis.annotation.SpringRedisValueEvict;

@Service("studentService")
@SpringRedisConfig("studentRedisTemplate")
public class StudentService {
	
	private StudentDAO studentDAO;
	
	@SpringRedisValueCache(key = "'student:' + #id", condition = "#id > 100",
			timeout = 60, timeUnit = TimeUnit.MINUTES, refreshTTL = true)
	public Student getById(long id) {
		return studentDAO.getById(id);
	}
	
	@SpringRedisValueEvict(key = "'student:' + #student.id", condition = "#student.id > 100")
	public void updateStudent(Student student) {
		studentDAO.updateStudent(student);
	}
	
	@SpringRedisHashCache(key = "'students'", hashKey = "#id.toString()", condition = "#id > 100",
			timeout = 60, timeUnit = TimeUnit.MINUTES, refreshTTL = true)
	public Student getById2(long id) {
		return studentDAO.getById(id);
	}
	
	@SpringRedisHashEvict(key = "'students'", hashKey = "#student.id.toString()", condition = "#student.id > 100")
	public void updateStudent2(Student student) {
		studentDAO.updateStudent(student);
	}
	
	public StudentDAO getStudentDAO() {
		return studentDAO;
	}

	public void setStudentDAO(StudentDAO studentDAO) {
		this.studentDAO = studentDAO;
	}
	
}

5)StudentServiceTest.java 

package com.siyuan.springredis.test;

import org.junit.After;

import static org.junit.Assert.*;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;

import static org.mockito.Mockito.*;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.siyuan.springredis.Student;
import com.siyuan.springredis.StudentDAO;
import com.siyuan.springredis.StudentService;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "/ApplicationContext-SpringRedis.xml")
public class StudentServiceTest {
	
	@Autowired
	@Qualifier("studentRedisTemplate")
	private RedisTemplate<String, Student> redisTemplate;
	
	@Autowired
	private StudentService service;
	
	private StudentDAO studentDAO;
	
	private StudentDAO mock;
	
	@Before
	public void setUp() {
		redisTemplate.delete("student:123");
		redisTemplate.delete("student:100");
		redisTemplate.delete("students");
		studentDAO = service.getStudentDAO();
		mock = mock(StudentDAO.class);
		service.setStudentDAO(mock);
	}
	
	@Test
	public void testGetById() {
		when(mock.getById(123L)).thenReturn(new Student(123L, "name:123"));
		// don't cache
		Student stu = service.getById(123L);
		assertArrayEquals(new Object[] { new Student(123L, "name:123") }, new Object[] { stu });
		// cache
		stu = service.getById(123L);
		assertArrayEquals(new Object[] { new Student(123L, "name:123") }, new Object[] { stu });
		verify(mock, times(1)).getById(123L);
		
		when(mock.getById(100L)).thenReturn(new Student(100L, "name:100"));
		// don't cache
		stu = service.getById(100L);
		assertArrayEquals(new Object[] { new Student(100L, "name:100") }, new Object[] { stu });
		// don't cache
		stu = service.getById(100L);
		assertArrayEquals(new Object[] { new Student(100L, "name:100") }, new Object[] { stu });
		verify(mock, times(2)).getById(100L);
	}
	
	@Test
	public void testUpdateStudent() {
		// evict
		Student stu = new Student(123L, "name:123");
		redisTemplate.opsForValue().set("student:123", stu);
		service.updateStudent(stu);
		assertNull(redisTemplate.opsForValue().get("student:123"));
		
		// do not evict
		stu = new Student(100L, "name:100");
		redisTemplate.opsForValue().set("student:100", stu);
		service.updateStudent(stu);
		assertNotNull(redisTemplate.opsForValue().get("student:100"));
	}
	
	@Test
	public void testGetById2() {
		when(mock.getById(123L)).thenReturn(new Student(123L, "name:123"));
		// don't cache
		Student stu = service.getById2(123L);
		assertArrayEquals(new Object[] { new Student(123L, "name:123") }, new Object[] { stu });
		// cache
		stu = service.getById2(123L);
		assertArrayEquals(new Object[] { new Student(123L, "name:123") }, new Object[] { stu });
		verify(mock, times(1)).getById(123L);
		
		when(mock.getById(100L)).thenReturn(new Student(100L, "name:100"));
		// don't cache
		stu = service.getById2(100L);
		assertArrayEquals(new Object[] { new Student(100L, "name:100") }, new Object[] { stu });
		// don't cache
		stu = service.getById2(100L);
		assertArrayEquals(new Object[] { new Student(100L, "name:100") }, new Object[] { stu });
		verify(mock, times(2)).getById(100L);
	}
	
	@Test
	public void testUpdateStudent2() {
		// evict
		Student stu = new Student(123L, "name:123");
		redisTemplate.opsForHash().put("students", "123", stu);
		service.updateStudent2(stu);
		assertNull(redisTemplate.opsForHash().get("students", "123"));
		
		// do not evict
		stu = new Student(100L, "name:100");
		redisTemplate.opsForHash().put("students", "100", stu);
		service.updateStudent2(stu);
		assertNotNull(redisTemplate.opsForHash().get("students", "100"));
	}
	
	@After
	public void clear() {
		service.setStudentDAO(studentDAO);
	}

}

 

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=326594527&siteId=291194637