Original Springboot practical case collection Spring Family Bucket practical case source code 2023-10-14 12:34 Published in Xinjiang
Spring Family Bucket practical case source code
Detailed explanation of spring, springboot, springcloud case development
376 original content
No public
Environment: springboot2.6.12 + JSR107 + Ehcache + JPA
Spring Cache is a framework that implements annotation-based caching functionality. It unifies different caching technologies through the CacheManager interface and provides simplification for business operation caching. Specifically, using Spring Cache’s annotations, such as @Cacheable, @CacheEvict and @CachePut, etc., you can implement cache operations very conveniently. , such as cache creation, update and deletion, etc.
Why use Spring Cache? There are mainly the following reasons:
-
Simplify operations: Through annotations, we can greatly simplify the code we use to operate the cache in our business. There is no need to write a lot of manual cache processing logic, and you can focus more on business logic processing.
-
Improving performance: Using caching can significantly improve your application’s performance. By storing frequently used data or calculation results in the cache, you can reduce the number of accesses to the database or other external data sources, thereby improving application responsiveness and performance.
-
Extensibility: Spring Cache provides an abstraction layer that allows us to switch to different cache implementations as needed. For example, we can use Redis as a cache, or we can use EhCache or other caching technologies. This scalability makes our applications more flexible and allows us to choose the most appropriate caching solution based on specific needs.
-
Security: Spring Cache also provides cache consistency guarantees. For example, in a distributed system, multiple application nodes may have concurrent access to and modification of the same data. Using Spring Cache’s annotations can ensure the consistency of these operations and avoid data inconsistency problems.
In general, the use of Spring Cache can improve the performance and maintainability of the application, making the application more robust and flexible.
Starting from 3.1, the Spring framework provides support for transparently adding cache to Spring applications. Like transaction support, abstract caching allows various caching solutions to be used consistently with minimal impact on the code.
Starting with Spring 4.1, the cache abstraction has been significantly improved by supporting JSR-107 annotations and more customization options.
1. Basic usage
Directly use spring annotations to implement caching
Spring provides the following annotations:
@Cacheable triggers caching mechanism
@CacheEvict triggers cache eviction
@CachePut updates the cache without affecting method execution
@Caching combines multiple caching operations into one method
@CacheConfig class-level shared system common cache-related configurations
<dependency></code><code> <groupId>org.springframework.boot</groupId></code><code> <artifactId>spring-boot-starter-cache</artifactId></code> <code></dependency>
Generally, the corresponding method in Service is to add annotations.
@Service</code><code>publicclass StorageService {<!-- --></code> <code> @Resource</code><code> private StorageRepository sr;</code><code> </code><code> // The keyGenerator here is the Bean name generated by your custom Key</code><code> @Cacheable(value = {"cache_storage"}, keyGenerator = "storageKey")</code><code> public Storage getStorage(Long id) {<!-- --></code><code> return sr.findById(id).get() ;</code><code> }</code><code>}
@Component("storageKey")</code><code>publicclass StorageKeyGenerator implements KeyGenerator {<!-- --></code> <code> privatestatic final String KEY_PREFIX = "storage_" ;</code> <code> @Override</code><code> publicObject generate(Object target, Method method, Object... params) {<!-- --></code><code> StringBuilder sb = new StringBuilder(); </code><code> for (Object param : params) {<!-- --></code><code> sb.append(param) ;</code><code> }</code><code> return KEY_PREFIX + sb.toString() ;</code><code> }</code><code>}
Test access interface
@RestController</code><code>@RequestMapping("/storages")</code><code>public class StorageController {<!-- --></code> <code> @Resource</code><code> private StorageService storageService ;</code> <code> @GetMapping("/{id}")</code><code> public Object get(@PathVariable("id") Long id) {<!-- --></code> <code> returnstorageService.getStorage(id) ;</code><code> }</code><code>}
Access the interface for the first time and check the console output of the sql statement:
When you access the interface again, you find that the console does not output any SQL, indicating that our cache has taken effect (you can also comment out the annotations here to see the effect). Regarding the update cache here, deleting the cache will not be demonstrated. Next is a complete demonstration of the annotations in the JSR107 specification:
Note that we can use SpEL expressions in these comments:
2. Combination of JSR107 and EhCache
Let’s first take a look at the comparison table between Spring and JSR107 annotations:
Add dependencies to pom.xml
<dependency></code><code> <groupId>org.springframework.boot</groupId></code><code> <artifactId>spring-boot-starter-cache</artifactId></code> <code></dependency>
mysql
mysql-connector-java
org.ehcache
ehcache
javax.cache < artifactId>cache-api
Service class
@Service</code><code>public class StorageService {<!-- --></code> <code> @Resource</code><code> private StorageRepository sr;</code> <code> // The @CacheValue description here is the parameter value to be cached. </code><code> @Transactional</code><code> @CachePut(cacheName = "cache_storage", cacheKeyGenerator = JCacheKeyGenerator.class)</code><code> public Storage save(@CacheValue Storage storage) { <!-- --></code><code> returnsr.saveAndFlush(storage) ;</code><code> }</code><code> @CacheResult(cacheName = "cache_storage", cacheKeyGenerator = JCacheKeyGenerator .class)</code><code> publicStoragegetStorage(Long id) {<!-- --></code><code> returnsr.findById(id).get() ;</code><code> }</code> <code> @Transactional</code><code> @CacheRemove(cacheName = "cache_storage", cacheKeyGenerator = JCacheKeyGenerator.class)</code><code> publicvoidremoveStorage(Long id) {<!-- --></code><code> sr.deleteById(id) ;</code><code> }</code> <code> @Transactional</code><code> @CachePut(cacheName = "cache_storage", cacheKeyGenerator = JCacheKeyGenerator.class)</code><code> publicStorageupdateStorage(@CacheValue Storage storage) {<!-- -- ></code><code> returnsr.saveAndFlush(storage) ;</code><code> }</code><code>}</code><code>// Note that the cacheKeyGenerator here must all use the same one. </code><code>// I tracked the source code and used the corresponding class name key to find the corresponding cache; I didn’t use the same one at the beginning and it was always incorrect. .
Source code debugging
There must be the same cacheKeyGenerator here
Cache Key: JCacheKeyGenerator.java
publicclass JCacheKeyGenerator implements CacheKeyGenerator {<!-- --></code> <code> private static final String KEY_PREFIX = "storage_" ;</code> <code> @Override</code><code> public GeneratedCacheKey generateCacheKey(</code><code> CacheKeyInvocationContext<? extends Annotation> cacheKeyInvocationContext) {<!-- --></code><code> CacheInvocationParameter[] params = cacheKeyInvocationContext.getAllParameters() ;</code><code> StringBuilder sb = new StringBuilder() ;</code><code> for (CacheInvocationParameter param : params) {<!-- --></code><code> if (param.getValue() instanceof Storage) {<!-- --></code><code> Storage s = (Storage) param.getValue() ;</code><code> sb.append(s .getId()) ;</code><code> } else {<!-- --></code><code> sb.append((Long)param.getValue()) ;</code><code> }</code><code> }</code><code> return new StorageGeneratedCacheKey(KEY_PREFIX + sb.toString()) ;</code><code> }</code><code>}
application.yml configuration
spring:</code><code> cache:</code><code> cacheNames:</code><code> - cache_storage</code><code> ehcache:</code><code> config: classpath:ehcache.xml
ehcache.xml
<?xml version="1.0" encoding="UTF-8"?></code><code><ehcache xmlns:xsi="http://www.w3.org/2001 /XMLSchema-instance"</code><code> xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"</code><code> updateCheck="false"></code> <code> <diskStore path="java.io.tmpdir/Tmp_EhCache"/></code><code> <defaultCache eternal="false" maxElementsInMemory="10000" overflowToDisk="false" diskPersistent="false" timeToIdleSeconds="1800" timeToLiveSeconds="259200" memoryStoreEvictionPolicy="LRU" /></code><code> <cache name="cache_storage" eternal=" false" maxElementsInMemory="5000" overflowToDisk="false" diskPersistent="false" timeToIdleSeconds="1800" timeToLiveSeconds="1800" memoryStoreEvictionPolicy="LRU" /></code><code></ehcache>
test
Add data first
The information with ID 4 was successfully added. We added the @CachePut annotation in the save method in Service. Next, we query the information with ID 4 to see if the console will generate a SQL statement.
No SQL statements are added to the console, indicating that the @CachePut added in the save method has taken effect.
Then do the delete operation:
The one with ID 4 has been deleted. Let’s check again:
This shows that after deleting the data, the cache is also deleted. The query statement is generated here.
complete! ! ! !