We know that the bottleneck of a program is the database. We also know that the speed of memory is much faster than that of hard disk. When we need to retrieve the same data repeatedly, we request database or remote service again and again, which leads to a large amount of time consuming in data query or remote method invocation, resulting in deterioration of program performance, which is the problem to be solved by data caching.
8.5.1 Spring cache support
Spring defines an interface between org. spring framework. cache. CacheManager and org. spring framework. cache. Cache to unify different caches. Cache Manager is the abstract interface of various caching technologies provided by Spring. Cache interface includes all kinds of operations of caching (adding, deleting and obtaining caches, we usually do not deal with this interface directly).
1.Spring-supported Cache Manager
For different caching technologies, different Cache Managers need to be implemented. Spring defines the implementation of Cache Manager as shown in the table.
CacheManager | describe |
---|---|
SimpleCacheManager | Use a simple Collection to store caches, mainly for testing purposes |
ConcurrentMapCacheManager | Use Concurrent Map to cache |
NoOpCacheManager | Testing purposes only, not actually storing caches |
EhCacheCacheManager | Using EhCache as Caching Technology |
GuavaCacheManager | Using Google Guava's Guava Cache as Caching Technology |
HazelcastCacheManager | Using Hazelcast as Caching Technology |
JCacheCacheManager | Supporting the implementation of JCache (jsr-107) standard as a caching technology, such as Apache Commons JCS |
RedisCacheManager | Using Redis as Caching Technology |
When we use Cache Manager of any implementation, we need to register the Bean of the implemented Cache Manager, for example:
@Bean public EhCacheCacheManager cacheManager(CacheManager ehCacheCacheManager) { return new EhCacheCacheManager(ehCacheCacheManager); }
Of course, there are many additional configurations for each caching technology, but configuring the cache manager is essential.
2. Nominal Cache Annotations
Spring provides four annotations to declare caching rules (another vivid example of using annotated AOP). These four annotations are shown in the table.
annotation | explain |
---|---|
@Cacheable | Before the method is executed, Spring first checks whether there is data in the cache, and if there is data, returns the cached data directly; if there is no data, it calls the method and puts the method return value into the cache. |
@CachePut | In any case, the return value of the method is placed in the cache. @ CachePut's attributes are consistent with @Cacheable |
@CacheEvict | Delete one or more data from the cache |
@Caching | Multiple annotation strategies can be combined on one method through @Caching annotations |
3. Open Famous Cache Support
It's easy to turn on fame caching support by simply using the @EnableCaching annotation on the configuration class, such as:
@Configuration @EnableCaching public class AppConfig{ }
8.5.2 Spring Boot support
The key to using caching technology in Spring is to configure Cache Manager, and Spring Boot automatically configures several Cache Manager implementations for us.
The automatic configuration of Spring Boot's Cache Manager is placed in the org.sprinframework.boot.autoconfigure.cache package, as shown in the figure
As you can see from the figure above, Spring Boot automatic configures EhCache Configuration (using EhCache), GenericCache Configuration (using Collection), Guava Cache Configuration (using Guava), Hazelcast Cache Configuration (using Hazelcast), Infinispan Cache Configuration (using Infinispan), JC Cache Configuration (using JCAC Cache Co.) He), NoOpCache Configuration (no storage), RedisCache Configuration (using Redis), SimpleCache Configuration (using Concurrent Map). Without any additional configuration, the default is SimpleCache Configuration, even with Concurrent Map Cache Manager. Spring Boot supports the configuration of caches with properties“ Spring. cache ".
spring.cache.type= # Optional generic,ehcache,hazelcast,infinispan,jcache,redis,guava,simple,none spring.cache.cache-names=#Create a cache name at program startup spring.cache.ehcache.config=#ehcache profile address spring.cache.hazelcast.config=#hazelcast configuration file address spring.cache.infinispan.config = # infinispan configuration file address spring.cache.jcache.config = # jcache configuration file steep spring.cache.jcache.provider = #When multiple jcache implementations are in the classpath, specify the jcache implementation spring.cache.guava.spec = # guava specs
In Spring Book environment, using caching technology only needs to import dependency packages of related caching technology into the project and use @EnableCaching to open caching support in the configuration class.
8.5.3 Actual Warfare
This example uses Spring Boot's default Concurrent Map Cache Manager as the cache technology, demonstrates @Cacheable,@CachePut,@CacheEvit, and finally replaces the cache technology with EhCache and Guava.
1. New Spring Book Project
New Spring Book projects rely on Cache (spring-boot-starter-cache), JPA (spring-boot-starter-data-jpa) and Web (spring-boot-starter-web).
Project information:
groupId:com.wisely arctifactId:ch8_5 package:com.wisely.ch8_5
Add Oracle JDBC driver and configure related properties in application.properties, which is consistent with the previous example.
2. entity class
package com.wisely.ch8_5.domain; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; @Entity public class Person { @Id @GeneratedValue private Long id; private String name; private Integer age; private String address; public Person() { super(); } public Person(Long id, String name, Integer age, String address) { super(); this.id = id; this.name = name; this.age = age; this.address = address; } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } }
3. Entity class Repository
package com.wisely.ch8_5.dao; import org.springframework.data.jpa.repository.JpaRepository; import com.wisely.ch8_5.domain.Person; public interface PersonRepository extends JpaRepository<Person, Long> { }
4. Business Services
(1) Interface:
package com.wisely.ch8_5.service; import com.wisely.ch8_5.domain.Person; public interface DemoService { public Person save(Person person); public void remove(Long id); public Person findOne(Person person); }
(2) Implementation class:
package com.wisely.ch8_5.service.impl; import org.springframework.beans.factory.annotation.Autowired; 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.wisely.ch8_5.dao.PersonRepository; import com.wisely.ch8_5.domain.Person; import com.wisely.ch8_5.service.DemoService; @Service public class DemoServiceImpl implements DemoService { @Autowired PersonRepository personRepository; @Override @CachePut(value="people" , key="#Person.id"/@CachePut caches newly added or updated data to the cache, where the cache name is people and the key of the data is the ID of person. public Person save(Person person) { Person p = personRepository.save(person); System.out.println("by id,key For:"+p.getId()+"Data is cached"); return p; } @Override @CacheEvict(value="people",key="#person.id"// Delete the data whose key is ID from the cache people. public void remove(Long id) { System.out.println("Deleted id,key by"+id+"Data caching"); personRepository.deleteById(id); } @Override @CacheEvict(value="people",key="#id "// Delete the data whose key is id from the cache people. public void remove(Long id) { System.out.println("Deleted id,key by"+id+"Data caching"); } }
5. controller
package com.wisely.ch8_5.controller; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import com.wisely.ch8_5.domain.Person; import com.wisely.ch8_5.service.DemoService; @RestController public class CacheController { @Autowired DemoService demoService; @RequestMapping("/put") public Person put(Person person) { return demoService.save(person); } @RequestMapping("/able") public Person cacheable(Person person) { return demoService.findOne(person); } @RequestMapping("/evit") public String evit(Long id) { demoService.remove(id); return "ok"; } }
6. Turn on cache support
package com.wisely.ch8_5; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cache.annotation.EnableCaching; @SpringBootApplication @EnableCaching //Turn on cache support public class Ch885Application { public static void main(String[] args) { SpringApplication.run(Ch885Application.class, args); } }
7. operation
When we cache the data, the data will be obtained from the cache, not from the database. The data situation of the current database is shown in the figure.
We restarted the application every time we ran the test.
(1) Test @Cacheable
The first visit to http://localhost:8080/able?id=1, the first call method queries the database, and puts the data into the cache people.
At this time, the console output is as follows:
The page output is as follows
Re-visit http://localhost:8080/able?id=1. At this time, the console does not output Hibernate's query statement again, and the words "cached for id and key: 1 data" indicate that this method is not invoked, and the page obtains data directly from the data cache.
The output of the page is as follows
(2) Test @CachePut
Visit http://localhost:8080/put?Name=cc&age=22&adress=Chengdu, and the console output is as follows:
The page output is shown in Figure 1.
We visited http://localhost:8080/able?id=4 again. The console had no output. We got the data directly from the cache. The page display was the same as the figure above.
(3) Test @CacheEvit
Visit http://localhost:8080/able?id=1 to cache the data with id 1, and then visit http://localost:8080/able?id=1 again to confirm that the data has been obtained from the cache.
Access http://localhost:8080/evit?id=1 and delete the cached data with key 1 from the cache
Visit http://localhost:8080/able?id=1 again and watch the console re-caching: