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

MINA 多路复用协议编解码器工厂一(多路复用协议编码器)

    博客分类:
  • Mina
阅读更多
MINA 多路分离解码器实例:http://donald-draper.iteye.com/blog/2375324
Mina 协议编解码过滤器一(协议编解码工厂、协议编码器):
http://donald-draper.iteye.com/blog/2376663
Mina 协议编解码过滤器二(协议解码器):
http://donald-draper.iteye.com/blog/2376679
Mina 队列Queue:http://donald-draper.iteye.com/blog/2376712
Mina 协议编解码过滤器三(会话write与消息接收过滤):
http://donald-draper.iteye.com/blog/2376818
/**
 * A composite {@link ProtocolCodecFactory} that consists of multiple
 * {@link MessageEncoder}s and {@link MessageDecoder}s.
 * {@link ProtocolEncoder} and {@link ProtocolDecoder} this factory
 * returns demultiplex incoming messages and buffers to
 * appropriate {@link MessageEncoder}s and {@link MessageDecoder}s. 
 * 多路复用的协议编解码器工厂DemuxingProtocolCodecFactory包含多个消息编码器和解码器,此多路复用编解码器工厂,
 可以返回消息或buffer对应的编解码器,及多路分离。
 * <h2>Disposing resources acquired by {@link MessageEncoder} and {@link MessageDecoder}</h2>
 * <p>消息编解码器需要释放相应的资源。
 * We didn't provide any <tt>dispose</tt> method for {@link MessageEncoder} and {@link MessageDecoder}
 * because they can give you a big performance penalty in case you have a lot of
 * message types to handle.
 * 在消息编解码器中,我们没有提供dispose方法,因为dispose方法可能会对大量消息类型编码的情况下的性能有影响。
 * @author The Apache Directory Project (mina-dev@directory.apache.org)
 * @version $Rev$, $Date$
 * 
 * @see MessageEncoder
 * @see MessageDecoder
 */
public class DemuxingProtocolCodecFactory
    implements ProtocolCodecFactory
{
    private final DemuxingProtocolEncoder encoder = new DemuxingProtocolEncoder();//多路复用的协议编码器
    private final DemuxingProtocolDecoder decoder = new DemuxingProtocolDecoder();//多路复用的协议解码器
    public DemuxingProtocolCodecFactory()
    {
    }
    public ProtocolEncoder getEncoder(IoSession session)
        throws Exception
    {
        return encoder;
    }
    public ProtocolDecoder getDecoder(IoSession session)
        throws Exception
    {
        return decoder;
    }
    ...
}

从上面来看多路复用协议编解码工厂,包含一个多路复用的协议编码器和解码器。在往下看之前,我们先看一下多路复用的协议编码器和解码器。
先来看多路复用的协议编码器DemuxingProtocolEncoder:
public class DemuxingProtocolEncoder
    implements ProtocolEncoder
{
    private final AttributeKey STATE = new AttributeKey(getClass(), "state");
    //消息类型Class与编码器工厂MessageEncoderFactory映射关系CopyOnWriteMap<Class,MessageEncoderFactory>
    private final Map type2encoderFactory = new CopyOnWriteMap();
    private static final Class EMPTY_PARAMS[] = new Class[0];
     public DemuxingProtocolEncoder()
    {
    }
}

来看多路复用的协议编码器添加消息编码器操作:
//根据消息类型和消息编码器类型,添加消息编码器
 public void addMessageEncoder(Class messageType, Class encoderClass)
    {
        if(encoderClass == null)
            throw new IllegalArgumentException("encoderClass");
        try
        {
            encoderClass.getConstructor(EMPTY_PARAMS);//获取编码器无参构造
        }
        catch(NoSuchMethodException e)
        {
            throw new IllegalArgumentException("The specified class doesn't have a public default constructor.");
        }
        boolean registered = false;
	//如果编码器为MessageEncoder,则添加消息与消息编码工厂映射到消息编码器Map映射type2encoderFactory
        if(org/apache/mina/filter/codec/demux/MessageEncoder.isAssignableFrom(encoderClass))
        {
            addMessageEncoder(messageType, ((MessageEncoderFactory) (new DefaultConstructorMessageEncoderFactory(encoderClass))));
            registered = true;
        }
        if(!registered)
            throw new IllegalArgumentException((new StringBuilder()).append("Unregisterable type: ").append(encoderClass).toString());
        else
            return;
 }


