spring boot 集成 redis lettuce
一、简介
spring boot 框架中已经集成了 redis,在 1.x.x 的版本时默认使用的 jedis 客户端,现在是 2.x.x 版本默认使用的 lettuce 客户端,两种客户端的区别如下
# Jedis 和 Lettuce 都是 Redis Client
# Jedis 是直连模式,在多个线程间共享一个 Jedis 实例时是线程不安全的,
# 如果想要在多线程环境下使用 Jedis,需要使用连接池,
# 每个线程都去拿自己的 Jedis 实例,当连接数量增多时,物理连接成本就较高了。
# Lettuce 的连接是基于 Netty 的,连接实例可以在多个线程间共享,
# 所以,一个多线程的应用可以使用同一个连接实例,而不用担心并发线程的数量。
# 当然这个也是可伸缩的设计,一个连接实例不够的情况也可以按需增加连接实例。
# 通过异步的方式可以让我们更好的利用系统资源,而不用浪费线程等待网络或磁盘 I/O。
# Lettuce 是基于 netty 的,netty 是一个多线程、事件驱动的 I/O 框架,
# 所以 Lettuce 可以帮助我们充分利用异步的优势。
由于我的项目是 spring boot 2.0.4 的,所以我是用 lettuce 来配置,在我的这个文章里面和其他文章不一样的地方是,其他文章直接把 cache 操作类放在跟 spring boot 同一个模块中
而实际开发时,这种缓存类都是独立放在 common 模块中的,所以 Autowired 就失效了,使用其他方式进行注入
以下是我的项目结构:
二、Common 模块代码
1、先在 pom 中引入 redis 及其它 jar 包
<dependencies> <!-- spring boot redis 缓存引入 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> <version>2.0.4.RELEASE</version> </dependency> <!-- lettuce pool 缓存连接池 --> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId> <version>2.5.0</version> </dependency> <!-- jackson json 优化缓存对象序列化 --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.9.6</version> </dependency> </dependencies>
2、编写缓存配置类 CacheConfig 用于调优缓存默认配置,RedisTemplate<String, Object> 的类型兼容性更高
大家可以看到在 redisTemplate() 这个方法中更换掉了 Redis 默认的序列化方式
spring-data-redis 中序列化类有以下几个:
- GenericToStringSerializer:可以将任何对象泛化为字符创并序列化
- Jackson2JsonRedisSerializer:序列化 Object 对象为 json 字符创(与 JacksonJsonRedisSerializer 相同)
- JdkSerializationRedisSerializer:序列化 java 对象
- StringRedisSerializer:简单的字符串序列化
JdkSerializationRedisSerializer 序列化
被序列化对象必须实现 Serializable 接口,被序列化除属性内容还有其他内容,长度长且不易阅读
存储内容如下:
"\xac\xed\x00\x05sr\x00!com.oreilly.springdata.redis.User\xb1\x1c \n\xcd\xed%\xd8\x02\x00\x02I\x00\x03ageL\x00\buserNamet\x00\x12Ljava/lang/String;xp\x00\x00\x00\x14t\x00\x05user1"
JacksonJsonRedisSerializer 序列化
被序列化对象不需要实现 Serializable 接口,被序列化的结果清晰,容易阅读,而且存储字节少,速度快
存储内容如下:
"{\"userName\":\"user1\",\"age\":20}"
StringRedisSerializer 序列化
一般如果 key、value 都是 string 字符串的话,就是用这个就可以了
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.lettuce.LettuceConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;import java.lang.reflect.Method;
/**
缓存配置 - 使用 Lettuce 客户端,自动注入配置的方式
*/
@Configuration
@EnableCaching //启用缓存
public class CacheConfig extends CachingConfigurerSupport {/**
- 自定义缓存 key 的生成策略。默认的生成策略是看不懂的 (乱码内容) 通过 Spring 的依赖注入特性进行自定义的配置注入并且此类是一个配置类可以更多程度的自定义配置
- @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();
}
};
}/**
- 缓存配置管理器
/
@Bean
public CacheManager cacheManager(LettuceConnectionFactory factory) {
//以锁写入的方式创建 RedisCacheWriter 对象
RedisCacheWriter writer = RedisCacheWriter.lockingRedisCacheWriter(factory);
/
设置 CacheManager 的 Value 序列化方式为 JdkSerializationRedisSerializer,
但其实 RedisCacheConfiguration 默认就是使用
StringRedisSerializer 序列化 key,
JdkSerializationRedisSerializer 序列化 value,
所以以下注释代码就是默认实现,没必要写,直接注释掉
*/
// RedisSerializationContext.SerializationPair pair = RedisSerializationContext.SerializationPair.fromSerializer(new JdkSerializationRedisSerializer(this.getClass().getClassLoader()));
// RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig().serializeValuesWith(pair);
//创建默认缓存配置对象
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig();
RedisCacheManager cacheManager = new RedisCacheManager(writer, config);
return cacheManager;
}/**
- 获取缓存操作助手对象
- @return
*/
@Bean
public RedisTemplate<String, String> redisTemplate(LettuceConnectionFactory factory) {
//创建 Redis 缓存操作助手 RedisTemplate 对象
StringRedisTemplate template = new StringRedisTemplate();
template.setConnectionFactory(factory);
//以下代码为将 RedisTemplate 的 Value 序列化方式由 JdkSerializationRedisSerializer 更换为 Jackson2JsonRedisSerializer
//此种序列化方式结果清晰、容易阅读、存储字节少、速度快,所以推荐更换
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
template.setValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
return template;//StringRedisTemplate 是 RedisTempLate<String, String> 的子类
}
}
3、编写缓存操作提供类 CacheProvider,用于给开发提供缓存操作
import com.google.gson.Gson; import org.springframework.dao.DataAccessException; import org.springframework.data.redis.connection.RedisConnection; import org.springframework.data.redis.core.RedisCallback; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.serializer.RedisSerializer;/**
缓存提供类
*/
public class CacheProvider {//由于当前 class 不在 spring boot 框架内(不在 web 项目中)所以无法使用 autowired,使用此种方法进行注入
private static RedisTemplate<String, String> template = (RedisTemplate<String, String>) SpringBeanUtil.getBean("redisTemplate");public static <T> boolean set(String key, T value) {
Gson gson = new Gson();
return set(key, gson.toJson(value));
}public static boolean set(String key, String value, long validTime) {
boolean result = template.execute(new RedisCallback<Boolean>() {
@Override
public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
RedisSerializer<String> serializer = template.getStringSerializer();
connection.set(serializer.serialize(key), serializer.serialize(value));
connection.expire(serializer.serialize(key), validTime);
return true;
}
});
return result;
}public static <T> T get(String key, Class<T> clazz) {
Gson gson = new Gson();
return gson.fromJson(get(key), clazz);
}public static String get(String key) {
String result = template.execute(new RedisCallback<String>() {
@Override
public String doInRedis(RedisConnection connection) throws DataAccessException {
RedisSerializer<String> serializer = template.getStringSerializer();
byte[] value = connection.get(serializer.serialize(key));
return serializer.deserialize(value);
}
});
return result;
}public static boolean del(String key) {
return template.delete(key);
}
}
4、此时你会发现我们并没有用 Autowired 做自动注入,而是用 SpringBeanUtil.getBean("redisTemplate") 自己写的类进行注入,
因为这个 Common 模块并不在 Spring boot 框架内,自动注入无效,所以改用这个
import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.stereotype.Component;@Component
public class SpringBeanUtil implements ApplicationContextAware {</span><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">static</span> ApplicationContext applicationContext = <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">; @Override </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span> setApplicationContext(ApplicationContext applicationContext) <span style="color: rgba(0, 0, 255, 1)">throws</span><span style="color: rgba(0, 0, 0, 1)"> BeansException { </span><span style="color: rgba(0, 0, 255, 1)">if</span> (SpringBeanUtil.applicationContext == <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">) { SpringBeanUtil.applicationContext </span>=<span style="color: rgba(0, 0, 0, 1)"> applicationContext; } } </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span><span style="color: rgba(0, 0, 0, 1)"> ApplicationContext getApplicationContext() { </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> applicationContext; } </span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)"> * 通过Bean名字获取Bean * * </span><span style="color: rgba(128, 128, 128, 1)">@param</span><span style="color: rgba(0, 128, 0, 1)"> beanName * </span><span style="color: rgba(128, 128, 128, 1)">@return</span> <span style="color: rgba(0, 128, 0, 1)">*/</span> <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span><span style="color: rgba(0, 0, 0, 1)"> Object getBean(String beanName) { </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> getApplicationContext().getBean(beanName); } </span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)"> * 通过Bean类型获取Bean * * </span><span style="color: rgba(128, 128, 128, 1)">@param</span><span style="color: rgba(0, 128, 0, 1)"> beanClass * </span><span style="color: rgba(128, 128, 128, 1)">@param</span><span style="color: rgba(0, 128, 0, 1)"> <T> * </span><span style="color: rgba(128, 128, 128, 1)">@return</span> <span style="color: rgba(0, 128, 0, 1)">*/</span> <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <T> T getBean(Class<T><span style="color: rgba(0, 0, 0, 1)"> beanClass) { </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> getApplicationContext().getBean(beanClass); } </span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)"> * 通过Bean名字和Bean类型获取Bean * * </span><span style="color: rgba(128, 128, 128, 1)">@param</span><span style="color: rgba(0, 128, 0, 1)"> beanName * </span><span style="color: rgba(128, 128, 128, 1)">@param</span><span style="color: rgba(0, 128, 0, 1)"> beanClass * </span><span style="color: rgba(128, 128, 128, 1)">@param</span><span style="color: rgba(0, 128, 0, 1)"> <T> * </span><span style="color: rgba(128, 128, 128, 1)">@return</span> <span style="color: rgba(0, 128, 0, 1)">*/</span> <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <T> T getBean(String beanName, Class<T><span style="color: rgba(0, 0, 0, 1)"> beanClass) { </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> getApplicationContext().getBean(beanName, beanClass); }
}
5、现在 Common 模块就编写完成了,大家可以发现 CacheConfig 类中使用的自动读取配置文件的方式,以下再提供一种手动配置的方式
import com.fasterxml.jackson.annotation.JsonAutoDetect; import com.fasterxml.jackson.annotation.PropertyAccessor; import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.commons.pool2.impl.GenericObjectPoolConfig; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.context.properties.ConfigurationProperties; 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.*; import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; import org.springframework.data.redis.connection.lettuce.LettucePoolingClientConfiguration; 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;/**
缓存配置 - 使用 Lettuce 客户端,手动注入配置的方式
*/
@Configuration
@EnableCaching //启用缓存
@ConfigurationProperties(prefix = "spring.redis") //指明配置节点
public class CacheConfigLettuceManual extends CachingConfigurerSupport {// Redis 服务器地址
@Value("${spring.redis.host}")
private String host;
// Redis 服务器连接端口
@Value("${spring.redis.port}")
private Integer port;
// Redis 数据库索引(默认为 0)
@Value("${spring.redis.database}")
private Integer database;
// Redis 服务器连接密码(默认为空)
@Value("${spring.redis.password}")
private String password;
// 连接超时时间(毫秒)
@Value("${spring.redis.timeout}")
private Integer timeout;// 连接池最大连接数(使用负值表示没有限制)
@Value("${spring.redis.lettuce.pool.max-active}")
private Integer maxTotal;
// 连接池最大阻塞等待时间(使用负值表示没有限制)
@Value("${spring.redis.lettuce.pool.max-wait}")
private Integer maxWait;
// 连接池中的最大空闲连接
@Value("${spring.redis.lettuce.pool.max-idle}")
private Integer maxIdle;
// 连接池中的最小空闲连接
@Value("${spring.redis.lettuce.pool.min-idle}")
private Integer minIdle;
// 关闭超时时间
@Value("${spring.redis.lettuce.shutdown-timeout}")
private Integer shutdown;/**
- 自定义缓存 key 的生成策略。默认的生成策略是看不懂的 (乱码内容) 通过 Spring 的依赖注入特性进行自定义的配置注入并且此类是一个配置类可以更多程度的自定义配置
- @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();
}
};
}/**
- 缓存配置管理器
/
@Bean
@Override
public CacheManager cacheManager() {
//以锁写入的方式创建 RedisCacheWriter 对象
RedisCacheWriter writer = RedisCacheWriter.lockingRedisCacheWriter(getConnectionFactory());
/
设置 CacheManager 的 Value 序列化方式为 JdkSerializationRedisSerializer,
但其实 RedisCacheConfiguration 默认就是使用
StringRedisSerializer 序列化 key,
JdkSerializationRedisSerializer 序列化 value,
所以以下注释代码就是默认实现,没必要写,直接注释掉
*/
// RedisSerializationContext.SerializationPair pair = RedisSerializationContext.SerializationPair.fromSerializer(new JdkSerializationRedisSerializer(this.getClass().getClassLoader()));
// RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig().serializeValuesWith(pair);
//创建默认缓存配置对象
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig();
RedisCacheManager cacheManager = new RedisCacheManager(writer, config);
return cacheManager;
}/**
- 获取缓存操作助手对象
- @return
*/
@Bean
public RedisTemplate<String, String> redisTemplate() {
//创建 Redis 缓存操作助手 RedisTemplate 对象
RedisTemplate<String, String> template = new RedisTemplate<>();
template.setConnectionFactory(getConnectionFactory());
//以下代码为将 RedisTemplate 的 Value 序列化方式由 JdkSerializationRedisSerializer 更换为 Jackson2JsonRedisSerializer
//此种序列化方式结果清晰、容易阅读、存储字节少、速度快,所以推荐更换
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
template.setValueSerializer(jackson2JsonRedisSerializer);
template.setKeySerializer(new StringRedisSerializer());//RedisTemplate 对象需要指明 Key 序列化方式,如果声明 StringRedisTemplate 对象则不需要
//template.setEnableTransactionSupport(true);//是否启用事务
template.afterPropertiesSet();
return template;
}/**
- 获取缓存连接
- @return
*/
@Bean
public RedisConnectionFactory getConnectionFactory() {
//单机模式
RedisStandaloneConfiguration configuration = new RedisStandaloneConfiguration();
configuration.setHostName(host);
configuration.setPort(port);
configuration.setDatabase(database);
configuration.setPassword(RedisPassword.of(password));
//哨兵模式
//RedisSentinelConfiguration configuration1 = new RedisSentinelConfiguration();
//集群模式
//RedisClusterConfiguration configuration2 = new RedisClusterConfiguration();
LettuceConnectionFactory factory = new LettuceConnectionFactory(configuration, getPoolConfig());
//factory.setShareNativeConnection(false);//是否允许多个线程操作共用同一个缓存连接,默认 true,false 时每个操作都将开辟新的连接
return factory;
}/**
- 获取缓存连接池
- @return
*/
@Bean
public LettucePoolingClientConfiguration getPoolConfig() {
GenericObjectPoolConfig config = new GenericObjectPoolConfig();
config.setMaxTotal(maxTotal);
config.setMaxWaitMillis(maxWait);
config.setMaxIdle(maxIdle);
config.setMinIdle(minIdle);
LettucePoolingClientConfiguration pool = LettucePoolingClientConfiguration.builder()
.poolConfig(config)
.commandTimeout(Duration.ofMillis(timeout))
.shutdownTimeout(Duration.ofMillis(shutdown))
.build();
return pool;
}}
三、Web 模块代码
这里只是一个调用方,使用 spring boot 先添加 pom.xml 信息
<dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>2.0.3.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement><span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">dependencies</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">dependency</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">groupId</span><span style="color: rgba(0, 0, 255, 1)">></span>org.springframework.boot<span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">groupId</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">artifactId</span><span style="color: rgba(0, 0, 255, 1)">></span>spring-boot-starter-web<span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">artifactId</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">dependency</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">dependency</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">groupId</span><span style="color: rgba(0, 0, 255, 1)">></span>javademo.tyh<span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">groupId</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">artifactId</span><span style="color: rgba(0, 0, 255, 1)">></span>javademo-tyh-common<span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">artifactId</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">version</span><span style="color: rgba(0, 0, 255, 1)">></span>1.0-SNAPSHOT<span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">version</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">dependency</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">dependencies</span><span style="color: rgba(0, 0, 255, 1)">></span></pre>
添加配置文件及里面的配置
spring.application.name=javademo-tyh-job server.port=15000#redis
# Redis 服务器地址
spring.redis.host=10.11.12.237
# Redis 服务器连接端口
spring.redis.port=6379
# Redis 数据库索引(默认为 0)
spring.redis.database=0
# Redis 服务器连接密码(默认为空)
spring.redis.password=
# 连接超时时间(毫秒)
spring.redis.timeout=10000# 以下连接池已在 SpringBoot2.0 不推荐使用
#spring.redis.pool.max-active=8
#spring.redis.pool.max-wait=-1
#spring.redis.pool.max-idle=8
#spring.redis.pool.min-idle=0# Jedis
#spring.redis.jredis.max-active=8
#spring.redis.jredis.max-wait=10000
#spring.redis.jredis.max-idle=8
#spring.redis.jredis.min-idle=0# Lettuce
# 连接池最大连接数(使用负值表示没有限制)
spring.redis.lettuce.pool.max-active=8
# 连接池最大阻塞等待时间(使用负值表示没有限制)
spring.redis.lettuce.pool.max-wait=10000
# 连接池中的最大空闲连接
spring.redis.lettuce.pool.max-idle=8
# 连接池中的最小空闲连接
spring.redis.lettuce.pool.min-idle=0
# 关闭超时时间
spring.redis.lettuce.shutdown-timeout=100
启动 main() 方法
SpringBoot 在写启动类的时候如果不使用 @ComponentScan 指明对象扫描范围,默认只扫描当前启动类所在的包里的对象,
因为启动类不能直接放在 main/java 文件夹下,必须要建一个包把它放进去,这是就需要使用 @ComponentScan 指明要扫描的包。
如:
javademo-tyh-common 模块的包名:javademo.tyh.common
javademo-tyh-job 模块的包名:javademo.tyh.job
这样默认就不会把 common 模块中标记 @Component 的组件装配到 SpringBoot 中,因为它默认只扫描 javademo.tyh.job 包下的组件,
所以这时就需要在 main()启动类中使用 @ComponentScan 注解来指明要扫描那些包,但只扫描该注解指定的包,当前 mian() 方法所在的包就不会被扫描了
所以要写它的上级包“javademo.tyh”
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.ComponentScan;/
SpringBoot 在写启动类的时候如果不使用 @ComponentScan 指明对象扫描范围,默认只扫描当前启动类所在的包里的对象,
因为启动类不能直接放在 main/java 文件夹下,必须要建一个包把它放进去,这是就需要使用 @ComponentScan 指明要扫描的包。
如:
javademo-tyh-common 模块的包名:javademo.tyh.common
javademo-tyh-job 模块的包名:javademo.tyh.job
这样默认就不会把 common 模块中标记 @Component 的组件装配到 SpringBoot 中,因为它默认只扫描 javademo.tyh.job 包下的组件,
所以这时就需要在 main()启动类中使用 @ComponentScan 注解来指明要扫描那些包,但只扫描该注解指定的包,当前 mian() 方法所在的包就不会被扫描了,
所以要写它的上级包“javademo.tyh”
/
@ComponentScan("javademo.tyh")
@SpringBootApplication
public class AppJob
{
public static void main(String[] args )
{
SpringApplication.run(AppJob.class);
}
}
controller 控制器
import javademo.tyh.common.CacheProvider; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody;import javax.servlet.http.Cookie;
@Controller
@RequestMapping("/test")
public class TestController {@ResponseBody @RequestMapping(</span>"index"<span style="color: rgba(0, 0, 0, 1)">) </span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> String index(){ String str </span>= ""<span style="color: rgba(0, 0, 0, 1)">; str </span>+= CacheProvider.set("tyh", "aaaaaaaaaaaaaaaaaa"<span style="color: rgba(0, 0, 0, 1)">); str </span>+= "|"<span style="color: rgba(0, 0, 0, 1)">; str </span>+= CacheProvider.get("tyh"<span style="color: rgba(0, 0, 0, 1)">); str </span>+= "|"<span style="color: rgba(0, 0, 0, 1)">; str </span>+= CacheProvider.del("tyh"<span style="color: rgba(0, 0, 0, 1)">); str </span>+= "|||"<span style="color: rgba(0, 0, 0, 1)">; Cookie cookie </span>= <span style="color: rgba(0, 0, 255, 1)">new</span> Cookie("aaa", "bbb"<span style="color: rgba(0, 0, 0, 1)">); str </span>+= CacheProvider.set("cookie"<span style="color: rgba(0, 0, 0, 1)">, cookie); str </span>+= "|"<span style="color: rgba(0, 0, 0, 1)">; str </span>+= CacheProvider.get("cookie", Cookie.<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">); str </span>+= "|"<span style="color: rgba(0, 0, 0, 1)">; str </span>+= CacheProvider.del("cookie"<span style="color: rgba(0, 0, 0, 1)">); </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> str.toString(); }
}
好了,启动程序,打开 http://localhost:15000/cacheManage/test 可以看到如下结果,就证明已经集成完成了