springboot整合redis,通过自带注解和自定义注解实现自动缓存和更新缓存

配置文件

<!--   继承默认值为Spring Boot  -->
	<parent> 
		<groupId> org.springframework.boot </groupId> 
		<artifactId> spring-boot-starter-parent </artifactId> 
		<version> 2.0.4.RELEASE </version> 
	</parent>

	<dependencies> 
		<!-- SpringBoot web 核心组件 -->
		<dependency> 
			<groupId> org.springframework.boot </groupId> 
			<artifactId> spring-boot-starter-web </artifactId> 
		</dependency> 
		<!-- SpringBoot对Redis支持 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-redis</artifactId>
		</dependency>
		<!-- mysql -->
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
		</dependency>
		<!-- jpa 默认集成了hibernate。 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-jpa</artifactId>
		</dependency>
		<!-- aop依赖 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-aop</artifactId>
		</dependency>
		<!-- 热部署 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-devtools</artifactId>
			<optional>true</optional>
		</dependency>
		<!-- 测试包 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		 
	</dependencies>

	<!-- 作为可执行jar的包  -->
	<build> 
		<plugins> 
			<plugin> 
				<groupId> org.springframework.boot </groupId> 
				<artifactId> spring-boot-maven-plugin </artifactId> 
			</plugin > 
		</plugins> 
	</build>

application.yml配置

server:
  port: 8080
spring:
  jpa:
    database: mysql
    show-sql: true #显示执行的sql
    hibernate:
      ddl-auto: update #每次运行更新表
  jackson:
    serialization:
      fail-on-empty-beans: false
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/springboot-redis?useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true&useSSL=false
    username: root
    password: 123456
    driver-class-name: com.mysql.jdbc.Driver
  redis:
    database: 0
    host: #redis安装的服务器地址
    port: 6379
    password: #redis的密码
    jedis:
      pool:
        max-active: 10 # 连接池最大连接数(使用负值表示没有限制)
        max-wait: -1  # 连接池最大阻塞等待时间(使用负值表示没有限制)
        max-idle: 8  # 连接池中的最大空闲连接
        min-idle: 1 # 连接池中的最小空闲连接

代码实现

1.注解类

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
 * 该注解用于当redis中的信息修改之后,将查询的语句的redis缓存清除
 * @author MY
 *
 */
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Change {
	
	String key() default "";
	
}

2.aop类


import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import com.my.annotation.Change;

@Component
@Aspect
public class AnnotationAspect {
	
	@Autowired
	private RedisTemplate<String,String> redisTemplate;
	
	//要处理的key的后缀
	private static List<String> KEY = new ArrayList<String>();
	//要处理的key的前缀  如果使用@CacheConfig redis中key 的值会是
	private static List<String> CACHE_NAMES = new ArrayList<String>();
	
	private static String JOINT = ":";
	
	//切入点
	@Pointcut("execution(public * com.my.service.impl.*.*(..))")
	public void aspect() {
	}
	
	@Before("aspect()")
	public void doBefore(JoinPoint joinPoint) throws Throwable {
		//获取当前类
		Class<? extends Object> curClass = joinPoint.getTarget().getClass();
		//获取CacheConfig注解
		CacheConfig annotation = curClass.getAnnotation(CacheConfig.class);
		//判断CacheConfig注解是否存在
		if(annotation!=null) {
			if(annotation.cacheNames()!=null && annotation.cacheNames().length>0) {
				CACHE_NAMES = Arrays.asList(annotation.cacheNames());
			}
		}
		
		//获取类的所有方法
       Method[] methods = curClass.getMethods();
        for(Method method:methods){
        	//看是否存在方法上有change注解的方法
    		if(method.isAnnotationPresent(Change.class)){
    			Change chage = method.getAnnotation(Change.class);
    			String changeKey = chage.key();
    			if(changeKey!=null&&!"".equals(changeKey)) {
    				KEY.add(changeKey);
    			}else {
    				KEY.add(method.getName());
    			}
            }
        }		
	}
	@AfterReturning(returning = "ret", pointcut = "aspect()")
	public void doAfterReturning(Object ret) throws Throwable {
		
		List<String> deleteKeys = new ArrayList<String>();
		for(String prefix : CACHE_NAMES) {
			for(String suffix : KEY) {
			    //redis中存的key book::10
				deleteKeys.add(prefix+JOINT+JOINT+suffix);
			}
		}
		//请求成功,清空带有@Change标签方法的缓存
		redisTemplate.delete(deleteKeys);
		
	}
	
}

3.controller

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.my.entity.BookEntity;
import com.my.service.BookService;
@RestController
@RequestMapping("book")
public class BookController {

	@Autowired
	private BookService bookService;

	@RequestMapping("/save")
	public BookEntity save(@RequestBody BookEntity book) {
		return bookService.save(book);
	}
	
	@RequestMapping("/getById")
	public BookEntity getById(Long id) {
		BookEntity book = bookService.getBookById(id);
		return book;
	}
	
