SpringBoot | 字数总计: 4.7k | 阅读时长: 22分钟 | 阅读量:
定时器 定时器的数值放到配置文件,如果使用@Scheduled(fixedDelay = 类中的变量)
这种方式试过不行
1 2 3 @Scheduled(fixedDelayString = "${fixedDelayString}") public void open () {}
RocketMQ 下载源码或者二进制包
1 2 3 4 5 6 7 8 # 源码安装 # 解压文件 unzip rocketmq-all-5.2.0-source-release.zip cd rocketmq-all-5.2.0-source-release/ # 编译 mvn -Prelease-all -DskipTests -Dspotbugs.skip=true clean install -U # 编译后的二进制的目录,配置文件在这里 cd ./distribution
修改配置文件
1 2 3 4 5 6 7 # 修改配置文件 # 修改内存配置,虚拟机的内存太小了 # vim ./bin/runserver.sh JAVA_OPT="${JAVA_OPT} -server -Xms512m -Xmx521m -Xmn256g -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=320m" # vim ./bin/runbroker.sh JAVA_OPT="${JAVA_OPT} -server -Xms512m -Xmx512m"
启动
1 2 3 4 5 6 # 第一步.启动Name Server sh bin/mqnamesrv The Name Server boot success... # 第二步.启动Broker sh bin/mqbroker -n localhost:9876 The broker[%s, 172.30.30.233:10911] boot success...
测试发送消息
1 2 3 4 5 export NAMESRV_ADDR=localhost:9876 # 发送消息 sh bin/tools.sh org.apache.rocketmq.example.quickstart.Producer # 接收消息 sh bin/tools.sh org.apache.rocketmq.example.quickstart.Consumer
关闭服务 1 2 sh bin/mqshutdown broker sh bin/mqshutdown namesrv
监控 1 2 3 4 5 6 7 # 记得checkout release-rocketmq-console-1.0.0分支 git clone https://github.com/apache/rocketmq-externals/tree/release-rocketmq-console-1.0.0 # 修改配置文件里的rocketMQ远程地址 NameSvrAddrList = 192.168.254.124:9876 # 或者 rocketmq.config.namesrvAddr=192.168.254.124:9876
代码 单个生产者消费者 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 public class Provider { public static void main (String[] args) throws Exception { DefaultMQProducer producer = new DefaultMQProducer ("group1" ); producer.setNamesrvAddr("192.168.254.190:9876" ); producer.start(); String msg = "什么鬼,咋莫名其妙就收到了" ; Message message = new Message ("topic1" , "tag1" , msg.getBytes()); SendResult sendResult = producer.send(message); System.out.printf("%s%n" , sendResult); producer.shutdown(); } } public class Consumer { public static void main (String[] args) throws MQClientException { DefaultMQPushConsumer consumer = new DefaultMQPushConsumer ("group1" ); consumer.setNamesrvAddr("192.168.254.190:9876" ); consumer.subscribe("topic1" , "*" ); consumer.registerMessageListener((MessageListenerConcurrently) (list, consumeConcurrentlyContext) -> { list.forEach(one->{ byte [] body = one.getBody(); System.out.println(new String (body)); }); return ConsumeConcurrentlyStatus.CONSUME_SUCCESS; }); consumer.start(); System.out.println("消费者启起来了" ); } }
单个生产者多个消费者 相同的Topic,相同的Group-负载均衡 默认就是负载均衡,多个消费者,每个人收一条信息,不重复
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 public class Provider { public static void main (String[] args) throws Exception { DefaultMQProducer producer = new DefaultMQProducer ("group2" ); producer.setNamesrvAddr("192.168.254.190:9876" ); producer.start(); for (int i = 0 ; i < 10 ; i++) { String msg = "默认接受者是负载均衡" +i; Message message = new Message ("topic2" , "tag1" , msg.getBytes()); SendResult sendResult = producer.send(message); System.out.printf("%s%n" , sendResult); } producer.shutdown(); } } public class Consumer { public static void main (String[] args) throws MQClientException { DefaultMQPushConsumer consumer = new DefaultMQPushConsumer ("group2" ); consumer.setNamesrvAddr("192.168.254.190:9876" ); consumer.subscribe("topic2" , "*" ); consumer.registerMessageListener((MessageListenerConcurrently) (list, consumeConcurrentlyContext) -> { list.forEach(one->{ byte [] body = one.getBody(); System.out.println(new String (body)); }); return ConsumeConcurrentlyStatus.CONSUME_SUCCESS; }); consumer.start(); System.out.println("消费者启起来了" ); } } 默认接受者是负载均衡0 默认接受者是负载均衡1 默认接受者是负载均衡4 默认接受者是负载均衡5 默认接受者是负载均衡8 默认接受者是负载均衡9 默认接受者是负载均衡2 默认接受者是负载均衡3 默认接受者是负载均衡6 默认接受者是负载均衡7
相同的Topic,相同的Group-轮训 只是添加了消费者的一段代码:consumer.setMessageModel(MessageModel.BROADCASTING);
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 public class Provider { public static void main (String[] args) throws Exception { DefaultMQProducer producer = new DefaultMQProducer ("group3" ); producer.setNamesrvAddr("192.168.254.190:9876" ); producer.start(); for (int i = 0 ; i < 10 ; i++) { String msg = "默认接受者是负载均衡" +i; Message message = new Message ("topic3" , "tag1" , msg.getBytes()); SendResult sendResult = producer.send(message); System.out.printf("%s%n" , sendResult); } producer.shutdown(); } } public class Consumer { public static void main (String[] args) throws MQClientException { DefaultMQPushConsumer consumer = new DefaultMQPushConsumer ("group3" ); consumer.setNamesrvAddr("192.168.254.190:9876" ); consumer.subscribe("topic3" , "*" ); consumer.setMessageModel(MessageModel.BROADCASTING); consumer.registerMessageListener((MessageListenerConcurrently) (list, consumeConcurrentlyContext) -> { list.forEach(one->{ byte [] body = one.getBody(); System.out.println(new String (body)); }); return ConsumeConcurrentlyStatus.CONSUME_SUCCESS; }); consumer.start(); System.out.println("消费者启起来了" ); } } 默认接受者是负载均衡0 默认接受者是负载均衡1 默认接受者是负载均衡2 默认接受者是负载均衡3 默认接受者是负载均衡4 默认接受者是负载均衡5 默认接受者是负载均衡6 默认接受者是负载均衡7 默认接受者是负载均衡8 默认接受者是负载均衡9
不同的Topic,不同的Group
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 public class Consumer { public static void main (String[] args) throws MQClientException { DefaultMQPushConsumer consumer = new DefaultMQPushConsumer ("group4" ); consumer.setNamesrvAddr("192.168.254.190:9876" ); consumer.subscribe("topic4" , "*" ); consumer.registerMessageListener((MessageListenerConcurrently) (list, consumeConcurrentlyContext) -> { list.forEach(one->{ byte [] body = one.getBody(); System.out.println(new String (body)); }); return ConsumeConcurrentlyStatus.CONSUME_SUCCESS; }); consumer.start(); System.out.println("消费者启起来了" ); } } public class Consumer { public static void main (String[] args) throws MQClientException { DefaultMQPushConsumer consumer = new DefaultMQPushConsumer ("group4" ); consumer.setNamesrvAddr("192.168.254.190:9876" ); consumer.subscribe("topic4" , "*" ); consumer.registerMessageListener((MessageListenerConcurrently) (list, consumeConcurrentlyContext) -> { list.forEach(one->{ byte [] body = one.getBody(); System.out.println(new String (body)); }); return ConsumeConcurrentlyStatus.CONSUME_SUCCESS; }); consumer.start(); System.out.println("消费者启起来了" ); } } public class Consumer { public static void main (String[] args) throws MQClientException { DefaultMQPushConsumer consumer = new DefaultMQPushConsumer ("group4-1" ); consumer.setNamesrvAddr("192.168.254.190:9876" ); consumer.subscribe("topic4" , "*" ); consumer.registerMessageListener((MessageListenerConcurrently) (list, consumeConcurrentlyContext) -> { list.forEach(one->{ byte [] body = one.getBody(); System.out.println(new String (body)); }); return ConsumeConcurrentlyStatus.CONSUME_SUCCESS; }); consumer.start(); System.out.println("消费者启起来了" ); } } 默认接受者是负载均衡2 默认接受者是负载均衡3 默认接受者是负载均衡6 默认接受者是负载均衡7 默认接受者是负载均衡0 默认接受者是负载均衡1 默认接受者是负载均衡4 默认接受者是负载均衡5 默认接受者是负载均衡8 默认接受者是负载均衡9 默认接受者是负载均衡0 默认接受者是负载均衡1 默认接受者是负载均衡2 默认接受者是负载均衡3 默认接受者是负载均衡4 默认接受者是负载均衡5 默认接受者是负载均衡6 默认接受者是负载均衡7 默认接受者是负载均衡8 默认接受者是负载均衡9
Swagger 1 2 3 4 5 6 <dependency > <groupId > io.springfox</groupId > <artifactId > springfox-boot-starter</artifactId > <version > 3.0.0</version > </dependency >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 import io.swagger.annotations.ApiOperation;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import springfox.documentation.builders.ApiInfoBuilder;import springfox.documentation.builders.PathSelectors;import springfox.documentation.builders.RequestHandlerSelectors;import springfox.documentation.oas.annotations.EnableOpenApi;import springfox.documentation.service.ApiInfo;import springfox.documentation.service.Contact;import springfox.documentation.spi.DocumentationType;import springfox.documentation.spring.web.plugins.Docket;@EnableOpenApi @Configuration public class SwaggerConfig { @Bean public Docket docket () { return new Docket (DocumentationType.OAS_30) .apiInfo(apiInfo()).enable(true ) .select() .apis(RequestHandlerSelectors.basePackage("com.example.study.controller" )) .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class)) .paths(PathSelectors.any()) .build(); } private ApiInfo apiInfo () { return new ApiInfoBuilder () .title("XX项目接口文档" ) .description("XX项目描述" ) .contact(new Contact ("作者" , "作者URL" , "作者Email" )) .version("1.0" ) .build(); } }
1 2 3 spring.mvc.pathmatch.matching-strategy =ant_path_matcher
knife4j 1 2 3 4 5 <dependency > <groupId > com.github.xiaoymin</groupId > <artifactId > knife4j-spring-boot-starter</artifactId > <version > 3.0.3</version > </dependency >
application.properties
1 2 spring.mvc.pathmatch.matching-strategy=ant_path_matcher knife4j.enable: true
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 @RestController @RequestMapping("/test") @Api(tags = "测试2") @ApiSort(value = 1) public class TestController2 { @GetMapping("/3") @ApiOperation("3") public String method () { return "hello wolrd" ; } @GetMapping("/4") @ApiOperation("4") public String method2 () { return "hello wolrd" ; } }
Log4j2 Log4j2 日志所有级别级别从上到下 ,级别从低到高,报错(更重要)这种,级别最高,info,debug相对不怎么重要
all
trace
debug
info
warn
error
fail
Log4j2.xml配置例子
1 2 3 4 info级别输出到info.log warn级别输出warn.log error级别输出到error.log debug级别输出到debug.log
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 <?xml version="1.0" encoding="UTF-8" ?> <Configuration > <properties > <property name ="LOG_HOME" > ./service-logs</property > </properties > <Appenders > <Console name ="consoleAppender" target ="SYSTEM_OUT" > <PatternLayout pattern ="%style{%d{ISO8601}}{bright,green} %highlight{%-5level} [%style{%t}{bright,blue}] %style{%C{}}{bright,yellow}: %msg%n%style{%throwable}{red}" disableAnsi ="false" noConsoleNoAnsi ="false" /> </Console > <RollingFile name ="allFileAppender" fileName ="${LOG_HOME}/all.log" filePattern ="${LOG_HOME}/$${date:yyyy-MM}/all-%d{yyyy-MM-dd}-%i.log.gz" > <PatternLayout > <pattern > %d %p %C{} [%t] %m%n</pattern > </PatternLayout > <Policies > <SizeBasedTriggeringPolicy size ="100 MB" /> <TimeBasedTriggeringPolicy /> </Policies > <DefaultRolloverStrategy max ="100" /> </RollingFile > <RollingFile name ="debugFileAppender" fileName ="${LOG_HOME}/debug.log" filePattern ="${LOG_HOME}/$${date:yyyy-MM}/debug-%d{yyyy-MM-dd}-%i.log.gz" > <Filters > <ThresholdFilter level ="info" onMatch ="DENY" onMismatch ="NEUTRAL" /> </Filters > <PatternLayout > <pattern > %d %p %C{} [%t] %m%n</pattern > </PatternLayout > <Policies > <SizeBasedTriggeringPolicy size ="100 MB" /> <TimeBasedTriggeringPolicy /> </Policies > <DefaultRolloverStrategy max ="100" /> </RollingFile > <RollingFile name ="infoFileAppender" fileName ="${LOG_HOME}/info.log" filePattern ="${LOG_HOME}/$${date:yyyy-MM}/info-%d{yyyy-MM-dd}-%i.log.gz" > <Filters > <ThresholdFilter level ="warn" onMatch ="DENY" onMismatch ="NEUTRAL" /> </Filters > <PatternLayout > <pattern > %d %p %C{} [%t] %m%n</pattern > </PatternLayout > <Policies > <SizeBasedTriggeringPolicy size ="100 MB" /> <TimeBasedTriggeringPolicy interval ="1" modulate ="true" /> </Policies > </RollingFile > <RollingFile name ="warnFileAppender" fileName ="${LOG_HOME}/warn.log" filePattern ="${LOG_HOME}/$${date:yyyy-MM}/warn-%d{yyyy-MM-dd}-%i.log.gz" > <Filters > <ThresholdFilter level ="error" onMatch ="DENY" onMismatch ="NEUTRAL" /> </Filters > <PatternLayout > <pattern > %d %p %C{} [%t] %m%n</pattern > </PatternLayout > <Policies > <SizeBasedTriggeringPolicy size ="100 MB" /> <TimeBasedTriggeringPolicy /> </Policies > <DefaultRolloverStrategy max ="100" /> </RollingFile > <RollingFile name ="errorFileAppender" fileName ="${LOG_HOME}/error.log" filePattern ="${LOG_HOME}/$${date:yyyy-MM}/error-%d{yyyy-MM-dd}-%i.log.gz" > <PatternLayout > <pattern > %d %p %C{} [%t] %m%n</pattern > </PatternLayout > <Policies > <SizeBasedTriggeringPolicy size ="100 MB" /> <TimeBasedTriggeringPolicy /> </Policies > <DefaultRolloverStrategy max ="100" /> </RollingFile > <RollingFile name ="errorJsonAppender" fileName ="${LOG_HOME}/error-json.log" filePattern ="${LOG_HOME}/error-json-%d{yyyy-MM-dd}-%i.log.gz" > <JSONLayout compact ="true" eventEol ="true" locationInfo ="true" /> <Policies > <SizeBasedTriggeringPolicy size ="100 MB" /> <TimeBasedTriggeringPolicy interval ="1" modulate ="true" /> </Policies > </RollingFile > </Appenders > <Loggers > <Root level ="debug" > <AppenderRef ref ="allFileAppender" level ="all" /> <AppenderRef ref ="consoleAppender" level ="debug" /> <AppenderRef ref ="debugFileAppender" level ="debug" /> <AppenderRef ref ="infoFileAppender" level ="info" /> <AppenderRef ref ="warnFileAppender" level ="warn" /> <AppenderRef ref ="errorFileAppender" level ="error" /> <AppenderRef ref ="errorJsonAppender" level ="error" /> </Root > <Logger name ="org.springframework" level ="debug" /> <Logger name ="druid.sql.Statement" level ="warn" /> <Logger name ="com.mybatis" level ="warn" /> <Logger name ="org.hibernate" level ="warn" /> <Logger name ="com.zaxxer.hikari" level ="info" /> <Logger name ="org.quartz" level ="info" /> <Logger name ="com.andya.demo" level ="debug" /> </Loggers > </Configuration >
1 2 3 error级别 打印error.log info级别 打印info,error 日志到info.log debug级别 打印info,error,debug日志到debug.log
基本结构是:
Configuration
properties 属性配置,可以在这里配置全局变量,可以在xml别的地方引入
Appenders 具体配置日志框架该如何收集日志的动作
Console 控制台输出
RollingFile 滚动日志文件
Loggers
Root 理论上只有一个Root,level属性,是全局日志级别,如果AppenderRef没有配置level,就使用全局级别
AppenderRef 引用具体配置的动作,level 没有的话,就使用全局级别,就像CSS
属性那样,标签里的属性优先级最高
Logger 单独配置一些类,level 没有的话,就使用全局级别,就像CSS
属性那样,标签里的属性优先级最高
过滤器的具体使用方法
1 2 3 4 <Filters > <ThresholdFilter level ="info" onMatch ="DENY" onMismatch ="NEUTRAL" /> </Filters >
level
指定日志等级的阈值。
onMatch
定义当日志事件等级等于或高于 level
属性指定的等级时的行为。
ACCEPT
:接受日志事件,让它通过过滤器。
DENY
:拒绝日志事件,不让它通过过滤器。
NEUTRAL
:对日志事件不做决定,继续应用其他的过滤规则。
onMismatch
定义当日志事件等级低于 level
属性指定的等级时的行为。
ACCEPT
:接受日志事件,让它通过过滤器。
DENY
:拒绝日志事件,不让它通过过滤器。
NEUTRAL
:对日志事件不做决定,继续应用其他的过滤规则。1 2 3 4 5 6 7 8 9 if 日志的级别 >= level配置的级别 ACCEPT 接受日志 DENY 拒绝日志 NEUTRAL 对日志事件不做决定,继续应用其他的过滤规则 if 日志的级别 < level配置的级别 ACCEPT 接受日志 DENY 拒绝日志 NEUTRAL 对日志事件不做决定,继续应用其他的过滤规则
还是没有搞清楚 onMismatch=”NEUTRAL” 的作用是怎样的
使用ChatGPT提供的demo,没有验证
info级别 记录到info.log error级别 记录到error.log info级别和error级别 记录到dev.log
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 <Configuration > <Appenders > <File name ="InfoAppender" fileName ="logs/info.log" > <ThresholdFilter level ="INFO" onMatch ="ACCEPT" onMismatch ="DENY" /> <PatternLayout pattern ="%d{yyyy-MM-dd HH:mm:ss} [%t] %-5level %logger{36} - %msg%n" /> </File > <File name ="ErrorAppender" fileName ="logs/error.log" > <ThresholdFilter level ="ERROR" onMatch ="ACCEPT" onMismatch ="DENY" /> <PatternLayout pattern ="%d{yyyy-MM-dd HH:mm:ss} [%t] %-5level %logger{36} - %msg%n" /> </File > <File name ="DevAppender" fileName ="logs/dev.log" > <Filters > <ThresholdFilter level ="INFO" onMatch ="ACCEPT" onMismatch ="DENY" /> <ThresholdFilter level ="ERROR" onMatch ="ACCEPT" onMismatch ="NEUTRAL" /> </Filters > <PatternLayout pattern ="%d{yyyy-MM-dd HH:mm:ss} [%t] %-5level %logger{36} - %msg%n" /> </File > </Appenders > <Loggers > <Root level ="DEBUG" > <AppenderRef ref ="InfoAppender" /> <AppenderRef ref ="ErrorAppender" /> <AppenderRef ref ="DevAppender" /> </Root > </Loggers > </Configuration >
只是引入web框架 只是引入web框架
1 2 3 4 <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-web</artifactId > </dependency >
1 2 3 4 5 6 7 8 9 10 11 12 @GetMapping("/test") public String test () { String formattedDateTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss" )); log.debug("当前日期时间:{}" , formattedDateTime); log.info("当前日期时间:{}" , formattedDateTime); log.error("当前日期时间:{}" , formattedDateTime); log.warn("当前日期时间:{}" , formattedDateTime); log.trace("当前日期时间:{}" , formattedDateTime); return formattedDateTime; }
1 2 3 4 5 # 控制台打印 INFO 64710 --- [nio-8080-exec-1] c.e.s.controller.IndexController : 当前日期时间:2024-03-03 21:37:40 ERROR 64710 --- [nio-8080-exec-1] c.e.s.controller.IndexController : 当前日期时间:2024-03-03 21:37:40 WARN 64710 --- [nio-8080-exec-1] c.e.s.controller.IndexController : 当前日期时间:2024-03-03 21:37:40 # 为什么控制台没有打印 trace和debug日志