• 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

  • 相关阅读:
    call方法的实现
    es6扩展字符串
    关于this的错题
    当promise实例A的resolve值为另一个promise实例对象B时,这个实例对象B的状态会替代实例对象A的状态。
    new Promise 出来的promise实例对象的默认状态是pendding,不能像then/catch方法一样返回一个新的promise实例对象!!!
    中断promise链式调用(中间返回一个pendding状态的promise)
    测试分析promise异常穿透原理
    .then内的回调函数返回结果为一个promise实例对象时,这个.then返回的promise结果就是回调函数内的promise实例对象的返回结果(等待回调函数内的promise实例对象有了结果再返回)
    vue 学习笔记(一)
    three.js初涉略(一)
  • 原文地址:https://www.cnblogs.com/juepei/p/3940396.html
Copyright © 2020-2023  润新知