Mina入门教程(二)----Spring4 集成Mina

在spring和mina集成的时候,要十分注意一个问题:版本。

这是一个非常严重的问题,mina官网的demo没错,网上很多网友总结的代码也是对的,但是很多人将mina集成到spring中的时候,总是会发现有个问题:

java.lang.IllegalArgumentException: Cannot convert value of type [org.apache.mina.integration.beans.InetSocketAddressEditor] to required
 type [java.lang.Class] for property ‘customEditors[java.net.SocketAddress]‘: PropertyEditor .....

类型不匹配。估计很多人按照网上的demo来做的话,都会遇到这个错误(除非spring是用的2.5或者之前的版本)。这是因为新版的spring有改动:

将一个PropertyEditor 实例传入CustomEditorConfigurer 已经被废除了

所以很多人会遇到这个错误。笔者也是查了N久资料,发现某位学php的牛人解决了该问题。是对spring的配置文件做一点修改:
将原来的:

<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
    <property name="customEditors">
        <map>
            <entry key="java.net.SocketAddress">
                <bean class="org.apache.mina.integration.beans.InetSocketAddressEditor" />

            </entry>
        </map>
    </property>
</bean>

改成:

    <bean
        class="org.springframework.beans.factory.config.CustomEditorConfigurer">
        <property name="customEditors">
            <map>         <!-- 修改这里 -->
                <entry key="java.net.SocketAddress" value="org.apache.mina.integration.beans.InetSocketAddressEditor" >
                </entry>
            </map>
        </property>
    </bean>

这样,这个问题就解决了。想想原本的项目中,用的spring+mina没出现问题,真是个侥幸。。。

好了,下面把整合的写一下。

首先是用到的包,这里使用maven,pom.xml:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>mymina</groupId>
  <artifactId>MyMina</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>MyMina</name>
  <url>http://maven.apache.org</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

<build>
    <plugins>
    <plugin>
    <groupId>org.apache.felix</groupId>
    <artifactId>maven-bundle-plugin</artifactId>
    <extensions>true</extensions>
</plugin>
    </plugins>
</build>

  <dependencies>

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-jdk14</artifactId>
    <version>1.7.7</version>
</dependency>
  <dependency>
    <groupId>org.apache.mina</groupId>
    <artifactId>mina-integration-beans</artifactId>
    <version>2.0.7</version>
</dependency>
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-beans</artifactId>
    <version>4.0.6.RELEASE</version>
</dependency>
      <dependency>
        <groupId>org.apache.mina</groupId>
            <artifactId>mina-core</artifactId>
            <version>2.0.4</version>
             <type>bundle</type>
           <scope>compile</scope>
    </dependency>
    <dependency>
    <groupId>org.apache.mina</groupId>
    <artifactId>mina-integration-spring</artifactId>
    <version>1.1.7</version>
    </dependency>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
        <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>4.0.6.RELEASE</version>
    </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.3.0</version>
        </dependency>
  </dependencies>
</project>

这里面有几个配置是比较讲究的,包括那个plugin和mina-core中的配置,配置有点差别,会报一个bundle的错误。
因为用maven,会方便很多,找包的时候,知道依赖就可以了。这里有个网站,可以查找自己需要的依赖包:http://mvnrepository.com/ ,这个网站很不错,类似以前的findjar.com。

然后是spring整合的配置:

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
    <bean
        class="org.springframework.beans.factory.config.CustomEditorConfigurer">
        <property name="customEditors">
            <map>
                <entry key="java.net.SocketAddress" value="org.apache.mina.integration.beans.InetSocketAddressEditor" >
                </entry>
            </map>
        </property>
    </bean>

    <bean id="ioAcceptor"
        class="org.apache.mina.transport.socket.nio.NioSocketAcceptor"
        init-method="bind" destroy-method="unbind">

        <property name="defaultLocalAddress" value=":8888" />
        <property name="handler" ref="SampleHandler" />
        <property name="filterChainBuilder" ref="filterChainBuilder" />
        <property name="reuseAddress" value="true" />

    </bean>
    <bean id="executorFilter"
        class="org.apache.mina.filter.executor.ExecutorFilter" />
    <bean id="mdcInjectionFilter"
        class="org.apache.mina.filter.logging.MdcInjectionFilter">
        <constructor-arg value="remoteAddress" />
    </bean>
    <bean id="codecFilter"
        class="org.apache.mina.filter.codec.ProtocolCodecFilter">
        <constructor-arg>
        <!--
            <bean
                class="org.apache.mina.filter.codec.textline.TextLineCodecFactory" />
                -->
                <bean class="cn.org.handler.MyCodeFactory"></bean>
        </constructor-arg>
    </bean>
    <bean id="loggingFilter"
        class="org.apache.mina.filter.logging.LoggingFilter" />
    <bean id="SampleHandler" class="cn.org.handler.HandlerTwo" />
    <!--boss server  -->
    <bean id="bossSampleHandler" class="cn.org.handler.HandlerOne" />

    <bean id="filterChainBuilder"
        class="org.apache.mina.core.filterchain.DefaultIoFilterChainBuilder">
        <property name="filters">
            <map>
                <entry key="executor" value-ref="executorFilter" />
                <entry key="mdcInjectionFilter"
                    value-ref="mdcInjectionFilter" />
                <entry key="codecFilter" value-ref="codecFilter" />
                <entry key="loggingFilter" value-ref="loggingFilter" />
            </map>
        </property>
    </bean>
