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

在spring和mina集成的時候,要十分注意一個問題:版本。php

這是一個很是嚴重的問題,mina官網的demo沒錯,網上不少網友總結的代碼也是對的,可是不少人將mina集成到spring中的時候,老是會發現有個問題:html

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有改動:java

將一個PropertyEditor 實例傳入CustomEditorConfigurer 已經被廢除了

因此不少人會遇到這個錯誤。筆者也是查了N久資料,發現某位學php的牛人解決了該問題。是對spring的配置文件作一點修改:
將原來的: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>

改爲:apache

    <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沒出現問題,真是個僥倖。。。session

好了,下面把整合的寫一下。app

首先是用到的包,這裏使用maven,pom.xml:socket

<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。maven

而後是spring整合的配置:ide

<?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

相關文章
相關標籤/搜索