来看添加消息类型与消息编码工厂的映射关系
 public void addMessageEncoder(Class messageType, MessageEncoderFactory factory)
    {
        if(messageType == null)
            throw new IllegalArgumentException("messageType");
        if(factory == null)
            throw new IllegalArgumentException("factory");
        synchronized(type2encoderFactory)
        {
	   //将消息类型与消息编码工厂的映射关系添加到type2encoderFactory
            if(type2encoderFactory.containsKey(messageType))
                throw new IllegalStateException((new StringBuilder()).append("The specified message type (").append(messageType.getName()).append(") is registered already.").toString());
            type2encoderFactory.put(messageType, factory);
        }
    }

来看默认构造消息编码工厂DefaultConstructorMessageEncoderFactory
private static class DefaultConstructorMessageEncoderFactory
        implements MessageEncoderFactory
    {
         private final Class encoderClass;//消息编码器类
	 private DefaultConstructorMessageEncoderFactory(Class encoderClass)
        {
            if(encoderClass == null)
                throw new IllegalArgumentException("encoderClass");
            if(!org/apache/mina/filter/codec/demux/MessageEncoder.isAssignableFrom(encoderClass))
            {
                throw new IllegalArgumentException("encoderClass is not assignable to MessageEncoder");
            } else
            {
                this.encoderClass = encoderClass;
                return;
            }
        }
	//生产消息编码器
        public MessageEncoder getEncoder()
            throws Exception
        {
	   //创建消息编码器实例
            return (MessageEncoder)encoderClass.newInstance();
        }
}

从上可以看出,多路复用的协议编码器添加消息编码器,如果参数为消息类型和消息编码器类型,添加消息类型与默认构造消息编码工厂
到消息编码器Map映射type2encoderFactory。
再来看根据消息类型和消息编码器实例添加消息编码器
 
 public void addMessageEncoder(Class messageType, MessageEncoder encoder)
    {
        //编码器工厂为单例消息编码器工厂
        addMessageEncoder(messageType, ((MessageEncoderFactory) (new SingletonMessageEncoderFactory(encoder))));
    }

//单例消息编码器工厂SingletonMessageEncoderFactory
 private static class SingletonMessageEncoderFactory
        implements MessageEncoderFactory
    {
        private final MessageEncoder encoder;//消息编码器实例
        private SingletonMessageEncoderFactory(MessageEncoder encoder)
        {
            if(encoder == null)
            {
                throw new IllegalArgumentException("encoder");
            } else
            {
                this.encoder = encoder;
                return;
            }
        }
	//获取单例消息解码器
        public MessageEncoder getEncoder()
        {
            return encoder;
        }
    }

从上可以看出,多路复用的协议编码器添加消息编码器,如果参数为消息类型和消息编码器实例,添加消息类型与单例消息编码器工厂
到消息编码器Map映射type2encoderFactory。
下面这几个消息编码器的方法,与上面两类方法无异,很容易理解
public void addMessageEncoder(Iterable messageTypes, Class encoderClass)
    {
        Class messageType;
        for(Iterator iterator = messageTypes.iterator(); iterator.hasNext(); addMessageEncoder(messageType, encoderClass))
            messageType = (Class)iterator.next();

    }
    public void addMessageEncoder(Iterable messageTypes, MessageEncoder encoder)
    {
        Class messageType;
        for(Iterator iterator = messageTypes.iterator(); iterator.hasNext(); addMessageEncoder(messageType, encoder))
            messageType = (Class)iterator.next();

    }
    public void addMessageEncoder(Iterable messageTypes, MessageEncoderFactory factory)
    {
        Class messageType;
        for(Iterator iterator = messageTypes.iterator(); iterator.hasNext(); addMessageEncoder(messageType, factory))
            messageType = (Class)iterator.next();
    }