</beans>

这里需要注意的问题,前面已经有写。
再者就是服务端和客户端的代码编写,服务端已经和spring整合了,里面配置了服务端的handler,所以这里主要是服务端的handler:

package cn.org.handler;

import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.core.session.IoSession;

public class HandlerTwo extends IoHandlerAdapter {

    @Override
    public void messageReceived(IoSession session, Object message)
            throws Exception {
        // TODO Auto-generated method stub
    //    super.messageReceived(session, message);
        System.out.println("received message :"+message);
    }

    @Override
    public void sessionClosed(IoSession session) throws Exception {
        // TODO Auto-generated method stub
        super.sessionClosed(session);
    }

    @Override
    public void sessionIdle(IoSession session, IdleStatus status)
            throws Exception {
        // TODO Auto-generated method stub
        super.sessionIdle(session, status);
    }

}

写一个启动入口:

package cn.org.test;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test {
    /**
     * @param args
     */
    public static void main(String[] args) {
        ClassPathXmlApplicationContext ct =    new ClassPathXmlApplicationContext("applicationContext-mina.xml");
    }

}

还缺少一个服务端的编码过滤器:

package cn.org.handler;

import java.nio.charset.Charset;

import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolCodecFactory;
import org.apache.mina.filter.codec.ProtocolDecoder;
import org.apache.mina.filter.codec.ProtocolEncoder;
import org.apache.mina.filter.codec.textline.LineDelimiter;
import org.apache.mina.filter.codec.textline.TextLineDecoder;
import org.apache.mina.filter.codec.textline.TextLineEncoder;

public  class MyCodeFactory implements ProtocolCodecFactory {

        private final TextLineEncoder encoder;
        private final TextLineDecoder decoder;
        /*final static char endchar = 0x1a;*/
        final static char endchar = 0x0d;
        public MyCodeFactory() {
            this(Charset.forName("gb2312"));
        }
        public MyCodeFactory(Charset charset) {
             encoder = new TextLineEncoder(charset, LineDelimiter.UNIX);
             decoder = new TextLineDecoder(charset, LineDelimiter.AUTO);
             }

        public ProtocolDecoder getDecoder(IoSession session) throws Exception {
            // TODO Auto-generated method stub
            return decoder;
        }
        public ProtocolEncoder getEncoder(IoSession session) throws Exception {
            // TODO Auto-generated method stub
            return encoder;
        }
        public int getEncoderMaxLineLength() {
            return encoder.getMaxLineLength();
        }
        public void setEncoderMaxLineLength(int maxLineLength) {
            encoder.setMaxLineLength(maxLineLength);
        }
        public int getDecoderMaxLineLength() {
            return decoder.getMaxLineLength();
        }
        public void setDecoderMaxLineLength(int maxLineLength) {
            decoder.setMaxLineLength(maxLineLength);
        }

}

这样,运行入口程序,服务端就启动了。除了入口,在spring中都有配置,包括端口这些。

然后写一个客户端:

客户端的handler:

package cn.org.handler;

import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.core.session.IoSession;

public class HandlerOne extends IoHandlerAdapter {
    @Override
    public void messageReceived(IoSession session, Object message)
            throws Exception {
        // TODO Auto-generated method stub
        //super.messageReceived(session, message);
        System.out.println("message :"+message);
    }

    @Override
    public void sessionClosed(IoSession session) throws Exception {
        // TODO Auto-generated method stub
        super.sessionClosed(session);
    }

