真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

淺談SpringBoot集成Redis實現(xiàn)緩存處理(SpringAOP實現(xiàn))

第一章 需求分析

武山網(wǎng)站制作公司哪家好,找成都創(chuàng)新互聯(lián)!從網(wǎng)頁設(shè)計、網(wǎng)站建設(shè)、微信開發(fā)、APP開發(fā)、成都響應(yīng)式網(wǎng)站建設(shè)等網(wǎng)站項目制作,到程序開發(fā),運(yùn)營維護(hù)。成都創(chuàng)新互聯(lián)2013年開創(chuàng)至今到現(xiàn)在10年的時間,我們擁有了豐富的建站經(jīng)驗和運(yùn)維經(jīng)驗,來保證我們的工作的順利進(jìn)行。專注于網(wǎng)站建設(shè)就選成都創(chuàng)新互聯(lián)。

計劃在Team的開源項目里加入redis實現(xiàn)緩存處理,因為業(yè)務(wù)功能已經(jīng)實現(xiàn)了一部分,通過寫Redis工具類,然后引用,改動量較大,而且不可以實現(xiàn)解耦合,所以想到了Spring框架的AOP(面向切面編程)。

開源項目:https://github.com/u014427391/jeeplatform

第二章 SpringBoot簡介

Spring框架作為JavaEE框架領(lǐng)域的一款重要的開源框架,在企業(yè)應(yīng)用開發(fā)中有著很重要的作用,同時Spring框架及其子框架很多,所以知識量很廣。

SpringBoot:一款Spring框架的子框架,也可以叫微框架,是2014年推出的一款使Spring框架開發(fā)變得容易的框架。學(xué)過Spring框架的都知識,Spring框架難以避免地需要配置不少XMl,而使用SpringBoot框架的話,就可以使用注解開發(fā),極大地簡化基于Spring框架的開發(fā)。SpringBoot充分利用了JavaConfig的配置模式以及“約定優(yōu)于配置”的理念,能夠極大的簡化基于SpringMVC的Web應(yīng)用和REST服務(wù)開發(fā)。

第三章 Redis簡介

3.1 Redis安裝部署(Linux)

Redis安裝部署的可以參考我的博客(Redis是基于C編寫的,所以安裝前先安裝gcc編譯器):https://www.jb51.net/article/79096.htm

3.2 Redis簡介

Redis如今已經(jīng)成為Web開發(fā)社區(qū)最火熱的內(nèi)存數(shù)據(jù)庫之一,隨著Web2.0的快速發(fā)展,再加上半結(jié)構(gòu)數(shù)據(jù)比重加大,網(wǎng)站對高效性能的需求也越來越多。

而且大型網(wǎng)站一般都有幾百臺或者更多Redis服務(wù)器。Redis作為一款功能強(qiáng)大的系統(tǒng),無論是存儲、隊列還是緩存系統(tǒng),都有其用武之地。

SpringBoot框架入門的可以參考之前的文章:https://www.jb51.net/article/111197.htm

第四章 Redis緩存實現(xiàn)

4.1下面結(jié)構(gòu)圖

項目結(jié)構(gòu)圖:

淺談SpringBoot集成Redis實現(xiàn)緩存處理(Spring AOP實現(xiàn)) 

4.2 SpringBoot的yml文件配置

添加resource下面的application.yml配置,這里主要配置MySQL,druid,redis

