ActiveMQ学习总结(6)——ActiveMQ集成Spring和Log4j实现异步日志
我的团队和我正在创建一个由一组RESTful JSON服务组成的服务平台,该平台中的每个服务在平台中的作用就是分别提供一些独特的功能和/或数据。由于平台中产生的日志四散各处,所以我们想,要是能将这些日志集中化处理一下,并提供一个能够让我们查看、过滤、排序和搜索我们所有的日志的基本型的日志查看工具就好了。我们还想让我们的日志是异步式的,因为我们可不想在写日志的时候(比方说,可能会将日志直接写入数据库),让我们提供的服务因为写日志而暂时被阻挡住。

实现这个目标的策略非常简单明了。
- 安装ActiveMQ
- 创建一个log4j的日志追加器,将日志写入队列(log4j自带了一个这样的追加器,不过现在让我们自己来写一个吧。)
- 写一个消息侦听器,从MQ服务器上所设置的JMS队列中读取日志并将日志持久化
下面让我们分步来看这个策略是如何得以实现的。
安装ActiveMQ
创建一个Lo4j的JMS日志追加器
首先,我们来创建一个log4j的JMS日志追加器。log4j自带了一个这样的追加器(该追加器没有将日志写入一个队列,而是写给了一个话题)
|
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
|
importimportimportimportimportimportimportimportimportimportimport/** * * * */public extendsimplementsprivate "JMSQueueAppender");privateprivate@Overridepublic }@Overridepublic return;}@Overrideprotected try ActiveMQConnectionFactorynew this.brokerUri); // javax.jms.Connection connection.start();np // Sessionfalse,Session.AUTO_ACKNOWLEDGE); // Destinationthis.queueName); // MessageProducer producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); ObjectMessagenew // producer.send(message); // session.close(); connection.close(); } catch e.printStackTrace(); }}public this.brokerUri}public return}public this.queueName}public return}} |
下面让我们看看这里面发生了什么事情。
第19行:We我们实现了的Log4J日志追加器接口,该接口要求我们实现三个方法:requiresLayout, close和append。我们将暂时简化处理过程,实现所需的append方法。在对logger进行调用时这个方法就会被调用。
第37行: log4j将一个LoggingEvent对象作为参数对append方法进行调用,这个LoggingEvent对象表示了对logger的一次调用,它封装了每一个日志项的所有信息。
第41和42行:将指向JMS的uri作为参数,创建一个连接工厂对象,在我们的情况下,该uri指向的是我们的ActiveMQ服务器。
第45, 46和49行: 我们同JMS服务器建立一个连接和会话。会话有多种打开模式。在Auto_Acknowledge模式的会话中,消息的应答会自动发生。Client_Acknowledge 模式下,客户端需要对消息的接收和/或处理进行显式地应答。另外还有两种其它的模式。有关细节,请参考文档http://download.oracle.com/javaee/1.4/api/javax/jms/Session.html
第52行: 创建一个队列。将队列的名字作为参数发送给连接
第56行: 我们将发送模式设置为Non_Persistent。另一个可选的模式是Persistent ,在这种模式下,消息会持久化到一个持久性存储系统中。持久化模式会降低系统速度,但能增加了消息传递的可靠性。
第58行: 这行我们做了很多事。首先我将一个LoggingEvent对象封装到了一个LoggingEventWrapper对象之中。这么做是因为LoggingEvent对象有一些属性不支持序列化,另外还有一个原因是我想记录一些额外的信息,比如IP地址和主机名。接下来,使用JMS的会话对象,我们把一个对象(LoggingEventWrapper对象)做好了发送前的准备。
第61行: 我将该对象发送到了队列中。
下面所示是LoggingEventWrapper的代码。
|
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
|
importimportimportimportimport/** * * * * * * */public implements private "%throwable"; private private private private private private private private private public this.loggingEvent //Format EnhancedPatternLayoutnew layout.setConversionPattern(ENHANCED_PATTERN_LAYOUT); this.detailthis.loggingEvent); } public return.loggingEvent.timeStamp; } public return.loggingEvent.getLevel().toString(); } public return.loggingEvent.getLoggerName(); } public return.loggingEvent.getRenderedMessage(); } public return.detail; } public return } public try return } catch return; } } public try return } catch return; } }} |
消息侦听器
消息侦听器会对队列(或话题)进行“侦听”。一旦有新消息添加到了队列中,onMessage 方法就会得到调用。
|
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
|
importimportimportimportimportimportimport@Componentpublic implements{ public class); @Autowired private public final { ifinstanceof { try{ final loggingService.saveLog(loggingEventWrapper); } catchfinal { logger.error(e.getMessage(), } catch logger.error(e.getMessage(),e); } } }} |
第23行: 检查从队列中拿到的对象是否是ObjectMessage的实例
第26行: 从消息中提取出LoggingEventWrapper对象
第27行: 调用服务方法将日志持久化
Spring配置
|
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
|
<?xml="1.0"="UTF-8"?><beans="http://www.springframework.org/schema/beans"="http://www.w3.org/2001/XMLSchema-instance"="http://www.springframework.org/schema/p"="http://www.springframework.org/schema/context"="http://www.springframework.org/schema/jms"="http://activemq.apache.org/schema/core"="http://www.springframework.org/schema/aop"="http://www.springframework.org/schema/beans><!--<!--<!-- <amq:transportConnectors> <amq:transportConnector </amq:transportConnectors></amq:broker--><!--<amq:queue="destination"="logQueue"<!--<amq:connectionFactory="jmsFactory"="tcp://localhost:61616"<bean="connectionFactory"="org.springframework.jms.connection.CachingConnectionFactory"> <constructor-arg="jmsFactory" <property="exceptionListener"="JMSExceptionListener" <property="sessionCacheSize"="100"</bean><!--<bean="jmsTemplate"="org.springframework.jms.core.JmsTemplate"> <constructor-arg="connectionFactory"</bean><!--is<jms:listener-container="10"> <jms:listener="QueueListener"="logQueue"="logQueueListener"</jms:listener-container></beans> |
第5到9行: 使用代理标签建立一个嵌入式消息代理。既然我用的是外部消息代理,所以我就不需要它了。
第12行: 给出你想要连接的队列的名字
第14行: 代理服务器的URI
第15到19行: 连接工厂的设置
第26到28行: 消息侦听器的设置,这里可以指定用于从队列中读取消息的并发现线程的个数
当然,上面的例子做不到让你能够拿来就用。你还需要包含所有的JMS依赖库并实现完成日志持久化任务的服务。但是,我希望本文能够为你提供一个相当不错的思路。
ActiveMQ学习总结(6)——ActiveMQ集成Spring和Log4j实现异步日志的更多相关文章
- Spring Boot log4j多环境日志级别的控制
之前介绍了在<Spring boot中使用log4j>,仅通过log4j.properties对日志级别进行控制,对于需要多环境部署的环境不是很方便,可能我们在开发环境大部分模块需要采用D ...
- ActiveMQ学习总结(3)——spring整合ActiveMQ
1.参考文献 Spring集成ActiveMQ配置 Spring JMS异步发收消息 ActiveMQ 2.环境 在前面的一篇ActiveMQ入门实例中我们实现了消息的异步传送,这篇博文将如何在spr ...
- ActiveMQ学习笔记(二) JMS与Spring
上文可见,JMS Native API使用起来不是特别方便.好在Spring提供了很好的JMS支持. (一)配置ConnectionFactory 如果使用连接池的话,不要忘记activemq-poo ...
- SSM学习(三)--集成spring mvc
spirng mvc是一个mvc框架,与struts2类似,都是基于Servlet封装而成的框架,所以要了解spring mvc或者struts2比需先了解Servlet,本篇我们先把spring m ...
- 采用Spring AOP+Log4j记录项目日志
转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/6567672.html 项目日志记录是项目开发.运营必不可少的内容,有了它可以对系统有整体的把控,出现任何问题 ...
- Spring AOP+Log4j记录项目日志
转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/6567672.html 项目日志记录是项目开发.运营必不可少的内容,有了它可以对系统有整体的把控,出现任何问题 ...
- spring mvc: log4j插件 log日志的输出
准备: log插件:log4j <!-- log日志插件 --> <!-- https://mvnrepository.com/artifact/log4j/log4j --> ...
- Spring Boot log4j实现把日志存入mongodb
准备工作 1.自定义appender的实现 log4j提供的输出器实现自Appender接口,要自定义appender输出到MongoDB,只需要继承AppenderSkeleton类,并实现几个方法 ...
- ActiveMQ学习笔记(5)----Broker的启动方式
Broker:相当于一个ActiveMQ服务器实例,在实际的开发中我们可以启动多个Broker. 命令行启动参数示例如下: 1. activemq start 使用默认的activemq.xml来启动 ...
随机推荐
- xml Data Type Methods in sql server
nodes() Method (xml Data Type) https://docs.microsoft.com/en-us/sql/t-sql/xml/nodes-method-xml-data- ...
- hdoj--5053--the Sum of Cube(水)
the Sum of Cube Time Limit : 2000/1000ms (Java/Other) Memory Limit : 32768/32768K (Java/Other) Tot ...
- bean初始化、注销
关于在spring 容器初始化 bean 和销毁前所做的操作定义方式有三种: 第一种:通过@PostConstruct 和 @PreDestroy 方法 实现初始化和销毁bean之前进行的操作 第二 ...
- Weka中数据挖掘与机器学习系列之为什么要写Weka这一系列学习笔记?(一)
本人正值科研之年,同时也在使用Weka来做相关数据挖掘和机器学习的论文工作. 为了记录自己的学习历程,也便于分享和带领入门的你们.废话不多说,直接上干货!
- 定时器函数SetTimer
原文链接:http://www.cnblogs.com/zhangpengshou/archive/2009/04/05/1429770.html 一.SetTimer表示的是定义个定时器.根据定义指 ...
- node.js状态码
100——客户必须继续发出请求101——客户要求服务器根据请求转换HTTP协议版本200——交易成功201——提示知道新文件的URL202——接受和处理.但处理未完成203——返回信息不确定或不完整2 ...
- jquery正则匹配URL地址
JQuery代码: var regexp = /((http|ftp|https|file):\/\/([\w\-]+\.)+[\w\-]+(\/[\w\u4e00-\u9fa5\-\.\/?\@\% ...
- HDU——T 3072 Intelligence System
http://acm.hdu.edu.cn/showproblem.php?pid=3072 Time Limit: 2000/1000 MS (Java/Others) Memory Limi ...
- storm单词计数 本地运行
import java.io.File; import java.io.IOException; import java.util.Collection; import java.util.HashM ...
- Qt Quick 之 PathView 具体解释
PathView ,顾名思义,沿着特定的路径显示 Model 内的数据. Model 能够是 QML 内建的 ListModel . XmlListModel ,也能够是在 C++ 中实现的 QAbs ...