`
Donald_Draper
  • 浏览: 981609 次
社区版块
存档分类
最新评论

Mina 日志过滤器与引用计数过滤器

    博客分类:
  • Mina
阅读更多
MINA TCP简单通信实例:http://donald-draper.iteye.com/blog/2375297
Mina 过滤链默认构建器:http://donald-draper.iteye.com/blog/2375985
Mina 过滤器定义:http://donald-draper.iteye.com/blog/2376161
引言:
前面一篇文章我们看了一下过滤器定义,先来回顾一下:
     IoFilter添加到过滤链时,一般以ReferenceCountingIoFilter包装,添加到过滤链,init方法在添加到过滤链时,由ReferenceCountingIoFilter调用,所以可以在init方法初始化一些共享资源。如果过滤器没有包装成ReferenceCountingIoFilter,init方法将不会调用。然后调用onPreAdd通知过滤器将会添加到过滤连上,当过滤器添加到过滤链上时,所有IoHandler事件和IO请求,将会被过滤器拦截当过滤器添加到过滤链上后,将会调用onPostAdd,如果方法有异常,过滤器在过滤链的链尾,ReferenceCountingIoFilter将调用#destroy方法释放共享资源。过滤器IoFilter,主要是监听会话IoSession相关事件(创建,打开,空闲,异常,关闭,接受数据,发送数据) 及IoSesssion的Write与close事件;过滤器后继NextFilter关注的事件与过滤器IoFilter相同,主要是转发相关事件。WriteRequest是会话IoSession写操作write的包装,内部有一个消息对象用于存放write的内容,一个socket地址,即会话写请求的目的socket地址,一个写请求结果返回值WriteFuture,用于获取会话write消息的操作结果。当一个过滤器从过滤链上移除时,#onPreRemove被调用,用于通知过滤器将从过滤链上移除;如果过滤器从过滤链上移除,所有IoHandler事件和IO请求,过滤器不再拦截;#onPostRemove调用通知过滤器已经从过滤链上移除;移除后,如果过滤器在过滤链的链尾,ReferenceCountingIoFilter将调用#destroy方法释放共享资源。
        IoFilter生命周期如下:
inti->onPreAdd->onPostAdd->(拦截IoHandler相关事件:sessionCreated,Opened,Idle,
exceptionCaught,Closed,messageSent,messageReceived;会话相关事件:filterWrite,filterClose)->onPreRemove
->onPostRemove->destroy。
在TCP简单通信实例这篇文章中我们用到的Mina的日志过滤器LoggingFilter如下:
//配置过滤器
DefaultIoFilterChainBuilder defaultIoFilterChainBuilder = acceptor.getFilterChain();
LoggingFilter loggingFilter = new LoggingFilter();
defaultIoFilterChainBuilder.addLast("loggingFilter", loggingFilter);

今天我们来看一下LoggingFilter。
package org.apache.mina.filter;

import org.apache.mina.common.IdleStatus;
import org.apache.mina.common.IoFilterAdapter;
import org.apache.mina.common.IoSession;
import org.apache.mina.util.SessionLog;
import org.slf4j.Logger;

/**
 * Logs all MINA protocol events to {@link Logger}.
 * 
 * @author The Apache Directory Project (mina-dev@directory.apache.org)
 * @version $Rev$, $Date$
 * 
 * @see SessionLog
 */
public class LoggingFilter extends IoFilterAdapter {
    /**
     * Session attribute key: prefix string
     */
    public static final String PREFIX = SessionLog.PREFIX;

    /**
     * Session attribute key: {@link Logger}
     */
    public static final String LOGGER = SessionLog.LOGGER;

    /**
     * Creates a new instance.
     */
    public LoggingFilter() {
    }
    //拦截IoHandler的sessionCreated事件,将日志输出委托给SessionLog,
    //然后将相关事件传递给过滤器后继,拦截sessionOpened,sessionClosed思路基本相同
    public void sessionCreated(NextFilter nextFilter, IoSession session) {
        SessionLog.info(session, "CREATED");
        nextFilter.sessionCreated(session);
    }
    public void sessionOpened(NextFilter nextFilter, IoSession session) {
        SessionLog.info(session, "OPENED");
        nextFilter.sessionOpened(session);
    }
    public void sessionClosed(NextFilter nextFilter, IoSession session) {
        SessionLog.info(session, "CLOSED");
        nextFilter.sessionClosed(session);
    }

    public void sessionIdle(NextFilter nextFilter, IoSession session,
            IdleStatus status) {
	//先判断会话日志Info级别是否开启
        if (SessionLog.isInfoEnabled(session)) {
            SessionLog.info(session, "IDLE: " + status);
        }
        nextFilter.sessionIdle(session, status);
    }

    public void exceptionCaught(NextFilter nextFilter, IoSession session,
            Throwable cause) {
        if (SessionLog.isWarnEnabled(session)) {
            SessionLog.warn(session, "EXCEPTION:", cause);
        }
        nextFilter.exceptionCaught(session, cause);
    }

    public void messageReceived(NextFilter nextFilter, IoSession session,
            Object message) {
        if (SessionLog.isInfoEnabled(session)) {
            SessionLog.info(session, "RECEIVED: " + message);
        }
        nextFilter.messageReceived(session, message);
    }

    public void messageSent(NextFilter nextFilter, IoSession session,
            Object message) {
        if (SessionLog.isInfoEnabled(session)) {
            SessionLog.info(session, "SENT: " + message);
        }
        nextFilter.messageSent(session, message);
    }

    public void filterWrite(NextFilter nextFilter, IoSession session,
            WriteRequest writeRequest) {
        if (SessionLog.isInfoEnabled(session)) {
            SessionLog.info(session, "WRITE: " + writeRequest);
        }
        nextFilter.filterWrite(session, writeRequest);
    }

    public void filterClose(NextFilter nextFilter, IoSession session)
            throws Exception {
        SessionLog.info(session, "CLOSE");
        nextFilter.filterClose(session);
    }
}

LoggingFilter拦截IoHandler的sessionCreated事件,将日志输出委托给SessionLog,
然后将相关事件传递给过滤器后继,拦截sessionOpened,sessionClosed,filterClose事件思路基本相同。对于sessionIdle,messageSent,messageReceived,filterWrite先判断会话log的info级别是否开启,开启则输出相应事件日志。上面这些事件的日志级别都是Info;exceptionCaught则先判断会话log的warn级别是否开启,开启则输出相应事件日志。

再来看SessionLog:
package org.apache.mina.util;

import org.apache.mina.common.IoSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
//从包引入来看MINA默认用slf4j日志组件
/**
 * Provides utility methods to log protocol-specific messages.
 * <p>
 * Set {@link #PREFIX} and {@link #LOGGER} session attributes
 * to override prefix string and logger.
 *
 * @author The Apache Directory Project (mina-dev@directory.apache.org)
 * @version $Rev$, $Date$
 *
 */
public class SessionLog {
    /**
     * Session attribute key: prefix string
     */
    public static final String PREFIX = SessionLog.class.getName() + ".prefix";

    /**
     * Session attribute key: {@link Logger}
     */
    public static final String LOGGER = SessionLog.class.getName() + ".logger";
    //获取会话IoHandler类型
    private static Class getClass(IoSession session) {
        return session.getHandler().getClass();
    }
    //Debug输出,如果会话日志开启debug级别,则输出debug日志
    public static void debug(IoSession session, String message) {
        Logger log = getLogger(session);
        if (log.isDebugEnabled()) {
            log.debug(String.valueOf(session.getAttribute(PREFIX)) + message);
        }
    }
    public static void debug(IoSession session, String message, Throwable cause) {
        Logger log = getLogger(session);
        if (log.isDebugEnabled()) {
            log.debug(String.valueOf(session.getAttribute(PREFIX)) + message,
                    cause);
        }
    }
    //获取会话日志
      private static Logger getLogger(IoSession session) {
        Logger log = (Logger) session.getAttribute(LOGGER);
        if (log == null) {
	    //如果会话日志为空,则从LoggerFactory获取Logger
            log = LoggerFactory.getLogger(getClass(session));
            String prefix = (String) session.getAttribute(PREFIX);
            if (prefix == null) {
                prefix = "[" + session.getRemoteAddress() + "] ";
                session.setAttribute(PREFIX, prefix);
            }
            //将日志log,添加到会话中
            session.setAttribute(LOGGER, log);
        }

        return log;
    }
    //判断log的debug级别是否开启
     public static boolean isDebugEnabled(IoSession session) {
        return getLogger(session).isDebugEnabled();
    }
    /*下面的info,warn,error与debug的思想是一致的这里不再说
    */
    public static void info(IoSession session, String message) {
        Logger log = getLogger(session);
        if (log.isInfoEnabled()) {
            log.info(String.valueOf(session.getAttribute(PREFIX)) + message);
        }
    }
    public static void info(IoSession session, String message, Throwable cause) {
        Logger log = getLogger(session);
        if (log.isInfoEnabled()) {
            log.info(String.valueOf(session.getAttribute(PREFIX)) + message,
                    cause);
        }
    }
    public static void warn(IoSession session, String message) {
        Logger log = getLogger(session);
        if (log.isWarnEnabled()) {
            log.warn(String.valueOf(session.getAttribute(PREFIX)) + message);
        }
    }
    public static void warn(IoSession session, String message, Throwable cause) {
        Logger log = getLogger(session);
        if (log.isWarnEnabled()) {
            log.warn(String.valueOf(session.getAttribute(PREFIX)) + message,
                    cause);
        }
    }
    public static void error(IoSession session, String message) {
        Logger log = getLogger(session);
        if (log.isErrorEnabled()) {
            log.error(String.valueOf(session.getAttribute(PREFIX)) + message);
        }
    }
    public static void error(IoSession session, String message, Throwable cause) {
        Logger log = getLogger(session);
        if (log.isErrorEnabled()) {
            log.error(String.valueOf(session.getAttribute(PREFIX)) + message,
                    cause);
        }
    }
    public static boolean isInfoEnabled(IoSession session) {
        return getLogger(session).isInfoEnabled();
    }
    public static boolean isWarnEnabled(IoSession session) {
        return getLogger(session).isWarnEnabled();
    }
    public static boolean isErrorEnabled(IoSession session) {
        return getLogger(session).isErrorEnabled();
    }
}

在TCP简单通信实例这篇文章中我们创建过一个测试的过滤器TestFilter,通过ReferenceCountingFilter包装添加
过滤链上:
TestFilter testFilter = new TestFilter(); 
ReferenceCountingFilter referenceCountingFilter = new ReferenceCountingFilter(testFilter);
defaultIoFilterChainBuilder.addLast("testFilter",referenceCountingFilter);

在前面过滤器的文章我们也提到过ReferenceCountingFilter,下面我们再来看一下ReferenceCountingFilter
package org.apache.mina.filter;

import org.apache.mina.common.IdleStatus;
import org.apache.mina.common.IoFilter;
import org.apache.mina.common.IoFilterChain;
import org.apache.mina.common.IoSession;

/**
 * An {@link IoFilter}s wrapper that keeps track of the number of usages of this filter and will call init/destroy
 * when the filter is not in use.
 *ReferenceCountingIoFilter用于包装过滤器,用于记录过滤器的使用量,
 当过滤器添加到过滤链上时,调用过滤器的init方法,从过滤链上移除时,调用过滤器的destroy方法。
 * @author The Apache Directory Project (mina-dev@directory.apache.org)
 * @version $Rev$, $Date$
 */
public class ReferenceCountingIoFilter implements IoFilter {
    private final IoFilter filter;//包装的过滤器

    private int count = 0;//过滤器使用计数器

    public ReferenceCountingIoFilter(IoFilter filter) {
        this.filter = filter;
    }
    public void init() throws Exception {
        // no-op, will init on-demand in pre-add if count == 0
    }
    public void destroy() throws Exception {
        //no-op, will destroy on-demand in post-remove if count == 0
    }
    public void onPostAdd(IoFilterChain parent, String name,
            NextFilter nextFilter) throws Exception {
        filter.onPostAdd(parent, name, nextFilter);
    }
    public synchronized void onPreAdd(IoFilterChain parent, String name,
            NextFilter nextFilter) throws Exception {
        if (0 == count) {
	    //当过滤器首次添加到过滤链上时,调用过滤器的init方法。
            filter.init();
            ++count;
        }

        filter.onPreAdd(parent, name, nextFilter);
    }
    public void onPreRemove(IoFilterChain parent, String name,
            NextFilter nextFilter) throws Exception {
        filter.onPreRemove(parent, name, nextFilter);
    }
    public synchronized void onPostRemove(IoFilterChain parent, String name,
            NextFilter nextFilter) throws Exception {
        filter.onPostRemove(parent, name, nextFilter);
        --count;
	//当过滤器从过滤链上完全移除时,调用过滤器的destroy方法。
        if (0 == count) {
            filter.destroy();
        }
    }
    public void exceptionCaught(NextFilter nextFilter, IoSession session,
            Throwable cause) throws Exception {
        filter.exceptionCaught(nextFilter, session, cause);
    }
    public void filterClose(NextFilter nextFilter, IoSession session)
            throws Exception {
        filter.filterClose(nextFilter, session);
    }

    public void filterWrite(NextFilter nextFilter, IoSession session,
            WriteRequest writeRequest) throws Exception {
        filter.filterWrite(nextFilter, session, writeRequest);
    }

    public void messageReceived(NextFilter nextFilter, IoSession session,
            Object message) throws Exception {
        filter.messageReceived(nextFilter, session, message);
    }

    public void messageSent(NextFilter nextFilter, IoSession session,
            Object message) throws Exception {
        filter.messageSent(nextFilter, session, message);
    }
    public void sessionClosed(NextFilter nextFilter, IoSession session)
            throws Exception {
        filter.sessionClosed(nextFilter, session);
    }
    public void sessionCreated(NextFilter nextFilter, IoSession session)
            throws Exception {
        filter.sessionCreated(nextFilter, session);
    }
    public void sessionIdle(NextFilter nextFilter, IoSession session,
            IdleStatus status) throws Exception {
        filter.sessionIdle(nextFilter, session, status);
    }
    public void sessionOpened(NextFilter nextFilter, IoSession session)
            throws Exception {
        filter.sessionOpened(nextFilter, session);
    }
}

一个过滤器可以多次添加到过滤链上,如何保证过滤器第一次添加到过滤链上时,初始化过滤器,完全从过滤链上移除时,销毁过滤器,释放资源?这就是ReferenceCountingIoFilter的作用,ReferenceCountingIoFilter同时也是一个过滤器,内部一个count用于记录过滤器filter添加到过滤链上的次数,即过滤链上存在filter的个数,一个filter,即ReferenceCountingIoFilter包装的过滤器,触发IoHandler和IoSession的相关事件,直接交给包装的内部filter处理。


总结:
     LoggingFilter拦截IoHandler的sessionCreated事件,将日志输出委托给SessionLog,然后将相关事件传递给过滤器后继,拦截sessionOpened,sessionClosed,
filterClose事件思路基本相同。对于sessionIdle,messageSent,messageReceived,
filterWrite先判断会话log的info级别是否开启,开启则输出相应事件日志。上面这些事件的日志级别都是Info;exceptionCaught则先判断会话log的warn级别是否开启,开启则输出相应
事件日志。
     一个过滤器可以多次添加到过滤链上,ReferenceCountingIoFilter用于保证过滤器第一次添加到过滤链上时,初始化过滤器,完全从过滤链上移除时,销毁过滤器,释放资源;ReferenceCountingIoFilter内部一个count用于记录包装过滤器filter添加到过滤链上的次数,即过滤链上存在filter的个数,一个filter,即ReferenceCountingIoFilter包装的过滤器,ReferenceCountingIoFilter触发IoHandler和IoSession的相关事件,直接交给包装的内部filter处理。
0
1
分享到:
评论

相关推荐

    MINA 协议解码过滤器

    过滤器链的概念是MINA框架的核心特性之一,它允许开发者插入自定义的过滤器来处理进来的数据或者发送出去的数据。协议解码过滤器(ProtocolDecoderFilter)就是这样的一个过滤器,它的主要任务是从接收到的原始字节...

    mina自定义编解码器详解

    **mina自定义编解码器详解** mina是一个Java开发的网络通信框架,广泛应用于TCP和UDP协议的服务器和客户端开发。在mina框架中,编解码器(Codec)扮演着至关重要的角色,它负责将应用层的数据转换为网络传输的字节...

    apache-mina-2.0.4.rar_apache mina_mina

    Apache Mina是一个高性能、异步事件驱动的网络应用程序框架,用于快速开发可维护的高性能协议服务器和...同时,这也有助于你理解如何将Mina与其他技术(如Spring框架)结合使用,提升整体系统的灵活性和可维护性。

    mina使用详细教程

    mina socket 使用详解,这个文档简单易懂,是初学者的大大福音。

    基于spring的Mina框架

    过滤器可以实现日志记录、性能监控、安全检查等各种功能,并按照定义的顺序执行。 **6. 异步处理与线程模型** Mina基于NIO(Non-blocking I/O)实现,提供异步的I/O操作,降低了系统资源消耗。线程模型的配置也很...

    Mina2中文文档

    - **日志管理**:讲解了如何使用Mina的日志过滤器记录应用程序运行时的各种日志信息。 ### Part III - Mina Advanced 高级 #### Chapter 13 - 调试 - **调试技巧**:提供了调试Mina应用程序的一些建议和技巧,...

    MINA源码与例子

    通过阅读源码,你可以深入了解MINA的设计思想和实现细节,例如如何实现非阻塞I/O、过滤器链的工作原理、以及如何自定义协议编码解码器等。 学习MINA源码可以帮助你: 1. **理解网络编程**:MINA是基于Java NIO实现...

    mina自定义编码器-自行做会话累积

    实现这个功能,我们需要创建一个新的编码器类,继承自Mina提供的基础编码器,如`org.apache.mina.filter.codec.ProtocolEncoder`或`org.apache.mina.filter.codec.ProtocolCodecFilter`。 在编码器的实现中,我们...

    Mina客户端服务器Demo

    过滤器可以对数据进行预处理、后处理,实现如日志记录、性能监控等功能。 在**Mina客户端服务器Demo**中,你可以看到以下关键部分: - **服务器端**:首先,服务器会创建一个Acceptor,监听指定端口的连接请求。...

    MINA中文官方教程

    在实际开发中,MINA提供了多种预定义的过滤器,例如,TCP心跳检测过滤器、日志过滤器等,开发者可以通过组合这些过滤器来构建自己的网络应用。同时,MINA还支持自定义过滤器,以满足特定的业务需求。 MINA官方教程...

    Apache MINA 2.0 用户指南中英文对照阅读版[带书签]

    本资源包含两个 pdf 文档,一本根据官方最新文档 ...第十二章:日志过滤器 第十三章:调试 第十四章:状态机 第十五章:代理 第十六章:JMX 集成 第十七章:Spring 集成

    mina 所需jar包

    对于初学者,了解并实践如何设置过滤器、编写自定义过滤器、处理I/O事件以及集成日志框架SLF4J是学习MINA的关键步骤。通过这个2.0.2版本的jar包,你可以开始你的MINA之旅,虽然可能需要更新到更现代的版本以获得最新...

    Mina源码解析

    Mina框架主要由两个核心模块组成:mina-core负责基本的网络I/O操作,而mina-filter则包含了一系列预定义的过滤器,如日志记录、压缩、加密等。开发者可以根据需要选择或组合使用这些过滤器,以增强应用的功能。 ...

    mina自定义编码解码器

    在Java的网络编程中,...理解Mina的过滤器机制和编码解码器接口,能够帮助开发者高效地处理网络通信中的数据转换,从而实现复杂的应用场景。通过不断地实践和优化,你可以构建出符合业务需求的高效、可靠的网络服务。

    apache-mina-2.0.7架包与源码

    4. **过滤器链**:MINA的过滤器机制允许开发者通过定义和串联一系列处理单元(过滤器)来构建复杂的网络应用逻辑,每个过滤器可以对数据进行读写、转换或者日志记录等操作。 5. **高性能**:MINA的设计目标是高性能...

    socket 与 mina 交互数据

    Mina提供了一种基于过滤器的架构,开发者可以通过添加和定制过滤器来处理各种网络协议,如解码和编码。 描述中提到的"熟悉解码协议"是指在使用Mina进行数据交互时,我们需要理解并实现数据的编解码过程。因为网络...

    MINA长连接框架实现通讯

    4. **MINA的过滤器机制**:MINA的FilterChain允许开发者插入自定义的过滤器,每个过滤器可以执行特定的任务,如数据编码/解码、安全认证、日志记录等。过滤器之间按照添加顺序依次调用,形成一个处理流水线,提高了...

    apache mina 简单示例

    8. **编码与解码**:Mina提供了一些内置的编码器和解码器,如LineDelimiter、CrLfLineDecoder等,帮助将原始字节流转换为可处理的对象。如果需要自定义编码解码规则,可以实现相应接口。 9. **测试与调试**:在...

    Mina学习资料

    通过阅读Mina2源码分析.doc,你可以了解到实际项目中如何应用Mina框架,包括设置服务器、配置过滤器链、处理网络事件等。这份文档将提供具体案例,帮助你将理论知识转化为实践技能。 总结来说,Apache Mina是一个...

Global site tag (gtag.js) - Google Analytics