spring:
 datasource:
  # 主數(shù)據(jù)源
  shop:
   url: jdbc:mysql://127.0.0.1:3306/jeeplatform?autoReconnect=true&useUnicode=true&characterEncoding=utf8&characterSetResults=utf8&useSSL=false
   username: root
   password: root
  driver-class-name: com.mysql.jdbc.Driver
  type: com.alibaba.druid.pool.DruidDataSource

  # 連接池設(shè)置
  druid:
   initial-size: 5
   min-idle: 5
   max-active: 20
   # 配置獲取連接等待超時的時間
   max-wait: 60000
   # 配置間隔多久才進(jìn)行一次檢測,檢測需要關(guān)閉的空閑連接,單位是毫秒
   time-between-eviction-runs-millis: 60000
   # 配置一個連接在池中最小生存的時間,單位是毫秒
   min-evictable-idle-time-millis: 300000
   # Oracle請使用select 1 from dual
   validation-query: SELECT 'x'
   test-while-idle: true
   test-on-borrow: false
   test-on-return: false
   # 打開PSCache,并且指定每個連接上PSCache的大小
   pool-prepared-statements: true
   max-pool-prepared-statement-per-connection-size: 20
   # 配置監(jiān)控統(tǒng)計攔截的filters,去掉后監(jiān)控界面sql無法統(tǒng)計,'wall'用于防火墻
   filters: stat,wall,slf4j
   # 通過connectProperties屬性來打開mergeSql功能;慢SQL記錄
   connection-properties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
   # 合并多個DruidDataSource的監(jiān)控數(shù)據(jù)
   use-global-data-source-stat: true
 jpa:
  database: mysql
  hibernate:
   show_sql: true
   format_sql: true
   ddl-auto: none
   naming:
    physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
 mvc:
  view:
   prefix: /WEB-INF/jsp/
   suffix: .jsp
 #Jedis配置
 jedis :
  pool :
   host : 127.0.0.1
   port : 6379
   password : password
   timeout : 0
   config :
    maxTotal : 100
    maxIdle : 10
    maxWaitMillis : 100000

編寫一個配置類啟動配置JedisConfig.java:

package org.muses.jeeplatform.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
@Configuration
//@ConfigurationProperties(prefix = JedisConfig.JEDIS_PREFIX )
public class JedisConfig {
  //public static final String JEDIS_PREFIX = "jedis";
  @Bean(name= "jedisPool")
  @Autowired
  public JedisPool jedisPool(@Qualifier("jedisPoolConfig") JedisPoolConfig config,
                  @Value("${spring.jedis.pool.host}")String host,
                  @Value("${spring.jedis.pool.port}")int port,
                  @Value("${spring.jedis.pool.timeout}")int timeout,
                  @Value("${spring.jedis.pool.password}")String password) {
      return new JedisPool(config, host, port,timeout,password);
  }

  @Bean(name= "jedisPoolConfig")
  public JedisPoolConfig jedisPoolConfig (@Value("${spring.jedis.pool.config.maxTotal}")int maxTotal,
                        @Value("${spring.jedis.pool.config.maxIdle}")int maxIdle,
                        @Value("${spring.jedis.pool.config.maxWaitMillis}")int maxWaitMillis) {
      JedisPoolConfig config = new JedisPoolConfig();
      config.setMaxTotal(maxTotal);
      config.setMaxIdle(maxIdle);
      config.setMaxWaitMillis(maxWaitMillis);
      return config;
    }
}

4.3 元注解類編寫

編寫一個元注解類RedisCache.java,被改注解定義的類都自動實現(xiàn)AOP緩存處理

package org.muses.jeeplatform.annotation;
import org.muses.jeeplatform.common.RedisCacheNamespace;
import java.lang.annotation.*;

/**
 * 元注解 用來標(biāo)識查詢數(shù)據(jù)庫的方法
 */
@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RedisCache {
//  RedisCacheNamespace nameSpace();
}

JDK 5提供的注解,除了Retention以外,還有另外三個,即Target 、Inherited 和 Documented?;谶@個,我們可以實現(xiàn)自定義的元注解

我們設(shè)置RedisCache基于Method方法級別引用。

1.RetentionPolicy.SOURCE 這種類型的Annotations只在源代碼級別保留,編譯時就會被忽略
2.RetentionPolicy.CLASS 這種類型的Annotations編譯時被保留,在class文件中存在,但JVM將會忽略
3.RetentionPolicy.RUNTIME 這種類型的Annotations將被JVM保留,所以他們能在運(yùn)行時被JVM或其他使用反射機(jī)制的代碼所讀取和使用.

4.4 調(diào)用JedisPool實現(xiàn)Redis緩存處理

package org.muses.jeeplatform.cache;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import javax.annotation.Resource;
@Component("redisCache")
public class RedisCache {
  
  @Autowired
  private JedisPool jedisPool;
  private JedisPool getJedisPool(){
    return jedisPool;
  }  
  public void setJedisPool(JedisPool jedisPool){
    this.jedisPool = jedisPool;
  }
  
  /**
   * 從Redis緩存獲取數(shù)據(jù)
   * @param redisKey
   * @return
   */
  public Object getDataFromRedis(String redisKey){
    Jedis jedis = jedisPool.getResource();
    byte[] byteArray = jedis.get(redisKey.getBytes());
    
    if(byteArray != null){
      return SerializeUtil.unSerialize(byteArray);
    }
    return null;
  }
  