再来看消息编码:
public void encode(IoSession session, Object message, ProtocolEncoderOutput out)
        throws Exception
    {
        State state = getState(session);//获取会话消息编码器状态
	//获取消息对应的编码器
        MessageEncoder encoder = findEncoder(state, message.getClass());
        if(encoder != null)
	    //编码消息
            encoder.encode(session, message, out);
        else
            throw new UnknownMessageTypeException((new StringBuilder()).append("No message encoder found for message: ").append(message).toString());
    }

编码消息方法有两点要关注
1.
State state = getState(session);//获取会话消息编码器状态

先来看会话编码器状态的定义:
private class State
    {

        private final ConcurrentHashMap findEncoderCache;//消息编码器缓存
        private final Map type2encoder;//消息与消息编码器映射关系
        final DemuxingProtocolEncoder this$0;
        private State()
            throws Exception
        {
            this$0 = DemuxingProtocolEncoder.this;
            super();
            findEncoderCache = new ConcurrentHashMap();
            type2encoder = new ConcurrentHashMap();
            java.util.Map.Entry e;
	    //遍历多路复用协议编码器的消息编码器Map映射type2encoderFactory
	    //将消息类型,与工厂生产的消息编码器映射添加到会话编码器状态State消息与消息编码器映射关系type2encoder
            for(Iterator iterator = type2encoderFactory.entrySet().iterator(); iterator.hasNext(); type2encoder.put(e.getKey(), ((MessageEncoderFactory)e.getValue()).getEncoder()))
                e = (java.util.Map.Entry)iterator.next();

        }
    }

再来看获取会话编码器状态:
private State getState(IoSession session)
        throws Exception
    {
        //从会话获取消息编码器状态,为空,则添加消息编码器状态到会话,否则返回会话编码器状态
        State state = (State)session.getAttribute(STATE);
        if(state == null)
        {
            state = new State();
            State oldState = (State)session.setAttributeIfAbsent(STATE, state);
            if(oldState != null)
                state = oldState;
        }
        return state;
    }


2.
//获取消息对应的编码器
MessageEncoder encoder = findEncoder(state, message.getClass());

//从会话消息编码器状态,获取消息类型对应的编码器
protected MessageEncoder findEncoder(State state, Class type)
    {
        return findEncoder(state, type, null);
    }
    private MessageEncoder findEncoder(State state, Class type, Set triedClasses)
    {
        MessageEncoder encoder = null;
        if(triedClasses != null && triedClasses.contains(type))
            return null;
	//从会话消息编码器状态缓存获取消息编码器
        encoder = (MessageEncoder)state.findEncoderCache.get(type);
	//不为null,则返回
        if(encoder != null)
            return encoder;
	//否则从会话消息编码器状态的消息编码器映射Map中获取消息编码器
        encoder = (MessageEncoder)state.type2encoder.get(type);
        if(encoder == null)
        {
	    //如果编码器为空,则获取消息类型的副接口对应的编码器
            if(triedClasses == null)
                triedClasses = new IdentityHashSet();
            triedClasses.add(type);
            Class interfaces[] = type.getInterfaces();
            Class aclass[] = interfaces;
            int i = aclass.length;
            int j = 0;
            do
            {
                if(j >= i)
                    break;
                Class element = aclass[j];
                encoder = findEncoder(state, element, triedClasses);
                if(encoder != null)
                    break;
                j++;
            } while(true);
        }
        if(encoder == null)
        {
	   //获取消息类型的父类对应的消息编码器
            Class superclass = type.getSuperclass();
            if(superclass != null)
                encoder = findEncoder(state, superclass);
        }
        if(encoder != null)
        {
	   //不为空,则添加消息编码器到会话消息编码器状态findEncoderCache
            state.findEncoderCache.put(type, encoder);
            MessageEncoder tmpEncoder = (MessageEncoder)state.findEncoderCache.putIfAbsent(type, encoder);
            if(tmpEncoder != null)
                encoder = tmpEncoder;
        }
        return encoder;
    }

