Spring's caching mechanism is very flexible and can cache any bean or bean methods in the container. Therefore, this caching mechanism can be cached at any level of JavaEE application.
The underlying layer of Spring cache also needs to be implemented with the help of other cache tools, such as EhCache (Hibernate cache tool), and the upper layer uses a unified API programming.
To use Spring cache, the following three steps are required
For example
<?xml version="1.0" encoding="UTF-8"?><ehcache> <diskStore path="java.io.tmpdir" /> <!-- Configure the default cache --> <defaultCache maxElementsInMemory="10000" eternal="false" timeToIdleSeconds="120" timeToLiveSeconds="120" maxElementsOnDisk="10000000" diskExpiryThreadIntervalSeconds="120" memoryStoreEvictionPolicy="LRU"/> <!-- Configure the cache named users --> <cache name="users" maxElementsInMemory="10000" eternal="false" overflowToDisk="true" timeToIdleSeconds="300" timeToLiveSeconds="600" /></ehcache>
The above ehcache.xml configures two cache areas. The beans in Spring will be cached in these cache areas. Generally, how many beans there are in the Spring container will be defined in ehcache.
Then configure the cache manager in the Spring configuration file as follows, where the first bean is a factory bean used to configure the CacheManager of EhCache, and the second bean is the cache manager configured for Spring cache, so the first bean is injected into the second bean.
<cache:annotation-driven cache-manager="cacheManager" /> <!-- Configure EhCache CacheManager to specify the location of the ehcache.xml file through configLocation --> <bean id="ehCacheManager" p:configLocation="classpath:ehcache.xml" p:shared="false" /> <!-- Configure EhCache-based cache manager and inject EhCache CacheManager into the cache manager Bean --> <bean id="cacheManager" p:cacheManager-ref="ehCacheManager" > </bean>
Here is a complete Spring configuration.
<?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:cache="http://www.springframework.org/schema/cache" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-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="com.service"/> <cache:annotation-driven cache-manager="cacheManager" /> <!-- Configure EhCache CacheManager Specify the location of the ehcache.xml file through configLocation --> <bean id="ehCacheManager" p:configLocation="classpath:ehcache.xml" p:shared="false" /> <!-- Configure the EhCache-based cache manager and inject EhCache's CacheManager into the cache manager Bean --> <bean id="cacheManager" p:cacheManager-ref="ehCacheManager" > </bean> </beans>
The following will use @Cacheable as an example to demonstrate the usage of Spring based on EhCache cache. Cacheable is used to modify classes or methods. If the class is modified, all methods in the class will be cached.
Class-level cache
For example, there are the following Bean classes,
@Service("userService")@Cacheable(value="users")public class UserServiceImpl implements UserService { @Override public User getUsersByNameAndAge(String name, int age) { System.out.println("Executing getUsersByNameAndAge().."); return new User(name,age); } @Override public User getAnotherUser(String name, int age) { System.out.println("Executing getAnotherUser().."); return new User(name,age); }}Class-based cache will cache all methods in the class. After cache, the program calls any method of the instance of this class. As long as the passed parameters are the same, Spring will not actually execute the method, but will directly search for the cached data based on the passed parameters!
For example, use cached data like below.
public static void test2() { ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml"); UserService us = ctx.getBean("userService", UserService.class); User u1 = us.getUsersByNameAndAge("Zhang San", 50); //Because the same parameter is used when the userService method is called the second time, the real method will not be executed, //Spring will directly search for data by parameters from the cache User u2 = us.getAnotherUser("Zhang San", 50); System.out.println(u1==u2); }Output result,
GetUsersByNameAndAge() is being executed..
true
As you can see, the above getAnotherUser() is not actually executed because the passed parameters are the same as the parameters passed in by the previous method, so Spring directly comes from the cache area data.
In addition to the required attribute value, the annotation @Cacheable in the Bean class above also has key, condition, and unless attributes. The last three are used to set Spring storage policies. For class-based caches, Spring uses the parameters passed in the method as key to search for results in the cache by default.
Of course, we can also modify the key's strategy and let Spring follow other standards, such as whether the first parameter is the same as the key, and look up the results in the cache.
Modify the above Bean class as follows,
@Service("userService")@Cacheable(value="users", key="#name")public class UserServiceImpl implements UserService { @Override public User getUsersByNameAndAge(String name, int age) {Meaning that we pass in the same name, Spring will not really execute the method. Only when the name is different will the method be executed, for example,
public static void test2() { ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml"); UserService us = ctx.getBean("userService", UserService.class); User u1 = us.getUsersByNameAndAge("Zhang San", 50); //After changing the key parameter of @Cacheable to key="#name", the following method will be able to be executed. User u2 = us.getAnotherUser("Li Si", 50); System.out.println(u1==u2); } You can see that this time getAnotherUser() method has been executed.
1 GetUsersByNameAndAge() is being executed..
2 GetAnotherUser() is being executed..
3 false
We can also set the condition property, for example,
@Service("userService")@Cacheable(value="users", condition="#age<100")public class UserServiceImpl implements UserService { @Override public User getUsersByNameAndAge(String name, int age) {So for the following code, neither method will be cached. Spring executes the real method to get the result every time.
public static void test2() { ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml"); UserService us = ctx.getBean("userService", UserService.class); User u1 = us.getUsersByNameAndAge("Zhang San", 500); User u2 = us.getAnotherUser("Li Si", 500); System.out.println(u1==u2); }Execution results,
GetUsersByNameAndAge() is being executed..
GetAnotherUser() is being executed..
false
Method-level cache will only work for the method. Different methods can set unnecessary cache areas, such as the following,
@Service("userService")public class UserServiceImpl implements UserService { @Cacheable("users1") @Override public User getUsersByNameAndAge(String name, int age) { System.out.println("Execution getUsersByNameAndAge().."); return new User(name,age); } @Cacheable("users2") @Override public User getAnotherUser(String name, int age) { System.out.println("getAnotherUser().."); return new User(name,age); }}Use the following test code,
public static void test2() { ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml"); UserService us = ctx.getBean("userService", UserService.class); //The first time the method is executed, the method will be executed and cached User u1 = us.getUsersByNameAndAge("Zhang San", 500); //Although the following method passes the same parameters, because these two methods are in different cache areas, the cache data cannot be used. User u2 = us.getAnotherUser("Zhang San", 500); System.out.println(u1==u2); //The above has been cached, and it will not be executed here. Use cache directly. User u3 = us.getAnotherUser("Zhang San", 500); System.out.println(u3==u2); }Execution results,
GetUsersByNameAndAge() is being executed..
GetAnotherUser() is being executed..
false
true
The method modified by @CacheEvict can be used to clear the cache, and the following properties can be specified using @CacheEvict .
allEntries, whether to clear the entire cache area
beforeInvocation: Whether to clear the cache before executing the method. The default is to clear it only after the method is executed successfully.
condition and key, the same meaning as in @Cacheable .
The following demonstration is simple.
@Service("userService")@Cacheable("users")public class UserServiceImpl implements UserService {@Override public User getUsersByNameAndAge(String name, int age) {System.out.println("Executing getUsersByNameAndAge()..");return new User(name,age);}@Override public User getAnotherUser(String name, int age) {System.out.println("Executing getAnotherUser()..");return new User(name,age);}//Specify clear cache according to name and age parameters @CacheEvict(value="users") public void evictUser(String name, int age) {System.out.println("--Clearing the corresponding cache of "+name+","+age+");}//Specify clearing all cached data in the user cache area @CacheEvict(value="users", allEntries=true) public void evictAll() {System.out.println("-Clearing the entire cache--");}}Below is the test class,
public static void test2() { ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml"); UserService us = ctx.getBean("userService", UserService.class); //The system will cache two methods User u1 = us.getUsersByNameAndAge("Zhang San", 500); User u2 = us.getAnotherUser("Li Si", 400); //Call the evictUser() method to clear the data specified in the buffer us.evictUser("Li Si", 400); //Clear Li Si, 400 before The data returned by the following method will be cached again User u3 = us.getAnotherUser("Li Si", 400); System.out.println(us == u3); //false //The data of Zhang San and 500 have been cached before, and the following method will not be re-execute, and the data in the cache will be directly retrieved User u4 = us.getAnotherUser("Zhang San", 500); System.out.println(u1==u4); //Output true //Clear the entire cache us.evictAll(); //Because the entire cache has been cleared, the following code will be re-execute User u5 = us.getAnotherUser("Zhang San", 500); User u6 = us.getAnotherUser("Li Si", 400); System.out.println(u1==u5); //Output false System.out.println(u3==u6); //Output false }Execution results,
GetUsersByNameAndAge() is being executed..
GetAnotherUser() is being executed..
--Clearing the cache corresponding to Li Si, 400-
GetAnotherUser() is being executed..
false
true
--Clearing the entire cache-
GetAnotherUser() is being executed..
GetAnotherUser() is being executed..
false
false
The above is all about the Spring caching mechanism example code in this article, I hope it will be helpful to everyone. Interested friends can continue to refer to other related topics on this site. If there are any shortcomings, please leave a message to point it out. Thank you friends for your support for this site!