  /**
   * 保存數(shù)據(jù)到Redis
   * @param redisKey
   */
  public String saveDataToRedis(String redisKey,Object obj){    
    byte[] bytes = SerializeUtil.serialize(obj);    
    Jedis jedis = jedisPool.getResource();    
    String code = jedis.set(redisKey.getBytes(), bytes);    
    return code;
  }
}

對象序列化的工具類:

package org.muses.jeeplatform.cache;
import java.io.*;
public class SerializeUtil {  
  /**
   * 序列化對象
   * @param obj
   * @return
   */
  public static byte[] serialize(Object obj){
    ObjectOutputStream oos = null;
    ByteArrayOutputStream baos = null;
    try{
      baos = new ByteArrayOutputStream();
      oos = new ObjectOutputStream(baos);
      
      oos.writeObject(obj);
      byte[] byteArray = baos.toByteArray();
      return byteArray;
      
    }catch(IOException e){
      e.printStackTrace();
    }
    return null;
  }
  
  /**
   * 反序列化對象
   * @param byteArray
   * @return
   */
  public static Object unSerialize(byte[] byteArray){
    ByteArrayInputStream bais = null;
    try {
      //反序列化為對象
      bais = new ByteArrayInputStream(byteArray);
      ObjectInputStream ois = new ObjectInputStream(bais);
      return ois.readObject();      
    } catch (Exception e) {
      e.printStackTrace();
    }
    return null;
  }  
}

這里記得Vo類都要實現(xiàn)Serializable

例如菜單信息VO類,這是一個JPA映射的實體類

package org.muses.jeeplatform.core.entity.admin;
import javax.persistence.*;
import java.io.Serializable;
import java.util.List;

/**
 * @description 菜單信息實體
 * @author Nicky
 * @date 2017年3月17日
 */
@Table(name="sys_menu")
@Entity
public class Menu implements Serializable {
  /** 菜單Id**/
  private int menuId;  
  /** 上級Id**/
  private int parentId;  
  /** 菜單名稱**/
  private String menuName;  
  /** 菜單圖標(biāo)**/
  private String menuIcon;  
  /** 菜單URL**/
  private String menuUrl;  
  /** 菜單類型**/
  private String menuType;  
  /** 菜單排序**/
  private String menuOrder;
  /**菜單狀態(tài)**/
  private String menuStatus;
  private List subMenu;
  private String target;
  private boolean hasSubMenu = false;
  public Menu() {
    super();
  }  
  
  @Id
  @GeneratedValue(strategy=GenerationType.IDENTITY)
  public int getMenuId() {
    return this.menuId;
  }

  public void setMenuId(int menuId) {
    this.menuId = menuId;
  }

  @Column(length=100)
  public int getParentId() {
    return parentId;
  }

  public void setParentId(int parentId) {
    this.parentId = parentId;
  }

  @Column(length=100)
  public String getMenuName() {
    return this.menuName;
  }

  public void setMenuName(String menuName) {
    this.menuName = menuName;
  }  
  
  @Column(length=30)
  public String getMenuIcon() {
    return this.menuIcon;
  }

  public void setMenuIcon(String menuIcon) {
    this.menuIcon = menuIcon;
  }  
  
  @Column(length=100)
  public String getMenuUrl() {
    return this.menuUrl;
  }

  public void setMenuUrl(String menuUrl) {
    this.menuUrl = menuUrl;
  }  
  
  @Column(length=100)
  public String getMenuType() {
    return this.menuType;
  }

  public void setMenuType(String menuType) {
    this.menuType = menuType;
  }

  @Column(length=10)
  public String getMenuOrder() {
    return menuOrder;
  }

  public void setMenuOrder(String menuOrder) {
    this.menuOrder = menuOrder;
  }

  @Column(length=10)
  public String getMenuStatus(){
    return menuStatus;
  }

  public void setMenuStatus(String menuStatus){
    this.menuStatus = menuStatus;
  }

  @Transient
  public List getSubMenu() {
    return subMenu;
  }

  public void setSubMenu(List subMenu) {
    this.subMenu = subMenu;
  }

  public void setTarget(String target){
    this.target = target;
  }

  @Transient
  public String getTarget(){
    return target;
  }