	@RequestMapping("/selectAll")
	public List<BookEntity> selectAll(){
		return bookService.selectAll();
	}
	
	@RequestMapping("/delete")
	public String delete(Long id) {
		bookService.deleteById(id);
		return "success";
	}
	
}

4.service

import java.util.List;

import com.my.entity.BookEntity;

public interface BookService {
	//更新或保存
	BookEntity save(BookEntity book);
	
	BookEntity getBookById(Long id);
	
	List<BookEntity> selectAll();
	
	void deleteById(Long id);
}

5.service实现

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import com.my.annotation.Change;
import com.my.entity.BookEntity;
import com.my.repository.BookRepository;
import com.my.service.BookService;

@Service
@CacheConfig(cacheNames = "book")//spring自带注解
public class BookServiceImpl implements BookService{
	@Autowired
	private BookRepository bookRepository;
	
	@CachePut(key = "#p0.id")//spring自带注解
	public BookEntity save(BookEntity book) {
		BookEntity bookEntity = bookRepository.save(book);
		return bookEntity;
	}
	@Cacheable(key = "#p0")//spring自带注解
	public BookEntity getBookById(Long id) {
		BookEntity bookEntity = bookRepository.getOne(id);
		return bookEntity;
	}
	@Change//自定义注解
	@Cacheable(key="#root.methodName")//spring自带注解
	public List<BookEntity> selectAll() {
		List<BookEntity> findAll = bookRepository.findAll();
		return findAll;
	}
	@CacheEvict(key = "#p0")//spring自带注解
	public void deleteById(Long id) {
		bookRepository.deleteById(id);
	}
}

6.repository

import org.springframework.data.jpa.repository.JpaRepository;

import com.my.entity.BookEntity;
/**
 * extends JpaRepository<T, ID> 
 * @author MY
 *
 */
public interface BookRepository extends JpaRepository<BookEntity, Long>{
	
}

7.entity

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

import org.hibernate.annotations.Proxy;

@Entity
@Table(name="book")
@Proxy(lazy = false)//注意,该注解一定要加,否则 查询之后,再次从缓存中取值会报错
public class BookEntity implements Serializable{

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	@Id//主键
	@GeneratedValue(strategy = GenerationType.IDENTITY)//主键由数据库自动生成(主要是自动增长型) 
	private Long id;
	@Column(name="book_name")
	private String bookName;
	@Column(name="book_author")
	private String bookAuthor;
	@Column(name="book_count")
	private Integer bookCount;
	public Long getId() {
		return id;
	}
	public void setId(Long id) {
		this.id = id;
	}
	public String getBookName() {
		return bookName;
	}
	public void setBookName(String bookName) {
		this.bookName = bookName;
	}
	public String getBookAuthor() {
		return bookAuthor;
	}
	public void setBookAuthor(String bookAuthor) {
		this.bookAuthor = bookAuthor;
	}
	public Integer getBookCount() {
		return bookCount;
	}
	public void setBookCount(Integer bookCount) {
		this.bookCount = bookCount;
	}
}

8.util

import java.util.concurrent.TimeUnit;

import javax.annotation.Resource;

import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;

@Component
public class RedisUtils {

	@Resource(name="redisTemplate")
    private RedisTemplate<String, Object> redisTemplate;
	
	//判断是否存在该key
	public boolean hasKey(String key) {
		return redisTemplate.hasKey(key);
	}
	
	//根据对应的class返回key对应的值
	public <T> T getValue(String key,Class<T> cls) {
		ValueOperations<String, Object> opsForValue = redisTemplate.opsForValue();
		Object object = opsForValue.get(key);
		return cls.cast(object);
	}
	//根据对应的key对应的值
	public Object getValue(String key) {
		ValueOperations<String, Object> opsForValue = redisTemplate.opsForValue();
		return opsForValue.get(key);
	}
	/**
	 * 将查询结果放入缓存
	 * 超期时间默认单位为分钟
	 * @param key key
	 * @param obj value
	 * @param time 超期时间
	 */
	public void setValue(String key, Object obj, int time) {
		ValueOperations<String, Object> opsForValue = redisTemplate.opsForValue();
		opsForValue.set(key, obj, time, TimeUnit.MINUTES);
	}
	/**
	 * 将查询结果放入缓存
	 * 超期时间默认1小时(60分钟)
	 * @param key key
	 * @param obj value
	 */
	public void setValue(String key, Object obj) {
		setValue(key, obj, 60);
	}
	
	//删除key
	public void deleteKey(String key) {
		redisTemplate.delete(key);
	}
}

9.启动类

package com.my;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;

@SpringBootApplication
@EnableCaching
public class ApplicationMain {

	public static void main(String[] args) {
		SpringApplication.run(ApplicationMain.class, args);
	}
}

遇到的坑

在这里插入图片描述
在实体对象加上@Proxy(lazy = false),再删除redis中原有的数据,重新请求就可以了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值