Hello, I'm glacier~~
After three months, I finally finished the Spring source code, which is about to crack!! Subsequently, the distributed caching framework was opened source!!!
The frame address is as follows:
GitHub: https://github.com/sunshinelyz/mykit-cache
Gitee: https://gitee.com/binghe001/mykit-cache
Next, I'll introduce this framework to you. If this framework is helpful to you, please open Github and Gitee links to give this project a big Star and let more small partners benefit. You can also like, watch and forward this article~~
Framework description
The independent mykit cache component in the mykit architecture encapsulates various cache operations under the mykit architecture. Users only need to introduce the relevant Jar package to realize the easy operation of the cache.
Frame structure description
It encapsulates the cache operation, supports distributed cache databases such as Memcached, Redis and Ehcache, and supports Spring annotations. Through Spring annotations, you can set the cache expiration time and actively refresh the cache.
The overall structure is as follows.
mykit-cache-memcached
Components related to Memcached cache under mykit cache architecture
mykit-cache-memcached-spring
Under mykit cache Memcached, Spring integrates components related to Memcached operations, and supports setting the cache effective time through annotations
mykit-cache-memcached-spring-simple
Under mykit cache memcached spring, the simple spring memcached kernel is mainly used to implement annotation caching components, and it supports setting the cache effective time through annotations.
When the compatible Memcached server goes down or cannot connect to the Memcached server for other reasons, the main method is to throw relevant exception information and continue to execute the original method.
mykit-cache-memcached-spring-simple-core
The core module under mykit cache memcached spring simple provides core configuration items
mykit-cache-memcached-spring-simple-xml
Mykit cache Memcached Spring simple manages the plug-in classes of Spring container in XML, and provides the core configuration of Spring container to manage Memcached,
Other projects or projects only need to introduce this plug-in and load the Memcached core configuration of this component in their own Spring configuration file.
mykit-cache-memcached-spring-simple-test
The general test project mainly tests the cache operation with simple spring memcached as the kernel under mykit cache memcached spring. This plug-in module mainly provides the main test case encapsulation classes.
mykit-cache-memcached-spring-simple-test-xml
Under mykit cache Memcached spring, test simple spring Memcached as the entry project for kernel cache operation. The test entry class is io.mykit.cache.test.Memcached.test.xml.Memcached test. Meanwhile, the simple.memcache.server property in the classpath:properties/memcached.properties file under this project needs to be configured as the IP and port of its own Memcached server.
mykit-cache-redis
Components related to Redis cache under mykit cache architecture
mykit-cache-redis-java
Under mykit cache Redis, Redis cache encapsulation is used separately in Java.
mykit-cache-redis-spring
Mykit cache Redis mainly integrates Redis operation related components with Spring, and supports setting the cache effective time and actively refreshing the cache through annotations
mykit-cache-redis-spring-core
Mykit cache Redis Spring mainly provides general tools and methods for Spring to integrate Redis, and the core implementation is provided by this module
mykit-cache-redis-spring-annotation
Mykit cache Redis Spring mainly integrates Redis operation related components with Spring, supports setting the cache effective time and actively refreshing the cache through annotations, mainly realizes the management operation of Spring container in the form of Java annotations, and is compatible with the situation when the Redis cluster is down or cannot be connected to the Redis cluster for other reasons.
If the Redis cluster is down or unable to connect to the Redis cluster for other reasons, print the relevant logs and continue to execute the original method downward.
mykit-cache-redis-spring-xml
Mykit cache Redis Spring mainly integrates Redis operation related components with Spring, supports setting the cache effective time and actively refreshing the cache through annotations, and mainly realizes the management operation of Spring container in the form of XML configuration. It is incompatible with the situation when the Redis cluster goes down or cannot connect to the Redis cluster for other reasons, If the Redis cluster is down or unable to connect to the Redis cluster for other reasons, an exception is thrown and execution is exited.
mykit-cache-redis-spring-test
Mykit cache Redis Spring integrates the core test case classes of Redis and provides the main test encapsulation;
mykit-cache-redis-spring-test-annotation
Under mykit cache redis Spring, the test entry of Spring container is managed in the form of Java annotation, and unit test cases are provided for mykit cache redis Spring annotation.
The test entry is io.mykit.cache.test.redis.spring.annotation.test.TestRedisConfig. Before executing the test method, you need to configure the classpath:properties/redis.properties file according to your own Redis cluster, and modify the node IP and port of Redis cluster in redis.properties to the IP and port of your own Redis cluster node
mykit-cache-redis-spring-test-xml
Mykit cache redis Spring tests manage the test entry of Spring container in the form of XML configuration. The test module of mykit cache redis Spring XML provides unit test cases for mykit cache redis Spring XML.
The test entry is io.mykit.cache.test.redis.spring.test.xml.RedisTest. Before executing the test method, you need to configure the classpath:properties/redis.properties file according to your own Redis cluster, and modify the node IP and port of Redis cluster in redis.properties to the IP and port of your own Redis cluster node
mykit-cache-ehcache
Components related to ehcache in mykit cache architecture
mykit-cache-ehcache-spring
Mykit cache Ehcache mainly integrates components related to Ehcache operation with Spring, and supports setting cache effective time through annotation
The usage scenario is as follows:
1. Redis needs to be operated directly using Java
1) Add the following configuration to Maven's pom.xml file:
<dependency> <groupId>io.mykit.cache</groupId> <artifactId>mykit-cache-redis-java</artifactId> <version>1.0.0-SNAPSHOT</version> </dependency>
2) Create the Redis configuration file redis.properties file in the resources directory of the project
For Redis stand-alone mode, the contents of redis.properties file are as follows.
redis.host=10.2.2.231 redis.port=6379 redis.max_idle=200 redis.max_wait=10000 redis.max_total=1024 redis.timeout=3000 redis.test_on_borrow=true
For Redis cluster mode, the contents of redis.properties file are as follows.
#Redis cluster mode redis.cluster.password= redis.cluster.max.total=100 redis.cluster.max.idle=20 redis.cluster.min.idle=10 redis.cluster.timeout=2000 redis.cluster.maxAttempts=100 redis.cluster.redisDefaultExpiration=3600 redis.cluster.usePrefix=true redis.cluster.blockWhenExhausted=true redis.cluster.maxWaitMillis=3000 redis.cluster.testOnBorrow=false redis.cluster.testOnReturn=false redis.cluster.testWhileIdle=true redis.cluster.minEvictableIdleTimeMillis=60000 redis.cluster.timeBetweenEvictionRunsMillis=30000 redis.cluster.numTestsPerEvictionRun=-1 redis.cluster.defaultExpirationKey=defaultExpirationKey redis.cluster.expirationSecondTime=300 redis.cluster.preloadSecondTime=280 # virsual env redis.cluster.node.one=192.168.175.151 redis.cluster.node.one.port=7001 redis.cluster.node.two=192.168.175.151 redis.cluster.node.two.port=7002 redis.cluster.node.three=192.168.175.151 redis.cluster.node.three.port=7003 redis.cluster.node.four=192.168.175.151 redis.cluster.node.four.port=7004 redis.cluster.node.five=192.168.175.151 redis.cluster.node.five.port=7005 redis.cluster.node.six=192.168.175.151 redis.cluster.node.six.port=7006 redis.cluster.node.seven=192.168.175.151 redis.cluster.node.seven.port=7006
be careful:
When configuring the redis.properties file, you can modify the Redis IP and port number, but the Key in the file must be the same as the Key given in the above example, otherwise the Redis client cannot connect to the Redis server.
3) Using Redis cache in Java programs
If the configuration is in stand-alone mode, Redis cache is used as follows
Jedis jedis = RedisBuilder.getInstance(); jedis.set("name", "binghe"); String value = jedis.get("name"); System.out.println(value);
If the cluster environment is configured, Redis cache is used as follows
JedisCluster jedisCluster = RedisClusterBuilder.getInstance(); jedisCluster.set("name", "binghe"); String value = jedisCluster.get("name"); System.out.println(value);
2. You need to use Spring+Redis cluster to configure cache:
1) When a compatible Redis cluster is down or the Redis cluster cannot be connected for other reasons:
Add the following configuration to Maven's pom.xml:
<dependency> <groupId>io.mykit.cache</groupId> <artifactId>mykit-cache-redis-spring-annotation</artifactId> <version>1.0.0-SNAPSHOT</version> </dependency>
At this time, you also need to create Redis configuration classes in the appropriate modules of your project according to the specific situation. The main function is to provide Spring container management for configuring Spring and Redis cluster integration in the form of Java annotations.
The sample program is io.mykit.cache.test.redis.spring.annotation.config.AnnotationConfig class in mykit cache redis spring test annotation test module.
package io.mykit.cache.test.redis.spring.annotation.config; import io.mykit.cache.redis.spring.annotation.config.CacheRedisConfig; import org.springframework.cache.annotation.EnableCaching; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.EnableAspectJAutoProxy; import org.springframework.context.annotation.PropertySource; /** * @author binghe * @version 1.0.0 * @description Provides Spring container management for configuring Spring and Redis cluster integration in the form of Java annotations */ @Configuration @EnableCaching @EnableAspectJAutoProxy(proxyTargetClass = true) @ComponentScan(value = {"io.mykit.cache"}) @PropertySource(value = {"classpath:properties/redis-default.properties", "classpath:properties/redis.properties"}) public class AnnotationConfig extends CacheRedisConfig { }
2) When a compatible Redis cluster is not required to be down or the Redis cluster cannot be connected for other reasons:
Add the following configuration to Maven's pom.xml:
<dependency> <groupId>io.mykit.cache</groupId> <artifactId>mykit-cache-redis-spring-xml</artifactId> <version>1.0.0-SNAPSHOT</version> </dependency>
At this time, you also need to make relevant configuration in the spring configuration file of your own project according to the specific situation. The main configuration items are: start spring annotation scanning and proxy, add io.mykit.cache package to the scanned basic classes, and load them in order
classpath*:properties/redis-default.properties, classpath*:properties/redis.properties file. The specific example is: classpath:spring/spring-context.xml configuration file under mykit cache redis spring test 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:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xmlns:cache="http://www.springframework.org/schema/cache" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache-4.2.xsd"> <context:annotation-config /> <aop:aspectj-autoproxy/> <context:component-scan base-package="io.mykit.cache"/> <!-- Import profile --> <context:property-placeholder location="classpath*:properties/redis-default.properties, classpath*:properties/redis.properties" system-properties-mode="FALLBACK"/> <context:annotation-config /> <context:component-scan base-package="io.mykit.cache" /> <import resource="classpath:redis/spring-redis.xml"/> </beans>
be careful:
(1) Regardless of whether the Redis cluster needs to be compatible or not, or when the Redis cluster cannot be connected for other reasons, you need to create the redis.properties file in the classpath directory of your project to configure the IP and port of your Redis cluster node.
At present, mykit cache Redis spring annotation and mykit cache Redis spring XML support up to 7 Redis clusters, which can be expanded according to their actual situation;
If there are less than 7 Redis clusters, you can configure the IP and port of duplicate Redis cluster nodes in the redis.properties file;
(2) Create the redis.properties file in the classpath directory of your project. This file name is not mandatory and can be replaced by other file names. However, this file name must be consistent with the redis configuration file name loaded in the spring configuration file and the redis configuration file name loaded in the configuration class that manages the spring container in the form of Java annotations;
(3) The configuration item names of cluster node IP and port in the customized Redis cluster configuration file must be the same as those in the instance classpath:properties/redis.properties configuration file;
(4) Configuration instance:
For example, under classpath:properties in my own project, the redis cluster configuration file is redis.properties. The details are as follows:
#redis cluster config redis.cluster.defaultExpirationKey=defaultExpirationKey redis.cluster.expirationSecondTime=300000 redis.cluster.preloadSecondTime=280000 #node info redis.cluster.node.one=10.2.2.231 redis.cluster.node.one.port=7001 redis.cluster.node.two=10.2.2.231 redis.cluster.node.two.port=7002 redis.cluster.node.three=10.2.2.231 redis.cluster.node.three.port=7003 redis.cluster.node.four=10.2.2.231 redis.cluster.node.four.port=7004 redis.cluster.node.five=10.2.2.231 redis.cluster.node.five.port=7005 redis.cluster.node.six=10.2.2.231 redis.cluster.node.six.port=7006 redis.cluster.node.seven=10.2.2.231 redis.cluster.node.seven.port=7006
The configuration files to be loaded in the spring configuration file of my project are:
<context:property-placeholder location="classpath*:properties/redis-default.properties, classpath*:properties/redis.properties" system-properties-mode="FALLBACK"/>
Or in the configuration class of my project, the annotation of the configuration file to be loaded is:
@PropertySource(value = {"classpath:properties/redis-default.properties", "classpath:properties/redis.properties"})
That is, the classpath:properties/redis-default.properties file should be written in front of the customized configuration file, and the framework will load classpath:properties/redis-default.properties first.
Then load the customized configuration file. If the customized configuration file has the same property configuration as the classpath:properties/redis-default.properties file, the framework will overwrite the same property in classpath:properties/redis-default.properties with the customized configuration property
(5) Specific use
1) Add @ Cacheable annotation without key attribute to relevant query methods:
@Cacheable(value={"test#10#2"})
The key attribute of @ Cacheable is not configured. At this time, the key attribute value of @ Cacheable is generated according to a certain policy, that is, the HashCode of the current class name (full package name + class name) + method name + method type list + method parameter list is the key attribute of the Current @ Cacheable. The specific key generation policy class is io.mykit.cache.redis.spring.cache.CacheKeyGenerator in mykit cache redis spring core;
2) Add the @ Cacheable annotation with the key attribute to the relevant query methods
@Cacheable(value={"test#10#2"} key="key" + ".#defaultValue")
The key property of @ Cacheable is configured. At this time, the key property value of @ Cacheable is the HashCode value of the result of the value of the key splicing parameter defaultValue.
be careful:
(1) If there is no key attribute in the @ Cacheable annotation, the framework will generate a key attribute for @ Cacheable, that is, the key attribute is not required;
(2) If the @ Cacheable annotation is not configured with the key attribute, the HashCode of the current class name (full package name + class name) + method name + method type list + method parameter list is the key attribute of the current @ Cacheable;
(3) If the @ Cacheable annotation is configured with the key attribute, the HashCode of the current key is used as the key attribute of the current @ Cacheable;
(4) In the value attribute of @ Cacheable, the value we configured is test#10#2. At this time, it means that the cache name of @ Cacheable is test, where 10 represents the effective length of cache (in seconds), and 2 represents the remaining length of time from cache invalidation (in seconds),
That is, the configuration format of the value attribute of @ Cacheable is: cache name #expireTime#reloadTime. The framework stipulates that # must be used as the separator
- expireTime: indicates the effective duration of the cache, in seconds;
- reloadTime: indicates the remaining time from cache invalidation, in seconds;
- expireTime needs to be greater than reloadTime, otherwise it is meaningless
(5) Description of the value attribute of @ Cacheable
- After configuring the value attribute of @ Cacheable in the format of cache name #expireTime#reloadTime, the framework will put the query results into the cache. The effective length is expireTime seconds and the remaining length from cache invalidation is reloadTime seconds;
- When the time range from 0 seconds to (expireTime reloadtime) seconds elapses when the data is stored in the cache, call the method again to obtain the data directly from the cache;
- When the data is stored in the cache, the method is called again after the time range of reloadTime seconds - expireTime seconds, and the framework will actively call the original method through proxy and reflection to refresh the cache after obtaining data from the real data source;
- When the data is stored in the cache for more than expireTime seconds, the cache will become invalid. If the method is called again, the original method will be executed to query the data, and the framework will automatically store the query results in the cache;
- When the framework actively calls the original method through proxy and reflection to refresh the cache after obtaining data from the real data source, in order to prevent multiple threads requesting to refresh the cache at the same time, the framework provides a distributed lock to ensure that only one thread performs the cache refresh operation;
- After the framework actively calls the original method to obtain data from the real data source, the operation of refreshing the cache is asynchronous with the user's request operation, which will not affect the performance of the user's request;
- After the framework actively calls the original method to obtain data from the real data source, the operation of refreshing the cache is transparent to the user's request, that is, the user cannot perceive the operation of the framework actively refreshing the cache;
other:
1) When the Value of @ Cacheable is only configured with the cache name, for example, @ Cacheable(value = "test")
At this time, the expireTime defaults to the redis.cluster.expirationSecondTime property value of the redis configuration file, with the unit of seconds; reloadTime is the redis.cluster.preloadSecondTime attribute value of the redis configuration file by default, and the unit is seconds;
The loading order of attribute values is: first load the redis.cluster.expirationSecondTime attribute value and redis.cluster.preloadSecondTime attribute value of the customized redis configuration file. If the customized redis configuration file has no relevant attribute value; Load the redis-default.properties file from the framework default redis configuration file;
2) When the Value of @ Cacheable is configured with the cache name and expiration time, for example, @ Cacheable(value = "test#10")
At this time, the reloadTime defaults to the redis.cluster.preloadSecondTime attribute value of the redis configuration file, in seconds;
The loading order of attribute values is: first load the redis.cluster.preloadSecondTime attribute value of the customized redis configuration file. If the customized redis configuration file has no relevant attribute value; Load the redis-default.properties file from the framework default redis configuration file;
3) When the Value of @ Cacheable configures the cache name, expiration time and remaining time from cache expiration, for example, @ Cacheable(value = "test#10#2")
At this time, the default expireTime and reloadTime will not be loaded. The framework will directly use the expireTime and reloadTime configured by the value attribute in the @ Cacheable annotation;
4) No matter whether the value property of @ Cacheable is configured with cache duration information or not, only reloadTime will not be configured without expireTime. The format of the value property specified by the framework is: cache name #expireTime#reloadTime
That is, only the following format will appear:
- Cache name
- Cache name #expireTime
- Cache name #expireTime#reloadTime
reloadTime does not appear separately. The cache name #expireTime is configured, and reloadTime is configured using the default duration of the configuration file;
matters needing attention
1. Mykit cache redis spring XML reference and mykit cache redis spring annotation reference are mutually exclusive, that is, in a project, mykit cache redis spring XML and mykit cache redis spring annotation can only reference one at the same time;
2. The functions of mykit cache Redis spring XML and mykit cache Redis spring annotation are the same, but the mykit cache Redis spring annotation project is compatible with the situation when the Redis cluster is down or unable to connect to the Redis cluster for other reasons;
3. If the Redis cluster is down or cannot be connected for other reasons, mykit cache Redis spring XML will throw an exception and exit the execution; Mykit cache Redis spring annotation will print relevant exception information and continue to execute the original method downward.
4. If Spring container and Spring MVC are configured in the way of XML configuration in your project, and you want to configure the cache in the way of compatible Redis cluster downtime or failure to connect to Redis cluster for other reasons, you can go through the following configuration:
1) Add the following configuration classes to the project:
SpringContextConfig: configure Spring container:
package io.mykit.cache.redis.spring.utils.config; import org.springframework.cache.annotation.EnableCaching; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.EnableAspectJAutoProxy; import org.springframework.context.annotation.ImportResource; import org.springframework.context.annotation.PropertySource; import io.mykit.cache.redis.spring.annotation.config.CacheRedisConfig; /** * @ClassName SpringContextConfig * @Description Spring Java to configure * @author binghe */ @Configuration @EnableCaching @EnableAspectJAutoProxy(proxyTargetClass = true) @ComponentScan(value = {"io.mykit.cache"}) @PropertySource(value = {"classpath:properties/redis-default.properties", "classpath:properties/redis.properties"}) @ImportResource("classpath:spring/applicationContext.xml") public class SpringContextConfig extends CacheRedisConfig{ }
Spring MVC config: configure spring MVC:
package io.mykit.cache.redis.spring.utils.config; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.ImportResource; /** * @ClassName SpringMVCConfig * @Description SpringMVC Java to configure * @author binghe */ @Configuration @ImportResource("classpath:spring/SpringMVC-servlet.xml") public class SpringMVCConfig { }
2) The web.xml of the web project is modified as follows:
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0"> <!-- to configure spring monitor --> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <context-param> <param-name>contextClass</param-name> <param-value> org.springframework.web.context.support.AnnotationConfigWebApplicationContext </param-value> </context-param> <context-param> <param-name>contextConfigLocation</param-name> <param-value>io.mykit.cache.redis.spring.utils.config.SpringContextConfig</param-value> </context-param> <listener> <listener-class>org.springframework.web.util.IntrospectorCleanupListener</listener-class> </listener> <servlet> <servlet-name>SpringMVC</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextClass</param-name> <param-value> org.springframework.web.context.support.AnnotationConfigWebApplicationContext </param-value> </init-param> <init-param> <param-name>contextConfigLocation</param-name> <param-value>io.mykit.cache.redis.spring.utils.config.SpringMVCConfig</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>SpringMVC</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> </web-app>
3. You need to use Spring+Memcached cluster to configure cache
1. It needs to be referenced in pom.xml of the project
<dependency> <groupId>io.mykit.cache</groupId> <artifactId>mykit-cache-memcached-spring-simple-xml</artifactId> <version>1.0.0-SNAPSHOT</version> </dependency>
Note: This module of the framework does not support active cache refresh. The underlying core uses the simple spring memcached kernel.
2. Method of use
1) Create a new Memcached configuration file in the classpath:properties directory of your project, such as the memcached.properties file, and configure the properties of connecting to Memcached;
The properties are configured as follows:
#simple memcached config simple.memcache.server=127.0.0.1:12000 simple.memcache.consistenthashing=true simple.memcache.connectionpoolsize=1 simple.memcache.optimizeget=false simple.memcache.optimizemergebuffer=false simple.memcache.mergefactor=50 simple.memcache.usebinaryprotocol=true simple.memcache.connectiontimeout=3000 simple.memcache.operationtimeout=2000 simple.memcache.enableheartbeat=true simple.memcache.failureMode=false
Note: the properties of the customized memcached file must be the same as the default configured property key of memcached-default.properties, that is, the same as the above configured key, but you don't need to overwrite the above complete configuration,
You can configure only:
simple.memcache.server=192.168.209.121:12000
To override the simple.memcache.server attribute
2) Create a new spring configuration file in the classpath directory of your project, such as spring-context.xml. The configuration contents are as follows:
<?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:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xmlns:cache="http://www.springframework.org/schema/cache" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache-4.2.xsd"> <context:annotation-config /> <aop:aspectj-autoproxy/> <context:component-scan base-package="io.mykit.cache"/> <!-- Import profile --> <context:property-placeholder location="classpath*:properties/memcached-default.properties, classpath*:properties/memcached.properties" system-properties-mode="FALLBACK"/> <context:annotation-config /> <context:component-scan base-package="io.mykit.cache" /> <import resource="classpath:memcached/memcached-simple.xml"/> </beans>
According to the order of loading the properties file according to the above configuration, the framework will overwrite the properties of the memcached-default.properties file with the custom memcached.properties file properties.
If there are properties in the memcached-default.properties file that do not exist in memcached.properties, the framework will use the default properties in memcached-default.properties.
At this point, you can configure the cache using the annotations provided by simple spring memcached.
3. Introduction to simple spring memcached
3-1. Basic introduction
Simple spring memcached essentially uses AOP to call and manage the cache. Its core component declares some Advice. When encountering the corresponding entry point, it will execute these Advice to manage memcached.
Pointcuts are declared in the form of labels. During project development, corresponding label descriptions are usually given on DAO methods to represent the interception of the method by components. The pointcuts provided by components mainly include the following:
ReadThroughSingleCache,ReadThroughMultiCache,ReadThroughAssignCache
1) When these pointcuts are declared by the query method, the component will first read the data from the cache, and then skip the query method and return directly. If the data cannot be retrieved, execute the query method, and put the query results into the cache for next retrieval. InvalidateSingleCache,InvalidateMultiCache,InvalidateAssignCache
2) When these pointcuts are declared by the deletion method, the component will delete the corresponding entities in the cache so that the data status read from the cache next time is the latest UpdateSingleCache, UpdateMultiCache and updateasigncache
3-2 notes
Detailed description of each Annotation
- ReadThroughSingleCache
Function: read the data in the Cache. If it does not exist, store the read data in the Cachekey. Generation rules: the parameter specified by ParameterValueKeyProvider. If the parameter object contains the method annotated by CacheKeyMethod, call its method, otherwise call toString method
@ReadThroughSingleCache(namespace = "Alpha", expiration = 30) public String getDateString(@ParameterValueKeyProvider final String key) { final Date now = new Date(); try { Thread.sleep(1500); } catch (InterruptedException ex) { } return now.toString() + ":" + now.getTime(); }
- InvalidateSingleCache
Function: invalidate data in Cache
key generation rules:
1) When using ParameterValueKeyProvider annotation, it is consistent with ReadThroughSingleCache
2) When using the ReturnValueKeyProvider annotation, the key is generated by the CacheKeyMethod or toString method of the returned object
@InvalidateSingleCache(namespace = "Charlie") public void updateRandomString(@ParameterValueKeyProvider final Long key) { // Nothing really to do here. } @InvalidateSingleCache(namespace = "Charlie") @ReturnValueKeyProvider public Long updateRandomStringAgain(final Long key) { return key; }
- UpdateSingleCache
Function: update data in Cache
key generation rule: specified by ParameterValueKeyProvider
1)ParameterDataUpdateContent: the data in the method parameter is used as the data to update the cache
2)ReturnDataUpdateContent: the data generated after the method call is used as the data to update the cache
Note: the above two annotations must be used together with the annotation of Update * series
@UpdateSingleCache(namespace = "Alpha", expiration = 30) public void overrideDateString(final int trash, @ParameterValueKeyProvider final String key, @ParameterDataUpdateContent final String overrideData) { } @UpdateSingleCache(namespace = "Bravo", expiration = 300) @ReturnDataUpdateContent public String updateTimestampValue(@ParameterValueKeyProvider final Long key) { try { Thread.sleep(100); } catch (InterruptedException ex) { } final Long now = new Date().getTime(); final String result = now.toString() + "-U-" + key.toString(); return result; }
- ReadThroughAssignCache
Function: read the data in the Cache. If it does not exist, store the read data in the Cache
key generation rule: specified by the assignedKey field in the ReadThroughAssignCache annotation
@ReadThroughAssignCache(assignedKey = "SomePhatKey", namespace = "Echo", expiration = 3000) public List<String> getAssignStrings() { try { Thread.sleep(500); } catch (InterruptedException ex) { } final List<String> results = new ArrayList<String>(); final long extra = System.currentTimeMillis() % 20; final String base = System.currentTimeMillis() + ""; for (int ix = 0; ix < 20 + extra; ix++) { results.add(ix + "-" + base); } return results; }
- InvalidateAssignCache
Function: invalidate the data of the specified key in the cache
key generation rule: specified in the assignedKey field
@InvalidateAssignCache(assignedKey = "SomePhatKey", namespace = "Echo") public void invalidateAssignStrings() { }
- UpdateAssignCache
Role: updates the specified cache
key generation rule: specified in the assignedKey field
@UpdateAssignCache(assignedKey = "SomePhatKey", namespace = "Echo", expiration = 3000) public void updateAssignStrings(int bubpkus, @ParameterDataUpdateContent final List<String> newData) { }
4. You need to use Spring + Ehcache cluster to configure cache
This module of the framework will not be implemented for the time being. Because the integration of Spring and Ehcache is too simple, you can implement the integration of Spring and Ehcache by yourself. This module does not provide encapsulation.
Spring 4 configuring annotation based ehcache caching
1. ehcache configuration file ehcache.xml
<?xml version="1.0" encoding="UTF-8"?> <ehcache name="es"> <diskStore path="java.io.tmpdir"/> <defaultCache maxElementsInMemory="10000" eternal="false" timeToIdleSeconds="30" timeToLiveSeconds="30" overflowToDisk="true"> </defaultCache> <!-- Configure custom cache maxElementsInMemory: Maximum number of objects allowed to be created in the cache eternal: Whether the object in the cache is permanent. If so, the timeout setting will be ignored and the object will never expire. timeToIdleSeconds: The passivation time of cached data, that is, the maximum time interval between two accesses before an element dies, which is valid only when the element does not reside permanently, If the value is 0, it means that the element can pause for an infinite time. timeToLiveSeconds: The lifetime of cached data, that is, the maximum time interval between the construction and extinction of an element, This is only valid if the element does not reside permanently. If the value is 0, it means that the element can pause for an infinite time. overflowToDisk: Whether to enable disk caching when memory is low. memoryStoreEvictionPolicy: The elimination algorithm after the cache is full. --> <cache name="statisticServiceCache" maxElementsInMemory="1000" eternal="false" overflowToDisk="true" timeToIdleSeconds="900" timeToLiveSeconds="1800" diskPersistent="false" memoryStoreEvictionPolicy="LFU" /> </ehcache>
2. Spring cache annotation and ehcache bean configuration
<cache:annotation-driven cache-manager="cacheManager"/> <!-- cacheManager Factory class, specifying ehcache.xml Location of --> <bean id="ehcache" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"> <property name="configLocation" value="/WEB-INF/ehcache.xml"/> <!-- <property name="shared" value="true"/> --> </bean> <!-- statement cacheManager --> <bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager"> <property name="cacheManager" ref="ehcache" /> </bean>
3. Confirm that spring aop support is enabled
<aop:aspectj-autoproxy/>
4. Use of spring cache annotation
(1)@Cacheable
@Main parameters of Cacheable
- value
The name of the cache, defined in the spring configuration file, must specify at least one
For example:
@Cacheable(value="mycache") perhaps @Cacheable(value={"cache1","cache2"}
- key
The cached key can be empty. If it is specified to be written according to the spiel expression, if it is not specified, it will be combined according to all the parameters of the method by default
For example:
@Cacheable(value="testcache",key="#userName")
- condition
The cache condition can be null. It is written in spiel and returns true or false. It can be cached only when it is true
For example:
@Cacheable(value="testcache",condition="#userName.length()
Examples are as follows:
@Cacheable(value = "statisticServiceCache", key = "'activityChartData_' + #urlID") public ResultInfo getActivityChartData(String urlID, Date startMonth,Date endMonth) { ... }
This annotation is used to check whether there is a cache with key value in the current cache system when calling the annotated method. If it exists, the cache object is returned directly without executing the method. If it does not exist, the method is called and the resulting return value is written to the cache.
(2)@CachePut
@Main parameters of CachePut
- value
The name of the cache, defined in the spring configuration file, must specify at least one
For example:
@Cacheable(value="mycache") perhaps @Cacheable(value={"cache1","cache2"}
- key
The cached key can be empty. If it is specified to be written according to the spiel expression, if it is not specified, it will be combined according to all the parameters of the method by default
For example:
@Cacheable(value="testcache",key="#userName")
- condition
The cache condition can be null. It is written in spiel and returns true or false. It can be cached only when it is true
For example:
@Cacheable(value="testcache",condition="#userName.leng
@CachePut is used to write to the cache, but unlike @ Cacheable, the method of @ CachePut annotation is always executed, and then the return value of the method is written to the cache. This annotation is mainly used to add or update the cache.
(3) @CacheEvict
@Main parameters of CacheEvict
- value
The name of the cache, defined in the spring configuration file, must specify at least one
For example:
@CachEvict(value="mycache") perhaps @CachEvict(value={"cache1","cache2"}
- key
The cached key can be empty. If it is specified to be written according to the spiel expression, if it is not specified, it will be combined according to all the parameters of the method by default
For example:
@CachEvict(value="testcache",key="#userName")
- condition
The cache condition can be empty. It is written in spiel and returns true or false. Only when it is true will the cache be cleared
For example:
@CachEvict(value="testcache", condition="#userName.length()>2")
- allEntries
Whether to clear all cache contents. The default value is false. If true is specified, all caches will be cleared immediately after the method is called
For example:
@CachEvict(value="testcache",allEntries=true)
- beforeInvocation
Whether to clear the method before execution. The default is false. If it is specified as true, the cache will be cleared before the method is executed. By default, if the method throws an exception, the cache will not be cleared
For example:
@CachEvict(value="testcache"ļ¼beforeInvocation=true)
@CacheEvict is used to delete the cache
matters needing attention
No matter which module is used, the ApplicationContext needs to be configured into the SpringContextWrapper in the relevant project.
The example code is as follows:
package io.mykit.cache.test.redis.spring.utils; import io.mykit.cache.redis.spring.context.SpringContextWrapper; import lombok.extern.slf4j.Slf4j; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.stereotype.Component; import redis.clients.util.Hashing; /** * @author binghe * @version 1.0.0 * @description Save the Spring ApplicationContext as a static variable, and you can get the ApplicaitonContext from any code, anywhere and at any time */ @Slf4j @Component public class SpringContext implements ApplicationContextAware { private static ApplicationContext applicationContext; /** * Implement the context injection function of ApplicationContextAware interface and store it into static variables */ @Override public void setApplicationContext(ApplicationContext applicationContext) { SpringContext.applicationContext = applicationContext; // NOSONAR log.debug(SpringContext.class.getName() + " Path to class load:" + this.getClass().getResource("/").getPath() + ", hashcode:" + Hashing.MURMUR_HASH.hash(this.getClass().getResource("/").getPath())); log.debug(SpringContext.class.getName() + " applicationContext===>>>" + applicationContext); SpringContextWrapper.setApplicationContext(SpringContextWrapper.getContextKey(this.getClass()), applicationContext); } /** * Get the ApplicationContext stored in the static variable * @return ApplicationContext object */ public static ApplicationContext getApplicationContext() { checkApplicationContext(); return applicationContext; } /** * Get the Bean from the static variable ApplicationContext and automatically convert it to the type of the assigned object * @param name Spring The name of the Bean in the * @return Generic object */ @SuppressWarnings("unchecked") public static <T> T getBean(String name) { checkApplicationContext(); return (T) applicationContext.getBean(name); } /** * Get the Bean from the static variable ApplicationContext and automatically convert it to the type of the assigned object * @param clazz Specified clazz object * @return Generic object */ public static <T> T getBean(Class<T> clazz) { checkApplicationContext(); return (T) applicationContext.getBean(clazz); } /** * Clear the applicationContext static variable */ public static void cleanApplicationContext() { applicationContext = null; } private static void checkApplicationContext() { if (applicationContext == null) { throw new IllegalStateException("applicaitonContext Not injected,Please in applicationContext.xml Defined in SpringContextHolder"); } } }
The project is still under development and has not been added to Maven central warehouse at present. It will be added to Maven central warehouse after subsequent development.
If this framework is helpful to you, please open Github and Gitee links to give this project a big Star and let more small partners benefit. You can also like, watch and forward this article~~
Write at the end
If you want to enter a big factory, want to be promoted and raised, or are confused about your existing work, you can communicate with me privately. I hope some of my experience can help you~~
Recommended reading:
- <Practice makes true knowledge: the strongest seckill system architecture in the whole network is decrypted. Not all seckills are seckills!!>
- <From zero to hundreds of millions of users, how do I optimize MySQL database step by step? (recommended Collection)>
- <I further optimized the massive data proofreading system under 100 million traffic e-commerce business with multithreading, and the performance has been improved by 200%!! (dry goods in the whole process, collection recommended)>
- <I used multithreading to optimize the massive data proofreading system under the 100 million traffic e-commerce business, and the performance was directly improved by 200%!! (dry goods in the whole process, collection recommended)>
- <I use 10 diagrams to summarize the best learning route of concurrent programming!! (recommended Collection)>
- <A faster lock than read-write lock in high concurrency scenario. I was completely impressed after reading it!! (recommended Collection)>
- <Summary of the most complete performance optimization of the whole network!! (glacier hematemesis finishing, recommended Collection)>
- <After three days of rolling up MyBatis, please ask!! (glacier hematemesis finishing, recommended Collection)>
- <I advise those students who have just joined the work: if you want to enter the big factory, you must master these concurrent programming knowledge! Complete learning route!! (recommended Collection)>
- <I advise those students who have just joined the work: if you want to enter the big factory, you must master these core skills! Complete learning route!! (recommended Collection)>
- <I advise those students who have just joined the work: the sooner they know the basic knowledge of computers and operating systems, the better! Ten thousand words long text is too top!! (recommended Collection)>
- <I developed a national game suitable for all ages in three days. It supports playing music. Now I open the complete source code and comments (recommended Collection)!!>
- <I am the author of high concurrency programming with the hardest core in the network and the most noteworthy blogger of CSDN. Do you agree? (recommended Collection)>
- <Five years after graduation, from a monthly salary of 3000 to an annual salary of one million, what core skills have I mastered? (recommended Collection)>
- <I invaded the Wifi of my sister next door and found... (actual dry goods in the whole process, collection recommended)>
- <Don't try "panda burning incense" easily. I regret it!>
- <On the Qingming Festival, I secretly trained "panda burning incense". As a result, my computer "died" for the panda!>
- <73000 words liver burst Java 8 new features, I don't believe you can read it! (recommended Collection)>
- <What kind of experience is it to unplug the server during peak business hours?>
- <Summary of the most complete Linux commands in the whole network!! (the most complete in history, recommended Collection)>
- <Write a tool in Python and crack MySQL perfectly!! (recommended Collection)>
- <Why isn't the SimpleDateFormat class thread safe? (six solutions are attached, recommended Collection)>
- <The three new indexes in MySQL 8 directly let MySQL take off. You don't even know!! (recommended Collection)>
- <After rolling out the Spring source code, I open source this distributed caching framework!! (recommended Collection)>
- <The commodities of the 100 million level traffic high concurrent second kill system are "oversold", just because there are these two huge pits in the JDK synchronization container!! (actual record of stepping on the pit, recommended Collection)>
- <I advise those students who have just joined the work: if you want to learn concurrent programming well, you must pay attention to the pits of these concurrent containers!! (recommended Collection)>
- <The company's report tool is too difficult to use. I have an Excel tool for three days. The direct call of miss operation is very easy to use. It is now open source!! (recommended Collection)>
- <I advise those students who have just joined the work: if you want to enter the big factory, these core skills of concurrent programming must be mastered!! (recommended Collection)>
Well, that's all for today. Let's praise, collect and comment. Let's walk up three times with one button. I'm glacier. I'll see you next time~~