• Spring 的缓存抽象


    https://docs.spring.io/spring/docs/5.0.13.RELEASE/spring-framework-reference/integration.html#cache

    从3.1版开始,Spring Framework提供了对现有Spring应用程序透明地添加缓存的支持。 与事务支持类似,缓存抽象允许一致地使用各种缓存解决方案,而对代码的影响最小。

    从Spring 4.1开始,通过JSR-107注释和更多自定义选项的支持,缓存抽象得到了显着改进。

    抽象的核心是将缓存应用于Java方法,从而减少了基于缓存中可用信息的执行次数。也就是说,每次调用目标方法时,抽象都会应用缓存行为检查方法是否已经为给定的参数执行。如果有,则返回缓存的结果,而不必执行实际的方法;如果没有,则执行方法,缓存结果并返回给用户,以便在下次调用方法时返回缓存的结果。这样,对于给定的一组参数,昂贵的方法(CPU或IO绑定)只能执行一次,并且结果可以重用,而不必实际再次执行该方法。缓存逻辑被透明地应用,没有任何对调用程序的干扰。

    就像Spring Framework中的其他服务一样,缓存服务是一种抽象(不是缓存实现),需要使用实际存储来存储缓存数据 - 也就是说,抽象使开发人员不必编写缓存逻辑 但不提供实际的存储。 这种抽象由org.springframework.cache.Cache和org.springframework.cache.CacheManager接口实现。

    这个抽象的一些实现可以直接使用:基于JDK java.util.concurrent.ConcurrentMap的缓存(即默认的缓存是基于JVM的ConcurrentMap),Ehcache 2.x,Gemfire缓存,符合Caffeine和JSR-107的缓存(例如Ehcache 3.x)。 有关插入其他缓存存储/提供程序的更多信息,请参阅插入不同的后端缓存。

    对于缓存声明,抽象提供了一组Java注释:

    @Cacheable 触发数据存储于缓存

    @CacheEvict 触发删除缓存条目

    @CachePut 更新缓存而不会干扰方法执行

    @Caching 重新组合要在方法上应用的多个缓存操作

    @CacheConfig 在类级别共享一些常见的缓存相关设置

    @ Cacheable

    顾名思义,@ Cacheable用于划分可缓存的方法 - 即,将结果存储到缓存中的方法,以便在后续调用(具有相同的参数)时,返回缓存中的值而不必 实际执行该方法。

    @CachePut

    对于需要在不干扰方法执行的情况下更新缓存的情况,可以使用@CachePut批注。 也就是说,该方法将始终执行并将其结果放入缓存中(根据@CachePut选项)。 它支持与@Cacheable相同的选项

    @CacheEvict

    缓存抽象不仅允许缓存存储的填充,还允许驱逐。 此过程对于从缓存中删除陈旧或未使用的数据非常有用。 与@Cacheable相反,注释@CacheEvict划分了执行缓存逐出的方法,即用作从缓存中删除数据的触发器的方法。

    @Caching

    有些情况下需要指定相同类型的多个注释,例如@CacheEvict或@CachePut,例如因为条件或键表达式在不同的缓存之间是不同的。 @Caching允许在同一方法上使用多个嵌套的@ Cacheable,@ CachePut和@CacheEvict:

    基于内存ConcurrentMap的缓存实例

    @Slf4j
    @Service
    @CacheConfig(cacheNames = "coffee")
    public class CoffeeService {
        @Autowired
        private CoffeeRepository coffeeRepository;
    
        /**
         * 查询结果存储于缓存中
         * @return List<Coffee>
         */
        @Cacheable
        public List<Coffee> findAllCoffee() {
            return coffeeRepository.findAll();
        }
    
        /**
         * 剔除缓存
         */
        @CacheEvict
        public void reloadCoffee() {
        }
    
        public Optional<Coffee> findOneCoffee(String name) {
            ExampleMatcher matcher = ExampleMatcher.matching()
                    .withMatcher("name", exact().ignoreCase());
            Optional<Coffee> coffee = coffeeRepository.findOne(
                    Example.of(Coffee.builder().name(name).build(), matcher));
            log.info("Coffee Found: {}", coffee);
            return coffee;
        }
    }
    @Slf4j
    @EnableTransactionManagement
    @SpringBootApplication
    @EnableJpaRepositories
    //开启缓存
    @EnableCaching(proxyTargetClass = true)
    public class SpringBucksApplication implements ApplicationRunner {
    	@Autowired
    	private CoffeeService coffeeService;
    
    	public static void main(String[] args) {
    		SpringApplication.run(SpringBucksApplication.class, args);
    	}
    
    	@Override
    	public void run(ApplicationArguments args) throws Exception {
    		log.info("Count: {}", coffeeService.findAllCoffee().size());
    		for (int i = 0; i < 10; i++) {
    			log.info("Reading from cache.");
    			coffeeService.findAllCoffee();
    		}
    		coffeeService.reloadCoffee();
    		log.info("Reading after refresh.");
    		coffeeService.findAllCoffee().forEach(c -> log.info("Coffee {}", c.getName()));
    	}
    }

    扩展

    启用Spring的注释驱动的缓存管理功能,类似于Spring的<cache:*> XML命名空间中的支持。 要与@Configuration类一起使用,如下所示:

       @Configuration
       @EnableCaching
       public class AppConfig {
      
           @Bean
           public MyService myService() {
               // configure and return a class having @Cacheable methods
               return new MyService();
           }
      
           @Bean
           public CacheManager cacheManager() {
               // configure and return an implementation of Spring's CacheManager SPI
               SimpleCacheManager cacheManager = new SimpleCacheManager();
               cacheManager.setCaches(Arrays.asList(new ConcurrentMapCache("default")));
               return cacheManager;
           }
       }

    基于xml的配置

      <beans>
           <cache:annotation-driven/>
           <bean id="myService" class="com.foo.MyService"/>
           <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>
                   </set>
               </property>
           </bean>
       </beans>

      在上述两种情况中,@ EnableCaching和<cache:annotation-driven />负责注册为注释驱动的缓存管理提供支持的必要Spring组件,例如CacheInterceptor和基于代理或基于AspectJ的建议。 调用@Cacheable方法时,拦截器进入调用堆栈。


    如果存在JSR-107 API和Spring的JCache实现,则还会注册管理标准高速缓存注释的必要组件。 这会创建基于代理或基于AspectJ的建议,当调用使用CacheResult,CachePut,CacheRemove或CacheRemoveAll注释的方法时,它会将拦截器编织到调用堆栈中。

    必须注册CacheManager类型的bean,因为框架没有合理的默认值可用作约定。 虽然<cache:annotation-driven>元素假定一个名为“cacheManager”的bean,但@EnableCaching按类型搜索缓存管理器bean。 因此,缓存管理器bean方法的命名并不重要。

    对于那些希望在@EnableCaching和要使用的确切缓存管理器bean之间建立更直接关系的人,可以实现CachingConfigurer回调接口。 请注意下面的@ Override-annotated方法:

       @Configuration
       @EnableCaching
       public class AppConfig extends CachingConfigurerSupport {
      
           @Bean
           public MyService myService() {
               // configure and return a class having @Cacheable methods
               return new MyService();
           }
      
           @Bean
           @Override
           public CacheManager cacheManager() {
               // configure and return an implementation of Spring's CacheManager SPI
               SimpleCacheManager cacheManager = new SimpleCacheManager();
               cacheManager.setCaches(Arrays.asList(new ConcurrentMapCache("default")));
               return cacheManager;
           }
      
           @Bean
           @Override
           public KeyGenerator keyGenerator() {
               // configure and return an implementation of Spring's KeyGenerator SPI
               return new MyKeyGenerator();
           }
       }

    根据Spring的KeyGenerator SPI,这允许自定义缓存密钥生成策略。 通常,@ EnableCaching将为此配置Spring的SimpleKeyGenerator,但在实现CachingConfigurer时,必须明确提供密钥生成器。 如果不需要自定义,则从此方法返回null或新的SimpleKeyGenerator()。

    基于Redis的缓存

    #缓存类型。 默认情况下,根据环境自动检测
    spring.cache.type=redis
    spring.cache.cache-names=coffee
    #缓存过期时间
    spring.cache.redis.time-to-live=5000
    #是否允许缓存null
    spring.cache.redis.cache-null-values=false
    spring.redis.host=localhost
    @Slf4j
    @Service
    @CacheConfig(cacheNames = "coffee")
    public class CoffeeService {
        @Autowired
        private CoffeeRepository coffeeRepository;
    
        @Cacheable
        public List<Coffee> findAllCoffee() {
            return coffeeRepository.findAll();
        }
    
        @CacheEvict
        public void reloadCoffee() {
        }
    
        public Optional<Coffee> findOneCoffee(String name) {
            ExampleMatcher matcher = ExampleMatcher.matching()
                    .withMatcher("name", exact().ignoreCase());
            Optional<Coffee> coffee = coffeeRepository.findOne(
                    Example.of(Coffee.builder().name(name).build(), matcher));
            log.info("Coffee Found: {}", coffee);
            return coffee;
        }
    }
    
    @Slf4j
    @EnableTransactionManagement
    @SpringBootApplication
    @EnableJpaRepositories
    @EnableCaching(proxyTargetClass = true)
    public class SpringBucksApplication implements ApplicationRunner {
    	@Autowired
    	private CoffeeService coffeeService;
    
    	public static void main(String[] args) {
    		SpringApplication.run(SpringBucksApplication.class, args);
    	}
    
    	@Override
    	public void run(ApplicationArguments args) throws Exception {
    		log.info("Count: {}", coffeeService.findAllCoffee().size());
    		for (int i = 0; i < 5; i++) {
    			log.info("Reading from cache.");
    			coffeeService.findAllCoffee();
    		}
    		Thread.sleep(5_000);
    		log.info("Reading after refresh.");
    		coffeeService.findAllCoffee().forEach(c -> log.info("Coffee {}", c.getName()));
    	}
    }
    

        

    微信公众号

                              
  • 相关阅读:
    PowerDesigner中利用数据库表反向生成PDM(jdk必须是32位)
    Struts2 Web Project 实现中文、英语的切换
    一张图解决Struts2添加源码
    Struts2配置文件struts.xml的编辑自动提示代码功能
    Hibernate多对一(注解)
    SQL Server 日期和时间函数
    ORACLE日期时间函数大全
    ORACLE中函数MONTHS_BETWEEN的使用
    SQL经典面试题及答案
    SQL数据库面试题以及答案
  • 原文地址:https://www.cnblogs.com/niugang0920/p/12186508.html
Copyright © 2020-2023  润新知