在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的配置文件做一点修改:
将原来的:
改成:
这样,这个问题就解决了。想想原本的项目中,用的spring+mina没出现问题,真是个侥幸。。。
好了,下面把整合的写一下。
首先是用到的包,这里使用maven,pom.xml:
4.0.0
mymina
MyMina
0.0.1-SNAPSHOT
jar
MyMina
http://maven.apache.org
UTF-8
org.apache.felix
maven-bundle-plugin
true
org.slf4j
slf4j-jdk14
1.7.7
org.apache.mina
mina-integration-beans
2.0.7
org.springframework
spring-beans
4.0.6.RELEASE
org.apache.mina
mina-core
2.0.4
bundle
compile
org.apache.mina
mina-integration-spring
1.1.7
junit
junit
3.8.1
test
org.springframework
spring-context
4.0.6.RELEASE
org.slf4j
slf4j-log4j12
1.3.0
这里面有几个配置是比较讲究的,包括那个plugin和mina-core中的配置,配置有点差别,会报一个bundle的错误。
因为用maven,会方便很多,找包的时候,知道依赖就可以了。这里有个网站,可以查找自己需要的依赖包:http://mvnrepository.com/ ,这个网站很不错,类似以前的findjar.com。
然后是spring整合的配置:
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
这里需要注意的问题,前面已经有写。
再者就是服务端和客户端的代码编写,服务端已经和spring整合了,里面配置了服务端的handler,所以这里主要是服务端的handler:
packagecn.org.handler;importorg.apache.mina.core.service.IoHandlerAdapter;importorg.apache.mina.core.session.IdleStatus;importorg.apache.mina.core.session.IoSession;public class HandlerTwo extendsIoHandlerAdapter {
@Overridepublic voidmessageReceived(IoSession session, Object message)throwsException {//TODO Auto-generated method stub//super.messageReceived(session, message);
System.out.println("received message :"+message);
}
@Overridepublic void sessionClosed(IoSession session) throwsException {//TODO Auto-generated method stub
super.sessionClosed(session);
}
@Overridepublic voidsessionIdle(IoSession session, IdleStatus status)throwsException {//TODO Auto-generated method stub
super.sessionIdle(session, status);
}
}
写一个启动入口:
packagecn.org.test;importorg.springframework.context.support.ClassPathXmlApplicationContext;public classTest {/***@paramargs*/
public static voidmain(String[] args) {
ClassPathXmlApplicationContext ct= new ClassPathXmlApplicationContext("applicationContext-mina.xml");
}
}
还缺少一个服务端的编码过滤器:
packagecn.org.handler;importjava.nio.charset.Charset;importorg.apache.mina.core.session.IoSession;importorg.apache.mina.filter.codec.ProtocolCodecFactory;importorg.apache.mina.filter.codec.ProtocolDecoder;importorg.apache.mina.filter.codec.ProtocolEncoder;importorg.apache.mina.filter.codec.textline.LineDelimiter;importorg.apache.mina.filter.codec.textline.TextLineDecoder;importorg.apache.mina.filter.codec.textline.TextLineEncoder;public class MyCodeFactory implementsProtocolCodecFactory {private finalTextLineEncoder encoder;private finalTextLineDecoder decoder;/*final static char endchar = 0x1a;*/
final static char endchar = 0x0d;publicMyCodeFactory() {this(Charset.forName("gb2312"));
}publicMyCodeFactory(Charset charset) {
encoder= newTextLineEncoder(charset, LineDelimiter.UNIX);
decoder= newTextLineDecoder(charset, LineDelimiter.AUTO);
}public ProtocolDecoder getDecoder(IoSession session) throwsException {//TODO Auto-generated method stub
returndecoder;
}public ProtocolEncoder getEncoder(IoSession session) throwsException {//TODO Auto-generated method stub
returnencoder;
}public intgetEncoderMaxLineLength() {returnencoder.getMaxLineLength();
}public void setEncoderMaxLineLength(intmaxLineLength) {
encoder.setMaxLineLength(maxLineLength);
}public intgetDecoderMaxLineLength() {returndecoder.getMaxLineLength();
}public void setDecoderMaxLineLength(intmaxLineLength) {
decoder.setMaxLineLength(maxLineLength);
}
}
这样,运行入口程序,服务端就启动了。除了入口,在spring中都有配置,包括端口这些。
然后写一个客户端:
客户端的handler:
packagecn.org.handler;importorg.apache.mina.core.service.IoHandlerAdapter;importorg.apache.mina.core.session.IdleStatus;importorg.apache.mina.core.session.IoSession;public class HandlerOne extendsIoHandlerAdapter {
@Overridepublic voidmessageReceived(IoSession session, Object message)throwsException {//TODO Auto-generated method stub//super.messageReceived(session, message);
System.out.println("message :"+message);
}
@Overridepublic void sessionClosed(IoSession session) throwsException {//TODO Auto-generated method stub
super.sessionClosed(session);
}
@Overridepublic voidsessionIdle(IoSession session, IdleStatus status)throwsException {//TODO Auto-generated method stub
super.sessionIdle(session, status);
}
@Overridepublic void messageSent(IoSession session, Object message) throwsException {
System.out.println("发送的消息是:"+message.toString());//super.messageSent(session, message);
}
@Overridepublic void sessionCreated(IoSession session) throwsException {super.sessionCreated(session);
}
@Overridepublic void sessionOpened(IoSession session) throwsException {super.sessionOpened(session);
}
}
客户端的入口:
packagecn.org.test;importjava.net.InetSocketAddress;importjava.nio.charset.Charset;importorg.apache.mina.core.future.ConnectFuture;importorg.apache.mina.filter.codec.ProtocolCodecFilter;importorg.apache.mina.filter.codec.textline.TextLineCodecFactory;importorg.apache.mina.filter.logging.LoggingFilter;importorg.apache.mina.transport.socket.nio.NioSocketConnector;importcn.org.handler.HandlerOne;public classClintTest {/***@paramargs*/
public static voidmain(String[] args) {//创建客户端连接器.
NioSocketConnector connector = newNioSocketConnector();
connector.getFilterChain().addLast("logger", newLoggingFilter() );
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