• 8 -- 深入使用Spring -- 5...2 使用@Cacheable执行缓存


          8.5.2 使用@Cacheable执行缓存

            @Cacheable可用于修饰类或修饰方法,当使用@Cacheable修饰类时,用于告诉Spring在类级别上进行缓存 ------ 程序调用该类的实例的任何方法时都需要缓存,而且共享同一个缓存区;当使用@Cacheable修饰方法时,用于告诉Spring在方法级别上进行缓存 ------ 只有当程序调用该方法时才需要缓存。

            1. 类级别的缓存

              当使用@Cacheable修饰类时,就可控制Spring在类级别进行缓存,这样程序调用类的任意方法时,只要传入的参数相同,Spring就会使用缓存。

              Component : UserServiceImpl

    package edu.pri.lime._8_5_2.classrank.impl;
    
    import org.springframework.cache.annotation.Cacheable;
    import org.springframework.stereotype.Service;
    
    import edu.pri.lime._8_5_2.classrank.UserService;
    import edu.pri.lime._8_5_2.classrank.bean.User;
    
    @Service(value="userService")
    @Cacheable(value = "users")
    public class UserServiceImpl implements UserService{
    
        @Override
        public User getUserByNameAndAge(String name, int age) {
            System.out.println("---正在执行getUserByNameAndAge()查询方法---");
            return new User(name,age);
        }
    
        @Override
        public User getAnotherUser(String name, int age) {
            System.out.println("---正在执行findAnotherUser()查询方法---");
            return new User(name,age);
        }
    
    }

              app_8_5_2_ehcache.xml:不成功,请使用SimpleCacheManager作为缓存管理器

    <?xml version="1.0" encoding="UTF-8"?>
    <!-- Spring 配置文件的根元素,使用Spring-beans-4.0.xsd语义约束 -->
    <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context"
        xmlns:cache="http://www.springframework.org/schema/cache" xmlns:aop="http://www.springframework.org/schema/aop"
        xmlns:P="http://www.springframework.org/schema/p"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
    http://www.springframework.org/schema/aop
    http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
    http://www.springframework.org/schema/cache
    http://www.springframework.org/schema/cache/spring-cache-4.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-4.0.xsd">
    
    
        <context:component-scan base-package="edu.pri.lime._8_5_2.classrank">
        </context:component-scan>
    
        <cache:annotation-driven cache-manager="cacheManager" />
    
        <bean id="cacheManager" class="org.springframework.cache.support.SimpleCacheManager">
            <property name="caches">
                <set>
                    <bean
                        class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean">
                        <property name="name" value="default" />
                    </bean>
                    <bean
                        class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean">
                        <property name="name" value="users" />
                    </bean>
    
                </set>
            </property>
        </bean>
    
        <!-- 
        <bean id="ehCacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"> 
            <property name="configLocation" value="classpath:app_8_5_2_ehcache.xml"/> 
            <property name="shared" value="false"/>
        </bean>
        <bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager"> 
            <property name="cacheManager" ref="ehCacheManager"/>
        </bean> -->
    
    </beans>

              Class : SpringTest

    package edu.pri.lime._8_5_2.classrank.impl;
    
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    import edu.pri.lime._8_5_2.classrank.UserService;
    import edu.pri.lime._8_5_2.classrank.bean.User;
    
    public class SpringTest {
    
        public static void main(String[] args) {
            ApplicationContext ctx = new ClassPathXmlApplicationContext("app_8_5_2_classrank.xml");
            UserService userService = (UserService) ctx.getBean("userService");
            User userA = userService.getUserByNameAndAge("lime", 24);
            User userB = userService.getAnotherUser("lime", 24);
            System.out.println(userA == userB);
        }
    }

              Console : 

    ---正在执行getUserByNameAndAge()查询方法---
    true

              @Cacheable(value="users")指定UserServiceImple进行类级别的缓存,这样程序调用该类的任意方法时,只要传入的参数相同,Spring就会使用缓存,即时方法的返回值并不真正的同一个对象。

              此处所指的缓存的意义是:当程序第一次调用该类的实例的某个方法时,Spring缓存机制会将该方法返回的数据放入指定缓存区 ------ 就是@Cacheable注解的value属性所指定的缓存区(此处指定将数据放入users缓存区,正是缓存管理器配置的users缓存区)。以后程序调用该类的实例的任何方法时,只要出入的参数相同,Spring将不会真正执行该方法,而是直接利用缓存区中的数据。

              类级别的缓存默认以所有方法参数作为key来缓存方法返回的数据 ------ 同一类不管调用哪个方法,只要调用方法时传入的参数相同,Spring都会直接利用缓存区中的数据。

              使用@Cacheable时可指定如下属性:

                ⊙ value : 必需属性。该属性可指定多个缓存区的名字,用于指定将方法返回值放入指定的缓存区内。

                ⊙ key : 通过SpEL表达式显式指定缓存的key。多个参数组合的key 用#name + #age + ...

                ⊙ condition : 该属性指定一个返回boolean值的SpEL表达式,只有当该表达式返回true时,Spring才会缓存方法返回值。

                ⊙ unless : 该属性指定一个返回boolean值的SpEL表达式,当该表达式返回true时,Spring就不缓存方法返回值。

              提示:

                与@Cacheable注解功能类似的还有一个@CachePut注解,@CachePut注解同样会让Spring将方法返回值放入缓存区。与@Cacheable不同的是,@CachePut修饰的方法不会读取缓存区中的数据 ------ 这意味着不管缓存区是否已有数据,@CachePut总会告诉Spring要重新执行这些方法,并再次将方法返回值放入缓存区。

              修改UserServiceImpl : @Cacheable(value = “users” , key = “#name”) 显式指定以name参数作为缓存的key,这样只要调用的方法具有相同的name参数,Spring缓存机制就会生效。

    package edu.pri.lime._8_5_2.classrank.service.cacheablekey.main;
    
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    import edu.pri.lime._8_5_2.classrank.bean.User;
    import edu.pri.lime._8_5_2.classrank.service.cacheable.UserService;
    
    public class SpringTest {
    
        public static void main(String[] args) {
            ApplicationContext ctx = new ClassPathXmlApplicationContext("app_8_5_2_classrankkey.xml");
            UserService userService = (UserService) ctx.getBean("userService");
            User userA = userService.getUserByNameAndAge("lime", 22);
            User userB = userService.getAnotherUser("lime", 24);
            System.out.println(userA == userB);
            
        }
    }

                Console : 

    ---正在执行getUserByNameAndAge()查询方法---
    true

              使用@Cacheable注解显式指定key = “#name” ,这就意味着缓存使用name参数作为缓存的key。

              condition属性与unless属性的功能基本相似,但规则恰好相反:当condition指定的条件为true时,Spring缓存机制才会执行缓存;当unless指定的条件为true时,Spring缓存机制就不执行缓存。

                Class : UserServiceImpl

    package edu.pri.lime._8_5_2.classrank.service.cacheablecondition.impl;
    
    import org.springframework.cache.annotation.Cacheable;
    import org.springframework.stereotype.Service;
    
    import edu.pri.lime._8_5_2.classrank.bean.User;
    import edu.pri.lime._8_5_2.classrank.service.cacheablecondition.UserService;
    
    @Service("userService")
    @Cacheable(value="users" ,condition="#age<100")
    public class UserServiceImpl implements UserService{
    
        @Override
        public User getUserByNameAndAge(String name, int age) {
            System.out.println("---正在执行getUserByNameAndAge()查询方法---");
            return new User(name,age);
        }
    
        @Override
        public User getAnotherUser(String name, int age) {
            System.out.println("---正在执行getAnotherUser()查询方法---");
            return new User("oracle",25);
        }
    
    }

                XML : 

    <?xml version="1.0" encoding="UTF-8"?>
    <!-- Spring 配置文件的根元素,使用Spring-beans-4.0.xsd语义约束 -->
    <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context"
        xmlns:cache="http://www.springframework.org/schema/cache" xmlns:aop="http://www.springframework.org/schema/aop"
        xmlns:P="http://www.springframework.org/schema/p"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
    http://www.springframework.org/schema/aop
    http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
    http://www.springframework.org/schema/cache
    http://www.springframework.org/schema/cache/spring-cache-4.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-4.0.xsd">
    
    
        <context:component-scan base-package="edu.pri.lime._8_5_2.classrank.service.cacheablecondition.impl">
        </context:component-scan>
    
        <!-- 启用Spring缓存 -->
        <cache:annotation-driven cache-manager="cacheManager" />
    
        <!-- 使用simpleCacheManager缓存管理器 -->
        <bean id="cacheManager" class="org.springframework.cache.support.SimpleCacheManager">
            <!-- 配置缓存区 -->
            <property name="caches">
                <set>
                    <!-- 使用ConcurrentMapCacheFactoryBean工程Bean生产缓存区 -->
                    <bean
                        class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean">
                        <!-- 定义缓存区名称 -->
                        <property name="name" value="default" />
                    </bean>
                    <bean
                        class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean">
                        <!-- 定义缓存区名称 -->
                        <property name="name" value="users" />
                    </bean>
    
                </set>
            </property>
        </bean>
    
    </beans>

                Console : 

    ---正在执行getUserByNameAndAge()查询方法---
    ---正在执行getAnotherUser()查询方法---
    false
    ---正在执行getUserByNameAndAge()查询方法---
    ---正在执行getAnotherUser()查询方法---
    false
    ---正在执行getUserByNameAndAge()查询方法---
    ---正在执行getAnotherUser()查询方法---
    false

                疑惑 : 跟想象中的不一样啊! 说好的condition表达式呢?

                使用@Cacheable修饰方法时,可控制Spring在方法级别进行缓存,这样当程序调用该方法时,只要传入的参数相同,Spring就会使用缓存。

            2.方法级别的缓存

              Class : UserServiceImpl

    package edu.pri.lime._8_5_2.functionrank.service.impl;
    
    import org.springframework.cache.annotation.Cacheable;
    import org.springframework.stereotype.Service;
    
    import edu.pri.lime._8_5_2.functionrank.bean.User;
    import edu.pri.lime._8_5_2.functionrank.service.UserService;
    
    @Service("userService")
    public class UserServiceImpl implements UserService{
    
        @Override
        @Cacheable(value="userA")
        public User getUserByNameAndAge(String name, int age) {
            System.out.println("---正在执行getUserByNameAndAge()查询方法---");
            return new User(name,age);
        }
    
        @Override
        @Cacheable(value="userB")
        public User getAnotherUser(String name, int age) {
            System.out.println("---正在执行findAnotherUser()查询方法---");
            return new User("oracle",25);
        }
    
    }

              XML : app_8_5_2_functionrankvalue.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <!-- Spring 配置文件的根元素,使用Spring-beans-4.0.xsd语义约束 -->
    <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context"
        xmlns:cache="http://www.springframework.org/schema/cache" xmlns:aop="http://www.springframework.org/schema/aop"
        xmlns:P="http://www.springframework.org/schema/p"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
    http://www.springframework.org/schema/aop
    http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
    http://www.springframework.org/schema/cache
    http://www.springframework.org/schema/cache/spring-cache-4.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-4.0.xsd">
    
    
        <!-- 扫描Spring的组件 -->
        <context:component-scan base-package="edu.pri.lime._8_5_2.functionrank.service.impl"/>
    
        <!-- 启用Spring缓存 -->
        <cache:annotation-driven cache-manager="cacheManager" />
    
        <!-- 使用simpleCacheManager缓存管理器 -->
        <bean id="cacheManager" class="org.springframework.cache.support.SimpleCacheManager">
            <!-- 配置缓存区 -->
            <property name="caches">
                <set>
                    <!-- 使用ConcurrentMapCacheFactoryBean工程Bean生产缓存区 -->
                    <bean
                        class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean">
                        <!-- 定义缓存区名称 -->
                        <property name="name" value="userA" />
                    </bean>
                    <bean
                        class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean">
                        <!-- 定义缓存区名称 -->
                        <property name="name" value="userB" />
                    </bean>
                </set>
            </property>
        </bean>
    </beans>

              Class : SpringTest

    package edu.pri.lime._8_5_2.functionrank;
    
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    import edu.pri.lime._8_5_2.functionrank.bean.User;
    import edu.pri.lime._8_5_2.functionrank.service.UserService;
    
    public class SpringTest {
    
        public static void main(String[] args) {
            ApplicationContext ctx = new ClassPathXmlApplicationContext("app_8_5_2_functionrankvalue.xml");
            UserService userService = ctx.getBean("userService",UserService.class);
            User userA = userService.getUserByNameAndAge("lime", 24);
            User userB = userService.getAnotherUser("lime", 24);
            System.out.println(userA == userB);
            User userC = userService.getUserByNameAndAge("lime", 24);
            User userD = userService.getAnotherUser("lime", 24);
            System.out.println(userA == userC);
            
        }
    }

              Console : 

    ---正在执行getUserByNameAndAge()查询方法---
    ---正在执行findAnotherUser()查询方法---
    false
    true

              方法级别的缓存中,方法之间使用不同的缓存区,因此它们不能共享缓存。

    啦啦啦

    啦啦啦

    啦啦啦

    啦啦啦

  • 相关阅读:
    Flutter | 如何优雅的解决依赖版本冲突
    Flutter包依赖冲突解决方法
    Cannot run with sound null safety because dependencies don't support null safety
    软件工程实践2019第三次作业
    【题解】洛谷 P3704 [SDOI2017]数字表格
    关于学历和素质成正比的隐晦思考
    斐波那契数列通项公式
    某不知名比赛游记
    CCPC-final 2020 北京游记
    EC-final 2020-2021 西安游记
  • 原文地址:https://www.cnblogs.com/ClassNotFoundException/p/6498588.html
Copyright © 2020-2023  润新知