1、SpringBoot配置類
2.SpringBoot整合redis及其注解式開發
SpringBoot配置類
注解標簽
@Configuration
@Configuration底層是含有@Component ,所以@Configuration 具有和 @Component 的作用。
@Configuration可理解為用spring的時候xml里面的<beans>標簽。
注:
1) 配置類必須以類的形式提供(不能是工廠方法返回的實例),允許通過生成子類在運行時增強(cglib 動態代理)。
2) 配置類不能是 final 類(沒法動態代理)。
3) 配置注解通常為了通過 @Bean 注解生成 Spring 容器管理的類。
4) 配置類必須是非本地的(即不能在方法中聲明,不能是 private)。
5) 任何嵌套配置類都必須聲明為static。
6) @Bean方法不能創建進一步的配置類(也就是返回的bean如果帶有@Configuration,也不會被特殊處理,只會作為普通的 bean)。
@EnableCaching
1) @EnableCaching注解是spring framework中的注解驅動的緩存管理功能。自spring版本3.1起加入了該注解。
2) 如果你使用了這個注解,那么你就不需要在XML文件中配置cache manager了。
3) 當你在配置類(@Configuration)上使用@EnableCaching注解時,會觸發一個post processor,這會掃描每一個spring bean,查看是否已經存在注解對應的緩存。如果找到了,就會自動創建一個代理攔截方法調用,使用緩存的bean執行處理。
@Bean
@Bean可理解為用spring的時候xml里面的<bean>標簽。
注:
1) @Bean注解在返回實例的方法上,如果未通過@Bean指定bean的名稱,則默認與標注的方法名相同;
2) @Bean注解默認作用域為單例singleton作用域,可通過@Scope(“prototype”)設置為原型作用域;
3) 既然@Bean的作用是注冊bean對象,那么完全可以使用@Component、@Controller、@Service、@Repository等注解注冊bean(在需要注冊的類上加注解),當然需要配置@ComponentScan注解進行自動掃描。
導入redis的依賴
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> </dependency>
配置application.yml
redis:
database: 0
host: 192.168.197.128
port: 6379
password: 123456
jedis:
pool:
max-active: 100
max-idle: 3
max-wait: -1
min-idle: 0
timeout: 1000
創建RedisConfig
RedisConfig類用於Redis數據緩存。
//繼承CachingConfigurerSupport,為了自定義生成KEY的策略。可以不繼承。
package com.hmc.springboot02.redis; import com.fasterxml.jackson.annotation.JsonAutoDetect; import com.fasterxml.jackson.annotation.PropertyAccessor; import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.cache.CacheManager; import org.springframework.cache.annotation.CachingConfigurerSupport; import org.springframework.cache.annotation.EnableCaching; import org.springframework.cache.interceptor.KeyGenerator; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.cache.RedisCacheConfiguration; import org.springframework.data.redis.cache.RedisCacheManager; import org.springframework.data.redis.cache.RedisCacheWriter; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer; import org.springframework.data.redis.serializer.RedisSerializationContext; import org.springframework.data.redis.serializer.StringRedisSerializer; import java.lang.reflect.Method; import java.time.Duration; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; /** * redis配置類 **/ @Configuration @EnableCaching//開啟注解式緩存 //繼承CachingConfigurerSupport,為了自定義生成KEY的策略。可以不繼承。 public class RedisConfig extends CachingConfigurerSupport { /** * 生成key的策略 根據類名+方法名+所有參數的值生成唯一的一個key * * @return */ @Bean @Override public KeyGenerator keyGenerator() { return new KeyGenerator() { @Override public Object generate(Object target, Method method, Object... params) { StringBuilder sb = new StringBuilder(); sb.append(target.getClass().getName()); sb.append(method.getName()); for (Object obj : params) { sb.append(obj.toString()); } return sb.toString(); } }; } /** * 管理緩存 * * @param redisConnectionFactory * @return */ @Bean public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) { //通過Spring提供的RedisCacheConfiguration類,構造一個自己的redis配置類,從該配置類中可以設置一些初始化的緩存命名空間 // 及對應的默認過期時間等屬性,再利用RedisCacheManager中的builder.build()的方式生成cacheManager: RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig(); // 生成一個默認配置,通過config對象即可對緩存進行自定義配置 config = config.entryTtl(Duration.ofMinutes(1)) // 設置緩存的默認過期時間,也是使用Duration設置 .disableCachingNullValues(); // 不緩存空值 // 設置一個初始化的緩存空間set集合 Set<String> cacheNames = new HashSet<>(); cacheNames.add("my-redis-cache1"); cacheNames.add("my-redis-cache2"); // 對每個緩存空間應用不同的配置 Map<String, RedisCacheConfiguration> configMap = new HashMap<>(); configMap.put("my-redis-cache1", config); configMap.put("my-redis-cache2", config.entryTtl(Duration.ofSeconds(120))); RedisCacheManager cacheManager = RedisCacheManager.builder(redisConnectionFactory) // 使用自定義的緩存配置初始化一個cacheManager .initialCacheNames(cacheNames) // 注意這兩句的調用順序,一定要先調用該方法設置初始化的緩存名,再初始化相關的配置 .withInitialCacheConfigurations(configMap) .build(); return cacheManager; } @Bean public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory) { RedisTemplate<Object, Object> template = new RedisTemplate<>(); template.setConnectionFactory(connectionFactory); //使用Jackson2JsonRedisSerializer來序列化和反序列化redis的value值(默認使用JDK的序列化方式) Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer(Object.class); ObjectMapper mapper = new ObjectMapper(); mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); serializer.setObjectMapper(mapper); template.setValueSerializer(serializer); //使用StringRedisSerializer來序列化和反序列化redis的key值 template.setKeySerializer(new StringRedisSerializer()); template.afterPropertiesSet(); return template; } @Bean public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory factory) { StringRedisTemplate stringRedisTemplate = new StringRedisTemplate(); stringRedisTemplate.setConnectionFactory(factory); return stringRedisTemplate; } }
詳細針對下面這段代碼進行講解
/**
* 管理緩存
*
* @param redisConnectionFactory
* @return
*/
@Bean
public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
//通過Spring提供的RedisCacheConfiguration類,構造一個自己的redis配置類,從該配置類中可以設置一些初始化的緩存命名空間
// 及對應的默認過期時間等屬性,再利用RedisCacheManager中的builder.build()的方式生成cacheManager:
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig(); // 生成一個默認配置,通過config對象即可對緩存進行自定義配置
config = config.entryTtl(Duration.ofMinutes(1)) // 設置緩存的默認過期時間,也是使用Duration設置
.disableCachingNullValues(); // 不緩存空值
// 設置一個初始化的緩存空間set集合
Set<String> cacheNames = new HashSet<>();
cacheNames.add("my-redis-cache1");
cacheNames.add("my-redis-cache2");
// 對每個緩存空間應用不同的配置
Map<String, RedisCacheConfiguration> configMap = new HashMap<>();
configMap.put("my-redis-cache1", config);
configMap.put("my-redis-cache2", config.entryTtl(Duration.ofSeconds(120)));
RedisCacheManager cacheManager = RedisCacheManager.builder(redisConnectionFactory) // 使用自定義的緩存配置初始化一個cacheManager
.initialCacheNames(cacheNames) // 注意這兩句的調用順序,一定要先調用該方法設置初始化的緩存名,再初始化相關的配置
.withInitialCacheConfigurations(configMap)
.build();
return cacheManager;
}
在整合ehcache的時候,會有一個配置文件spring-ehcache.xml如下
<!-- 使用ehcache緩存 --> <bean id="cacheManagerFactory" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"> <property name="configLocation" value="classpath:ehcache.xml"/> <property name="shared" value="true"></property> </bean> <!-- 默認是cacheManager --> <bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager"> <property name="cacheManager" ref="cacheManagerFactory"/> </bean>
ehcache.xml
<!--defaultCache:默認的管理策略--> <!--eternal:設定緩存的elements是否永遠不過期。如果為true,則緩存的數據始終有效,如果為false那么還要根據timeToIdleSeconds,timeToLiveSeconds判斷--> <!--maxElementsInMemory:在內存中緩存的element的最大數目--> <!--overflowToDisk:如果內存中數據超過內存限制,是否要緩存到磁盤上--> <!--diskPersistent:是否在磁盤上持久化。指重啟jvm后,數據是否有效。默認為false--> <!--timeToIdleSeconds:對象空閑時間(單位:秒),指對象在多長時間沒有被訪問就會失效。只對eternal為false的有效。默認值0,表示一直可以訪問--> <!--timeToLiveSeconds:對象存活時間(單位:秒),指對象從創建到失效所需要的時間。只對eternal為false的有效。默認值0,表示一直可以訪問--> <!--memoryStoreEvictionPolicy:緩存的3 種清空策略--> <!--FIFO:first in first out (先進先出)--> <!--LFU:Less Frequently Used (最少使用).意思是一直以來最少被使用的。緩存的元素有一個hit 屬性,hit 值最小的將會被清出緩存--> <!--LRU:Least Recently Used(最近最少使用). (ehcache 默認值).緩存的元素有一個時間戳,當緩存容量滿了,而又需要騰出地方來緩存新的元素的時候,那么現有緩存元素中時間戳離當前時間最遠的元素將被清出緩存--> <defaultCache eternal="false" maxElementsInMemory="1000" overflowToDisk="false" diskPersistent="false" timeToIdleSeconds="0" timeToLiveSeconds="600" memoryStoreEvictionPolicy="LRU"/>
所以紅色代碼的意思是:從RedisCacheConfiguration獲取一個默認的緩存策略,針對這一策略做對應的調整,生成一個全新的策略。然后,初始化兩個緩存槽,賦予名字my-redis-cache1和my-redis-cache2,,賦予再基於之前的緩存策略,初始化兩個緩存策略,存儲與configMap,然后策略與緩存槽對應上,生成緩存管理器交個spring進行管理,替代掉SSM時代的配置文件。
ssm框架中如果整合redis,那么會有個spring-redis.xml配置文件,里面的配置內容如下
<!-- 1. 引入properties配置文件 --> <!--<context:property-placeholder location="classpath:redis.properties" />--> <!-- 2. redis連接池配置--> <bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig"> <!--最大空閑數--> <property name="maxIdle" value="${redis.maxIdle}"/> <!--連接池的最大數據庫連接數 --> <property name="maxTotal" value="${redis.maxTotal}"/> <!--最大建立連接等待時間--> <property name="maxWaitMillis" value="${redis.maxWaitMillis}"/> <!--逐出連接的最小空閑時間 默認1800000毫秒(30分鍾)--> <property name="minEvictableIdleTimeMillis" value="${redis.minEvictableIdleTimeMillis}"/> <!--每次逐出檢查時 逐出的最大數目 如果為負數就是 : 1/abs(n), 默認3--> <property name="numTestsPerEvictionRun" value="${redis.numTestsPerEvictionRun}"/> <!--逐出掃描的時間間隔(毫秒) 如果為負數,則不運行逐出線程, 默認-1--> <property name="timeBetweenEvictionRunsMillis" value="${redis.timeBetweenEvictionRunsMillis}"/> <!--是否在從池中取出連接前進行檢驗,如果檢驗失敗,則從池中去除連接並嘗試取出另一個--> <property name="testOnBorrow" value="${redis.testOnBorrow}"/> <!--在空閑時檢查有效性, 默認false --> <property name="testWhileIdle" value="${redis.testWhileIdle}"/> </bean> <!-- 3. redis連接工廠 --> <bean id="connectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" destroy-method="destroy"> <property name="poolConfig" ref="poolConfig"/> <!--IP地址 --> <property name="hostName" value="${redis.hostName}"/> <!--端口號 --> <property name="port" value="${redis.port}"/> <!--如果Redis設置有密碼 --> <property name="password" value="${redis.password}"/> <!--客戶端超時時間單位是毫秒 --> <property name="timeout" value="${redis.timeout}"/> </bean> <!-- 4. redis操作模板,使用該對象可以操作redis --> <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate"> <property name="connectionFactory" ref="connectionFactory"/> <!--如果不配置Serializer,那么存儲的時候缺省使用String,如果用User類型存儲,那么會提示錯誤User can't cast to String!! --> <property name="keySerializer"> <bean class="org.springframework.data.redis.serializer.StringRedisSerializer"/> </property> <property name="valueSerializer"> <bean class="org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer"/> </property> <property name="hashKeySerializer"> <bean class="org.springframework.data.redis.serializer.StringRedisSerializer"/> </property> <property name="hashValueSerializer"> <bean class="org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer"/> </property> <!--開啟事務 --> <property name="enableTransactionSupport" value="true"/> </bean> <!-- 5.使用中間類解決RedisCache.RedisTemplate的靜態注入,從而使MyBatis實現第三方緩存 --> <bean id="redisCacheTransfer" class="com.javaxl.ssm2.util.RedisCacheTransfer"> <property name="redisTemplate" ref="redisTemplate"/> </bean>
其中前面redis鏈接工廠的創建,已經交於springboot中的application.yml文件來完成。所以,springboot整合redis我們只需要關注下面這部分配置。
@Bean public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory) { RedisTemplate<Object, Object> template = new RedisTemplate<>(); template.setConnectionFactory(connectionFactory); //使用Jackson2JsonRedisSerializer來序列化和反序列化redis的value值(默認使用JDK的序列化方式) Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer(Object.class); ObjectMapper mapper = new ObjectMapper(); mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); serializer.setObjectMapper(mapper); template.setValueSerializer(serializer); //使用StringRedisSerializer來序列化和反序列化redis的key值 template.setKeySerializer(new StringRedisSerializer()); template.afterPropertiesSet(); return template; } @Bean public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory factory) { StringRedisTemplate stringRedisTemplate = new StringRedisTemplate(); stringRedisTemplate.setConnectionFactory(factory); return stringRedisTemplate; } }
SpringBoot整合redis及其注解式開發
常用緩存注解
@Cacheable:作用是主要針對方法配置,能夠根據方法的請求參數對其結果進行緩存
主要參數說明:
1) value :
緩存的名稱,在 spring 配置文件中定義,必須指定至少一個,
例如:@Cacheable(value=”mycache”) 或者 @Cacheable(value={”cache1”,”cache2”}。
2) key :緩存的 key,可以為空,
如果指定要按照 SpEL 表達式編寫,如果不指定,則缺省按照方法的所有參數進行組合,
例如:@Cacheable(value=”testcache”,key=”#userName”)。
3) condition :緩存的條件,可以為空,
案例如下:
service層
實現類
測試代碼 id>500
id<500的時候就不會緩存
可以看出兩次查詢都查了數據庫
@CachePut:作用是主要針對方法配置,能夠根據方法的請求參數對其結果進行緩存,和 @Cacheable 不同的是,它每次都會觸發真實查詢
方法的調用
主要參數說明:
參數配置和@Cacheable一樣。
結果看出兩次都觸發了真實查詢
@CacheEvict:作用是主要針對方法配置,能夠根據一定的條件對緩存進行清空
主要參數說明:
1)value , key 和 condition 參數配置和@Cacheable一樣。
2) allEntries :
是否清空所有緩存內容,缺省為 false,
如果指定為 true,則方法調用后將立即清空所有緩存,
例如:@CachEvict(value=”testcache”,allEntries=true)。
這時redis里面是有數據的
緩存數據已清空