  public void setHasSubMenu(boolean hasSubMenu){
    this.hasSubMenu = hasSubMenu;
  }

  @Transient
  public boolean getHasSubMenu(){
    return hasSubMenu;
  }
}

4.5 Spring AOP實現(xiàn)監(jiān)控所有被@RedisCache注解的方法緩存

先從Redis里獲取緩存,查詢不到,就查詢MySQL數(shù)據(jù)庫,然后再保存到Redis緩存里,下次查詢時直接調(diào)用Redis緩存

package org.muses.jeeplatform.cache;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
/**
 * AOP實現(xiàn)Redis緩存處理
 */
@Component
@Aspect
public class RedisAspect {
  private static final Logger LOGGER = LoggerFactory.getLogger(RedisAspect.class);
  @Autowired
  @Qualifier("redisCache")
  private RedisCache redisCache;

  /**
   * 攔截所有元注解RedisCache注解的方法
   */
  @Pointcut("@annotation(org.muses.jeeplatform.annotation.RedisCache)")
  public void pointcutMethod(){

  }

  /**
   * 環(huán)繞處理,先從Redis里獲取緩存,查詢不到,就查詢MySQL數(shù)據(jù)庫,
   * 然后再保存到Redis緩存里
   * @param joinPoint
   * @return
   */
  @Around("pointcutMethod()")
  public Object around(ProceedingJoinPoint joinPoint){
    //前置:從Redis里獲取緩存
    //先獲取目標(biāo)方法參數(shù)
    long startTime = System.currentTimeMillis();
    String applId = null;
    Object[] args = joinPoint.getArgs();
    if (args != null && args.length > 0) {
      applId = String.valueOf(args[0]);
    }
    //獲取目標(biāo)方法所在類
    String target = joinPoint.getTarget().toString();
    String className = target.split("@")[0];
    //獲取目標(biāo)方法的方法名稱
    String methodName = joinPoint.getSignature().getName();
    //redis中key格式:  applId:方法名稱
    String redisKey = applId + ":" + className + "." + methodName;
    Object obj = redisCache.getDataFromRedis(redisKey);

    if(obj!=null){
      LOGGER.info("**********從Redis中查到了數(shù)據(jù)**********");
      LOGGER.info("Redis的KEY值:"+redisKey);
      LOGGER.info("REDIS的VALUE值:"+obj.toString());
      return obj;
    }
    long endTime = System.currentTimeMillis();
    LOGGER.info("Redis緩存AOP處理所用時間:"+(endTime-startTime));
    LOGGER.info("**********沒有從Redis查到數(shù)據(jù)**********");
    try{
      obj = joinPoint.proceed();
    }catch(Throwable e){
      e.printStackTrace();
    }
    LOGGER.info("**********開始從MySQL查詢數(shù)據(jù)**********");
    //后置:將數(shù)據(jù)庫查到的數(shù)據(jù)保存到Redis
    String code = redisCache.saveDataToRedis(redisKey,obj);
    if(code.equals("OK")){
      LOGGER.info("**********數(shù)據(jù)成功保存到Redis緩存!!!**********");
      LOGGER.info("Redis的KEY值:"+redisKey);
      LOGGER.info("REDIS的VALUE值:"+obj.toString());
    }
    return obj;
  }
}

然后調(diào)用@RedisCache實現(xiàn)緩存

/**
   * 通過菜單Id獲取菜單信息
   * @param id
   * @return
   */
  @Transactional
  @RedisCache
  public Menu findMenuById(@RedisCacheKey int id){
    return menuRepository.findMenuByMenuId(id);
  }

登錄系統(tǒng),然后加入@RedisCache注解的方法都會實現(xiàn)Redis緩存處理

淺談SpringBoot集成Redis實現(xiàn)緩存處理(Spring AOP實現(xiàn)) 

淺談SpringBoot集成Redis實現(xiàn)緩存處理(Spring AOP實現(xiàn)) 

可以看到Redis里保存到了緩存

淺談SpringBoot集成Redis實現(xiàn)緩存處理(Spring AOP實現(xiàn)) 

項目代碼:https://github.com/u014427391/jeeplatform

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持創(chuàng)新互聯(lián)。

 


網(wǎng)頁名稱:淺談SpringBoot集成Redis實現(xiàn)緩存處理(SpringAOP實現(xiàn))
網(wǎng)址分享:http://weahome.cn/article/igcojd.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部