从上面可以看出,多路复用的协议编码器编码消息,首先从会话获取消息编码器状态,从消息编码器状态获取消息对应的编码器(先从消息编码器查找,没有则从消息编码器映射type2encoder查找),如果没有消息对应的解码,则查找消息父接口和类对应的编码器,编码消息。

//释放会话编码器状态
 public void dispose(IoSession session)
        throws Exception
    {
        session.removeAttribute(STATE);
    }

我们再来消息编码器的定义:
//消息编码器工厂MessageEncoderFactory
public interface MessageEncoderFactory
{
    public abstract MessageEncoder getEncoder()
        throws Exception;
}

//MessageEncoder
public interface MessageEncoder
{
    public abstract void encode(IoSession iosession, Object obj, ProtocolEncoderOutput protocolencoderoutput)
        throws Exception;
}

多路复用的协议解码器DemuxingProtocolDecoder,我们在下一篇文章中再看。
总结:
多路复用的协议编码器添加消息编码器,如果参数为消息类型和消息编码器类型,添加消息类型与默认构造消息编码工厂到消息编码器Map映射type2encoderFactory;如果参数为消息类型和消息编码器实例,添加消息类型与单例消息编码器工厂到消息编码器Map映射type2encoderFactory。多路复用的协议编码器编码消息,首先从会话获取消息编码器状态,从消息编码器状态获取消息对应的编码器(先从消息编码器查找,没有则从消息编码器映射type2encoder查找),如果没有消息对应的解码,则查找消息父接口和类对应的编码器,编码消息。

0
1
分享到:
评论

