Spring boot学习笔记
官方地址:https://spring.io/projects
1. 从hello world 开始
1.1 maven 依赖
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.2.RELEASE</version>
</parent>
<dependencies>
<!--spring boot web 包-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
1.2 编写启动程序
1.2.1 方式一
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* <p>Spring boot "hello word"</p>
* @author vchar fred
* @version 1.0
* @date 2018/6/12 15:42
*/
@RestController//相当于Controller+ResponseBody;即自动是ajax的请求
@EnableAutoConfiguration//spring 会自动装配相关的配置,这个是必须有的
public class SpringBootHello {
@RequestMapping("/")
public String home(){
return "hello word!";
}
public static void main(String[] args) throws Exception{
SpringApplication.run(SpringBootHello.class, args);
}
}
运行main方法,在浏览器中访问:http://localhost:8080/ 即可看到hello word
打jar包运行的方法:添加如下maven插件依赖
<build>
<plugins>
<!--spring boot 打包工具-->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
运行maven的 package命令;然后运行 java -jar xxx.jar
1.2.2 方式二
@SpringBootApplication//这个注解包含了EnableAutoConfiguration;更多的配置可以查看源码
@RestController//相当于Controller+ResponseBody;即自动是ajax的请求
public class SpringBootHello {
@RequestMapping("/")
public String home(){
return "hello word!";
}
public static void main(String[] args) throws Exception{
SpringApplication.run(SpringBootHello.class, args);
}
}
@SpringBootApplication 注解源码如下:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class))
public @interface SpringBootApplication {
//排除自启动项
Class<?>[] exclude() default {};
//排除自动启动的beanName
String[] excludeName() default {};
//扫描包
@AliasFor(annotation = ComponentScan.class, attribute = "basePackages")
String[] scanBasePackages() default {};
//扫描类
@AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses")
Class<?>[] scanBasePackageClasses() default {};
}
2. log日志
来源:https://blog.csdn.net/king_is_everyone/article/details/53074006
SpringBoot默认是采用logback进行日志处理、Logback是由log4j创始人设计的又一个开源日志组件
logback当前分成三个模块:logback-core,logback- classic和logback-access
。logback-core是其它两个模块的基础模块
2.1 logback.xml详情
<?xml version="1.0" encoding="UTF-8"?>
<!--
configuration 根节点配置参数说明:
scan:当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true
scanPeriod:设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。配置示例: 120 seconds
debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false
-->
<configuration>
<!--contextName 设置日志上下文名称,可以通过%contextName来打印日志上下文名称
每个logger都关联到logger上下文,默认上下文名称为“default”。
但可以使用<contextName>设置成其他名字,用于区分不同应用程序的记录。一旦设置,不能修改
-->
<contextName>spring-boot-demo-log</contextName>
<!--property 可以用来设置变量,可以通过${name}来访问,有以下的属性
name:用于${name}访问的key;
value:用于${name}访问的value
例:<property name="log.path" value="c:\\logback.log" />
file: 用于指定配置文件的路径,他的作用在于,如果你有多个配置信息的话,可以直接写在配置文件中,然后通过file引入
例:<property file="src/main/java/resources/conf/log.properties" />
resource: 作用和file一样,但是,它是可以直接从classpath路径下引入配置文件
例:<property resource="/conf/log.properties" />
-->
<property name="APP_ID" value="top.vchar.learn.springboot"/>
<property name="LOG_PATH" value="log"></property>
<!--appender 格式化日志输出节点
1. 有2个属性name和class,class用来指定哪种输出策略,常用就是控制台输出策略[STDOUT/console]和文件输出策略[file].
2. appender有以下子节点:
2.1 filter: 日志输出拦截器,可以自定义拦截器也可以用系统一些定义好的拦截器
/**
* 自定义日志输出拦截器
* @author vf
* @date 2016-04-28 3:36
*/
public class MyFilter extends Filter<ILoggingEvent> {
@Override
public FilterReply decide(ILoggingEvent event) {
if (event.getMessage().contains("sample")) {
return FilterReply.ACCEPT; //允许输入串
} else {
return FilterReply.DENY; //不允许输出
}
}
}
系统自带的日志拦截器
例:用ThresholdFilter来过滤掉ERROR级别以下的日志不输出
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>ERROR</level>
</filter>
2.2 encoder和pattern节点组合用于具体输出的日志格式
2.3 file节点用来指明日志文件的输出位置,可以是绝对路径也可以是相对路径
2.4 rollingPolicy日志回滚策略.
2.4.1 TimeBasedRollingPolicy: 基于时间的回滚策略,有以下子节点
fileNamePattern:必要节点,可以用来设置指定时间的日志归档,例如每天将日志归档成一个zip包
maxHistory: 可选节点,控制保留的归档文件的最大数量,超出数量就删除旧文件,,例如设置为30的话,则30天之后,旧的日志就会被删除
totalSizeCap: 可选节点,用来指定日志文件的上限大小,例如设置为1GB的话,那么到了这个值,就会删除旧的日志
例:
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.path}.%d{yyyy-MM-dd}.zip</fileNamePattern>
<maxHistory>30</maxHistory>
<totalSizeCap>1GB</totalSizeCap>
</rollingPolicy>
2.4.2 SizeAndTimeBasedRollingPolicy 基于日志文件大小的回滚策略。
例:
<appender name="ROLLING" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>mylog.txt</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>mylog-%d{yyyy-MM-dd}.%i.txt</fileNamePattern>
<maxFileSize>100MB</maxFileSize>
<maxHistory>60</maxHistory>
<totalSizeCap>20GB</totalSizeCap>
</rollingPolicy>
<encoder>
<pattern>%msg%n</pattern>
</encoder>
</appender>
-->
<!--每个级别的日志配置-->
<!-- 控制台输出 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} %-4relative [%thread] %-5level %logger{35} - %msg %n</pattern>
</encoder>
</appender>
<!--<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">-->
<!--<!–<filter class="ch.qos.logback.classic.filter.ThresholdFilter">–>-->
<!--<!–<level>ERROR</level>–>-->
<!--<!–</filter>–>-->
<!--<encoder>-->
<!--<pattern>%d{HH:mm:ss.SSS} %contextName [%thread] %-5level %logger{36} - %msg%n</pattern>-->
<!--</encoder>-->
<!--</appender>-->
<!--maxHistory配置了日志在服务器上面只存留几个备份-->
<appender name="FILE_LOG"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>DEBUG</level>
</filter>
<file>${LOG_PATH}/${APP_ID}/access.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_PATH}/${APP_ID}/access.log.%d{yyyy-MM-dd}.zip</fileNamePattern>
<maxHistory>10</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} %-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
</encoder>
</appender>
<appender name="FILE_DEBUG"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>DEBUG</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<file>${LOG_PATH}/${APP_ID}/access_debug.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_PATH}/${APP_ID}/access_debug.log.%d{yyyy-MM-dd}.zip</fileNamePattern>
<maxHistory>10</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} %-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
</encoder>
</appender>
<appender name="FILE_INFO"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFO</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<file>${LOG_PATH}/${APP_ID}/access_info.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_PATH}/${APP_ID}/access_info.log.%d{yyyy-MM-dd}.zip</fileNamePattern>
<maxHistory>10</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} %-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
</encoder>
</appender>
<appender name="FILE_WARN"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>WARN</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<file>${LOG_PATH}/${APP_ID}/access_warn.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_PATH}/${APP_ID}/access_warn.log.%d{yyyy-MM-dd}.zip</fileNamePattern>
<maxHistory>10</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} %-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
</encoder>
</appender>
<appender name="FILE_ERROR"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<file>${LOG_PATH}/${APP_ID}/access_error.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_PATH}/${APP_ID}/access_error.log.%d{yyyy-MM-dd}.zip</fileNamePattern>
<maxHistory>10</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} %-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
</encoder>
</appender>
<!--在生产中往往会因为大量的日志导致io过高,所以通过AsyncAppender进行异步的日志记录。-->
<appender name="ASYNC_LOG" class="ch.qos.logback.classic.AsyncAppender">
<!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
<discardingThreshold>0</discardingThreshold>
<!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
<queueSize>64</queueSize>
<appender-ref ref="FILE_LOG"/>
</appender>
<appender name="ASYNC_LOG" class="ch.qos.logback.classic.AsyncAppender">
<!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
<discardingThreshold>0</discardingThreshold>
<!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
<queueSize>64</queueSize>
<appender-ref ref="FILE_LOG"/>
</appender>
<appender name="ASYNC_LOG_DEBUG" class="ch.qos.logback.classic.AsyncAppender">
<!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
<discardingThreshold>0</discardingThreshold>
<!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
<queueSize>64</queueSize>
<appender-ref ref="FILE_DEBUG"/>
</appender>
<appender name="ASYNC_LOG_INFO" class="ch.qos.logback.classic.AsyncAppender">
<!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
<discardingThreshold>0</discardingThreshold>
<!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
<queueSize>64</queueSize>
<appender-ref ref="FILE_INFO"/>
</appender>
<appender name="ASYNC_LOG_WARN" class="ch.qos.logback.classic.AsyncAppender">
<!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
<discardingThreshold>0</discardingThreshold>
<!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
<queueSize>64</queueSize>
<appender-ref ref="FILE_WARN"/>
</appender>
<appender name="ASYNC_LOG_ERROR" class="ch.qos.logback.classic.AsyncAppender">
<!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
<discardingThreshold>0</discardingThreshold>
<!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
<queueSize>64</queueSize>
<appender-ref ref="FILE_ERROR"/>
</appender>
<!--指定root的日志级别,一般来说都会指定到info级别,
因为SpringBoot运行的时候会产生大量的debug日志-->
<root level="INFO">
<!-- appender referenced after it is defined -->
<appender-ref ref="STDOUT"/>
<appender-ref ref="ASYNC_LOG"/>
<appender-ref ref="ASYNC_LOG_DEBUG"/>
<appender-ref ref="ASYNC_LOG_INFO"/>
<appender-ref ref="ASYNC_LOG_WARN"/>
<appender-ref ref="ASYNC_LOG_ERROR"/>
</root>
<!--定义org.springframework这个包里面输出debug日志、-->
<!--一般来说如果使用Mybatis或者hibernate,需要输出SQL都需要通过这里进行配置,输出debug级别的日志-->
<logger name="org.springframework" level="INFO"/>
</configuration>
3.统一异常处理
来源:https://blog.csdn.net/king_is_everyone/article/details/53080851
3.1 spring boot 自带的统一异常处理,重新配置异常地址和页面
SpringBoot在页面发生异常的时候会自动把请求转到/error; SpringBoot内置了一个BasicErrorController对异常进行统一的处理,
这个错误的地址是可以重新配置的。
在resources
目录下创建一个application.yaml配置文件;写入如下配置
server:
#访问端口号
port: 8082
error:
#设置错误路径
path: /test/error
开始编写测试程序
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
/**
* <p>测试异常</p>
*
* @author vchar fred
* @version 1.0
* @date 2018/6/13 11:17
*/
@SpringBootApplication
@Controller
public class TestExceptionController {
@RequestMapping(value = "/ajax")
@ResponseBody
public String ajaxRequestExceptionTest(int nu){
//传入参数为0时抛出异常
int num = 1/nu;
return "this ok "+ num;
}
@RequestMapping(value = "/htmls")
public String htmlRequestExceptionTest(int nu){
//传入参数为0时抛出异常
int num = 1/nu;
return "index";
}
//启动
public static void main(String[] args) throws Exception{
SpringApplication.run(TestExceptionController.class);
}
}
在resources
目录下创建templates目录(这个是默认放置模版文件的目录),并分别创建error.ftl和index.ftl 文件。error.ftl文件用于替换spring boot原有的错误页面,index.ftl用于测试页面
由于用到了freemarker,需要添加maven依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
启动后开始测试
#测试是否可正常访问
http://127.0.0.1:8082/htmls?nu=1
#测试异常页面
http://127.0.0.1:8082/htmls?nu=0
#ajax请求返回的错误提示
{
"timestamp": "2018-06-13T03:55:51.587+0000",
"status": 500,
"error": "Internal Server Error",
"message": "/ by zero",
"path": "/ajax"
}
3.2 通用Exception处理
通过使用@ControllerAdvice来进行统一异常处理,@ExceptionHandler(value = Exception.class)来指定捕获的异常
下面针对两种异常进行了特殊处理分别返回页面和json数据,使用这种方式有个局限,无法根据不同的头部返回不同的数据格式,而且无法针对404、403等多种状态进行处理
//异常处理类
@ControllerAdvice
public class GlobalExceptionHandler {
public static final String DEFAULT_ERROR_VIEW = "error";
@ExceptionHandler(value = CustomException.class)
@ResponseBody
public ResponseEntity defaultErrorHandler(HttpServletRequest req, CustomException e) throws Exception {
return ResponseEntity.ok("ok");
}
@ExceptionHandler(value = Exception.class)
public ModelAndView defaultErrorHandler(HttpServletRequest req, Exception e) throws Exception {
ModelAndView mav = new ModelAndView();
mav.addObject("exception", e);
mav.addObject("url", req.getRequestURL());
mav.setViewName(DEFAULT_ERROR_VIEW);
return mav;
}
}
//自定义异常
public class CustomException extends Exception {
CustomException(String errorMsg){
super(errorMsg);
}
}
//测试路由
@RequestMapping(value = "/coustom")
public String coustomExceptionTest() throws CustomException {
customExce();
return "index";
}
private void customExce() throws CustomException {
throw new CustomException("自定义异常");
}
3.3 自定义BasicErrorController 错误处理
在初始介绍哪里提到了BasicErrorController,这个是SpringBoot的默认错误处理,也是一种全局处理方式。咱们可以模仿这种处理方式自定义自己的全局错误处理
下面定义了一个自己的BasicErrorController,可以根据自己的需求自定义对应的错误处理。
@ResponseStatus 注解的异常类会被ResponseStatusExceptionResolver 解析
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.web.servlet.error.AbstractErrorController;
import org.springframework.boot.web.servlet.error.ErrorAttributes;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.NoHandlerFoundException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
/**
* <p>自定义异常controller</p>
*
* @author vchar fred
* @version 1.0
* @date 2018/6/13 14:25
*/
@Order(Ordered.HIGHEST_PRECEDENCE)
@ControllerAdvice
@Controller
@RequestMapping("${server.error.path:${error.path:/error}}")
public class BasicErrorController extends AbstractErrorController {
public BasicErrorController(ErrorAttributes errorAttributes) {
super(errorAttributes);
}
private static final Logger log = LoggerFactory.getLogger(BasicErrorController.class);
@Value("${server.error.path:${error.path:/error}}")
private static String errorPath = "/error";
/**
* 500 错误
* @param request
* @param response
* @param ex
* @return
* @throws Exception
*/
@ResponseStatus(code = HttpStatus.INTERNAL_SERVER_ERROR)
@ExceptionHandler(Exception.class)
public ModelAndView serverError(HttpServletRequest request, HttpServletResponse response, Exception ex) throws Exception {
return handleViewError(ex.getMessage(), "500", "error/500");
}
/**
* 404错误
* @param request
* @param response
* @param ex
* @return
* @throws Exception
*/
@ResponseStatus(code = HttpStatus.NOT_FOUND)
@ExceptionHandler(NoHandlerFoundException.class)
public ResponseEntity<Map<String, Object>> notFound(HttpServletRequest request, HttpServletResponse response, Exception ex) throws Exception {
Map<String, Object> map = new HashMap<>();
map.put("status", 404);
map.put("msg", "the resource is not found");
map.put("exception", ex.getMessage());
return ResponseEntity.ok(map);
}
/**
* 参数不完整错误.
* @param req
* @param rsp
* @param ex
* @return
* @throws Exception
*/
@ResponseStatus(code = HttpStatus.BAD_REQUEST)
@ExceptionHandler(MethodArgumentNotValidException.class)
public ModelAndView methodArgumentNotValidException(HttpServletRequest req, HttpServletResponse rsp, MethodArgumentNotValidException ex) throws Exception {
return handleViewError(ex.getMessage(), "404", "error/404");
}
private ModelAndView handleViewError(String errorStack, String errorMessage, String viewName) {
ModelAndView mav = new ModelAndView();
mav.addObject("exception", errorStack);
mav.addObject("msg", errorMessage);
mav.addObject("timestamp", new Date());
mav.setViewName(viewName);
return mav;
}
@Override
public String getErrorPath() {
return errorPath;
}
}
定义文件结构如下:
4. spring boot中使用redis
application.yaml配置文件中添加redis如下配置
spring:
rdeis:
host: 127.0.0.1
port: 6379
timeout: 3000
pool:
# 连接池最大连接数(使用负值表示没有限制)
max-total: 8
# 连接池最大阻塞等待时间(使用负值表示没有限制)
max-wait-millis: -1
# 连接池中的最大空闲连接
max-idle: 8
# 连接池中的最小空闲连接
min-idle: 0
加入需要的依赖包
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
注:网上其他有很多教程说引入的是下面这个包
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-redis</artifactId>
</dependency>
但是我在引入时发现当前这个版本中这个包已经无法下载了。
4.1 redis 配置方式1,使用默认的
因为上面依赖了spring-boot-starter-data-redis,可以使用默认的 org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration
类加载properties文件的配置。它的源码如下:
@Configuration
protected static class RedisConfiguration {
@Bean
@ConditionalOnMissingBean(name = "redisTemplate")
public RedisTemplate<Object, Object> redisTemplate(
RedisConnectionFactory redisConnectionFactory)
throws UnknownHostException {
RedisTemplate<Object, Object> template = new RedisTemplate<Object, Object>();
template.setConnectionFactory(redisConnectionFactory);
return template;
}
@Bean
@ConditionalOnMissingBean(StringRedisTemplate.class)
public StringRedisTemplate stringRedisTemplate(
RedisConnectionFactory redisConnectionFactory)
throws UnknownHostException {
StringRedisTemplate template = new StringRedisTemplate();
template.setConnectionFactory(redisConnectionFactory);
return template;
}
}
使用方法
@RestController
public class StartServe {
@Autowired
private StringRedisTemplate template;
@Autowired
private RedisTemplate<Object, Object> redisTemplate;
@RequestMapping("/redis")
public String redisTest(){
//这两个的是不一样的。因为RedisTemplate<Object,Object> 默认会将对象使用JdkSerializationRedisSerializer进行序列化
redisTemplate.opsForValue().set("test", "123456");
template.opsForValue().set("test", "abcdef");
return template.opsForValue().get("test")+"---|||---"+redisTemplate.opsForValue().get("test");
}
}
4.2 redis 配置方式2,自己手动配置
4.2.1 redis的单机版连接池配置
需要加入额外的jar包:
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>
编写相关代码:
- 单机版
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import redis.clients.jedis.JedisPoolConfig;
/**
* <p>redis 配置</p>
*
* @author vchar fred
* @version 1.0
* @date 2018/6/13 18:05
*/
@Configuration
public class RedisConfig {
@Value("${spring.redis.host}")
private String host;
@Value("${spring.redis.port}")
private int port;
@Value("${spring.redis.timeout}")
private int timeout;
//@Value("${spring.redis.password}")
//private String password;
@Value("${spring.redis.pool.max-idle}")
private int maxIdle;
@Value("${spring.redis.pool.min-idle}")
private int minIdle;
@Value("${spring.redis.pool.max-total}")
private int maxTotal;
@Value("${spring.redis.pool.max-wait-millis}")
private int maxWaitMillis;
/**
* 连接设置
* @return 返回连接工厂
*/
@Bean(name = "jedisConnectionFactory")
public JedisConnectionFactory getJedisConnectionFactory(JedisPoolConfig jedisPoolConfig){
JedisConnectionFactory factory = new JedisConnectionFactory();
factory.setHostName(host);
factory.setPort(port);
//factory.setPassword("");//设置认证密码
//factory.setDatabase();//设置库
factory.setTimeout(timeout);
factory.setUsePool(true);
factory.setPoolConfig(jedisPoolConfig);
return factory;
}
/**
* 连接池设置
* @return 返回连接池配置
*/
@Bean(name = "jedisPoolConfig")
public JedisPoolConfig getJedisPoolConfig(){
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
jedisPoolConfig.setMaxTotal(maxTotal);
jedisPoolConfig.setMaxIdle(maxIdle);
jedisPoolConfig.setMaxWaitMillis(maxWaitMillis);
jedisPoolConfig.setMinIdle(minIdle);
return jedisPoolConfig;
}
/**
* RedisTemplate<?,?>
* @param jedisConnectionFactory JedisConnectionFactory
* @return
*/
@Bean
public RedisTemplate<?,?> redisTemplate(JedisConnectionFactory jedisConnectionFactory){
RedisTemplate<?, ?> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(jedisConnectionFactory);
//key序列化方式;但是如果方法上有Long等非String类型的话,会报类型转换错误;
RedisSerializer<String> redisSerializer = new StringRedisSerializer();//Long类型不可以会出现异常信息;
redisTemplate.setKeySerializer(redisSerializer);
redisTemplate.setHashKeySerializer(redisSerializer);
//key序列化方式;但是如果方法上有Long等非String类型的话,会报类型转换错误;
redisTemplate.setValueSerializer(redisSerializer);
redisTemplate.setHashValueSerializer(redisSerializer);
redisTemplate.afterPropertiesSet();
//查看 StringRedisTemplate 的初始化源码,你会发现其实它和上面一样做了的key和value的序列化设置
return redisTemplate;
}
/**
* StringRedisTemplate
* @param jedisConnectionFactory JedisConnectionFactory
* @return StringRedisTemplate
*/
@Bean
public StringRedisTemplate stringRedisTemplate(JedisConnectionFactory jedisConnectionFactory){
StringRedisTemplate stringRedisTemplate = new StringRedisTemplate();
stringRedisTemplate.setConnectionFactory(jedisConnectionFactory);
return stringRedisTemplate;
}
}
- 集群版
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.JedisCluster;
import java.util.HashSet;
import java.util.Set;
/**
* redis集群配置
*/
@Configuration //相当于以前的配置文件
public class RedisConfig {
@Value("${spring.redis.cluster.nodes}")
private static String clusterNodes;
@Bean("jedisCluster")
public JedisCluster getJedisCluster(){
String[] cNodes = clusterNodes.split(",");
Set<HostAndPort> nodes = new HashSet<HostAndPort>();
for (String node: cNodes) {
String[] hp = node.split(":");
nodes.add(new HostAndPort(hp[0],Integer.parseInt(hp[1])));
}
//创建redis的集群对象
return new JedisCluster(nodes);
}
}
使用方式同上面方式一的,这次你会发现他们的key是一样(因为序列化的方式是一样的了)。
另附一个redis配置比较完整的配置文件
来源:https://www.cnblogs.com/EasonJim/p/7805665.html
- 单机版
# REDIS(RedisProperties)
# (普通集群,不使用则不用开启)在群集中执行命令时要遵循的最大重定向数目。
# spring.redis.cluster.max-redirects=
# (普通集群,不使用则不用开启)以逗号分隔的“主机:端口”对列表进行引导。
# spring.redis.cluster.nodes=
# 连接工厂使用的数据库索引。
spring.redis.database=0
# 连接URL,将覆盖主机,端口和密码(用户将被忽略),例如:redis://user:password@example.com:6379
spring.redis.url=
# Redis服务器主机。
spring.redis.host=localhost
# 登录redis服务器的密码。
spring.redis.password=
# 启用SSL支持。
spring.redis.ssl=false
# 池在给定时间可以分配的最大连接数。使用负值无限制。
spring.redis.pool.max-total=8
# 池中“空闲”连接的最大数量。使用负值表示无限数量的空闲连接。
spring.redis.pool.max-idle=8
# 连接分配在池被耗尽时抛出异常之前应该阻塞的最长时间量(以毫秒为单位)。使用负值可以无限期地阻止。
spring.redis.pool.max-wait-millis=-1
# 目标为保持在池中的最小空闲连接数。这个设置只有在正面的情况下才有效果。
spring.redis.pool.min-idle=0
# Redis服务器端口。
spring.redis.port=6379
# (哨兵模式,不使用则不用开启)Redis服务器的名称。
# spring.redis.sentinel.master=
# (哨兵模式,不使用则不用开启)主机:端口对的逗号分隔列表。
# spring.redis.sentinel.nodes=
# 以毫秒为单位的连接超时。
spring.redis.timeout=0
- 集群版,将下面这2项打开即可。
# (普通集群,不使用则不用开启)在群集中执行命令时要遵循的最大重定向数目。 spring.redis.cluster.max-redirects= # (普通集群,不使用则不用开启)以逗号分隔的“主机:端口”对列表进行引导。 spring.redis.cluster.nodes=127.0.0.1:1001,127.0.0.1:1002
注意:一旦开启了集群模式,那么基于单机的配置就会覆盖。
使用到的注解说明
注解 | 说明 |
---|---|
@EnableAutoConfiguration | spring会自动的猜测你需要的那些配置,智能的帮助你去扫描配置 |