zoukankan      html  css  js  c++  java
  • Spring Cache简单实现

    Spring Cache简单实现

    业务场景

    假定一个业务场景:在项目中,用户查询是一个非常频繁的操作,从性能优化的角度,自然会想到对用户的查询方法做缓存,以避免频繁的数据库访问操作,提高页面的响应速度。

    通常的做法是以用户的userId作为键值key,以返回的用户对象作为value值进行存储,而以相同的userId查询用户时,程序将直接从缓存中获取结果并返回,否则更新缓存。

    代码清单

    这里使用的是Spring默认的缓存管理器

    服务类

    package com.example.cache.springcache;
    import com.example.cache.customize.User;
    import org.springframework.cache.annotation.Cacheable;
    import org.springframework.stereotype.Service;
    
    /**
     * @author: 博客「成猿手册」
     * @description: com.example.cache.springcache
     * @date: 2020/6/7
     */
    @Service(value = "userServiceBean")
    public class UserService {
    
        //使用名为users的缓存
        @Cacheable(cacheNames = "users")
        public User getUserById(String userId) {
    
            //方法内部不考虑缓存逻辑直接实现业务
            System.out.println("query user by userId=" + userId);
            return getFromDB(userId);
        }
    
        //模拟数据库查询
        private User getFromDB(String userId) {
            System.out.println("querying id from DB..." + userId);
            return new User(userId);
        }
    }
    

    getUserById()方法被标注了一个注解,即 @Cacheable(cacheNames = "users")当调用这个方法时,会先从users缓存中查询匹配的缓存对象:

    1. 如果存在,则直接返回;

    2. 如果不存在,则执行方法体内的逻辑(查询数据库),并将返回值放进缓存中。对应缓存的key为userId的值,value就是userId所对应的User对象。

    相关配置

    applicationContext.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"
           xsi:schemaLocation="
    	http://www.springframework.org/schema/beans
    	http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
    
        <!-- 定义一个Bean -->
        <bean id="userServiceBean" class="com.example.cache.springcache.UserService"/>
        <!-- 引入缓存配置 -->
        <import resource="cache.xml"/>
    </beans>
    

    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" xmlns:p="http://www.springframework.org/schema/p"
           xsi:schemaLocation="
            http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/cache https://www.springframework.org/schema/cache/spring-cache.xsd">
    
        <!-- Spring通过该配置启动基于注解的缓存驱动 -->
        <cache:annotation-driven/>
    
        <!-- 也可以直接在这里定义Bean,省略applicationContext.xml -->
        <!--<bean id="userServiceBean" class="com.example.cache.springcache.UserService"/>-->
    
        <!-- cacheManager为默认的缓存管理器 -->
        <bean id="cacheManager" class="org.springframework.cache.support.SimpleCacheManager">
            <!-- 通过对SimpleCacheManager属性caches的配置实现默认缓存管理器的逻辑 -->
            <property name="caches">
                <set>
                    <!-- 默认的defaul缓存 -->
                    <!--<bean class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean" p:name="default"/>-->
                    <bean class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean" p:name="users"/>
                </set>
            </property>
        </bean>
    </beans>
    

    实体类

    Java对象和序列化是息息相关的,一般情况下,需要被缓存的实体类需要实现Serializable,只有实现了Serializable接口的类,JVM才可以将其对象进行序列化,对于Redis,EhCache等缓存套件来说,被缓存的对象应该是可序列化的,否则在网络传输,硬盘存储时,都会抛出序列化异常。

    package com.example.cache.customize;
    import java.io.Serializable;
    
    /**
     * @author: 博客「成猿手册」
     * @description: com.example.cache
     * @date: 2020/6/7
     */
    public class User  implements Serializable {
        private String userId;
        private String userName;
        private Integer age;
        
        //todo:此处省略get和set方法
    }
    

    进行测试

    这里写一个UserMain以测试上面我们所实现的代码效果:

    package com.example.cache.springcache;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    import org.springframework.context.ApplicationContext;
    
    /**
     * @author: 博客「成猿手册」
     * @description: com.example.cache.customize
     * @date: 2020/6/7
     */
    public class UserMain {
        public static void main(String[] args) {
            ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
            UserService userService = (UserService) context.getBean("userServiceBean");
            //第一次查询,缓存中没有,从数据库查询
            System.out.println("first query...");
            System.out.println("result object: " + userService.getUserById("test001"));
            //第二次查询,缓存中存在,从缓存查询
            System.out.println("second query...");
            System.out.println("result object: " + userService.getUserById("test001"));
        }
    }
    

    在控制台打印的相关信息如下:

    first query...
    query user by userId=test001
    querying id from DB...test001
    Disconnected from the target VM, address: '127.0.0.1:12371', transport: 'socket'
    result object: com.example.cache.customize.User@6fb365ed
    second query...
    result object: com.example.cache.customize.User@6fb365ed
    

    可以看出querying id from DB的信息只在我们第一次查询时出现。到此上面配置的基于注解的缓存起作用了,而回顾代码会发现,在UserService的代码中并没有任何属于缓存逻辑的代码,只是一个注解@Cacheable(cacheNames = "users")就实现了基本缓存方案,使得代码变得非常简洁。事实上,使用Spring Cache非常简单,只需要:

    • 缓存定义:确定需要缓存的方法和缓存策略。

    • 缓存配置:配置缓存。

  • 相关阅读:
    docker的核心概念和安装
    kettle在centos7下部署分布式集群
    Kettle在windows下分布式集群的搭建
    笔记本 原来win10系统改装win7系统遇到 invaid signature detected.check secure boot policy setup问题
    docker 在window10下的安装
    docker 在windows7 、8下的安装
    初识Docker
    MySql 外键约束 之CASCADE、SET NULL、RESTRICT、NO ACTION分析和作用
    学习前端框架Metronic
    Java中的动态代理是什么
  • 原文地址:https://www.cnblogs.com/WangJpBlog/p/13213888.html
Copyright © 2011-2022 走看看