相关推荐

    mina 多路分离解码

    例如,如果我们的应用使用了某种特定的二进制协议,我们可以创建一个解码器来解析这种协议的数据包,并将其转换为对应的Java对象。 多路分离解码的工作流程大致如下: 1. 数据进入mina服务端,首先经过IoFilter链...

    Mina开发之客户端

    4. **创建和添加Protocol Codec**: 配置一个编解码器工厂,例如TCPCodecFactory,将其添加到过滤器链中。 5. **设置Event Handler**: 定义一个实现了IoHandler接口的类,处理客户端的网络事件。 6. **发送和接收...

    Mina 框架研究与实现

    Mina通过其内置的协议编解码器,为这些操作提供了高度封装,大大提高了代码的复用性和维护性。 #### 总结 Mina框架以其卓越的性能和灵活的架构,成为了开发高性能网络应用程序的理想选择。它不仅简化了底层I/O和...

    Apache Mina 入门Demo

    4. **协议编码和解码**:Mina提供了多种编码器和解码器,用于将用户数据转换为网络传输格式,如ByteToMessageDecoder和MessageToByteEncoder。你可以根据需要自定义这些编码器和解码器以适应特定的协议。 5. **事件...

    JAVA mina 框架源码

    4. **协议编解码**:Mina提供了多种编码解码工厂,如LineDelimiter codec用于按行分割数据,或者ProtocolDecoderOutput和ProtocolEncoderInput接口,用于自定义复杂的编解码策略。 5. **线程模型**:Mina的线程模型...

    mina的高级使用,mina文件图片传送,mina发送文件,mina报文处理,mina发送xml和json

    通过使用I/O多路复用技术,如NIO(非阻塞I/O),Mina能够高效地管理多个连接,而无需为每个连接创建单独的线程。这极大地降低了系统资源的消耗,提高了服务器的并发能力。 2. **Mina文件图片传送** 在Mina中,我们...

    Mina in Action preview

    2. **Filter Chain**:Mina的过滤器链机制是其核心特性之一,它允许开发者通过一系列预定义或自定义的过滤器来处理网络通信的各个阶段,如数据编码解码、安全性和性能优化。 3. **Session管理**:学习如何创建、...

    apache下的mina框架的源码

    4. **异步IO(Asynchronous IO)**:MINA使用Java NIO(非阻塞I/O)库,支持多路复用,允许在单线程中处理多个连接,提高了系统资源利用率和性能。 在`apache-mina-2.0.5`这个压缩包中,你可以找到以下关键组件和...

    mina2技术知识

    MINA 提供了多种预定义的解码器和编码器,比如LineBasedFrameDecoder用于按行处理数据,ByteToMessageDecoder和MessageToByteEncoder则用于字节到消息对象和反向转换。 4. **Handler**:Handler 是业务逻辑的容器,...

    apache mina socket

    Mina提供了多种预定义的编码器和解码器,也可以自定义实现。 3. **Handler**:业务逻辑处理单元,接收到编码后的消息后,调用相应的方法进行处理。 4. **Filters**:过滤器允许你在数据传递过程中添加额外的功能,...

    mina服务器实例

    1. **事件驱动模型**:Mina采用I/O多路复用技术,如NIO(非阻塞I/O)和EPOLL,通过事件驱动模型处理网络连接,有效提升了并发处理能力。 2. **过滤器链**:Mina的过滤器链是其核心设计之一,它允许开发者插入自定义...

    Mina框架+常用JAR包

    1. **异步I/O模型**:Mina采用NIO(非阻塞I/O)模式,通过多路复用器和回调机制,提高了系统在高并发场景下的性能。 2. **丰富的协议库**:内建对多种网络协议的支持,方便开发者快速实现各种网络服务。 3. **过滤器...

    MINA长连接框架实现通讯

    8. **性能优化**:MINA框架允许开发者进行各种性能优化,例如调整缓冲区大小、选择合适的编码/解码器、合理设置线程池大小等,以适应不同规模的网络应用需求。 综上所述,MINA长连接框架在实现服务器与Android...

    apache mina-spring 服务端程序

    4. **协议编码解码器**:用于将网络传输的数据转换为业务对象,反之亦然,可能实现了Mina的ProtocolCodec接口。 5. **测试用例**:验证服务端功能的JUnit或其他测试框架的测试类。 通过这个项目,开发者可以学习到...

    基于MINA构建简单高性能的NIO应用.pdf

    3. **MINA的时间服务器示例**:如何使用MINA搭建一个基础的时间服务器,包括创建服务端监听器、定义协议解码器和编码器、处理客户端连接请求和发送时间响应等步骤。 4. **多客户端处理**:MINA如何通过Selector和多...

    Java-mina实现推送

    Mina提供了基于I/O多路复用技术(如NIO)的API,使得开发者可以轻松处理大量并发连接。其异步模型允许系统在处理新连接和数据传输时保持高效。在Java-Mina中,我们通常会创建一个`Acceptor`来监听客户端连接,并为每...

    Mina基础(一)

    1. **事件驱动模型**:Mina基于I/O多路复用技术,如Java的NIO(Non-blocking I/O),实现了一个事件驱动的模型。这意味着当数据准备好读取或写入时,Mina会触发相应的事件,而不是一直阻塞等待。 2. **Session**:...

    mina2.0.3源代码

    每个过滤器都可以对数据进行读取、修改或写入,这样可以实现解码、编码、安全加密、流量控制等功能。过滤器链的设计提高了代码的可重用性和模块化。 5. **多协议支持**: 虽然MINA最初设计用于TCP和UDP,但它也...

    mina2.0相关jar包

    - **自定义协议**:MINA允许用户实现自己的协议编码器和解码器,以满足特定业务需求。 总之,MINA 2.0是一个强大而灵活的Java网络编程框架,其核心优势在于简化网络编程的复杂性,提高程序的可扩展性和性能。通过...

    mina源代码学习提供下载

    4. **过滤器链**:MINA引入了过滤器的概念,数据在传输过程中会经过一系列过滤器,每个过滤器可以执行特定的操作,如编码、解码、日志记录等。这种设计使得模块化和复用变得简单。 5. **多线程支持**:MINA支持多...

Global site tag (gtag.js) - Google Analytics