    @Override
    public void sessionIdle(IoSession session, IdleStatus status)
            throws Exception {
        // TODO Auto-generated method stub
        super.sessionIdle(session, status);
    }

    @Override
    public void messageSent(IoSession session, Object message) throws Exception {

        System.out.println("发送的消息是:"+message.toString());
        //super.messageSent(session, message);
    }

    @Override
    public void sessionCreated(IoSession session) throws Exception {

        super.sessionCreated(session);
    }

    @Override
    public void sessionOpened(IoSession session) throws Exception {
        super.sessionOpened(session);
    }  

}

客户端的入口:

package cn.org.test;

import java.net.InetSocketAddress;
import java.nio.charset.Charset;

import org.apache.mina.core.future.ConnectFuture;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.filter.codec.textline.TextLineCodecFactory;
import org.apache.mina.filter.logging.LoggingFilter;
import org.apache.mina.transport.socket.nio.NioSocketConnector;

import cn.org.handler.HandlerOne;

public class ClintTest {

    /**
     * @param args
     */
    public static void main(String[] args) {
        // 创建客户端连接器.
        NioSocketConnector connector = new NioSocketConnector();
        connector.getFilterChain().addLast( "logger", new LoggingFilter() );
        connector.getFilterChain().addLast( "codec", new ProtocolCodecFilter( new TextLineCodecFactory( Charset.forName( "GBK" )))); //设置编码过滤器
        connector.setHandler(new HandlerOne());//设置事件处理器
        ConnectFuture cf = connector.connect(
        new InetSocketAddress("127.0.0.1", 8888));//建立连接
        cf.awaitUninterruptibly();//等待连接创建完成
        cf.getSession().write("知识");//发送消息
        cf.getSession().close(true);
        cf.getSession().getCloseFuture().awaitUninterruptibly();//等待连接断开
        connector.dispose(); 

    }

}

这样,当服务端启动的时候,客户端发送一个信息,服务端就会收到,并作相应的处理。
运行结果

客户端控制台输出:

SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/C:/Users/wanglei/.m2/repository/org/slf4j/slf4j-jdk14/1.7.7/slf4j-jdk14-1.7.7.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/C:/Users/wanglei/.m2/repository/org/slf4j/slf4j-log4j12/1.3.0/slf4j-log4j12-1.3.0.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: Actual binding is of type [org.slf4j.impl.JDK14LoggerFactory]
八月 27, 2014 8:50:10 下午 org.apache.mina.filter.logging.LoggingFilter log
信息: CREATED
八月 27, 2014 8:50:10 下午 org.apache.mina.filter.logging.LoggingFilter log
信息: OPENED
八月 27, 2014 8:50:10 下午 org.apache.mina.filter.logging.LoggingFilter log
信息: SENT: HeapBuffer[pos=0 lim=0 cap=0: empty]
发送的消息是:知识
八月 27, 2014 8:50:10 下午 org.apache.mina.filter.logging.LoggingFilter log
信息: CLOSED

服务端输出:

SLF4J: Found binding in [jar:file:/C:/Users/wanglei/.m2/repository/org/slf4j/slf4j-log4j12/1.3.0/slf4j-log4j12-1.3.0.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: Actual binding is of type [org.slf4j.impl.JDK14LoggerFactory]
八月 27, 2014 8:50:10 下午 org.apache.mina.filter.logging.LoggingFilter log
信息: CREATED
八月 27, 2014 8:50:10 下午 org.apache.mina.filter.logging.LoggingFilter log
信息: OPENED
八月 27, 2014 8:50:10 下午 org.apache.mina.filter.logging.LoggingFilter log
信息: RECEIVED: 知识
received message :知识
八月 27, 2014 8:50:10 下午 org.apache.mina.filter.logging.LoggingFilter log
信息: CLOSED

时间: 2024-10-05 20:43:14

Mina入门教程(二)----Spring4 集成Mina的相关文章

C语言快速入门教程(二)

C语言快速入门教程(二) C语言的基本语法 本节学习路线图: 引言: C语言,顾名思义就是一门语言,可以类比一下英语; 你要说出一个英语的句子需要:  单词  +  语法!  将单词按照一定的语法拼凑起来就成了一个英语句子了; C语言同样是这样,只不过单词可以理解为一些固定的知识点,而语法可以理解为算法(可以理解为解决问题的方法) 在这一节中我们就对固定知识点中的语言描述与数据存储进行解析! 1.C语言的基本元素 1.1  标识符 什么是标识符? 答:在C语言中,符号常量,变量,数组,函数等都需

DataVeryLite入门教程(二) Entity篇

DataVeryLite 是基于.net 4.0的数据库持久化ORM框架. 目前支持的数据库有Sqlserver,Mysql,Oracle,Db2,PostgreSql,Sqlite和Access. 最好先阅读DataVeryLite入门教程(一) 配置篇,然后再阅读本篇.如果你觉得麻烦也可以跳过. Entity是ORM中的核心对象之一,一个继承Entity的对象对应于数据库中的一个表. Entity提供丰富的API对表中的单条数据进行操作. 比如根据id或其他条件,加载,删除,插入,更新和部分

Spring Cloud 入门教程(二): 配置管理

使用Config Server,您可以在所有环境中管理应用程序的外部属性.客户端和服务器上的概念映射与Spring Environment和PropertySource抽象相同,因此它们与Spring应用程序非常契合,但可以与任何以任何语言运行的应用程序一起使用.随着应用程序通过从开发人员到测试和生产的部署流程,您可以管理这些环境之间的配置,并确定应用程序具有迁移时需要运行的一切.服务器存储后端的默认实现使用git,因此它轻松支持标签版本的配置环境,以及可以访问用于管理内容的各种工具.很容易添加

jQuery 入门教程(二): 基本语法

学习jQuery之前需要你有下面几个方面的基本知识 HTML CSS JavaScript jQuery 的基本语法 $(selector).action() $ 符合定义这是一个jQuery语句 (selector) 用来选择某个HTML元素,其语法和CSS的selector语法一样. action() 定义操作该HTML元素的方法. 比如: $(this).hide() – 隐藏当前元素. $("p").hide() – 隐藏所以 <p> 元素. $(".te

Git的入门教程&lt;二&gt;

Git 的入门教程<二> 4> git远程仓库的使用 我们在使用git进行代码管理的时候,协同办公,需要一个24小时不间断的隐形同事,此时,如果在局域网内,则直接开一台局域网内的24小时开机运行的机器就可以,但是如果在homework的时候就需要这个24小时运行的机器拥有独立的外网IP,这样消耗就比较大,幸好,网上有一个github,提供给我们一个免费的仓库,让我们可以在同事之前推送代码,下面介绍github的使用. 4.1 github的使用 首先 登录github的官网: https

BootStrap入门教程 (二)

上讲回顾:Bootstrap的手脚架(Scaffolding)提供了固定(fixed)和流式(fluid)两种布局,它同时建立了一个宽达940px和12列的格网系统. 基于手脚架(Scaffolding)之上,Bootstrap的基础CSS(Base CSS)提供了一系列的基础Html页面要素,旨在为用户提供新鲜.一致的页面外观和感觉.本文将主要深入讲解排版(Typography),表格(Table),表单(Forms),按钮(Buttons)这四个方面的内容. 排版 (Typography),

PySide——Python图形化界面入门教程(二)

PySide——Python图形化界面入门教程(二) ——交互Widget和布局容器 ——Interactive Widgets and Layout Containers 原文链接:http://pythoncentral.io/pyside-pyqt-tutorial-interactive-widgets-and-layout-containers/ 上一个教程中,我们了解了一些QWidget提供的功能,还有一个特殊的子类QLabel.更进一步的,我们完成了一个用来说明简单Python/Q

无废话ExtJs 入门教程二[Hello World]

无废话ExtJs 入门教程二[Hello World] extjs技术交流,欢迎加群(201926085) 我们在学校里学习任何一门语言都是从"Hello World"开始,这里我们也不例外. 1.代码如下: 1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&

无废话ExtJs 入门教程二十一[继承:Extend]

无废话ExtJs 入门教程二十一[继承:Extend] extjs技术交流,欢迎加群(201926085) 在开发中,我们在使用视图组件时,经常要设置宽度,高度,标题等属性.而这些属性可以通过“继承”定义在我们定义的新组件中,从而达到重用的目地. 1.代码如下: 1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-

Elasticsearch入门教程(二):Elasticsearch核心概念

原文:Elasticsearch入门教程(二):Elasticsearch核心概念 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/vbirdbest/article/details/79200022 基本概念介绍 Elasticsearch是一个基于Lucene构建的开源.分布式.RESTful的搜索引擎,能够实现近实时(NRT)搜索,稳定.可靠.安装方便.Elasticsearch 不